diff options
Diffstat (limited to 'test')
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"): |