aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/meson.build22
-rw-r--r--test/pretty/meson.build16
-rwxr-xr-xtest/run_filter_suite.py2
-rwxr-xr-xtest/run_validation_test_suite.py278
-rw-r--r--test/test_string.c2
-rw-r--r--test/validate/bad-all-values-from.ttl24
-rw-r--r--test/validate/bad-anyuri.ttl13
-rw-r--r--test/validate/bad-cardinality-high.ttl19
-rw-r--r--test/validate/bad-cardinality-low.ttl17
-rw-r--r--test/validate/bad-cardinality.ttl19
-rw-r--r--test/validate/bad-class-type-undefined.ttl5
-rw-r--r--test/validate/bad-class-type.ttl9
-rw-r--r--test/validate/bad-datatype-cycle.ttl18
-rw-r--r--test/validate/bad-datatype-property.ttl19
-rw-r--r--test/validate/bad-deprecated-class.ttl12
-rw-r--r--test/validate/bad-deprecated-property.ttl13
-rw-r--r--test/validate/bad-disjoint-with.ttl18
-rw-r--r--test/validate/bad-domain.ttl27
-rw-r--r--test/validate/bad-functional-property.ttl13
-rw-r--r--test/validate/bad-inverse-functional-property.ttl15
-rw-r--r--test/validate/bad-literal-pattern.ttl22
-rw-r--r--test/validate/bad-literal-value-high-exclusive.ttl20
-rw-r--r--test/validate/bad-literal-value-high-inclusive.ttl20
-rw-r--r--test/validate/bad-literal-value-low-exclusive.ttl20
-rw-r--r--test/validate/bad-literal-value-low-inclusive.ttl21
-rw-r--r--test/validate/bad-literal-value.ttl7
-rw-r--r--test/validate/bad-object-property.ttl12
-rw-r--r--test/validate/bad-pattern.ttl23
-rw-r--r--test/validate/bad-plain-literal.ttl12
-rw-r--r--test/validate/bad-predicate-type-undefined.ttl5
-rw-r--r--test/validate/bad-predicate-type.ttl9
-rw-r--r--test/validate/bad-range-instance-not-literal.ttl19
-rw-r--r--test/validate/bad-range-instance.ttl24
-rw-r--r--test/validate/bad-range-literal-not-instance.ttl16
-rw-r--r--test/validate/bad-range-literal.ttl27
-rw-r--r--test/validate/bad-some-values-from.ttl19
-rw-r--r--test/validate/bad-string-literal-value-high.ttl21
-rw-r--r--test/validate/bad-string-literal-value-low.ttl21
-rw-r--r--test/validate/bad-subclass-cycle.ttl13
-rw-r--r--test/validate/bad-subproperty-cycle.ttl14
-rw-r--r--test/validate/bad-superclass-restriction.ttl22
-rw-r--r--test/validate/bad-union-of.ttl46
-rw-r--r--test/validate/bad-unknown-datatype.ttl7
-rw-r--r--test/validate/good-anyuri.ttl13
-rw-r--r--test/validate/good-cardinality.ttl18
-rw-r--r--test/validate/good-literal-value-high-inclusive.ttl21
-rw-r--r--test/validate/good-literal-value-low-inclusive.ttl21
-rw-r--r--test/validate/good-owl-thing.ttl16
-rw-r--r--test/validate/good-pattern.ttl22
-rw-r--r--test/validate/good-rdfs-resource.ttl12
-rw-r--r--test/validate/good-some-values-from.ttl18
-rw-r--r--test/validate/good-string-literal-value-low.ttl21
-rw-r--r--test/validate/good-union-of.ttl51
-rw-r--r--test/validate/manifest.ttl362
54 files changed, 1552 insertions, 4 deletions
diff --git a/test/meson.build b/test/meson.build
index eae5d42e..cd0991f8 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -4,6 +4,7 @@ run_filter_suite = find_program('run_filter_suite.py')
run_pipe_suite = find_program('run_pipe_suite.py')
run_pretty_suite = find_program('run_pretty_suite.py')
run_sort_suite = find_program('run_sort_suite.py')
+run_validation_test_suite = find_program('run_validation_test_suite.py')
wrapper = meson.get_cross_property('exe_wrapper', '')
@@ -403,6 +404,27 @@ if is_variable('serd_filter')
# RDF-driven test suite
subdir('filter')
+ validate_test_script_args = (common_script_options +
+ ['--pipe', serd_pipe] +
+ ['--validate', serd_validate])
+
+ # Validation test suite
+ test('validate',
+ run_validation_test_suite,
+ args: validate_test_script_args + [
+ files('validate/manifest.ttl'),
+ 'http://drobilla.net/sw/serd/test/validate/',
+ serd_src_root / 'schemas/dc.ttl',
+ serd_src_root / 'schemas/dcam.ttl',
+ serd_src_root / 'schemas/dcterms.ttl',
+ serd_src_root / 'schemas/owl.ttl',
+ serd_src_root / 'schemas/rdf.ttl',
+ serd_src_root / 'schemas/rdfs.ttl',
+ serd_src_root / 'schemas/xsd.ttl',
+ ],
+ env: test_env,
+ suite: ['suite', 'validate'],
+ timeout: 240)
endif
# Run RDF-driven test suites using serd-pipe and serd-sort
diff --git a/test/pretty/meson.build b/test/pretty/meson.build
index 634f1e0e..673759dc 100644
--- a/test/pretty/meson.build
+++ b/test/pretty/meson.build
@@ -1,17 +1,27 @@
base_uri = 'http://drobilla.net/sw/serd/test/good/'
-args = [files('manifest.ttl')]
+args = [
+ files('manifest.ttl')
+]
test('pretty',
run_pretty_suite,
- args: pipe_test_script_args + ['-o', meson.current_build_dir() / 'pipe'] + args,
+ args: common_script_options + [
+ '--tool', serd_pipe,
+ '--out-dir',
+ meson.current_build_dir() / 'pipe'
+ ] + args,
env: test_env,
suite: ['suite', 'extra', 'pipe'],
timeout: 240)
test('pretty',
run_pretty_suite,
- args: sort_test_script_args + ['-o', meson.current_build_dir() / 'sort'] + args,
+ args: common_script_options + [
+ '--tool', serd_sort,
+ '--out-dir',
+ meson.current_build_dir() / 'sort'
+ ] + args,
env: test_env,
suite: ['suite', 'extra', 'sort'],
timeout: 240)
diff --git a/test/run_filter_suite.py b/test/run_filter_suite.py
index 222b98e4..0e414c69 100755
--- a/test/run_filter_suite.py
+++ b/test/run_filter_suite.py
@@ -124,9 +124,11 @@ def main():
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")
diff --git a/test/run_validation_test_suite.py b/test/run_validation_test_suite.py
new file mode 100755
index 00000000..890ca7d6
--- /dev/null
+++ b/test/run_validation_test_suite.py
@@ -0,0 +1,278 @@
+#!/usr/bin/env python3
+
+"""Run the serd RDF validation test suite."""
+
+import argparse
+import os
+import re
+import shlex
+import subprocess
+import sys
+import tempfile
+import urllib.parse
+
+import serd_test_util
+
+NS_CHECKS = "http://drobilla.net/ns/serd/checks#"
+NS_MF = "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#"
+NS_SERD = "http://drobilla.net/ns/serd#"
+
+
+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 os.path.realpath(path) if not drive else path[1:]
+
+
+def _run_positive_test(command, out_filename):
+ command_string = " ".join([shlex.quote(c) for c in command])
+
+ with open(out_filename, "w") as stdout:
+ with tempfile.TemporaryFile() as stderr:
+ proc = subprocess.run(
+ command, check=False, stdout=stdout, stderr=stderr
+ )
+ if proc.returncode != 0:
+ log_error("Unexpected command failure\n")
+ sys.stderr.write(command_string + "\n")
+ err_output = stderr.read().decode("utf-8")
+ sys.stderr.write(err_output + "\n")
+ return 1
+
+ return proc.returncode
+
+ return 1
+
+
+def _run_negative_test(command, check_names, out_filename, verbose):
+ command_string = " ".join([shlex.quote(c) for c in command])
+
+ with open(out_filename, "w") as stdout:
+ with tempfile.TemporaryFile() as stderr:
+ proc = subprocess.run(
+ command, check=False, stdout=stdout, stderr=stderr
+ )
+
+ stderr.seek(0, 0) # Seek to beginning
+ err_output = stderr.read().decode("utf-8")
+ if verbose:
+ sys.stderr.write(err_output)
+
+ # Check that the tool returned with status SERD_ERR_INVALID
+ if proc.returncode != 21:
+ log_error("Unexpected status {}\n".format(proc.returncode))
+ sys.stderr.write(command_string + "\n")
+ sys.stderr.write(err_output + "\n")
+ return 1
+
+ # Check that an error message was printed
+ stderr.seek(0, 2) # Seek to end
+ if stderr.tell() == 0: # Empty
+ log_error("No error message printed\n")
+ sys.stderr.write(command_string + "\n")
+ return 1
+
+ # Check that the expected check printed an error message
+ stderr.seek(0) # Seek to start
+ triggered = True
+ for check_name in check_names:
+ if "[{}]".format(check_name) not in err_output:
+ triggered = False
+ break
+
+ if not triggered:
+ log_error("Test didn't trigger {}\n".format(check_names))
+ sys.stderr.write(command_string + "\n")
+ sys.stderr.write(err_output + "\n")
+ return 1
+
+ return 0
+
+ return 1
+
+
+def validation_test_suite(
+ manifest_path,
+ schemas,
+ base_uri,
+ report_filename,
+ pipe_command_prefix,
+ validate_command_prefix,
+ verbose,
+):
+ """Run all tests in a test suite manifest."""
+
+ schema_options = []
+ for schema in schemas:
+ schema_options += ["-s", schema]
+
+ test_dir = os.path.dirname(manifest_path)
+ model, instances = serd_test_util.load_rdf(
+ pipe_command_prefix + ["-B", base_uri], manifest_path
+ )
+
+ top_dir = os.path.commonpath([os.getcwd(), os.path.abspath(test_dir)])
+ out_test_dir = os.path.relpath(test_dir, top_dir)
+
+ os.makedirs(out_test_dir, exist_ok=True)
+
+ asserter = ""
+ if os.getenv("USER") == "drobilla":
+ asserter = "http://drobilla.net/drobilla#me"
+
+ class Results:
+ """Aggregated count of all tests and results."""
+
+ def __init__(self):
+ self.n_tests = 0
+ self.n_failures = 0
+
+ def run_tests(tests, expected_return, results):
+ for test in sorted(tests):
+ print(test)
+ test_uri = model[test][NS_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)
+ out_filename = os.path.join(out_test_dir, test_name + ".out")
+
+ results.n_tests += 1
+
+ if expected_return == 0: # Positive test
+ options = ["-W", "everything"]
+ command = (
+ validate_command_prefix
+ + options
+ + schema_options
+ + [test_path]
+ )
+
+ status = _run_positive_test(command, out_filename)
+ passed = status == 0
+ results.n_failures += status
+
+ else: # Negative test
+ if NS_SERD + "triggersCheck" not in model[test]:
+ log_error("{} has no serd:triggersCheck".format(test_name))
+
+ check_names = []
+ if NS_SERD + "triggersCheck" in model[test]:
+ for check in model[test][NS_SERD + "triggersCheck"]:
+ check_names += [check[len(NS_CHECKS) :]]
+
+ options = []
+ for check_name in check_names:
+ options += ["-W", check_name]
+
+ command = (
+ validate_command_prefix
+ + options
+ + schema_options
+ + [test_path]
+ )
+ status = _run_negative_test(
+ command, check_names, out_filename, verbose
+ )
+ passed = status == 0
+ results.n_failures += status
+
+ if passed:
+ options = ["-W", "everything"]
+ for check_name in check_names:
+ options += ["-X", check_name]
+
+ command = (
+ validate_command_prefix
+ + options
+ + schema_options
+ + [test_path]
+ )
+ status = _run_positive_test(command, out_filename)
+ passed = status == 0
+ results.n_failures += status
+
+ # 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_serd = "http://drobilla.net/ns/serd#"
+ for test_class, instances in instances.items():
+ if test_class.startswith(ns_serd):
+ expected = 1 if "Negative" in test_class else 0
+ run_tests(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 SCHEMA...",
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+
+ parser.add_argument(
+ "--pipe", default="tools/serd-pipe", help="serd-pipe executable"
+ )
+
+ parser.add_argument(
+ "--validate",
+ default="tools/serd-validate",
+ help="serd-validate executable",
+ )
+
+ parser.add_argument("--report", help="path to write result report to")
+ parser.add_argument("--wrapper", default="", help="executable wrapper")
+ parser.add_argument(
+ "-v", "--verbose", action="store_true", help="print expected errors"
+ )
+ parser.add_argument("manifest", help="test suite manifest.ttl file")
+ parser.add_argument("base_uri", help="base URI for tests")
+ parser.add_argument("schema", nargs="+", help="schema file")
+
+ args = parser.parse_args(sys.argv[1:])
+ pipe_command_prefix = shlex.split(args.wrapper) + [args.pipe]
+ validate_command_prefix = shlex.split(args.wrapper) + [args.validate]
+
+ return validation_test_suite(
+ args.manifest,
+ args.schema,
+ args.base_uri,
+ args.report,
+ pipe_command_prefix,
+ validate_command_prefix,
+ args.verbose,
+ )
+
+
+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"))
+
+ log_error(str(error) + "\n")
+ sys.exit(error.returncode)
diff --git a/test/test_string.c b/test/test_string.c
index cdc4bc33..52c43c8e 100644
--- a/test/test_string.c
+++ b/test/test_string.c
@@ -33,7 +33,7 @@ test_strerror(void)
const char* msg = serd_strerror(SERD_SUCCESS);
assert(!strcmp(msg, "Success"));
- for (int i = SERD_FAILURE; i <= SERD_BAD_WRITE; ++i) {
+ for (int i = SERD_FAILURE; i <= SERD_BAD_DATA; ++i) {
msg = serd_strerror((SerdStatus)i);
assert(strcmp(msg, "Success"));
}
diff --git a/test/validate/bad-all-values-from.ttl b/test/validate/bad-all-values-from.ttl
new file mode 100644
index 00000000..4d82bf3d
--- /dev/null
+++ b/test/validate/bad-all-values-from.ttl
@@ -0,0 +1,24 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:index
+ a rdf:Property ;
+ rdfs:label "index" .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty eg:index ;
+ owl:allValuesFrom xsd:nonNegativeInteger
+ ] .
+
+eg:s
+ a eg:Thing ;
+ eg:index 1.2 ,
+ 3 .
+
diff --git a/test/validate/bad-anyuri.ttl b/test/validate/bad-anyuri.ttl
new file mode 100644
index 00000000..ae5e88f0
--- /dev/null
+++ b/test/validate/bad-anyuri.ttl
@@ -0,0 +1,13 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:uri
+ a rdf:Property ;
+ rdfs:label "uri" ;
+ rdfs:range xsd:anyURI .
+
+eg:s
+ eg:uri _:blank .
+
diff --git a/test/validate/bad-cardinality-high.ttl b/test/validate/bad-cardinality-high.ttl
new file mode 100644
index 00000000..2ff8ede3
--- /dev/null
+++ b/test/validate/bad-cardinality-high.ttl
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:maxCardinality 1
+ ] .
+
+eg:s
+ a eg:Thing ;
+ rdf:value 1 ,
+ 2 .
+
diff --git a/test/validate/bad-cardinality-low.ttl b/test/validate/bad-cardinality-low.ttl
new file mode 100644
index 00000000..60bfc9f8
--- /dev/null
+++ b/test/validate/bad-cardinality-low.ttl
@@ -0,0 +1,17 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:minCardinality 1
+ ] .
+
+eg:s
+ a eg:Thing .
+
diff --git a/test/validate/bad-cardinality.ttl b/test/validate/bad-cardinality.ttl
new file mode 100644
index 00000000..5300e566
--- /dev/null
+++ b/test/validate/bad-cardinality.ttl
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:cardinality 3
+ ] .
+
+eg:s
+ a eg:Thing ;
+ rdf:value 1 ,
+ 2 .
+
diff --git a/test/validate/bad-class-type-undefined.ttl b/test/validate/bad-class-type-undefined.ttl
new file mode 100644
index 00000000..1e3c5eba
--- /dev/null
+++ b/test/validate/bad-class-type-undefined.ttl
@@ -0,0 +1,5 @@
+@prefix eg: <http://example.org/> .
+
+eg:s
+ a eg:Undefined .
+
diff --git a/test/validate/bad-class-type.ttl b/test/validate/bad-class-type.ttl
new file mode 100644
index 00000000..a0ddf454
--- /dev/null
+++ b/test/validate/bad-class-type.ttl
@@ -0,0 +1,9 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+
+eg:nonClass
+ a rdf:Bag .
+
+eg:s
+ a eg:nonClass .
+
diff --git a/test/validate/bad-datatype-cycle.ttl b/test/validate/bad-datatype-cycle.ttl
new file mode 100644
index 00000000..dd7cf0ce
--- /dev/null
+++ b/test/validate/bad-datatype-cycle.ttl
@@ -0,0 +1,18 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Alpha
+ a rdfs:Datatype ;
+ rdfs:label "Alpha" ;
+ owl:onDatatype eg:Beta .
+
+eg:Beta
+ a rdfs:Datatype ;
+ rdfs:label "Beta" ;
+ owl:onDatatype eg:Omega .
+
+eg:Omega
+ a rdfs:Datatype ;
+ rdfs:label "Omega" ;
+ owl:onDatatype eg:Alpha .
diff --git a/test/validate/bad-datatype-property.ttl b/test/validate/bad-datatype-property.ttl
new file mode 100644
index 00000000..3c2f7a9f
--- /dev/null
+++ b/test/validate/bad-datatype-property.ttl
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:name
+ a owl:DatatypeProperty ;
+ rdfs:label "name" .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" .
+
+eg:s1
+ a eg:Thing .
+
+eg:s2
+ eg:name eg:s1 .
+
diff --git a/test/validate/bad-deprecated-class.ttl b/test/validate/bad-deprecated-class.ttl
new file mode 100644
index 00000000..51d76d8f
--- /dev/null
+++ b/test/validate/bad-deprecated-class.ttl
@@ -0,0 +1,12 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Square
+ a rdfs:Class ;
+ owl:deprecated true ;
+ rdfs:label "Square" .
+
+eg:square
+ a eg:Square .
+
diff --git a/test/validate/bad-deprecated-property.ttl b/test/validate/bad-deprecated-property.ttl
new file mode 100644
index 00000000..b2bd392c
--- /dev/null
+++ b/test/validate/bad-deprecated-property.ttl
@@ -0,0 +1,13 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:stuff
+ a rdf:Property ;
+ owl:deprecated true ;
+ rdfs:label "stuff" .
+
+eg:s
+ eg:stuff eg:o .
+
diff --git a/test/validate/bad-disjoint-with.ttl b/test/validate/bad-disjoint-with.ttl
new file mode 100644
index 00000000..c56937f5
--- /dev/null
+++ b/test/validate/bad-disjoint-with.ttl
@@ -0,0 +1,18 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Square
+ a owl:Class ;
+ rdfs:label "Square" ;
+ owl:disjointWith eg:Circle .
+
+eg:Circle
+ a owl:Class ;
+ rdfs:label "Circle" ;
+ owl:disjointWith eg:Square .
+
+eg:magicShape
+ a eg:Square ,
+ eg:Circle .
+
diff --git a/test/validate/bad-domain.ttl b/test/validate/bad-domain.ttl
new file mode 100644
index 00000000..52c1849c
--- /dev/null
+++ b/test/validate/bad-domain.ttl
@@ -0,0 +1,27 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:cardinality 1
+ ] ;
+ rdfs:label "Thing" .
+
+eg:NonThing
+ a rdfs:Class ;
+ rdfs:label "NonThing" .
+
+eg:thingName
+ a rdf:Property ;
+ rdfs:label "thing name" ;
+ rdfs:domain eg:Thing .
+
+eg:nonthing
+ a eg:NonThing ;
+ eg:thingName "nonthing" .
+
diff --git a/test/validate/bad-functional-property.ttl b/test/validate/bad-functional-property.ttl
new file mode 100644
index 00000000..53a73ccd
--- /dev/null
+++ b/test/validate/bad-functional-property.ttl
@@ -0,0 +1,13 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:identity
+ rdfs:label "identity" ;
+ a owl:FunctionalProperty .
+
+eg:s
+ eg:identity "me" ,
+ "you" .
+
diff --git a/test/validate/bad-inverse-functional-property.ttl b/test/validate/bad-inverse-functional-property.ttl
new file mode 100644
index 00000000..95c0aaea
--- /dev/null
+++ b/test/validate/bad-inverse-functional-property.ttl
@@ -0,0 +1,15 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:identity
+ rdfs:label "identity" ;
+ a owl:InverseFunctionalProperty .
+
+eg:s1
+ eg:identity "me" .
+
+eg:s2
+ eg:identity "me" .
+
diff --git a/test/validate/bad-literal-pattern.ttl b/test/validate/bad-literal-pattern.ttl
new file mode 100644
index 00000000..fda954ed
--- /dev/null
+++ b/test/validate/bad-literal-pattern.ttl
@@ -0,0 +1,22 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:CapitalLiteral
+ a rdfs:Datatype ;
+ rdfs:label "Capital Literal" ;
+ owl:withRestrictions (
+ [
+ xsd:pattern "[A-Z][a-z]*"
+ ]
+ ) .
+
+eg:value
+ a rdf:Property ;
+ rdfs:label "value" ;
+ rdfs:range eg:CapitalLiteral .
+
+eg:s
+ eg:value "lowercase"^^eg:CapitalLiteral .
diff --git a/test/validate/bad-literal-value-high-exclusive.ttl b/test/validate/bad-literal-value-high-exclusive.ttl
new file mode 100644
index 00000000..fafc74c8
--- /dev/null
+++ b/test/validate/bad-literal-value-high-exclusive.ttl
@@ -0,0 +1,20 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxExclusive 1.0
+ ] [
+ xsd:minExclusive 0.0
+ ]
+ ) .
+
+eg:s
+ rdf:value "1.0"^^eg:Normal .
diff --git a/test/validate/bad-literal-value-high-inclusive.ttl b/test/validate/bad-literal-value-high-inclusive.ttl
new file mode 100644
index 00000000..db19f1cd
--- /dev/null
+++ b/test/validate/bad-literal-value-high-inclusive.ttl
@@ -0,0 +1,20 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive 1.0
+ ] [
+ xsd:minInclusive 0.0
+ ]
+ ) .
+
+eg:s
+ rdf:value "1.1"^^eg:Normal .
diff --git a/test/validate/bad-literal-value-low-exclusive.ttl b/test/validate/bad-literal-value-low-exclusive.ttl
new file mode 100644
index 00000000..082ae9d9
--- /dev/null
+++ b/test/validate/bad-literal-value-low-exclusive.ttl
@@ -0,0 +1,20 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxExclusive 1.0
+ ] [
+ xsd:minExclusive 0.0
+ ]
+ ) .
+
+eg:s
+ rdf:value "0.0"^^eg:Normal .
diff --git a/test/validate/bad-literal-value-low-inclusive.ttl b/test/validate/bad-literal-value-low-inclusive.ttl
new file mode 100644
index 00000000..c7203c81
--- /dev/null
+++ b/test/validate/bad-literal-value-low-inclusive.ttl
@@ -0,0 +1,21 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive 1.0
+ ] [
+ xsd:minInclusive 0.0
+ ]
+ ) .
+
+eg:s
+ rdf:value "-0.1"^^eg:Normal .
+
diff --git a/test/validate/bad-literal-value.ttl b/test/validate/bad-literal-value.ttl
new file mode 100644
index 00000000..af6af40e
--- /dev/null
+++ b/test/validate/bad-literal-value.ttl
@@ -0,0 +1,7 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:s
+ rdf:value "98765"^^xsd:byte .
+
diff --git a/test/validate/bad-object-property.ttl b/test/validate/bad-object-property.ttl
new file mode 100644
index 00000000..335db339
--- /dev/null
+++ b/test/validate/bad-object-property.ttl
@@ -0,0 +1,12 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:child
+ rdfs:label "child" ;
+ a owl:ObjectProperty .
+
+eg:s
+ eg:child "literal" .
+
diff --git a/test/validate/bad-pattern.ttl b/test/validate/bad-pattern.ttl
new file mode 100644
index 00000000..fef79aeb
--- /dev/null
+++ b/test/validate/bad-pattern.ttl
@@ -0,0 +1,23 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:BrokenLiteral
+ a rdfs:Datatype ;
+ rdfs:label "Broken Literal" ;
+ owl:withRestrictions (
+ [
+ xsd:pattern "["
+ ]
+ ) .
+
+# eg:value
+# a rdf:Property ;
+# rdfs:label "value" ;
+# rdfs:range eg:BrokenLiteral .
+
+eg:s
+ rdf:value "no match"^^eg:BrokenLiteral .
+
diff --git a/test/validate/bad-plain-literal.ttl b/test/validate/bad-plain-literal.ttl
new file mode 100644
index 00000000..c6f60c2c
--- /dev/null
+++ b/test/validate/bad-plain-literal.ttl
@@ -0,0 +1,12 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:value
+ a rdf:Property ;
+ rdfs:label "value" ;
+ rdfs:range rdf:PlainLiteral .
+
+eg:s
+ eg:value "typed"^^rdf:XMLLiteral .
+
diff --git a/test/validate/bad-predicate-type-undefined.ttl b/test/validate/bad-predicate-type-undefined.ttl
new file mode 100644
index 00000000..246594ee
--- /dev/null
+++ b/test/validate/bad-predicate-type-undefined.ttl
@@ -0,0 +1,5 @@
+@prefix eg: <http://example.org/> .
+
+eg:s
+ eg:undefined 0 .
+
diff --git a/test/validate/bad-predicate-type.ttl b/test/validate/bad-predicate-type.ttl
new file mode 100644
index 00000000..84163d64
--- /dev/null
+++ b/test/validate/bad-predicate-type.ttl
@@ -0,0 +1,9 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+
+eg:nonProperty
+ a rdf:Bag .
+
+eg:s
+ eg:nonProperty 0 .
+
diff --git a/test/validate/bad-range-instance-not-literal.ttl b/test/validate/bad-range-instance-not-literal.ttl
new file mode 100644
index 00000000..5132a70f
--- /dev/null
+++ b/test/validate/bad-range-instance-not-literal.ttl
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" .
+
+eg:value
+ a rdf:Property ;
+ rdfs:label "value" ;
+ rdfs:range rdfs:Literal .
+
+eg:thing
+ a eg:Thing .
+
+eg:s
+ eg:value eg:thing .
+
diff --git a/test/validate/bad-range-instance.ttl b/test/validate/bad-range-instance.ttl
new file mode 100644
index 00000000..d0a08a7a
--- /dev/null
+++ b/test/validate/bad-range-instance.ttl
@@ -0,0 +1,24 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:minCardinality 1
+ ] .
+
+eg:value
+ a rdf:Property ;
+ rdfs:label "value" ;
+ rdfs:range eg:Thing .
+
+eg:nonthing
+ rdfs:label "not a Thing" .
+
+eg:s
+ eg:value eg:nonthing .
diff --git a/test/validate/bad-range-literal-not-instance.ttl b/test/validate/bad-range-literal-not-instance.ttl
new file mode 100644
index 00000000..039fcea8
--- /dev/null
+++ b/test/validate/bad-range-literal-not-instance.ttl
@@ -0,0 +1,16 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" .
+
+eg:value
+ a rdf:Property ;
+ rdfs:label "value" ;
+ rdfs:range eg:Thing .
+
+eg:s
+ eg:value "literal" .
+
diff --git a/test/validate/bad-range-literal.ttl b/test/validate/bad-range-literal.ttl
new file mode 100644
index 00000000..d656aa16
--- /dev/null
+++ b/test/validate/bad-range-literal.ttl
@@ -0,0 +1,27 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive 1.0
+ ] [
+ xsd:minInclusive 0.0
+ ]
+ ) .
+
+eg:scaled
+ a rdf:Property ;
+ rdfs:label "scaled" ;
+ rdfs:range eg:Normal .
+
+eg:s
+ eg:scaled 2.0 .
+
+
diff --git a/test/validate/bad-some-values-from.ttl b/test/validate/bad-some-values-from.ttl
new file mode 100644
index 00000000..9a8ee849
--- /dev/null
+++ b/test/validate/bad-some-values-from.ttl
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdfs:label ;
+ owl:someValuesFrom rdf:PlainLiteral
+ ] .
+
+eg:s
+ a eg:Thing ;
+ rdfs:label "not plain"^^rdf:XMLLiteral .
+
+
diff --git a/test/validate/bad-string-literal-value-high.ttl b/test/validate/bad-string-literal-value-high.ttl
new file mode 100644
index 00000000..93e675ef
--- /dev/null
+++ b/test/validate/bad-string-literal-value-high.ttl
@@ -0,0 +1,21 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:startsWithC
+ a rdfs:Datatype ;
+ rdfs:label "Starts With C" ;
+ owl:onDatatype xsd:string ;
+ owl:withRestrictions (
+ [
+ xsd:maxExclusive "D"
+ ] [
+ xsd:minInclusive "B"
+ ]
+ ) .
+
+eg:s
+ rdf:value "Door"^^eg:startsWithC .
+
diff --git a/test/validate/bad-string-literal-value-low.ttl b/test/validate/bad-string-literal-value-low.ttl
new file mode 100644
index 00000000..2b6985f8
--- /dev/null
+++ b/test/validate/bad-string-literal-value-low.ttl
@@ -0,0 +1,21 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:betweenBAndD
+ a rdfs:Datatype ;
+ rdfs:label "Between B and D" ;
+ owl:onDatatype xsd:string ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive "D"
+ ] [
+ xsd:minExclusive "B"
+ ]
+ ) .
+
+eg:s
+ rdf:value "Aardvark"^^eg:betweenBAndD .
+
diff --git a/test/validate/bad-subclass-cycle.ttl b/test/validate/bad-subclass-cycle.ttl
new file mode 100644
index 00000000..1e702832
--- /dev/null
+++ b/test/validate/bad-subclass-cycle.ttl
@@ -0,0 +1,13 @@
+@prefix eg: <http://example.org/> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Square
+ a rdfs:Class ;
+ rdfs:subClassOf eg:Rectangle ;
+ rdfs:label "Square" .
+
+eg:Rectangle
+ a rdfs:Class ;
+ rdfs:subClassOf eg:Square ;
+ rdfs:label "Rectangle" .
+
diff --git a/test/validate/bad-subproperty-cycle.ttl b/test/validate/bad-subproperty-cycle.ttl
new file mode 100644
index 00000000..eb3bbee4
--- /dev/null
+++ b/test/validate/bad-subproperty-cycle.ttl
@@ -0,0 +1,14 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:stuff
+ a rdf:Property ;
+ rdfs:subPropertyOf eg:things ;
+ rdfs:label "stuff" .
+
+eg:things
+ a rdf:Property ;
+ rdfs:subPropertyOf eg:stuff ;
+ rdfs:label "things" .
+
diff --git a/test/validate/bad-superclass-restriction.ttl b/test/validate/bad-superclass-restriction.ttl
new file mode 100644
index 00000000..bd820de4
--- /dev/null
+++ b/test/validate/bad-superclass-restriction.ttl
@@ -0,0 +1,22 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:SuperThing
+ a rdfs:Class ;
+ rdfs:label "SuperThing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:minCardinality 1
+ ] .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf eg:SuperThing .
+
+eg:s
+ a eg:Thing .
+
diff --git a/test/validate/bad-union-of.ttl b/test/validate/bad-union-of.ttl
new file mode 100644
index 00000000..0198ce1d
--- /dev/null
+++ b/test/validate/bad-union-of.ttl
@@ -0,0 +1,46 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:index
+ a rdf:Property ;
+ rdfs:label "index" .
+
+eg:name
+ a rdf:Property ;
+ rdfs:label "name" .
+
+eg:ThingWithIndex
+ a rdfs:Class ;
+ rdfs:label "Thing With Index" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty eg:index ;
+ owl:minCardinality 1
+ ] .
+
+eg:ThingWithName
+ a rdfs:Class ;
+ rdfs:label "Thing With Name" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty eg:name ;
+ owl:minCardinality 1
+ ] .
+
+eg:something
+ a rdf:Property ;
+ rdfs:label "something" ;
+ rdfs:range [
+ owl:unionOf (
+ eg:ThingWithIndex
+ eg:ThingWithName
+ )
+ ] .
+
+eg:s1
+ eg:something [
+ rdfs:label "s1"
+ ] .
diff --git a/test/validate/bad-unknown-datatype.ttl b/test/validate/bad-unknown-datatype.ttl
new file mode 100644
index 00000000..ed879414
--- /dev/null
+++ b/test/validate/bad-unknown-datatype.ttl
@@ -0,0 +1,7 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:s
+ rdfs:label "bad datatype"^^rdf:UndefinedLiteral .
+
diff --git a/test/validate/good-anyuri.ttl b/test/validate/good-anyuri.ttl
new file mode 100644
index 00000000..e05f8b71
--- /dev/null
+++ b/test/validate/good-anyuri.ttl
@@ -0,0 +1,13 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:uri
+ a rdf:Property ;
+ rdfs:label "uri" ;
+ rdfs:range xsd:anyURI .
+
+eg:s
+ eg:uri <http://example.org> .
+
diff --git a/test/validate/good-cardinality.ttl b/test/validate/good-cardinality.ttl
new file mode 100644
index 00000000..74615fdc
--- /dev/null
+++ b/test/validate/good-cardinality.ttl
@@ -0,0 +1,18 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdf:value ;
+ owl:cardinality 2
+ ] .
+
+eg:s
+ a eg:Thing ;
+ rdf:value 1 ,
+ 2 .
diff --git a/test/validate/good-literal-value-high-inclusive.ttl b/test/validate/good-literal-value-high-inclusive.ttl
new file mode 100644
index 00000000..18cbed0e
--- /dev/null
+++ b/test/validate/good-literal-value-high-inclusive.ttl
@@ -0,0 +1,21 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive 1.0
+ ]
+ [
+ xsd:minInclusive 0.0
+ ]
+ ) .
+
+eg:s
+ rdf:value "1.0"^^eg:Normal .
diff --git a/test/validate/good-literal-value-low-inclusive.ttl b/test/validate/good-literal-value-low-inclusive.ttl
new file mode 100644
index 00000000..e6ad334c
--- /dev/null
+++ b/test/validate/good-literal-value-low-inclusive.ttl
@@ -0,0 +1,21 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:Normal
+ a rdfs:Datatype ;
+ rdfs:label "Normal" ;
+ owl:onDatatype xsd:double ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive 1.0
+ ]
+ [
+ xsd:minInclusive 0.0
+ ]
+ ) .
+
+eg:s
+ rdf:value "0.0"^^eg:Normal .
diff --git a/test/validate/good-owl-thing.ttl b/test/validate/good-owl-thing.ttl
new file mode 100644
index 00000000..9c4b570d
--- /dev/null
+++ b/test/validate/good-owl-thing.ttl
@@ -0,0 +1,16 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:someThing
+ a rdf:Property ;
+ rdfs:label "some thing" ;
+ rdfs:range owl:Thing .
+
+eg:thisThing
+ rdfs:label "this thing" .
+
+eg:s
+ eg:someThing eg:thisThing .
+
diff --git a/test/validate/good-pattern.ttl b/test/validate/good-pattern.ttl
new file mode 100644
index 00000000..740ec22c
--- /dev/null
+++ b/test/validate/good-pattern.ttl
@@ -0,0 +1,22 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:CapitalLiteral
+ a rdfs:Datatype ;
+ rdfs:label "Capital Literal" ;
+ owl:withRestrictions (
+ [
+ xsd:pattern "[A-Z][a-z]*"
+ ]
+ ) .
+
+eg:value
+ a rdf:Property ;
+ rdfs:label "value" ;
+ rdfs:range eg:CapitalLiteral .
+
+eg:s
+ eg:value "Uppercase"^^eg:CapitalLiteral .
diff --git a/test/validate/good-rdfs-resource.ttl b/test/validate/good-rdfs-resource.ttl
new file mode 100644
index 00000000..26310553
--- /dev/null
+++ b/test/validate/good-rdfs-resource.ttl
@@ -0,0 +1,12 @@
+@prefix eg: <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:resource
+ a rdf:Property ;
+ rdfs:label "resource" ;
+ rdfs:range rdfs:Resource .
+
+eg:s
+ eg:resource <http://example.org> .
+
diff --git a/test/validate/good-some-values-from.ttl b/test/validate/good-some-values-from.ttl
new file mode 100644
index 00000000..23f977fd
--- /dev/null
+++ b/test/validate/good-some-values-from.ttl
@@ -0,0 +1,18 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+eg:Thing
+ a rdfs:Class ;
+ rdfs:label "Thing" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty rdfs:label ;
+ owl:someValuesFrom rdf:PlainLiteral
+ ] .
+
+eg:s
+ a eg:Thing ;
+ rdfs:label "not plain"^^rdf:XMLLiteral ,
+ "plain" .
diff --git a/test/validate/good-string-literal-value-low.ttl b/test/validate/good-string-literal-value-low.ttl
new file mode 100644
index 00000000..7d71856b
--- /dev/null
+++ b/test/validate/good-string-literal-value-low.ttl
@@ -0,0 +1,21 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:betweenBAndD
+ a rdfs:Datatype ;
+ rdfs:label "Between B and D" ;
+ owl:onDatatype xsd:string ;
+ owl:withRestrictions (
+ [
+ xsd:maxInclusive "D"
+ ]
+ [
+ xsd:minExclusive "B"
+ ]
+ ) .
+
+eg:s
+ rdf:value "Cat"^^eg:betweenBAndD .
diff --git a/test/validate/good-union-of.ttl b/test/validate/good-union-of.ttl
new file mode 100644
index 00000000..67901f94
--- /dev/null
+++ b/test/validate/good-union-of.ttl
@@ -0,0 +1,51 @@
+@prefix eg: <http://example.org/> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+eg:index
+ a rdf:Property ;
+ rdfs:label "index" .
+
+eg:name
+ a rdf:Property ;
+ rdfs:label "name" .
+
+eg:ThingWithIndex
+ a rdfs:Class ;
+ rdfs:label "Thing With Index" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty eg:index ;
+ owl:minCardinality 1
+ ] .
+
+eg:ThingWithName
+ a rdfs:Class ;
+ rdfs:label "Thing With Name" ;
+ rdfs:subClassOf [
+ a owl:Restriction ;
+ owl:onProperty eg:name ;
+ owl:minCardinality 1
+ ] .
+
+eg:something
+ a rdf:Property ;
+ rdfs:label "something" ;
+ rdfs:range [
+ owl:unionOf (
+ eg:ThingWithIndex
+ eg:ThingWithName
+ )
+ ] .
+
+eg:s1
+ eg:something [
+ eg:index 42
+ ] .
+
+eg:s2
+ eg:something [
+ eg:name "ess"
+ ] .
diff --git a/test/validate/manifest.ttl b/test/validate/manifest.ttl
new file mode 100644
index 00000000..c2e9988a
--- /dev/null
+++ b/test/validate/manifest.ttl
@@ -0,0 +1,362 @@
+@prefix checks: <http://drobilla.net/ns/serd/checks#> .
+@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@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
+ a rdfs:Class ;
+ rdfs:subClassOf mf:ManifestEntry .
+
+serd:TestTurtleNegativeValidate
+ a rdfs:Class ;
+ rdfs:label "Turtle Negative Validation" ;
+ rdfs:subClassOf rdft:Test ,
+ [
+ a owl:Restriction ;
+ owl:onProperty serd:triggersCheck ;
+ owl:minCardinality 1
+ ] .
+
+serd:TestTurtlePositiveValidate
+ a rdfs:Class ;
+ rdfs:label "Turtle Positive Validation" ;
+ rdfs:subClassOf rdft:Test .
+
+serd:triggersCheck
+ a rdf:Property ;
+ rdfs:label "triggers check" ;
+ rdfs:range serd:ValidatorCheck .
+
+serd:triggersCheck
+ a rdf:Property ;
+ rdfs:label "triggers check" ;
+ rdfs:range serd:ValidatorCheck .
+
+<>
+ a mf:Manifest ;
+ rdfs:comment "Serd validation test cases" ;
+ mf:entries (
+ <#bad-all-values-from>
+ <#bad-anyuri>
+ <#bad-cardinality-high>
+ <#bad-cardinality-low>
+ <#bad-cardinality>
+ <#bad-datatype-cycle>
+ <#bad-datatype-property>
+ <#bad-deprecated-class>
+ <#bad-deprecated-property>
+ <#bad-domain>
+ <#bad-functional-property>
+ <#bad-inverse-functional-property>
+ <#bad-literal-pattern>
+ <#bad-literal-value-high-exclusive>
+ <#bad-literal-value-high-inclusive>
+ <#bad-literal-value-low-exclusive>
+ <#bad-literal-value-low-inclusive>
+ <#bad-literal-value>
+ <#bad-object-property>
+ <#bad-pattern>
+ <#bad-plain-literal>
+ <#bad-predicate-type-undefined>
+ <#bad-predicate-type>
+ <#bad-range-instance-not-literal>
+ <#bad-range-instance>
+ <#bad-range-literal-not-instance>
+ <#bad-range-literal>
+ <#bad-some-values-from>
+ <#bad-string-literal-value-high>
+ <#bad-string-literal-value-low>
+ <#bad-subclass-cycle>
+ <#bad-subproperty-cycle>
+ <#bad-superclass-restriction>
+ <#bad-union-of>
+ <#bad-unknown-datatype>
+ <#good-anyuri>
+ <#good-cardinality>
+ <#good-literal-value-high-inclusive>
+ <#good-literal-value-low-inclusive>
+ <#good-owl-thing>
+ <#good-pattern>
+ <#good-rdfs-resource>
+ <#good-some-values-from>
+ <#good-string-literal-value-low>
+ <#good-union-of>
+ ) .
+
+<#bad-all-values-from>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:allValuesFrom ,
+ checks:instanceType ;
+ serd:triggersCheck checks:literalPattern ;
+ serd:triggersCheck checks:literalRestriction ;
+ mf:name "bad-all-values-from" ;
+ mf:action <bad-all-values-from.ttl> .
+
+<#bad-anyuri>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:anyUri ,
+ checks:propertyRange ;
+ mf:name "bad-anyuri" ;
+ mf:action <bad-anyuri.ttl> .
+
+<#bad-cardinality-low>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:cardinalityMin ,
+ checks:instanceType ;
+ mf:name "bad-cardinality-low" ;
+ mf:action <bad-cardinality-low.ttl> .
+
+<#bad-cardinality-high>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:cardinalityMax ,
+ checks:instanceType ;
+ mf:name "bad-cardinality-high" ;
+ mf:action <bad-cardinality-high.ttl> .
+
+<#bad-cardinality>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:cardinalityEqual ,
+ checks:instanceType ;
+ mf:name "bad-cardinality" ;
+ mf:action <bad-cardinality.ttl> .
+
+<#bad-datatype-cycle>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:datatypeCycle ;
+ mf:name "bad-datatype-cycle" ;
+ mf:action <bad-datatype-cycle.ttl> .
+
+<#bad-datatype-property>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:datatypeProperty ;
+ mf:name "bad-datatype-property" ;
+ mf:action <bad-datatype-property.ttl> .
+
+<#bad-deprecated-class>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:deprecatedClass ;
+ mf:name "bad-deprecated-class" ;
+ mf:action <bad-deprecated-class.ttl> .
+
+<#bad-deprecated-property>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:deprecatedProperty ;
+ mf:name "bad-deprecated-property" ;
+ mf:action <bad-deprecated-property.ttl> .
+
+<#bad-domain>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:cardinalityEqual ,
+ checks:propertyDomain ;
+ mf:name "bad-domain" ;
+ mf:action <bad-domain.ttl> .
+
+<#bad-functional-property>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:functionalProperty ;
+ mf:name "bad-functional-property" ;
+ mf:action <bad-functional-property.ttl> .
+
+<#bad-inverse-functional-property>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:inverseFunctionalProperty ;
+ mf:name "bad-inverse-functional-property" ;
+ mf:action <bad-inverse-functional-property.ttl> .
+
+<#bad-literal-pattern>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalPattern ;
+ mf:name "bad-literal-pattern" ;
+ mf:action <bad-literal-pattern.ttl> .
+
+<#bad-literal-value-low-inclusive>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMinInclusive ;
+ mf:name "bad-literal-value-low-inclusive" ;
+ mf:action <bad-literal-value-low-inclusive.ttl> .
+
+<#bad-literal-value-high-inclusive>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMaxInclusive ;
+ mf:name "bad-literal-value-high-inclusive" ;
+ mf:action <bad-literal-value-high-inclusive.ttl> .
+
+<#bad-literal-value-low-exclusive>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMinExclusive ;
+ mf:name "bad-literal-value-low-exclusive" ;
+ mf:action <bad-literal-value-low-exclusive.ttl> .
+
+<#bad-literal-value-high-exclusive>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMaxExclusive ;
+ mf:name "bad-literal-value-high-exclusive" ;
+ mf:action <bad-literal-value-high-exclusive.ttl> .
+
+<#bad-literal-value>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalValue ;
+ mf:name "bad-literal-value" ;
+ mf:action <bad-literal-value.ttl> .
+
+<#bad-string-literal-value-low>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMinExclusive ;
+ mf:name "bad-string-literal-value-low" ;
+ mf:action <bad-string-literal-value-low.ttl> .
+
+<#bad-string-literal-value-high>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMaxExclusive ;
+ mf:name "bad-string-literal-value-high" ;
+ mf:action <bad-string-literal-value-high.ttl> .
+
+<#bad-subclass-cycle>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:classCycle ;
+ mf:name "bad-subclass-cycle" ;
+ mf:action <bad-subclass-cycle.ttl> .
+
+<#bad-subproperty-cycle>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:propertyCycle ;
+ mf:name "bad-subproperty-cycle" ;
+ mf:action <bad-subproperty-cycle.ttl> .
+
+<#bad-superclass-restriction>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:instanceType ,
+ checks:cardinalityMin ;
+ mf:name "bad-superclass-restriction" ;
+ mf:action <bad-superclass-restriction.ttl> .
+
+<#bad-object-property>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:objectProperty ;
+ mf:name "bad-object-property" ;
+ mf:action <bad-object-property.ttl> .
+
+<#bad-pattern>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalPattern ;
+ mf:name "bad-pattern" ;
+ mf:action <bad-pattern.ttl> .
+
+<#bad-plain-literal>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:plainLiteralDatatype ,
+ checks:propertyRange ;
+ mf:name "bad-plain-literal" ;
+ mf:action <bad-plain-literal.ttl> .
+
+<#bad-range-instance-not-literal>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:instanceLiteral ,
+ checks:propertyRange ;
+ mf:name "bad-range-instance-not-literal" ;
+ mf:action <bad-range-instance-not-literal.ttl> .
+
+<#bad-range-instance>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:cardinalityMin ,
+ checks:propertyRange ;
+ mf:name "bad-range-instance" ;
+ mf:action <bad-range-instance.ttl> .
+
+<#bad-range-literal-not-instance>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalInstance ,
+ checks:propertyRange ;
+ mf:name "bad-range-literal-not-instance" ;
+ mf:action <bad-range-literal-not-instance.ttl> .
+
+<#bad-range-literal>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:literalMaxInclusive ,
+ checks:propertyRange ;
+ mf:name "bad-range-literal" ;
+ mf:action <bad-range-literal.ttl> .
+
+<#bad-some-values-from>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:someValuesFrom ,
+ checks:instanceType ;
+ mf:name "bad-some-values-from" ;
+ mf:action <bad-some-values-from.ttl> .
+
+<#bad-union-of>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:propertyRange ;
+ mf:name "bad-union-of" ;
+ mf:action <bad-union-of.ttl> .
+
+<#bad-unknown-datatype>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:datatypeType ;
+ mf:name "bad-unknown-datatype" ;
+ mf:action <bad-unknown-datatype.ttl> .
+
+<#bad-predicate-type-undefined>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:predicateType ;
+ mf:name "bad-predicate-type-undefined" ;
+ mf:action <bad-predicate-type-undefined.ttl> .
+
+<#bad-predicate-type>
+ a serd:TestTurtleNegativeValidate ;
+ serd:triggersCheck checks:predicateType ;
+ mf:name "bad-predicate-type" ;
+ mf:action <bad-predicate-type.ttl> .
+
+<#good-anyuri>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-anyuri" ;
+ mf:action <good-anyuri.ttl> .
+
+<#good-cardinality>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-cardinality" ;
+ mf:action <good-cardinality.ttl> .
+
+<#good-literal-value-low-inclusive>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-literal-value-low-inclusive" ;
+ mf:action <good-literal-value-low-inclusive.ttl> .
+
+<#good-literal-value-high-inclusive>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-literal-value-high-inclusive" ;
+ mf:action <good-literal-value-high-inclusive.ttl> .
+
+<#good-some-values-from>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-some-values-from" ;
+ mf:action <good-some-values-from.ttl> .
+
+<#good-owl-thing>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-owl-thing" ;
+ mf:action <good-owl-thing.ttl> .
+
+<#good-pattern>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-pattern" ;
+ mf:action <good-pattern.ttl> .
+
+<#good-rdfs-resource>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-rdfs-resource" ;
+ mf:action <good-rdfs-resource.ttl> .
+
+<#good-string-literal-value-low>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-string-literal-value-low" ;
+ mf:action <good-string-literal-value-low.ttl> .
+
+<#good-union-of>
+ a serd:TestTurtlePositiveValidate ;
+ mf:name "good-union-of" ;
+ mf:action <good-union-of.ttl> .