aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--test/meson.build221
-rwxr-xr-xtest/run_suite.py18
-rwxr-xr-xtest/run_test_suite.py293
4 files changed, 117 insertions, 417 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c19cfcb2..2f327470 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -84,7 +84,7 @@ mingw32:
image: lv2plugin/debian-mingw32
script:
- meson setup build --cross-file=/usr/share/meson/cross/i686-w64-mingw32.ini -Dc_std=c11 -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- - ninja -C build
+ - ninja -C build test
- meson configure -Dbuildtype=release build
- ninja -C build test
variables:
diff --git a/test/meson.build b/test/meson.build
index 8f8e9e20..0f2268f6 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -2,7 +2,6 @@
# SPDX-License-Identifier: 0BSD OR ISC
run_suite = find_program('run_suite.py')
-run_test_suite = files('run_test_suite.py')
wrapper = meson.get_external_property('exe_wrapper', '')
@@ -22,9 +21,12 @@ if get_option('strict')
# Check licensing metadata
reuse = find_program('reuse', required: false)
if reuse.found()
- test('REUSE', reuse,
- args: ['--root', serd_src_root, 'lint'],
- suite: 'data')
+ test(
+ 'REUSE',
+ reuse,
+ args: ['--root', serd_src_root, 'lint'],
+ suite: 'data',
+ )
endif
endif
@@ -35,7 +37,6 @@ endif
python_scripts = files(
'../scripts/serd_bench.py',
'run_suite.py',
- 'run_test_suite.py',
'serd_test_util/__init__.py',
'test_quiet.py',
'test_stdin.py',
@@ -96,7 +97,29 @@ if wrapper != ''
common_script_args += ['--wrapper', wrapper]
endif
-if not get_option('tools').disabled()
+simple_command_tests = {
+ 'serdi': {
+ 'bad': [
+ ['-c'],
+ ['-fi'],
+ ['-i', 'turtle'],
+ ['-i', 'unknown'],
+ ['-i'],
+ ['-o', 'unknown'],
+ ['-o'],
+ ['-p'],
+ ['-r'],
+ ['-z'],
+ ],
+ 'good': [
+ ['-h'],
+ ['-s', '<urn:eg:s> a <urn:eg:T> .'],
+ ['-v'],
+ ],
+ },
+}
+
+if is_variable('serdi')
script_args = common_script_args + ['--serdi', serdi]
serd_ttl = files('../serd.ttl')[0]
@@ -104,87 +127,63 @@ if not get_option('tools').disabled()
# Command line options
- good_args = [
- ['-v'],
- ['-h'],
- ['-s', '<urn:eg:s> a <urn:eg:T> .'],
- ]
-
- foreach args : good_args
- test(args[0], serdi, args: args, suite: ['serdi', 'options'])
- endforeach
-
- bad_args = [
- ['/no/such/file'],
- ['ftp://unsupported.org'],
- ['-c'],
- ['-i', 'unknown'],
- ['-i', 'turtle'],
- ['-i'],
- ['-fi'],
- ['-o', 'unknown'],
- ['-o'],
- ['-p'],
- ['-r'],
- ['-z'],
- ['-s', '<foo> a <Bar> .'],
- ]
-
- foreach args : bad_args
- name = ' '.join(args).underscorify()
- test(name, serdi,
- args: args,
- should_fail: true,
- suite: ['serdi', 'options'])
+ cmd_suite = ['serdi', 'options']
+
+ foreach kind, cases : simple_command_tests['serdi']
+ foreach args : cases
+ test(
+ ' '.join(args).underscorify(),
+ serdi,
+ args: args,
+ should_fail: kind == 'bad',
+ suite: cmd_suite,
+ )
+ endforeach
endforeach
- test('none', serdi, should_fail: true, suite: ['serdi', 'options'])
+ test('none', serdi, should_fail: true, suite: cmd_suite)
- test('quiet', files('test_quiet.py'),
- args: script_args + files('bad/bad-base.ttl'),
- suite: ['serdi', 'options'])
+ test(
+ 'quiet',
+ files('test_quiet.py'),
+ args: script_args + files('bad/bad-base.ttl'),
+ suite: cmd_suite,
+ )
# Inputs
- test('stdin', files('test_stdin.py'),
- args: script_args,
- suite: ['serdi', 'input'])
-
- test('string', serdi,
- args: ['-s', '<foo> a <Bar> .'],
- should_fail: true,
- suite: ['serdi', 'input'])
+ input_suite = ['serdi', 'input']
- test('missing', serdi,
- args: ['-i', 'turtle'],
- should_fail: true,
- suite: ['serdi', 'input'])
+ bad_input_tests = {
+ 'string': ['-s', '<foo> a <Bar> .'],
+ 'no_such_file': ['no_such_file'],
+ 'remote': ['ftp://example.org/unsupported.ttl'],
+ }
- test('no_such_file', serdi,
- args: ['no_such_file'],
- should_fail: true,
- suite: ['serdi', 'input'])
+ foreach name, args : bad_input_tests
+ test(name, serdi, args: args, should_fail: true, suite: input_suite)
+ endforeach
- test('remote', serdi,
- args: ['ftp://example.org/unsupported.ttl'],
- should_fail: true,
- suite: ['serdi', 'input'])
+ test('stdin', files('test_stdin.py'), args: script_args, suite: input_suite)
# IO errors
- test('read_dir', serdi,
- args: ['-e', 'file://@0@/'.format(serd_src_root)],
- should_fail: true,
- suite: 'io_errors')
+ io_error_tests = {
+ 'read_dir_bulk': [serd_src_root],
+ 'read_dir_bytes': ['-e', serd_src_root],
+ 'read_dir_uri': ['file://@0@/'.format(serd_src_root)],
+ }
- test('bulk_read_dir', serdi,
- args: ['file://@0@/'.format(serd_src_root)],
- should_fail: true,
- suite: 'io_errors')
+ foreach name, args : io_error_tests
+ test(name, serdi, args: args, should_fail: true, suite: 'io')
+ endforeach
- test('write_error', files('test_write_error.py'),
- args: script_args + [serd_ttl],
- suite: 'io_errors')
+ test(
+ 'write_error',
+ files('test_write_error.py'),
+ args: script_args + [serd_ttl],
+ suite: 'io',
+ )
endif
###########################
@@ -195,10 +194,36 @@ ns_serdtest = 'http://drobilla.net/sw/serd/test/'
ns_w3 = 'http://www.w3.org/2013/'
test_suites = {
+ 'NQuads': [
+ files('NQuadsTests/manifest.ttl'), ns_w3 + 'NQuadsTests/',
+ '--', '-a', '-i', 'NQuads',
+ ],
+ 'NTriples': [
+ files('NTriplesTests/manifest.ttl'), ns_w3 + 'NTriplesTests/',
+ '--', '-a', '-i', 'NTriples',
+ ],
+ 'TriG': [
+ files('TriGTests/manifest.ttl'), ns_w3 + 'TriGTests/',
+ '--', '-a', '-f', '-i', 'TriG',
+ ],
+ 'Turtle': [
+ files('TurtleTests/manifest.ttl'), ns_w3 + 'TurtleTests/',
+ '--', '-a', '-i', 'Turtle',
+ ],
+ 'bad': [
+ files('bad/manifest.ttl'), ns_serdtest + 'bad/',
+ ],
+ 'bulk': [
+ files('good/manifest.ttl'), ns_serdtest + 'good/',
+ '--', '-b',
+ ],
'full': [
files('full/manifest.ttl'), ns_serdtest + 'full/',
'--', '-f',
],
+ 'good': [
+ files('good/manifest.ttl'), ns_serdtest + 'good/',
+ ],
'lax.lax': [
'--lax',
files('lax/manifest.ttl'), ns_serdtest + 'lax/',
@@ -221,6 +246,7 @@ test_suites = {
],
'qualify': [
files('qualify/manifest.ttl'), ns_serdtest + 'qualify/',
+ '--', '-i', 'turtle', # Just for coverage
],
'root': [
files('root/manifest.ttl'), ns_serdtest + 'root/',
@@ -228,59 +254,16 @@ test_suites = {
],
}
-if not get_option('tools').disabled()
+# Run every test suite with serdi
+if is_variable('serdi')
script_args = common_script_args + ['--serdi', serdi]
foreach name, args : test_suites
test(
name, run_suite,
args: script_args + args,
- suite: ['rdf'],
+ suite: ['suite'],
timeout: 240,
)
endforeach
-
- ## Serd-specific test suites
-
- serd_suites = ['good', 'bad']
-
- ### Run all suites with no special arguments
- foreach name : serd_suites
- manifest = files(name / 'manifest.ttl')
- base_uri = ns_serdtest + name + '/'
- test(name, run_test_suite,
- args: script_args + [manifest, base_uri],
- suite: ['rdf', 'serd'],
- timeout: 240)
- endforeach
-
- test('good.bulk', run_test_suite,
- args: script_args + [
- files('good/manifest.ttl'),
- ns_serdtest + 'good/',
- '--',
- '-b'
- ],
- is_parallel: false,
- suite: ['rdf', 'serd'],
- timeout: 240)
-
- ## Standard W3C test suites
-
- w3c_suites = ['Turtle', 'NTriples', 'NQuads', 'TriG']
-
- foreach syntax : w3c_suites
- manifest = files(syntax + 'Tests' / 'manifest.ttl')
- base_uri = ns_w3 + syntax + 'Tests/'
-
- args = [manifest, base_uri]
- if syntax == 'TriG'
- args += ['--', '-a']
- endif
-
- test(syntax, run_test_suite,
- args: script_args + args,
- suite: ['rdf', 'w3c'],
- timeout: 240)
- endforeach
endif
diff --git a/test/run_suite.py b/test/run_suite.py
index 6426b0c2..9c3d27ee 100755
--- a/test/run_suite.py
+++ b/test/run_suite.py
@@ -119,13 +119,21 @@ def run_suite(args, command, out_dir):
if klass not in TEST_TYPES:
raise RuntimeError("Unknown manifest entry type: " + klass)
- for instance in instances:
+ for uri in instances:
try:
- entry = model[instance]
+ entry = model[uri]
if check and NS_MF + "result" not in entry:
- raise RuntimeError("Eval test missing result: " + instance)
+ raise RuntimeError("Eval test missing result: " + uri)
- results.check(run_entry(args, entry, command, out_dir, top))
+ # Run test and record result
+ passed = run_entry(args, entry, command, out_dir, top)
+ results.check(passed)
+
+ # Write test report entry
+ if args.report:
+ with open(args.report, "a", encoding="utf-8") as report:
+ text = util.earl_assertion(uri, passed, args.asserter)
+ report.write(text)
except subprocess.CalledProcessError as exception:
if exception.stderr is not None:
@@ -144,7 +152,9 @@ def main():
description=__doc__,
)
+ parser.add_argument("--asserter", help="asserter URI for test report")
parser.add_argument("--lax", action="store_true", help="tolerate errors")
+ parser.add_argument("--report", help="path to write result report to")
parser.add_argument("--reverse", action="store_true", help="reverse test")
parser.add_argument("--serdi", default="serdi", help="path to serdi")
parser.add_argument("--wrapper", default="", help="executable wrapper")
diff --git a/test/run_test_suite.py b/test/run_test_suite.py
deleted file mode 100755
index a3211644..00000000
--- a/test/run_test_suite.py
+++ /dev/null
@@ -1,293 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright 2022-2023 David Robillard <d@drobilla.net>
-# SPDX-License-Identifier: ISC
-
-"""Run an RDF test suite with serdi."""
-
-# pylint: disable=too-many-arguments
-# pylint: disable=too-many-locals
-# pylint: disable=too-many-statements
-
-import argparse
-import itertools
-import os
-import shlex
-import subprocess
-import sys
-import tempfile
-
-import serd_test_util as util
-
-NS_MF = "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"
-NS_RDFT = "http://www.w3.org/ns/rdftest#"
-
-
-def test_thru(
- base_uri,
- path,
- check_lines,
- check_path,
- out_test_dir,
- flags,
- isyntax,
- osyntax,
- command_prefix,
-):
- """Test lossless round-tripping through two different syntaxes."""
-
- assert isyntax is not None
- assert osyntax is not None
-
- test_name = os.path.basename(path)
- out_path = os.path.join(out_test_dir, test_name + ".pass")
- thru_path = os.path.join(out_test_dir, test_name + ".thru")
-
- out_opts = itertools.chain(
- ["-i", isyntax],
- ["-o", isyntax],
- ["-p", "serd_test"],
- )
-
- out_cmd = (
- command_prefix
- + [f for sublist in flags for f in sublist]
- + list(out_opts)
- + [path, base_uri]
- )
-
- with open(out_path, "wb") as out:
- subprocess.run(out_cmd, check=True, stdout=out)
-
- thru_opts = itertools.chain(
- ["-c", "serd_test"],
- ["-i", isyntax],
- ["-o", osyntax],
- )
-
- thru_cmd = command_prefix + list(thru_opts) + [out_path, base_uri]
-
- proc = subprocess.run(
- thru_cmd, check=True, capture_output=True, encoding="utf-8"
- )
-
- return util.lines_equal(
- check_lines,
- proc.stdout.splitlines(True),
- check_path,
- thru_path,
- )
-
-
-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 RuntimeError("Unknown test class: " + 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 RuntimeError("Unknown test class: " + test_class)
-
-
-def _option_combinations(options):
- """Return an iterator that cycles through all combinations of options."""
-
- combinations = []
- for count in range(len(options) + 1):
- combinations += list(itertools.combinations(options, count))
-
- return itertools.cycle(combinations)
-
-
-def run_suite(
- manifest_path,
- base_uri,
- report_filename,
- input_syntax,
- command_prefix,
- out_test_dir,
-):
- """Run all tests in a test suite manifest."""
-
- test_dir = os.path.dirname(manifest_path)
- model, instances = util.load_rdf(manifest_path, base_uri, command_prefix)
-
- asserter = ""
- if os.getenv("USER") == "drobilla":
- asserter = "http://drobilla.net/drobilla#me"
-
- def run_tests(test_class, tests, expected_return, results):
- thru_flags = [["-e"], ["-f"], ["-b"], ["-r", "http://example.org/"]]
- osyntax = _test_output_syntax(test_class)
- thru_options_iter = _option_combinations(thru_flags)
-
- if input_syntax is not None:
- isyntax = input_syntax
- else:
- isyntax = _test_input_syntax(test_class)
-
- for test in sorted(tests):
- test_uri = model[test][NS_MF + "action"][0]
- test_uri_path = util.uri_path(test_uri)
- test_name = os.path.basename(test_uri_path)
- test_path = os.path.join(test_dir, test_name)
-
- command = command_prefix + ["-f", test_path, test_uri]
- command_string = " ".join(shlex.quote(c) for c in command)
- out_filename = os.path.join(out_test_dir, test_name + ".out")
-
- if expected_return == 0: # Positive test
- with tempfile.TemporaryFile("w+", encoding="utf-8") as out:
- proc = subprocess.run(command, check=False, stdout=out)
- passed = proc.returncode == 0
- results.check(
- passed, "Unexpected failure: " + command_string
- )
-
- if (
- proc.returncode == 0
- and NS_MF + "result" in model[test]
- ):
- # Check output against expected output from test suite
- check_uri = model[test][NS_MF + "result"][0]
- check_filename = os.path.basename(
- util.uri_path(check_uri)
- )
- check_path = os.path.join(test_dir, check_filename)
-
- with open(check_path, "r", encoding="utf-8") as check:
- check_lines = check.readlines()
-
- out.seek(0)
- results.check(
- util.lines_equal(
- check_lines,
- list(out),
- check_path,
- out_filename,
- )
- )
-
- # Run round-trip test
- check.seek(0)
- results.check(
- test_thru(
- test_uri,
- test_path,
- check_lines,
- check_path,
- out_test_dir,
- list(next(thru_options_iter)),
- isyntax,
- osyntax,
- command_prefix,
- ),
- "Corrupted round-trip: " + test_uri,
- )
-
- else: # Negative test
- with tempfile.TemporaryFile() as stderr:
- proc = subprocess.run(
- command,
- check=False,
- stdout=subprocess.DEVNULL,
- stderr=stderr,
- )
-
- passed = proc.returncode != 0
- results.check(
- passed, "Unexpected success: " + command_string
- )
-
- # Check that an error message was printed
- stderr.seek(0, 2) # Seek to end
- results.check(
- stderr.tell() > 0,
- "No error message printed: " + command_string,
- )
-
- # Write test report entry
- if report_filename:
- with open(report_filename, "a", encoding="utf-8") as report:
- report.write(util.earl_assertion(test, passed, asserter))
-
- # Run all test types in the test suite
- results = util.Results()
- for test_class, instances in instances.items():
- if test_class.startswith(NS_RDFT):
- expected = (
- 1
- if "-l" not in command_prefix and "Negative" in test_class
- else 0
- )
- run_tests(test_class, instances, expected, results)
-
- return util.print_result_summary(results)
-
-
-def main():
- """Run the command line tool."""
-
- parser = argparse.ArgumentParser(
- usage="%(prog)s [OPTION]... MANIFEST BASE_URI -- [SERDI_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("--syntax", default=None, help="input 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(
- "serdi_option", nargs=argparse.REMAINDER, help="option for serdi"
- )
-
- args = parser.parse_args(sys.argv[1:])
- command_prefix = (
- shlex.split(args.wrapper) + [args.serdi] + args.serdi_option
- )
-
- with tempfile.TemporaryDirectory() as test_out_dir:
- return run_suite(
- args.manifest,
- args.base_uri,
- args.report,
- args.syntax,
- 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)
-
- sys.stderr.write("error: ")
- sys.stderr.write(str(e))
- sys.stderr.write("\n")
- sys.exit(e.returncode)