aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-10-21 15:38:10 -0400
committerDavid Robillard <d@drobilla.net>2022-01-28 21:57:07 -0500
commitb404312686874e539b617d1f27ccbaa5a82936af (patch)
treec2fdb2cc046e6da53071629cd1750dcc327e6cd9 /test
parentd4aec28ba8ad24d5aef3ee12beeb1b805148eab1 (diff)
downloadserd-b404312686874e539b617d1f27ccbaa5a82936af.tar.gz
serd-b404312686874e539b617d1f27ccbaa5a82936af.tar.bz2
serd-b404312686874e539b617d1f27ccbaa5a82936af.zip
Replace serdi with more fine-grained tools
Especially with the new functionality, the complexity of the command-line interface alone was really becoming unmanageable. The serdi implementation also had the highest cyclomatic complexity of the entire codebase by a huge margin. So, take a page from the Unix philosophy and split serdi into several more finely-honed tools that can be freely composed. Though there is still unfortunately quite a bit of option overlap between them due to the common details of reading RDF, I think the resulting tools are a lot easier to understand, both from a user and a developer perspective.
Diffstat (limited to 'test')
-rw-r--r--test/NQuadsTests/meson.build13
-rw-r--r--test/NTriplesTests/meson.build13
-rw-r--r--test/TriGTests/meson.build13
-rw-r--r--test/TurtleTests/meson.build13
-rw-r--r--test/bad/meson.build11
-rw-r--r--test/canon/meson.build4
-rw-r--r--test/filter/input.ttl9
-rw-r--r--test/filter/manifest.ttl48
-rw-r--r--test/filter/meson.build15
-rw-r--r--test/filter/o1.pattern.nt1
-rw-r--r--test/filter/o1.result.nt2
-rw-r--r--test/filter/p1.pattern.nt1
-rw-r--r--test/filter/p1.result.nt2
-rw-r--r--test/filter/s1.pattern.nt1
-rw-r--r--test/filter/s1.result.nt2
-rw-r--r--test/good/meson.build13
-rw-r--r--test/lax/meson.build13
-rw-r--r--test/meson.build393
-rw-r--r--test/pattern/meson.build21
-rwxr-xr-xtest/run_filter_suite.py160
-rwxr-xr-xtest/run_pipe_suite.py (renamed from test/run_test_suite.py)183
-rwxr-xr-xtest/run_sort_suite.py234
-rw-r--r--test/serd_test_util/__init__.py71
-rw-r--r--test/sort/GOPS.nq10
-rw-r--r--test/sort/GOSP.nq10
-rw-r--r--test/sort/GPSO.nq10
-rw-r--r--test/sort/GSOP.nq10
-rw-r--r--test/sort/GSPO.nq10
-rw-r--r--test/sort/OPS.nq10
-rw-r--r--test/sort/OSP.nq10
-rw-r--r--test/sort/POS.nq10
-rw-r--r--test/sort/PSO.nq10
-rw-r--r--test/sort/SOP.nq10
-rw-r--r--test/sort/SPO.nq10
-rw-r--r--test/sort/input.trig19
-rw-r--r--test/sort/pretty.nq10
-rw-r--r--test/terse/meson.build29
-rwxr-xr-xtest/test_base.py46
-rwxr-xr-xtest/test_empty.py4
-rwxr-xr-xtest/test_filter.py14
-rwxr-xr-xtest/test_grep.py13
-rwxr-xr-xtest/test_multifile.py4
-rw-r--r--test/test_node_syntax.c3
-rwxr-xr-xtest/test_quiet.py6
-rwxr-xr-xtest/test_sort.py112
-rwxr-xr-xtest/test_stdin.py10
-rwxr-xr-xtest/test_write_error.py6
47 files changed, 1307 insertions, 315 deletions
diff --git a/test/NQuadsTests/meson.build b/test/NQuadsTests/meson.build
index 4fe84dd5..deaf41e8 100644
--- a/test/NQuadsTests/meson.build
+++ b/test/NQuadsTests/meson.build
@@ -7,8 +7,15 @@ args = [
]
test('NQuads',
- run_test_suite,
- args: script_args + args,
+ run_pipe_suite,
+ args: pipe_test_script_args + args,
env: test_env,
- suite: ['suite', 'w3c'],
+ suite: ['suite', 'w3c', 'pipe'],
+ timeout: 240)
+
+test('NQuads',
+ run_sort_suite,
+ args: sort_test_script_args + args,
+ env: test_env,
+ suite: ['suite', 'w3c', 'sort'],
timeout: 240)
diff --git a/test/NTriplesTests/meson.build b/test/NTriplesTests/meson.build
index cf773c64..f608e973 100644
--- a/test/NTriplesTests/meson.build
+++ b/test/NTriplesTests/meson.build
@@ -7,8 +7,15 @@ args = [
]
test('NTriples',
- run_test_suite,
- args: script_args + args,
+ run_pipe_suite,
+ args: pipe_test_script_args + args,
env: test_env,
- suite: ['suite', 'w3c'],
+ suite: ['suite', 'w3c', 'pipe'],
+ timeout: 240)
+
+test('NTriples',
+ run_sort_suite,
+ args: sort_test_script_args + args,
+ env: test_env,
+ suite: ['suite', 'w3c', 'sort'],
timeout: 240)
diff --git a/test/TriGTests/meson.build b/test/TriGTests/meson.build
index e7c305e0..95641b44 100644
--- a/test/TriGTests/meson.build
+++ b/test/TriGTests/meson.build
@@ -7,8 +7,15 @@ args = [
]
test('TriG',
- run_test_suite,
- args: script_args + args,
+ run_pipe_suite,
+ args: pipe_test_script_args + args,
env: test_env,
- suite: ['suite', 'w3c'],
+ suite: ['suite', 'w3c', 'pipe'],
+ timeout: 240)
+
+test('TriG',
+ run_sort_suite,
+ args: sort_test_script_args + args,
+ env: test_env,
+ suite: ['suite', 'w3c', 'sort'],
timeout: 240)
diff --git a/test/TurtleTests/meson.build b/test/TurtleTests/meson.build
index 492e1fe0..7a6d1475 100644
--- a/test/TurtleTests/meson.build
+++ b/test/TurtleTests/meson.build
@@ -7,8 +7,15 @@ args = [
]
test('Turtle',
- run_test_suite,
- args: script_args + args,
+ run_pipe_suite,
+ args: pipe_test_script_args + args,
env: test_env,
- suite: ['suite', 'w3c'],
+ suite: ['suite', 'w3c', 'pipe'],
+ timeout: 240)
+
+test('Turtle',
+ run_sort_suite,
+ args: sort_test_script_args + args,
+ env: test_env,
+ suite: ['suite', 'w3c', 'sort'],
timeout: 240)
diff --git a/test/bad/meson.build b/test/bad/meson.build
index 9c423367..2c99bbac 100644
--- a/test/bad/meson.build
+++ b/test/bad/meson.build
@@ -1,8 +1,15 @@
base_uri = 'http://drobilla.net/sw/serd/test/bad/'
test('bad',
- run_test_suite,
- args: script_args + [files('manifest.ttl'), base_uri],
+ run_pipe_suite,
+ args: pipe_test_script_args + [files('manifest.ttl'), base_uri],
env: test_env,
suite: ['suite', 'extra'],
timeout: 240)
+
+test('bad',
+ run_sort_suite,
+ args: sort_test_script_args + [files('manifest.ttl'), base_uri],
+ env: test_env,
+ suite: ['suite', 'extra', 'sort'],
+ timeout: 240)
diff --git a/test/canon/meson.build b/test/canon/meson.build
index 11d95469..f73a3527 100644
--- a/test/canon/meson.build
+++ b/test/canon/meson.build
@@ -1,8 +1,8 @@
base_uri = 'http://drobilla.net/sw/serd/test/canon/'
test('canon',
- run_test_suite,
- args: script_args + [
+ run_pipe_suite,
+ args: pipe_test_script_args + [
files('manifest.ttl'),
base_uri,
'--',
diff --git a/test/filter/input.ttl b/test/filter/input.ttl
new file mode 100644
index 00000000..59aa67f7
--- /dev/null
+++ b/test/filter/input.ttl
@@ -0,0 +1,9 @@
+@prefix eg: <http://example.org/> .
+
+eg:s1
+ eg:p1 eg:o1 ;
+ eg:p2 eg:o2 .
+
+eg:s2
+ eg:p1 eg:o1 ;
+ eg:p2 eg:o2 .
diff --git a/test/filter/manifest.ttl b/test/filter/manifest.ttl
new file mode 100644
index 00000000..59ce3f55
--- /dev/null
+++ b/test/filter/manifest.ttl
@@ -0,0 +1,48 @@
+@prefix checks: <http://drobilla.net/ns/serd/checks#> .
+@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix rdft: <http://www.w3.org/ns/rdftest#> .
+@prefix serd: <http://drobilla.net/ns/serd#> .
+
+rdft:Test
+ rdfs:subClassOf mf:ManifestEntry .
+
+serd:patternFile
+ a rdf:Property ;
+ rdfs:label "pattern file" .
+
+serd:TestFilterPositive
+ a rdfs:Class ;
+ rdfs:label "Positive Filtering" ;
+ rdfs:subClassOf rdft:Test .
+
+<>
+ a mf:Manifest ;
+ rdfs:comment "Serd filter test cases" ;
+ mf:entries (
+ <#s1>
+ <#p1>
+ <#o1>
+ ) .
+
+<#s1>
+ a serd:TestFilterPositive ;
+ serd:patternFile <s1.pattern.nt> ;
+ mf:name "s1" ;
+ mf:action <input.ttl> ;
+ mf:result <s1.result.nt> .
+
+<#p1>
+ a serd:TestFilterPositive ;
+ serd:patternFile <p1.pattern.nt> ;
+ mf:name "p1" ;
+ mf:action <input.ttl> ;
+ mf:result <p1.result.nt> .
+
+<#o1>
+ a serd:TestFilterPositive ;
+ serd:patternFile <o1.pattern.nt> ;
+ mf:name "o1" ;
+ mf:action <input.ttl> ;
+ mf:result <o1.result.nt> .
diff --git a/test/filter/meson.build b/test/filter/meson.build
new file mode 100644
index 00000000..fd2b1bca
--- /dev/null
+++ b/test/filter/meson.build
@@ -0,0 +1,15 @@
+base_uri = 'http://drobilla.net/sw/serd/test/filter/'
+
+test('filter',
+ run_filter_suite,
+ args: common_script_options + [
+ '--pipe',
+ serd_pipe,
+ '--filter',
+ serd_filter,
+ files('manifest.ttl'),
+ base_uri
+ ],
+ env: test_env,
+ suite: ['suite', 'extra'],
+ timeout: 240)
diff --git a/test/filter/o1.pattern.nt b/test/filter/o1.pattern.nt
new file mode 100644
index 00000000..41932fd7
--- /dev/null
+++ b/test/filter/o1.pattern.nt
@@ -0,0 +1 @@
+?s ?p <http://example.org/o1> .
diff --git a/test/filter/o1.result.nt b/test/filter/o1.result.nt
new file mode 100644
index 00000000..e7b1e759
--- /dev/null
+++ b/test/filter/o1.result.nt
@@ -0,0 +1,2 @@
+<http://example.org/s1> <http://example.org/p1> <http://example.org/o1> .
+<http://example.org/s2> <http://example.org/p1> <http://example.org/o1> .
diff --git a/test/filter/p1.pattern.nt b/test/filter/p1.pattern.nt
new file mode 100644
index 00000000..fca20e94
--- /dev/null
+++ b/test/filter/p1.pattern.nt
@@ -0,0 +1 @@
+?s <http://example.org/p1> ?o .
diff --git a/test/filter/p1.result.nt b/test/filter/p1.result.nt
new file mode 100644
index 00000000..e7b1e759
--- /dev/null
+++ b/test/filter/p1.result.nt
@@ -0,0 +1,2 @@
+<http://example.org/s1> <http://example.org/p1> <http://example.org/o1> .
+<http://example.org/s2> <http://example.org/p1> <http://example.org/o1> .
diff --git a/test/filter/s1.pattern.nt b/test/filter/s1.pattern.nt
new file mode 100644
index 00000000..f5b87db1
--- /dev/null
+++ b/test/filter/s1.pattern.nt
@@ -0,0 +1 @@
+<http://example.org/s1> ?p ?o .
diff --git a/test/filter/s1.result.nt b/test/filter/s1.result.nt
new file mode 100644
index 00000000..023faf42
--- /dev/null
+++ b/test/filter/s1.result.nt
@@ -0,0 +1,2 @@
+<http://example.org/s1> <http://example.org/p1> <http://example.org/o1> .
+<http://example.org/s1> <http://example.org/p2> <http://example.org/o2> .
diff --git a/test/good/meson.build b/test/good/meson.build
index 38c672ac..368a91bc 100644
--- a/test/good/meson.build
+++ b/test/good/meson.build
@@ -1,8 +1,15 @@
base_uri = 'http://drobilla.net/sw/serd/test/good/'
test('good',
- run_test_suite,
- args: script_args + [files('manifest.ttl'), base_uri],
+ run_pipe_suite,
+ args: pipe_test_script_args + [files('manifest.ttl'), base_uri],
env: test_env,
- suite: ['suite', 'extra'],
+ suite: ['suite', 'extra', 'pipe'],
+ timeout: 240)
+
+test('good',
+ run_sort_suite,
+ args: sort_test_script_args + [files('manifest.ttl'), base_uri],
+ env: test_env,
+ suite: ['suite', 'extra', 'sort'],
timeout: 240)
diff --git a/test/lax/meson.build b/test/lax/meson.build
index 6d4d7903..e71a677c 100644
--- a/test/lax/meson.build
+++ b/test/lax/meson.build
@@ -4,8 +4,8 @@ base_uri = 'http://drobilla.net/sw/serd/test/lax/'
# ... once with strict parsing to test the hard errors
test('lax.strict',
- run_test_suite,
- args: script_args + [files('manifest.ttl'), base_uri],
+ run_pipe_suite,
+ args: pipe_test_script_args + [files('manifest.ttl'), base_uri],
env: test_env,
is_parallel: false,
suite: ['suite', 'extra'],
@@ -13,14 +13,13 @@ test('lax.strict',
# ... and once with lax parsing to tolerate them
test('lax.lax',
- run_test_suite,
- args: script_args + [
+ run_pipe_suite,
+ args: pipe_test_script_args + [
files('manifest.ttl'),
base_uri,
'--',
- '-i',
- 'lax',
- ],
+ '-I', 'lax',
+ '-O', 'lax'],
env: test_env,
is_parallel: false,
suite: ['suite', 'extra'],
diff --git a/test/meson.build b/test/meson.build
index c19d99c0..9830a1dd 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -1,6 +1,8 @@
autoship = find_program('autoship', required: false)
-run_test_suite = find_program('run_test_suite.py')
+run_filter_suite = find_program('run_filter_suite.py')
+run_pipe_suite = find_program('run_pipe_suite.py')
+run_sort_suite = find_program('run_sort_suite.py')
wrapper = meson.get_cross_property('exe_wrapper', '')
@@ -50,185 +52,368 @@ if autoship.found()
test('autoship', autoship, args: ['test', serd_src_root], suite: 'data')
endif
-if is_variable('serdi')
-
- if wrapper != ''
- script_args = ['--wrapper', wrapper, '--serdi', serdi.full_path()]
- else
- script_args = ['--serdi', serdi.full_path()]
- endif
-
- serd_ttl = files('../serd.ttl')[0]
+serd_ttl = files('../serd.ttl')[0]
+common_script_options = []
+if wrapper != ''
+ common_script_options = ['--wrapper', wrapper]
+endif
- test('serd.ttl', serdi, args: [serd_ttl], env: test_env, suite: 'data')
+# Test serd-pipe as the main entry point to the common tool code
+if is_variable('serd_pipe')
+ tool = serd_pipe
+ pipe_test_script_args = common_script_options + ['--tool', serd_pipe]
- # Command line options
+ # Basic valid arguments
good_args = [
- ['-v'],
+ ['-V'],
['-h'],
- ['-k', '512', '-s', '<urn:eg:s> a <urn:eg:T> .'],
]
foreach args : good_args
- test(args[0], serdi, args: args, env: test_env, suite: ['serdi', 'options'])
+ test(args[0],
+ tool,
+ args: args,
+ env: test_env,
+ suite: ['tools', 'pipe', 'options'])
endforeach
+ # Basic invalid arguments
+
bad_args = [
- ['/no/such/file'],
- ['ftp://unsupported.org'],
- ['-F', '', '-G', ''],
- ['-F'],
- ['-F', '?s ?p ?o . ?q ?r ?s .', '-s', ''],
- ['-F', '?s ?p ?o .\n?q ?r ?s .\n', '-s', ''],
- ['-F', 'bad_pattern', '-s', ''],
- ['-G'],
- ['-G', '?s ?p ?o . ?q ?r ?s .', '-s', ''],
- ['-G', 'bad_pattern', '-s', ''],
+ ['-B', 'nonuriorpath'],
+ ['-B'],
+ ['-I', 'turtle'],
+ ['-I', 'unknown'],
['-I'],
- ['-b'],
+ ['-O', 'unknown'],
+ ['-O'],
['-b', '-1'],
- ['-b', '9223372036854775807'],
['-b', '1024junk'],
- ['-c'],
- ['-i', 'unknown'],
- ['-i', 'turtle'],
- ['-i'],
- ['-fi'],
- ['-k'],
+ ['-b', '9223372036854775807'],
+ ['-b'],
['-k', '-1'],
- ['-k', '9223372036854775807'],
['-k', '1024junk'],
- ['-o', 'unknown'],
+ ['-k', '9223372036854775807'],
+ ['-k'],
['-o'],
- ['-p'],
- ['-r'],
+ ['-s', '<foo> a <Bar> .'],
['-s'],
- ['-w'],
['-z'],
- ['-s', '<foo> a <Bar> .'],
+ ['/no/such/file'],
]
foreach args : bad_args
- name = ' '.join(args).underscorify()
- test(name, serdi,
+ test(' '.join(args),
+ tool,
args: args,
env: test_env,
should_fail: true,
- suite: ['serdi', 'options'])
+ suite: ['tools', 'pipe', 'options'])
endforeach
- test('ansi_clicolor_force',
- serdi,
- args: files('bad/bad-lang.ttl'),
- env: test_env + ['CLICOLOR_FORCE=1'],
- should_fail: true)
-
- test('ansi_clicolor_off',
- serdi,
- args: files('bad/bad-lang.ttl'),
- env: test_env + ['CLICOLOR=0'],
- should_fail: true)
-
- test('ansi_no_color',
- serdi,
- args: files('bad/bad-lang.ttl'),
- env: test_env + ['NO_COLOR=1'],
- should_fail: true)
-
test('none',
- serdi,
+ tool,
env: test_env,
should_fail: true,
- suite: ['serdi', 'options'])
+ suite: ['tools', 'pipe', 'options'])
- test('quiet', files('test_quiet.py'),
- args: script_args + files('bad/bad-base.ttl'),
+ test('remote',
+ tool,
+ args: ['ftp://unsupported.org'],
env: test_env,
- suite: ['serdi', 'options'])
+ should_fail: true,
+ suite: ['tools', 'pipe', 'options'])
- test('filter', files('test_filter.py'),
- args: script_args,
+ test('bad_rebase',
+ tool,
+ args: ['-B', 'rebase', serd_ttl],
env: test_env,
- suite: ['serdi', 'options'])
+ should_fail: true,
+ suite: ['tools', 'pipe', 'options'])
- test('grep', files('test_grep.py'),
- args: script_args,
+ test('base', files('test_base.py'),
+ args: pipe_test_script_args,
env: test_env,
- suite: ['serdi', 'options'])
+ suite: ['tools', 'pipe', 'options'])
- # Inputs
+ test('dir_base',
+ tool,
+ args: ['-B', serd_src_root / '', serd_ttl],
+ env: test_env,
+ suite: ['tools', 'pipe', 'options'])
+
+ # Smoke test common handling code for environment color configuration
+
+ test('CLICOLOR_FORCE',
+ tool,
+ args: files('bad/bad-lang.ttl'),
+ env: test_env + ['CLICOLOR_FORCE=1'],
+ should_fail: true,
+ suite: ['color'])
+
+ test('CLICOLOR',
+ tool,
+ args: files('bad/bad-lang.ttl'),
+ env: test_env + ['CLICOLOR=0'],
+ should_fail: true,
+ suite: ['color'])
+
+ test('NO_COLOR',
+ tool,
+ args: files('bad/bad-lang.ttl'),
+ env: test_env + ['NO_COLOR=1'],
+ should_fail: true,
+ suite: ['color'])
+
+ # Different input sources
test('stdin', files('test_stdin.py'),
- args: script_args,
+ args: pipe_test_script_args,
env: test_env,
- suite: ['serdi', 'input'])
+ suite: ['tools', 'pipe', 'input'])
- test('multiple', files('test_multifile.py'),
- args: script_args + [meson.current_source_dir() / 'multifile'],
+ test('multifile', files('test_multifile.py'),
+ args: pipe_test_script_args + [meson.current_source_dir() / 'multifile'],
env: test_env,
- suite: ['serdi', 'input'])
+ suite: ['tools', 'pipe', 'input'])
- test('string', serdi,
- args: ['-s', '<foo> a <Bar> .'],
+ test('serd.ttl',
+ tool,
+ args: [serd_ttl],
env: test_env,
- should_fail: true,
- suite: ['serdi', 'input'])
+ suite: ['tools', 'pipe', 'input'])
- test('missing', serdi,
- args: ['-i', 'turtle'],
+ test('good_string',
+ tool,
+ args: ['-I', 'turtle', '-s', '[] a [] .'],
env: test_env,
- should_fail: true,
- suite: ['serdi', 'input'])
+ suite: ['tools', 'pipe', 'input'])
- test('no_such_file', serdi,
- args: ['no_such_file'],
+ test('baseless_string',
+ tool,
+ args: ['-s', '<foo> a <Bar> .'],
env: test_env,
should_fail: true,
- suite: ['serdi', 'input'])
+ suite: ['tools', 'pipe', 'input'])
- test('remote', serdi,
- args: ['ftp://example.org/unsupported.ttl'],
+ test('unknown_type',
+ tool,
+ args: files('../README.md'),
env: test_env,
should_fail: true,
- suite: ['serdi', 'input'])
+ suite: ['tools', 'pipe', 'input'])
- # Output
+ # Suppressed output
test('empty', files('test_empty.py'),
- args: script_args + [serd_ttl],
+ args: pipe_test_script_args + files('../serd.ttl'),
env: test_env,
- suite: 'output')
+ suite: ['tools', 'pipe', 'output'])
- # FIXME: Old base URI argument?
+ test('quiet', files('test_quiet.py'),
+ args: pipe_test_script_args + files('bad/bad-base.ttl'),
+ env: test_env,
+ suite: ['tools', 'pipe', 'output'])
# IO errors
- test('read_dir', serdi,
+ test('read_dir',
+ tool,
args: [meson.source_root()],
env: test_env,
should_fail: true,
- suite: 'io_errors')
+ suite: ['tools', 'pipe', 'input'])
if host_machine.system() == 'linux'
- test('unreadable', serdi,
+ test('unreadable',
+ tool,
args: ['/sys/bus/pci/rescan'],
env: test_env,
should_fail: true,
- suite: 'io_errors')
+ suite: ['tools', 'pipe', 'input'])
endif
test('write_error', files('test_write_error.py'),
- args: script_args + [serd_ttl],
+ args: pipe_test_script_args + [serd_ttl],
env: test_env,
- suite: 'io_errors')
+ suite: ['tools', 'pipe', 'output'])
- test('write_bad_file', serdi,
- args: ['-w', '/does/not/exist.ttl', meson.source_root() / 'serd.ttl'],
+ test('missing_output',
+ tool,
+ args: ['-o', '/does/not/exist.ttl', meson.source_root() / 'serd.ttl'],
env: test_env,
should_fail: true,
- suite: 'io_errors')
+ suite: ['tools', 'pipe', 'output'])
+endif
+
+# Test specifics for serd-sort
+if is_variable('serd_sort')
+ tool = serd_sort
+ sort_test_script_args = common_script_options + ['--tool', serd_sort]
+
+ # Basic valid arguments
+
+ good_args = [
+ ['-V'],
+ ['-h'],
+ ]
+
+ foreach args : good_args
+ test(args[0],
+ tool,
+ args: args,
+ env: test_env,
+ suite: ['tools', 'sort', 'options'])
+ endforeach
+
+ # Basic invalid arguments
+
+ bad_args = [
+ ['-c', 'CHAOS', '-'],
+ ['-o'],
+ ['-s'],
+ ['-z', '-'],
+ ['-z', '-'],
+ ['/no/such/file'],
+ ]
+
+ foreach args : bad_args
+ test(' '.join(args),
+ tool,
+ args: args,
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'sort', 'options'])
+ endforeach
+
+ test('none',
+ tool,
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'sort', 'options'])
+
+ # IO errors
+
+ test('read_dir',
+ tool,
+ args: [meson.source_root()],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'sort', 'input'])
+
+ test('missing_output',
+ tool,
+ args: ['-o', '/does/not/exist.ttl', meson.source_root() / 'serd.ttl'],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'sort', 'output'])
+
+ # Collation test suite
+
+ test('sort', files('test_sort.py'),
+ args: sort_test_script_args + files('sort/input.trig'),
+ env: test_env,
+ suite: ['tools', 'sort'])
+
+endif
+
+# Test specifics for serd-filter
+if is_variable('serd_filter')
+ tool = serd_filter
+ filter_test_script_args = common_script_options + ['--tool', serd_filter]
+
+ # Basic valid arguments
+
+ good_args = [
+ ['-V'],
+ ['-h'],
+ ]
+
+ foreach args : good_args
+ test(args[0],
+ tool,
+ args: args,
+ env: test_env,
+ suite: ['tools', 'filter', 'options'])
+ endforeach
+
+ # Basic invalid arguments
+
+ bad_args = [
+ ['-f', '/no/such/file.nt', '-'],
+ ['-z'],
+ ['?s ?p ?o .'],
+ ]
+
+ foreach args : bad_args
+ test(' '.join(args),
+ tool,
+ args: args,
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'filter', 'options'])
+ endforeach
+
+ test('garbage_pattern',
+ tool,
+ args: ['junk', serd_ttl],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'filter', 'options'])
+
+ test('multiple_patterns',
+ tool,
+ args: ['?s ?p ?o .\n?t ?u ?v .\n',
+ meson.source_root() / 'serd.ttl'],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'filter', 'output'])
+
+ test('missing_output',
+ tool,
+ args: ['-o', '/does/not/exist.ttl',
+ '?s ?p ?o .',
+ meson.source_root() / 'serd.ttl'],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'filter', 'output'])
+
+ # Different input sources
+
+ test('missing_input',
+ tool,
+ args: ['?s ?p ?o .', '/does/not/exist.ttl'],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'filter', 'input'])
+
+ test('filter_dir',
+ tool,
+ args: ['?s ?p ?o .', meson.source_root()],
+ env: test_env,
+ should_fail: true,
+ suite: ['tools', 'filter', 'input'])
+
+ # Filtering
+
+ test('filter', files('test_filter.py'),
+ args: filter_test_script_args,
+ env: test_env,
+ suite: ['tools'])
+
+ test('grep', files('test_grep.py'),
+ args: filter_test_script_args,
+ env: test_env,
+ suite: ['tools'])
+
+ # RDF-driven test suite
+ subdir('filter')
+
+endif
+# Run RDF-driven test suites using serd-pipe and serd-sort
+if is_variable('serd_pipe') and is_variable('serd_sort')
# RDF-driven test suites from the W3C
subdir('NQuadsTests')
subdir('NTriplesTests')
diff --git a/test/pattern/meson.build b/test/pattern/meson.build
index 1d5a2140..1216cfe0 100644
--- a/test/pattern/meson.build
+++ b/test/pattern/meson.build
@@ -1,14 +1,27 @@
base_uri = 'http://drobilla.net/sw/serd/test/pattern/'
test('pattern',
- run_test_suite,
- args: script_args + [
+ run_pipe_suite,
+ args: pipe_test_script_args + [
files('manifest.ttl'),
base_uri,
'--',
- '-i',
+ '-I',
'variables',
],
env: test_env,
- suite: ['suite', 'extra'],
+ suite: ['suite', 'extra', 'pipe'],
+ timeout: 240)
+
+test('pattern',
+ run_sort_suite,
+ args: sort_test_script_args + [
+ files('manifest.ttl'),
+ base_uri,
+ '--',
+ '-I',
+ 'variables',
+ ],
+ env: test_env,
+ suite: ['suite', 'extra', 'sort'],
timeout: 240)
diff --git a/test/run_filter_suite.py b/test/run_filter_suite.py
new file mode 100755
index 00000000..222b98e4
--- /dev/null
+++ b/test/run_filter_suite.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+
+"""Run the RDF-based test suite for serd-filter."""
+
+import serd_test_util
+
+import argparse
+import datetime
+import difflib
+import itertools
+import os
+import re
+import shlex
+import subprocess
+import sys
+import tempfile
+import urllib.parse
+
+
+def log_error(message):
+ """Log an error message to stderr"""
+
+ sys.stderr.write("error: ")
+ sys.stderr.write(message)
+
+
+def _uri_path(test_dir, uri):
+ path = urllib.parse.urlparse(uri).path
+ drive = os.path.splitdrive(path[1:])[0]
+ path = path if not drive else path[1:]
+ return os.path.join(test_dir, os.path.basename(path))
+
+
+def test_suite(
+ manifest_path,
+ base_uri,
+ filter_command_prefix,
+ pipe_command_prefix,
+ out_dir,
+):
+ """Run all tests in the manifest."""
+
+ mf = "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"
+ suite_dir = os.path.dirname(manifest_path)
+
+ model, instances = serd_test_util.load_rdf(
+ pipe_command_prefix + ["-B", base_uri], manifest_path
+ )
+
+ class Results:
+ def __init__(self):
+ self.n_tests = 0
+ self.n_failures = 0
+
+ def run_test(entry, results):
+ """Run a single test entry from the manifest."""
+
+ pattern_uri = model[entry]["http://drobilla.net/ns/serd#patternFile"][0]
+ input_uri = model[entry][mf + "action"][0]
+ result_uri = model[entry][mf + "result"][0]
+ pattern_path = _uri_path(suite_dir, pattern_uri)
+ input_path = _uri_path(suite_dir, input_uri)
+ result_path = _uri_path(suite_dir, result_uri)
+
+ output_path = os.path.join(
+ out_dir, os.path.basename(result_path).replace(".result", "")
+ )
+
+ command = filter_command_prefix + [
+ "-B",
+ base_uri,
+ "-f",
+ pattern_path,
+ "-o",
+ output_path,
+ input_path,
+ ]
+
+ # Run the filter (which should return success)
+ results.n_tests += 1
+ try:
+ subprocess.run(command, check=True)
+
+ # Check output against the expected result
+ if not serd_test_util.file_equals(result_path, output_path):
+ results.n_failures += 1
+ log_error(
+ "Output {} differs from {}\n".format(
+ output_path, check_path
+ )
+ )
+
+ except Exception as e:
+ log_error(e)
+ results.n_failures += 1
+
+ # Run all test types in the test suite
+ results = Results()
+ for klass, instances in instances.items():
+ if klass == "http://drobilla.net/ns/serd#TestFilterPositive":
+ for entry in instances:
+ run_test(entry, results)
+
+ # Print result summary
+ if results.n_failures > 0:
+ log_error(
+ "{}/{} tests failed\n".format(results.n_failures, results.n_tests)
+ )
+ else:
+ sys.stdout.write("All {} tests passed\n".format(results.n_tests))
+
+ return results.n_failures
+
+
+def main():
+ """Run the command line tool."""
+
+ parser = argparse.ArgumentParser(
+ usage="%(prog)s [OPTION]... MANIFEST BASE_URI -- [TOOL_OPTION]...",
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+
+ parser.add_argument(
+ "--pipe", default="tools/serd-pipe", help="serd-pipe executable"
+ )
+ parser.add_argument(
+ "--filter", default="tools/serd-filter", help="serd-filter executable"
+ )
+ parser.add_argument("--wrapper", default="", help="executable wrapper")
+ parser.add_argument("manifest", help="test suite manifest.ttl file")
+ parser.add_argument("base_uri", help="base URI for tests")
+ parser.add_argument(
+ "tool_option", nargs=argparse.REMAINDER, help="option for serd-filter"
+ )
+
+ args = parser.parse_args(sys.argv[1:])
+ wrapper_prefix = shlex.split(args.wrapper)
+ filter_command_prefix = wrapper_prefix + [args.filter]
+ pipe_command_prefix = wrapper_prefix + [args.pipe]
+
+ with tempfile.TemporaryDirectory() as test_out_dir:
+ return test_suite(
+ args.manifest,
+ args.base_uri,
+ filter_command_prefix,
+ pipe_command_prefix,
+ test_out_dir,
+ )
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except subprocess.CalledProcessError as e:
+ if e.stderr is not None:
+ sys.stderr.write(e.stderr.decode("utf-8"))
+
+ sys.stderr.write("error: %s\n" % e)
+ sys.exit(e.returncode)
diff --git a/test/run_test_suite.py b/test/run_pipe_suite.py
index 457e7f81..65a894c4 100755
--- a/test/run_test_suite.py
+++ b/test/run_pipe_suite.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-"""Run an RDF test suite with serdi."""
+"""Run an RDF test suite with serd-pipe."""
import serd_test_util
@@ -41,7 +41,14 @@ def test_thru(
osyntax,
command_prefix,
):
- """Test lossless round-tripping through two different syntaxes."""
+ """Test rewriting a file in the input syntax.
+
+ This rewrites a source test file in the original fancy syntax, then
+ rewrites that output again in the simple syntax used for test output
+ (NTriples or NQuads). Checking the final output against the expected test
+ output tests that piping the file through serd with pretty-printing was
+ lossless.
+ """
assert isyntax is not None
assert osyntax is not None
@@ -54,51 +61,45 @@ def test_thru(
command_prefix
+ [f for sublist in flags for f in sublist]
+ [
- "-i",
+ "-B",
+ base_uri,
+ "-I",
isyntax,
- "-o",
+ "-O",
isyntax,
- "-w",
+ "-o",
out_path,
- "-I",
- base_uri,
path,
]
)
+ subprocess.run(out_cmd, check=True)
+
thru_cmd = (
command_prefix
+ test_osyntax_options(osyntax)
+ [
- "-i",
+ "-B",
+ base_uri,
+ "-I",
isyntax,
- "-o",
+ "-O",
+ "ascii",
+ "-O",
osyntax,
- "-w",
- thru_path,
"-o",
- "ascii",
- "-I",
- base_uri,
+ thru_path,
out_path,
]
)
- subprocess.run(out_cmd, check=True)
subprocess.run(thru_cmd, check=True)
- with open(thru_path, "wb") as out:
- subprocess.run(thru_cmd, check=True, stdout=out)
-
- if not _file_equals(check_path, thru_path):
- log_error(
- "Round-tripped output {} does not match {}\n".format(
- check_path, thru_path
- )
- )
- return 1
+ if serd_test_util.file_equals(check_path, thru_path):
+ return 0
- return 0
+ log_error("Rewritten {} differs from {}\n".format(thru_path, check_path))
+ return 1
def _uri_path(uri):
@@ -107,36 +108,6 @@ def _uri_path(uri):
return path if not drive else path[1:]
-def _test_input_syntax(test_class):
- """Return the output syntax use for a given test class."""
-
- if "NTriples" in test_class:
- return "NTriples"
-
- if "Turtle" in test_class:
- return "Turtle"
-
- if "NQuads" in test_class:
- return "NQuads"
-
- if "Trig" in test_class:
- return "Trig"
-
- raise Exception("Unknown test class <{}>".format(test_class))
-
-
-def _test_output_syntax(test_class):
- """Return the output syntax use for a given test class."""
-
- if "NTriples" in test_class or "Turtle" in test_class:
- return "NTriples"
-
- if "NQuads" in test_class or "Trig" in test_class:
- return "NQuads"
-
- raise Exception("Unknown test class <{}>".format(test_class))
-
-
def _option_combinations(options):
"""Return an iterator that cycles through all combinations of options."""
@@ -147,49 +118,6 @@ def _option_combinations(options):
return itertools.cycle(combinations)
-def _show_diff(from_lines, to_lines, from_filename, to_filename):
- same = True
- for line in difflib.unified_diff(
- from_lines,
- to_lines,
- fromfile=os.path.abspath(from_filename),
- tofile=os.path.abspath(to_filename),
- ):
- sys.stderr.write(line)
- same = False
-
- return same
-
-
-def _file_equals(patha, pathb):
-
- for path in (patha, pathb):
- if not os.access(path, os.F_OK):
- log_error("missing file {}\n".format(path))
- return False
-
- with open(patha, "r", encoding="utf-8") as fa:
- with open(pathb, "r", encoding="utf-8") as fb:
- return _show_diff(fa.readlines(), fb.readlines(), patha, pathb)
-
-
-def _file_lines_equal(patha, pathb, subst_from="", subst_to=""):
- import io
-
- for path in (patha, pathb):
- if not os.access(path, os.F_OK):
- sys.stderr.write("error: missing file %s" % path)
- return False
-
- la = sorted(set(io.open(patha, encoding="utf-8").readlines()))
- lb = sorted(set(io.open(pathb, encoding="utf-8").readlines()))
- if la != lb:
- _show_diff(la, lb, patha, pathb)
- return False
-
- return True
-
-
def test_suite(
manifest_path,
base_uri,
@@ -204,7 +132,7 @@ def test_suite(
mf = "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"
test_dir = os.path.dirname(manifest_path)
model, instances = serd_test_util.load_rdf(
- command_prefix + ["-I", base_uri], manifest_path
+ command_prefix + ["-B", base_uri], manifest_path
)
asserter = ""
@@ -217,17 +145,21 @@ def test_suite(
self.n_failures = 0
def run_tests(test_class, tests, expected_return, results):
- thru_flags = [["-f"], ["-b", "1"], ["-r", "http://example.org/"]]
+ thru_flags = [
+ ["-R", "http://example.org/"],
+ ["-b", "1"],
+ ["-b", "16384"],
+ ]
thru_options_iter = _option_combinations(thru_flags)
if output_syntax is not None:
osyntax = output_syntax
else:
- osyntax = _test_output_syntax(test_class)
+ osyntax = serd_test_util.test_output_syntax(test_class)
if input_syntax is not None:
isyntax = input_syntax
else:
- isyntax = _test_input_syntax(test_class)
+ isyntax = serd_test_util.test_input_syntax(test_class)
for test in sorted(tests):
test_uri = model[test][mf + "action"][0]
@@ -236,11 +168,11 @@ def test_suite(
test_path = os.path.join(test_dir, test_name)
command = command_prefix + [
- "-o",
+ "-O",
osyntax,
- "-o",
+ "-O",
"ascii",
- "-I",
+ "-B",
test_uri,
test_path,
]
@@ -272,7 +204,7 @@ def test_suite(
check_filename = os.path.basename(_uri_path(check_uri))
check_path = os.path.join(test_dir, check_filename)
- if not _file_equals(check_path, out_filename):
+ if not serd_test_util.file_equals(check_path, out_filename):
results.n_failures += 1
log_error(
"Output {} does not match {}\n".format(
@@ -292,32 +224,6 @@ def test_suite(
command_prefix,
)
- # Run model test for positive test (must succeed)
- out_filename = os.path.join(
- out_test_dir, test_name + ".model.out"
- )
-
- model_command = command_prefix + [
- "-m",
- "-o",
- osyntax,
- "-o",
- "ascii",
- "-w",
- out_filename,
- "-I",
- test_uri,
- test_path,
- ]
-
- proc = subprocess.run(model_command, check=True)
-
- if proc.returncode == 0 and (
- (mf + "result") in model[test]
- ):
- if not _file_lines_equal(check_path, out_filename):
- results.n_failures += 1
-
else: # Negative test
with open(out_filename, "w") as stdout:
with tempfile.TemporaryFile() as stderr:
@@ -380,13 +286,13 @@ def main():
"""Run the command line tool."""
parser = argparse.ArgumentParser(
- usage="%(prog)s [OPTION]... MANIFEST BASE_URI -- [SERDI_OPTION]...",
+ usage="%(prog)s [OPTION]... MANIFEST BASE_URI -- [TOOL_OPTION]...",
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--report", help="path to write result report to")
- parser.add_argument("--serdi", default="serdi", help="path to serdi")
+ parser.add_argument("--tool", default="tools/serd-pipe", help="executable")
parser.add_argument("--syntax", default=None, help="input syntax")
parser.add_argument("--osyntax", default=None, help="output syntax")
parser.add_argument("--wrapper", default="", help="executable wrapper")
@@ -394,14 +300,11 @@ def main():
parser.add_argument("base_uri", help="base URI for tests")
parser.add_argument(
- "serdi_option", nargs=argparse.REMAINDER, help="option for serdi"
+ "tool_option", nargs=argparse.REMAINDER, help="option to pass to tool"
)
args = parser.parse_args(sys.argv[1:])
-
- command_prefix = (
- shlex.split(args.wrapper) + [args.serdi] + args.serdi_option
- )
+ command_prefix = shlex.split(args.wrapper) + [args.tool] + args.tool_option
with tempfile.TemporaryDirectory() as test_out_dir:
return test_suite(
diff --git a/test/run_sort_suite.py b/test/run_sort_suite.py
new file mode 100755
index 00000000..27205665
--- /dev/null
+++ b/test/run_sort_suite.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python3
+
+"""Run an RDF test suite with serd-sort."""
+
+import serd_test_util
+
+import argparse
+import datetime
+import difflib
+import itertools
+import os
+import re
+import shlex
+import subprocess
+import sys
+import tempfile
+import urllib.parse
+
+
+def log_error(message):
+ """Log an error message to stderr"""
+
+ sys.stderr.write("error: ")
+ sys.stderr.write(message)
+
+
+def _uri_path(uri):
+ path = urllib.parse.urlparse(uri).path
+ drive = os.path.splitdrive(path[1:])[0]
+ return path if not drive else path[1:]
+
+
+def _file_lines_equal(patha, pathb, subst_from="", subst_to=""):
+ import io
+
+ for path in (patha, pathb):
+ if not os.access(path, os.F_OK):
+ sys.stderr.write("error: missing file %s" % path)
+ return False
+
+ la = sorted(set(io.open(patha, encoding="utf-8").readlines()))
+ lb = sorted(set(io.open(pathb, encoding="utf-8").readlines()))
+ if la != lb:
+ serd_test_util.show_diff(la, lb, patha, pathb)
+ return False
+
+ return True
+
+
+def _add_extension(filename, extension):
+ first_dot = filename.find(".")
+
+ return filename[0:first_dot] + extension + filename[first_dot:]
+
+
+def test_suite(
+ manifest_path,
+ base_uri,
+ report_filename,
+ input_syntax,
+ output_syntax,
+ command_prefix,
+ out_test_dir,
+):
+ """Run all tests in a test suite manifest."""
+
+ mf = "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"
+ test_dir = os.path.dirname(manifest_path)
+ model, instances = serd_test_util.load_rdf(
+ command_prefix + ["-B", base_uri], manifest_path
+ )
+
+ asserter = ""
+ if os.getenv("USER") == "drobilla":
+ asserter = "http://drobilla.net/drobilla#me"
+
+ class Results:
+ def __init__(self):
+ self.n_tests = 0
+ self.n_failures = 0
+
+ def run_tests(test_class, tests, expected_return, results):
+ osyntax = output_syntax
+ if osyntax is None:
+ osyntax = serd_test_util.test_output_syntax(test_class)
+
+ isyntax = input_syntax
+ if isyntax is None:
+ isyntax = serd_test_util.test_input_syntax(test_class)
+
+ for test in sorted(tests):
+ test_uri = model[test][mf + "action"][0]
+ test_uri_path = _uri_path(test_uri)
+ test_name = os.path.basename(test_uri_path)
+ test_path = os.path.join(test_dir, test_name)
+
+ command = command_prefix + [
+ "-B",
+ test_uri,
+ "-O",
+ osyntax,
+ "-O",
+ "ascii",
+ test_path,
+ ]
+
+ command_string = " ".join(shlex.quote(c) for c in command)
+ out_filename = os.path.join(
+ out_test_dir, _add_extension(test_name, ".sort")
+ )
+
+ results.n_tests += 1
+
+ if expected_return == 0: # Positive test
+
+ with open(out_filename, "w") as stdout:
+ proc = subprocess.run(command, check=False, stdout=stdout)
+ passed = proc.returncode == expected_return
+ if not passed:
+ results.n_failures += 1
+ log_error(
+ "Unexpected failure of command: {}\n".format(
+ command_string
+ )
+ )
+
+ if passed and (mf + "result") in model[test]:
+ # Check output against expected output from test suite
+ check_uri = model[test][mf + "result"][0]
+ check_filename = os.path.basename(_uri_path(check_uri))
+ check_path = os.path.join(test_dir, check_filename)
+
+ if not _file_lines_equal(check_path, out_filename):
+ results.n_failures += 1
+ log_error(
+ "Output {} differs from {}\n".format(
+ out_filename, check_path
+ )
+ )
+
+ else: # Negative test
+
+ with tempfile.TemporaryFile() as stderr:
+ with open(out_filename, "w") as stdout:
+ proc = subprocess.run(
+ command, check=False, stdout=stdout, stderr=stderr
+ )
+
+ passed = proc.returncode != 0
+ if passed:
+ # Check that an error message was printed
+ stderr.seek(0, 2) # Seek to end
+ if stderr.tell() == 0: # Empty
+ results.n_failures += 1
+ log_error("No error: {}\n".format(command_string))
+
+ else:
+ results.n_failures += 1
+ log_error("Should fail: {}\n".format(command_string))
+
+ # Write test report entry
+ if report_filename:
+ with open(report_filename, "a") as report:
+ report.write(
+ serd_test_util.earl_assertion(test, passed, asserter)
+ )
+
+ # Run all test types in the test suite
+ results = Results()
+ ns_rdftest = "http://www.w3.org/ns/rdftest#"
+ for test_class, instances in instances.items():
+ if test_class.startswith(ns_rdftest):
+ expected = (
+ 1
+ if "lax" not in command_prefix and "Negative" in test_class
+ else 0
+ )
+ run_tests(test_class, instances, expected, results)
+
+ # Print result summary
+ if results.n_failures > 0:
+ log_error(
+ "{}/{} tests failed\n".format(results.n_failures, results.n_tests)
+ )
+ else:
+ sys.stdout.write("All {} tests passed\n".format(results.n_tests))
+
+ return results.n_failures
+
+
+def main():
+ """Run the command line tool."""
+
+ parser = argparse.ArgumentParser(
+ usage="%(prog)s [OPTION]... MANIFEST BASE_URI -- [TOOL_OPTION]...",
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+
+ parser.add_argument("--report", help="path to write result report to")
+ parser.add_argument("--tool", default="tools/serd-sort", help="executable")
+ parser.add_argument("--syntax", default=None, help="input syntax")
+ parser.add_argument("--osyntax", default=None, help="output syntax")
+ parser.add_argument("--wrapper", default="", help="executable wrapper")
+ parser.add_argument("manifest", help="test suite manifest.ttl file")
+ parser.add_argument("base_uri", help="base URI for tests")
+ parser.add_argument(
+ "tool_option", nargs=argparse.REMAINDER, help="option to pass to tool"
+ )
+
+ args = parser.parse_args(sys.argv[1:])
+ command_prefix = shlex.split(args.wrapper) + [args.tool] + args.tool_option
+
+ with tempfile.TemporaryDirectory() as test_out_dir:
+ return test_suite(
+ args.manifest,
+ args.base_uri,
+ args.report,
+ args.syntax,
+ args.osyntax,
+ command_prefix,
+ test_out_dir,
+ )
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except subprocess.CalledProcessError as e:
+ if e.stderr is not None:
+ sys.stderr.write(e.stderr.decode("utf-8"))
+
+ sys.stderr.write("error: %s\n" % e)
+ sys.exit(e.returncode)
diff --git a/test/serd_test_util/__init__.py b/test/serd_test_util/__init__.py
index f0b1c19a..45cc6e64 100644
--- a/test/serd_test_util/__init__.py
+++ b/test/serd_test_util/__init__.py
@@ -3,8 +3,48 @@
"""Utilities for data-driven tests."""
import datetime
+import difflib
+import os
import re
import subprocess
+import sys
+
+
+def error(message):
+ """Log an error message to stderr"""
+
+ sys.stderr.write("error: ")
+ sys.stderr.write(message)
+
+
+def test_input_syntax(test_class):
+ """Return the output syntax use for a given test class."""
+
+ if "NTriples" in test_class:
+ return "NTriples"
+
+ if "Turtle" in test_class:
+ return "Turtle"
+
+ if "NQuads" in test_class:
+ return "NQuads"
+
+ if "Trig" in test_class:
+ return "Trig"
+
+ raise Exception("Unknown test class <{}>".format(test_class))
+
+
+def test_output_syntax(test_class):
+ """Return the output syntax use for a given test class."""
+
+ if "NTriples" in test_class or "Turtle" in test_class:
+ return "NTriples"
+
+ if "NQuads" in test_class or "Trig" in test_class:
+ return "NQuads"
+
+ raise Exception("Unknown test class <{}>".format(test_class))
def earl_assertion(test, passed, asserter):
@@ -33,7 +73,7 @@ def earl_assertion(test, passed, asserter):
def load_rdf(command_prefix, filename):
- """Load an RDF file as dictionaries via serdi (only supports URIs)."""
+ """Load an RDF file as dictionaries via serd-pipe (only supports URIs)."""
rdf_type = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
model = {}
@@ -61,3 +101,32 @@ def load_rdf(command_prefix, filename):
instances[o].update([s])
return model, instances
+
+
+def file_equals(patha, pathb):
+ """Return true if the file at patha is the same as the file at pathb."""
+
+ for path in (patha, pathb):
+ if not os.access(path, os.F_OK):
+ error("missing file {}\n".format(path))
+ return False
+
+ with open(patha, "r", encoding="utf-8") as fa:
+ with open(pathb, "r", encoding="utf-8") as fb:
+ return show_diff(fa.readlines(), fb.readlines(), patha, pathb)
+
+
+def show_diff(from_lines, to_lines, from_filename, to_filename):
+ """Print a diff between files to stderr."""
+
+ same = True
+ for line in difflib.unified_diff(
+ from_lines,
+ to_lines,
+ fromfile=os.path.abspath(from_filename),
+ tofile=os.path.abspath(to_filename),
+ ):
+ sys.stderr.write(line)
+ same = False
+
+ return same
diff --git a/test/sort/GOPS.nq b/test/sort/GOPS.nq
new file mode 100644
index 00000000..c7472e03
--- /dev/null
+++ b/test/sort/GOPS.nq
@@ -0,0 +1,10 @@
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GOSP.nq b/test/sort/GOSP.nq
new file mode 100644
index 00000000..c7472e03
--- /dev/null
+++ b/test/sort/GOSP.nq
@@ -0,0 +1,10 @@
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GPSO.nq b/test/sort/GPSO.nq
new file mode 100644
index 00000000..1a858017
--- /dev/null
+++ b/test/sort/GPSO.nq
@@ -0,0 +1,10 @@
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GSOP.nq b/test/sort/GSOP.nq
new file mode 100644
index 00000000..fc073a00
--- /dev/null
+++ b/test/sort/GSOP.nq
@@ -0,0 +1,10 @@
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GSPO.nq b/test/sort/GSPO.nq
new file mode 100644
index 00000000..726b1d42
--- /dev/null
+++ b/test/sort/GSPO.nq
@@ -0,0 +1,10 @@
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/OPS.nq b/test/sort/OPS.nq
new file mode 100644
index 00000000..456ade7f
--- /dev/null
+++ b/test/sort/OPS.nq
@@ -0,0 +1,10 @@
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
diff --git a/test/sort/OSP.nq b/test/sort/OSP.nq
new file mode 100644
index 00000000..456ade7f
--- /dev/null
+++ b/test/sort/OSP.nq
@@ -0,0 +1,10 @@
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
diff --git a/test/sort/POS.nq b/test/sort/POS.nq
new file mode 100644
index 00000000..51c675de
--- /dev/null
+++ b/test/sort/POS.nq
@@ -0,0 +1,10 @@
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
diff --git a/test/sort/PSO.nq b/test/sort/PSO.nq
new file mode 100644
index 00000000..0fb7bd68
--- /dev/null
+++ b/test/sort/PSO.nq
@@ -0,0 +1,10 @@
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
diff --git a/test/sort/SOP.nq b/test/sort/SOP.nq
new file mode 100644
index 00000000..1692689c
--- /dev/null
+++ b/test/sort/SOP.nq
@@ -0,0 +1,10 @@
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
diff --git a/test/sort/SPO.nq b/test/sort/SPO.nq
new file mode 100644
index 00000000..508debc7
--- /dev/null
+++ b/test/sort/SPO.nq
@@ -0,0 +1,10 @@
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
diff --git a/test/sort/input.trig b/test/sort/input.trig
new file mode 100644
index 00000000..154a9fb8
--- /dev/null
+++ b/test/sort/input.trig
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+
+eg:graph1 {
+eg:s
+ eg:blank [
+ eg:with eg:aProperty ,
+ eg:orAnother
+ ] ;
+ eg:list (
+ 1
+ 2
+ ) ;
+ eg:literal "s1" .
+}
+
+eg:graph2 {
+eg:a
+ eg:b eg:c .
+}
diff --git a/test/sort/pretty.nq b/test/sort/pretty.nq
new file mode 100644
index 00000000..451247d4
--- /dev/null
+++ b/test/sort/pretty.nq
@@ -0,0 +1,10 @@
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/terse/meson.build b/test/terse/meson.build
index 538a8d16..b0516fcb 100644
--- a/test/terse/meson.build
+++ b/test/terse/meson.build
@@ -1,16 +1,23 @@
base_uri = 'http://drobilla.net/sw/serd/test/terse/'
+args = [
+ '--osyntax', 'turtle',
+ files('manifest.ttl'),
+ base_uri,
+ '--',
+ '-O', 'terse'
+]
+
+test('terse',
+ run_pipe_suite,
+ args: pipe_test_script_args + args,
+ env: test_env,
+ suite: ['suite', 'extra', 'pipe'],
+ timeout: 240)
+
test('terse',
- run_test_suite,
- args: script_args + [
- '--osyntax', 'turtle',
- files('manifest.ttl'),
- base_uri,
- '--',
- '-o',
- 'terse',
- ],
+ run_sort_suite,
+ args: sort_test_script_args + args,
env: test_env,
- is_parallel: false,
- suite: ['suite', 'extra'],
+ suite: ['suite', 'extra', 'sort'],
timeout: 240)
diff --git a/test/test_base.py b/test/test_base.py
new file mode 100755
index 00000000..c3018da3
--- /dev/null
+++ b/test/test_base.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+
+"""Test reading from stdin with serd-pipe."""
+
+import argparse
+import sys
+import shlex
+import subprocess
+import tempfile
+
+parser = argparse.ArgumentParser(description=__doc__)
+
+parser.add_argument("--tool", default="tools/serd-pipe", help="executable")
+parser.add_argument("--wrapper", default="", help="executable wrapper")
+
+args = parser.parse_args(sys.argv[1:])
+command = shlex.split(args.wrapper) + [
+ args.tool,
+ "-B",
+ "http://example.org",
+ "-I",
+ "turtle",
+ "-",
+]
+
+IN_DOCUMENT = "<s> <p> <o> ."
+OUT_DOCUMENT = "<{0}s> <{0}p> <{0}o> .".format("http://example.org/")
+
+with tempfile.TemporaryFile() as out:
+ proc = subprocess.run(
+ command,
+ check=False,
+ encoding="utf-8",
+ input=IN_DOCUMENT,
+ stdout=out,
+ stderr=subprocess.PIPE,
+ )
+
+ assert proc.returncode == 0
+ assert args.wrapper or len(proc.stderr) == 0
+
+ out.seek(0)
+ lines = out.readlines()
+
+ assert len(lines) == 1
+ assert lines[0].decode("utf-8").strip() == OUT_DOCUMENT
diff --git a/test/test_empty.py b/test/test_empty.py
index a7978e6c..03264d8c 100755
--- a/test/test_empty.py
+++ b/test/test_empty.py
@@ -10,12 +10,12 @@ import tempfile
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-read", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
parser.add_argument("input", help="valid input file")
args = parser.parse_args(sys.argv[1:])
-command = shlex.split(args.wrapper) + [args.serdi, "-o", "empty", args.input]
+command = shlex.split(args.wrapper) + [args.tool, "-O", "empty", args.input]
with tempfile.TemporaryFile() as out:
diff --git a/test/test_filter.py b/test/test_filter.py
index d44677f5..5f25f22e 100755
--- a/test/test_filter.py
+++ b/test/test_filter.py
@@ -21,7 +21,7 @@ DOCUMENTS = {
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-filter", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
args = parser.parse_args(sys.argv[1:])
@@ -29,21 +29,21 @@ args = parser.parse_args(sys.argv[1:])
def check_pattern(syntax, pattern, result):
command = shlex.split(args.wrapper) + [
- args.serdi,
- "-i",
+ args.tool,
+ "-I",
syntax,
- "-F",
+ "-v",
pattern,
- "-s",
- DOCUMENTS[syntax],
+ "-",
]
with tempfile.TemporaryFile() as out:
proc = subprocess.run(
command,
+ capture_output=True,
check=False,
encoding="utf-8",
- capture_output=True,
+ input=DOCUMENTS[syntax],
)
assert proc.returncode == 0
diff --git a/test/test_grep.py b/test/test_grep.py
index 0c8c5228..44c3ce1f 100755
--- a/test/test_grep.py
+++ b/test/test_grep.py
@@ -21,7 +21,7 @@ DOCUMENTS = {
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-filter", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
args = parser.parse_args(sys.argv[1:])
@@ -29,21 +29,20 @@ args = parser.parse_args(sys.argv[1:])
def check_pattern(syntax, pattern, result):
command = shlex.split(args.wrapper) + [
- args.serdi,
- "-i",
+ args.tool,
+ "-I",
syntax,
- "-G",
pattern,
- "-s",
- DOCUMENTS[syntax],
+ "-",
]
with tempfile.TemporaryFile() as out:
proc = subprocess.run(
command,
+ capture_output=True,
check=False,
encoding="utf-8",
- capture_output=True,
+ input=DOCUMENTS[syntax],
)
assert proc.returncode == 0
diff --git a/test/test_multifile.py b/test/test_multifile.py
index 5fb44bc5..c5e11bf3 100755
--- a/test/test_multifile.py
+++ b/test/test_multifile.py
@@ -12,7 +12,7 @@ import tempfile
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-pipe", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
parser.add_argument("testdir", help="multifile test directory")
@@ -20,7 +20,7 @@ args = parser.parse_args(sys.argv[1:])
in1_path = os.path.join(args.testdir, "input1.ttl")
in2_path = os.path.join(args.testdir, "input2.trig")
check_path = os.path.join(args.testdir, "output.nq")
-command = shlex.split(args.wrapper) + [args.serdi, in1_path, in2_path]
+command = shlex.split(args.wrapper) + [args.tool, in1_path, in2_path]
def _show_diff(from_lines, to_lines, from_filename, to_filename):
diff --git a/test/test_node_syntax.c b/test/test_node_syntax.c
index a9829688..9875e656 100644
--- a/test/test_node_syntax.c
+++ b/test/test_node_syntax.c
@@ -66,6 +66,9 @@ test_common(const SerdSyntax syntax)
assert(test(syntax, serd_new_token(SERD_BLANK, SERD_STRING("b0")), "_:b0"));
+ assert(test(
+ syntax, serd_new_token(SERD_BLANK, SERD_STRING("named1")), "_:named1"));
+
assert(test(syntax,
serd_new_uri(SERD_STRING("http://example.org/")),
"<http://example.org/>"));
diff --git a/test/test_quiet.py b/test/test_quiet.py
index 7f141943..b88f0270 100755
--- a/test/test_quiet.py
+++ b/test/test_quiet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-"""Test serdi quiet option."""
+"""Test quiet command-line option."""
import argparse
import sys
@@ -9,12 +9,12 @@ import subprocess
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-pipe", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
parser.add_argument("input", help="invalid input file")
args = parser.parse_args(sys.argv[1:])
-command = shlex.split(args.wrapper) + [args.serdi, "-q", args.input]
+command = shlex.split(args.wrapper) + [args.tool, "-q", args.input]
proc = subprocess.run(command, check=False, capture_output=True)
assert proc.returncode != 0
diff --git a/test/test_sort.py b/test/test_sort.py
new file mode 100755
index 00000000..4080b93c
--- /dev/null
+++ b/test/test_sort.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+
+"""Run the collation tests for serd-sort."""
+
+import argparse
+import os
+import random
+import shlex
+import subprocess
+import sys
+import tempfile
+
+import serd_test_util
+
+collations = [
+ "GOPS",
+ "GOSP",
+ "GPSO",
+ "GSOP",
+ "GSPO",
+ "OPS",
+ "OSP",
+ "POS",
+ "PSO",
+ "SOP",
+ "SPO",
+ "pretty",
+]
+
+
+def check(test_dir, command_prefix, out_dir, input_path, name):
+ """Sort a single input in the named order and check the output.
+
+ The expected output is assumed to exist at test_dir/NAME.nq.
+ """
+
+ output_path = os.path.join(out_dir, name + ".nq")
+ result_path = os.path.join(test_dir, name + ".nq")
+ options = [] if name == "pretty" else ["-c", name]
+
+ # Randomly add irrelevant options just to cover them
+ if random.choice([True, False]):
+ options += ["-R", "http://example.org/"]
+ if random.choice([True, False]):
+ options += ["-I", "TriG"]
+
+ command = command_prefix + options + ["-o", output_path, input_path]
+
+ proc = subprocess.run(command, capture_output=True, check=False)
+ if proc.returncode != 0:
+ cmd_string = " ".join(shlex.quote(c) for c in command)
+ serd_test_util.error("Unexpected failure: {}".format(cmd_string))
+ sys.stderr.write(proc.stderr.decode("utf-8"))
+ return False
+
+ if not serd_test_util.file_equals(result_path, output_path):
+ serd_test_util.error(
+ "Output {} differs from {}\n".format(output_path, result_path)
+ )
+ return False
+
+ return True
+
+
+def run_tests(test_dir, command_prefix, out_dir):
+ """Run all the tests in the suite."""
+
+ input_trig = os.path.join(test_dir, "input.trig")
+
+ n_failures = 0
+ for name in collations:
+ if not check(test_dir, command_prefix, out_dir, input_trig, name):
+ n_failures += 1
+
+ return n_failures
+
+
+def main():
+ """Run the command line tool."""
+
+ parser = argparse.ArgumentParser(
+ usage="%(prog)s [OPTION]... INPUT",
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+
+ parser.add_argument(
+ "--tool", default="tools/serd-sort", help="serd-sort executable"
+ )
+
+ parser.add_argument("--wrapper", default="", help="executable wrapper")
+ parser.add_argument(
+ "input", help="path to input.trig in the test directory"
+ )
+
+ args = parser.parse_args(sys.argv[1:])
+ wrapper_prefix = shlex.split(args.wrapper)
+ command_prefix = wrapper_prefix + [args.tool]
+
+ with tempfile.TemporaryDirectory() as out_dir:
+ return run_tests(os.path.dirname(args.input), command_prefix, out_dir)
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except subprocess.CalledProcessError as error:
+ if error.stderr is not None:
+ sys.stderr.write(error.stderr.decode("utf-8"))
+
+ sys.stderr.write("error: %s\n" % error)
+ sys.exit(error.returncode)
diff --git a/test/test_stdin.py b/test/test_stdin.py
index 11b1ca21..2161a95a 100755
--- a/test/test_stdin.py
+++ b/test/test_stdin.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-"""Test reading from stdin with serdi."""
+"""Test reading from stdin with serd-pipe."""
import argparse
import sys
@@ -10,15 +10,15 @@ import tempfile
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-pipe", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
args = parser.parse_args(sys.argv[1:])
command = shlex.split(args.wrapper) + [
- args.serdi,
- "-I",
+ args.tool,
+ "-B",
"http://example.org",
- "-i",
+ "-I",
"ntriples",
"-",
]
diff --git a/test/test_write_error.py b/test/test_write_error.py
index 35b4693b..bc955ce9 100755
--- a/test/test_write_error.py
+++ b/test/test_write_error.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-"""Test errors writing to a file."""
+"""Test errors when writing to a file."""
import argparse
import sys
@@ -10,12 +10,12 @@ import os
parser = argparse.ArgumentParser(description=__doc__)
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
+parser.add_argument("--tool", default="tools/serd-pipe", help="executable")
parser.add_argument("--wrapper", default="", help="executable wrapper")
parser.add_argument("input", help="valid input file")
args = parser.parse_args(sys.argv[1:])
-command = shlex.split(args.wrapper) + [args.serdi, args.input]
+command = shlex.split(args.wrapper) + [args.tool, args.input]
if os.path.exists("/dev/full"):