From b404312686874e539b617d1f27ccbaa5a82936af Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 21 Oct 2021 15:38:10 -0400 Subject: 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. --- test/run_filter_suite.py | 160 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100755 test/run_filter_suite.py (limited to 'test/run_filter_suite.py') 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) -- cgit v1.2.1