File: run_suite.py

package info (click to toggle)
serd 0.32.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,696 kB
  • sloc: ansic: 7,137; python: 500; makefile: 5
file content (171 lines) | stat: -rwxr-xr-x 5,766 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python3

# Copyright 2022-2023 David Robillard <d@drobilla.net>
# SPDX-License-Identifier: ISC

"""Run a "simple" one-pass RDF-based test suite for serd."""

import argparse
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_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
NS_RDFT = "http://www.w3.org/ns/rdftest#"

DEVNULL = subprocess.DEVNULL
PIPE = subprocess.PIPE

TEST_TYPES = [
    NS_RDFT + "TestNQuadsNegativeSyntax",
    NS_RDFT + "TestNQuadsPositiveSyntax",
    NS_RDFT + "TestNTriplesNegativeSyntax",
    NS_RDFT + "TestNTriplesPositiveSyntax",
    NS_RDFT + "TestTrigEval",
    NS_RDFT + "TestTrigNegativeEval",
    NS_RDFT + "TestTrigNegativeSyntax",
    NS_RDFT + "TestTrigPositiveSyntax",
    NS_RDFT + "TestTurtleEval",
    NS_RDFT + "TestTurtleNegativeEval",
    NS_RDFT + "TestTurtleNegativeSyntax",
    NS_RDFT + "TestTurtlePositiveSyntax",
]


def run_eval_test(base_uri, command, in_path, good_path, out_path):
    """Run a positive eval test and return whether the output matches."""

    syntax = util.syntax_from_path(out_path)
    command = command + ["-o", syntax, in_path, base_uri]

    with subprocess.Popen(command, stdout=PIPE, encoding="utf-8") as proc:
        out = list(proc.stdout)

    with open(good_path, "r", encoding="utf-8") as good:
        return util.lines_equal(list(good), out, good_path, out_path)


def run_positive_test(base_uri, command, in_path):
    """Run a positive syntax test and ensure no errors occur."""

    command = command + [in_path, base_uri]
    subprocess.check_call(command, encoding="utf-8", stdout=DEVNULL)
    return True


def run_negative_test(base_uri, command, in_path):
    """Run a negative syntax test and return whether the error was detected."""

    if not os.path.exists(in_path):
        raise RuntimeError("Input file missing: " + in_path)

    command = command + [in_path, base_uri]
    proc = subprocess.run(command, check=False, stderr=PIPE, stdout=DEVNULL)

    if proc.returncode == 0:
        util.error("Unexpected successful return: " + in_path)
        return False

    if len(proc.stderr) == 0:
        util.error("Command failed with no error output: " + in_path)
        return False

    return True


def run_entry(args, entry, command, out_dir, suite_dir):
    """Run a single test entry from the manifest."""

    in_path = util.file_path(suite_dir, entry[NS_MF + "action"][0])
    base = args.base_uri + os.path.basename(in_path)

    negative = "Negative" in entry[NS_RDF + "type"][0]
    if negative and not args.lax:
        return run_negative_test(base, command, in_path)

    if NS_MF + "result" not in entry:
        return run_positive_test(base, command, in_path)

    good_path = util.file_path(suite_dir, entry[NS_MF + "result"][0])
    if args.reverse:
        in_path, good_path = good_path, in_path

    out_path = os.path.join(out_dir, os.path.basename(good_path))
    return run_eval_test(base, command, in_path, good_path, out_path)


def run_suite(args, command, out_dir):
    """Run all tests in the manifest."""

    # Load manifest model
    top = os.path.dirname(args.manifest)
    model, instances = util.load_rdf(args.manifest, args.base_uri, command)

    # Run all the listed tests that have known types
    command = command + args.arg
    results = util.Results()
    for klass, instances in instances.items():
        check = klass in [NS_RDFT + "TestTrigEval", NS_RDFT + "TestTurtleEval"]
        if klass == NS_MF + "Manifest":
            continue

        if klass not in TEST_TYPES:
            raise RuntimeError("Unknown manifest entry type: " + klass)

        for uri in instances:
            try:
                entry = model[uri]
                if check and NS_MF + "result" not in entry:
                    raise RuntimeError("Eval test missing result: " + uri)

                # 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:
                    sys.stderr.write(exception.stderr)

                results.check(False, str(exception) + "\n")

    return util.print_result_summary(results)


def main():
    """Run the command line tool."""

    parser = argparse.ArgumentParser(
        usage="%(prog)s [OPTION]... MANIFEST BASE_URI -- [ARG]...",
        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")
    parser.add_argument("manifest", help="test suite manifest.ttl file")
    parser.add_argument("base_uri", help="base URI for tests")
    parser.add_argument("arg", nargs=argparse.REMAINDER, help="serdi argument")

    args = parser.parse_args(sys.argv[1:])
    command = shlex.split(args.wrapper) + [args.serdi]

    with tempfile.TemporaryDirectory() as temp:
        return run_suite(args, command, temp)


if __name__ == "__main__":
    sys.exit(main())