This document defines the format of the tests in the SHACL test suite, the process to use them to evaluate SHACL implementations, and lists test results from implementations that have submitted their test results.
In this document we will employ the following namespace prefixes:
sh
http://www.w3.org/ns/shacl#
sht
http://www.w3.org/ns/shacl-test#
mf
http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#
earl
http://www.w3.org/ns/earl#
The tests are available in the folder structure starting at tests. Each folder contains one or more manifest files that describe the tests in that folder.
The manifest file is defined in RDF and is compatible with the manifest used by other W3c initiatives like RDF 1.1 or SPARQL
<> a mf:Manifest ; rdfs:label "...Manifest label" rdfs:comment "...Manifest comment" ; dc:creator "...creator..." mf:entries ( ....list of ManifestEntries ) .
Each manifest entry is a single test which can be one of the following types:
These tests verify that the validation of a given data graph against a given shapes graph produces a specified validation report. Both the data graph and the shapes graph may be identical.
Example:
<entry1> a sht:Validate ; mf:name "Validate simple RDF data with a simple shapes graph" ; mf:action [ sht:shapesGraph <example-shapes.ttl> ; sht:dataGraph <example-data.ttl> ; ] ; mf:result [ a sh:ValidationReport ; sh:conforms true ; ] ; mf:status sht:proposed .
To perform the test, a validation engine must validate the data graph specified by sht:dataGraph
against the shapes graph specified by sht:shapesGraph
.
The values of both must be relative URLs pointing at a Turtle file in the same directory as the test file itself.
It is also valid that either of these graphs point at the manifest graph itself, using the relative URL <>
.
Implementations may report two levels of compliance:
sh:conforms
as required by the expected report.
For full compliance:
Let R
be the blank node that is the value of mf:result
of the sht:Validate
test case
in the manifest graph.
Let expected
be the graph that consists of all triples from the manifest graph that have R
as subject
plus all triples that have all values of sh:result
of R
as their subject,
as well as any triples needed to correctly represent the sh:resultPath
.
Let actual
be the results graph produced by the validation, i.e. the validation report.
The test framework may post-process this results graph to ensure the following preconditions.
Before comparing the results graph with the expected
results, the actual
validation report
must not include any "nested" results, via sh:details
.
The actual
results also must not depend on subclass relationships, so that instances of subclasses of
sh:ValidationReport
and sh:ValidationResult
must have these as their (only) rdf:type
values.
Also, all instances of sh:ValidationResult
and sh:ValidationReport
must be blank nodes,
i.e. if the engine produces URIs then these need to be replaced with blank nodes.
Also, the blank node structures representing property paths via sh:resultPath
must not be shared among
multiple results, i.e. they may need to be cloned prior to comparison.
Blank node structures representing property paths via sh:resultPath
must not reuse the same path blank node
(as values of sh:inversePath
etc) in multiple places - these need to be normalized before the comparison,
i.e. share blank node structures need to be cloned into new blank nodes.
Furthermore, only the following predicates are used by triples in the expected
graph and therefore
any other triples need to be removed from the actual
graph prior to comparison:
rdf:type sh:ValidationReport
sh:result
sh:conforms
rdf:type sh:ValidationResult
sh:focusNode
sh:resultPath
(including depending blank node structures)sh:resultSeverity
sh:sourceConstraint
sh:sourceConstraintComponent
sh:sourceShape
sh:value
An exception is sh:resultMessage
: As a general rule, all triples with sh:resultMessage
as subject
need to be removed from the actual
graph, except those with object ?object
for which
the expected
graph contains a triple ?any sh:resultMessage ?object
.
This makes sure that certain tests can verify that sh:resultMessage
has been correctly
populated from the sh:message
triples in the shapes graph.
To pass full compliance, the actual
validation report must be isomorphic to expected
.
If the test case has sht:Failure
as its value for mf:result
then the test is passed if the validation reported a failure.
Alternatively, implementation may still report pass if they have manually checked that their validation reports satisfy the requirements specified by the SHACL specification.
The latter also applies to scenarios that are well-formed SHACL validation results according to [[!shacl]] while the
test framework has stricter expectations. For example, not all implementation are required to produce sh:sourceShape
triples.
In order to improve precision of comparing test results, blank nodes should be avoided as values
of sh:sourceShape
and sh:sourceConstraint
.
Tests are maintained by members of the Working Group in the
GitHub repository.
Anyone, including non-members, can submit or suggest test cases via GitHub pull requests.
Submissions by other means may be rejected without response.
Test cases that have not been accepted by the Working Group yet must have mf:status sht:proposed
.
At the chair's discretion, individual tests or groups of tests are put to the Working Group,
e.g. in the weekly telecon.
The Working Group has complete discretion to approve or reject tests.
Approved tests must have mf:status sht:approved
, those that have been rejected
may get marked as mf:status sht:rejected
or deleted from the main branch of the repository.
All approved tests must be reachable from the root manifest.mf file.
Editors may modify test cases, but SHOULD go through the WG process for non-trivial changes.
In addition to validation tests, we encourage users to submit examples of ill-formed shapes graphs. These may be used in the future to collect syntax tests.
Implementations listed here need to be submitted as a Turtle file in the format similar to the
TopBraid SHACL API EARL Report.
In a nutshell, we use [[EARL10-Schema]] to represent individual test results and metadata about the test subject.
To indicate full compliance, use earl:passed
as value for earl:outcome
.
To indicate partial compliance (i.e. can report true
and false
), use sht:partial
.
The preferred way of submitting test reports is via a pull request into the reports folder on GitHub. Alternatively, send your Turtle file to the public comments mailing list.
This section summarizes the outcomes of test reports for submitted SHACL implementations.
Homepage: | http://wimmics.inria.fr/corese |
Tests Updated: | 2017-05-04 |
Homepage: | https://github.com/dotnetrdf/dotnetrdf/pull/236 and http://langsamu.net/shacl |
Tests Updated: | 2019-07-01 |
Homepage: | http://www.netage.nl |
Tests Updated: | 2017-05-23 |
Homepage: | https://github.com/RDFLib/pySHACL |
Tests Updated: | 2018-09-24 |
Homepage: | http://aksw.org/projects/RDFUnit |
Tests Updated: | 2017-10-18 |
Homepage: | https://github.com/labra/shaclex |
Tests Updated: | 2018-08-11 |
Homepage: | https://github.com/TopQuadrant/shacl |
Tests Updated: | 2017-10-24 |
File | Status | Test Case | Corese | dotNetRDF | Netage | pySHACL | RDFUnit | shaclex | TopBraid |
---|---|---|---|---|---|---|---|---|---|
98 / 121 (81%) | 121 / 121 (100%) | 100 / 121 (83%) | 119 / 121 (99%) | 82 / 121 (68%) | 98 / 121 (81%) | 121 / 121 (100%) | |||
core/complex/personexample | approved | Test of personexample | passed | passed | passed | passed | passed | passed | passed |
core/complex/shacl-shacl | approved | frozen eat your own ( eat your own frozen dogfood ) | passed | passed | no data | passed | passed | passed | passed |
core/misc/deactivated-001 | approved | Test of sh:deactivated 001 | passed | passed | passed | passed | passed | passed | passed |
core/misc/deactivated-002 | approved | Test of sh:deactivated 002 | passed | passed | passed | passed | passed | passed | passed |
core/misc/message-001 | approved | Test of custom sh:message 001 | passed | passed | passed | passed | passed | passed | passed |
core/misc/severity-001 | approved | Test of sh:severity 001 | passed | passed | passed | passed | passed | passed | passed |
core/misc/severity-002 | approved | Test of sh:severity 002 | passed | passed | passed | passed | passed | passed | passed |
core/node/and-001 | approved | Test of sh:and at node shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/node/and-002 | approved | Test of sh:and at node shape 002 | passed | passed | passed | passed | partial | passed | passed |
core/node/class-001 | approved | Test of sh:class at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/class-002 | approved | Test of sh:class at node shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/node/class-003 | approved | Test of sh:class at node shape 003 multiple classes, overlapping target sets | passed | passed | passed | passed | partial | passed | passed |
core/node/closed-001 | approved | Test of sh:closed at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/closed-002 | approved | Test of sh:closed at node shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/node/datatype-001 | approved | Test of sh:datatype at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/datatype-002 | approved | Test of sh:datatype at node shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/node/disjoint-001 | approved | Test of sh:disjoint at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/equals-001 | approved | Test of sh:equals at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/hasValue-001 | approved | Test of sh:hasValue at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/in-001 | approved | Test of sh:in at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/languageIn-001 | approved | Test of sh:languageIn at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/maxExclusive-001 | approved | Test of sh:maxExclusive at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/maxInclusive-001 | approved | Test of sh:maxInclusive at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/maxLength-001 | approved | Test of sh:maxLength at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/minExclusive-001 | approved | Test of sh:minExclusive at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/minInclusive-001 | approved | Test of sh:minInclusive at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/minInclusive-002 | approved | Test of sh:minInclusive at node shape 002 - dateTime with timezone | passed | passed | no data | passed | passed | passed | passed |
core/node/minInclusive-003 | approved | Test of sh:minInclusive at node shape 003 - dateTime without timezone | passed | passed | no data | passed | passed | passed | passed |
core/node/minLength-001 | approved | Test of sh:minLength at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/node-001 | approved | Test of sh:node at node shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/node/nodeKind-001 | approved | Test of sh:nodeKind at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/not-001 | approved | Test of sh:not at node shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/node/not-002 | approved | Test of sh:not at node shape 002 | passed | passed | passed | passed | failed | passed | passed |
core/node/or-001 | approved | Test of sh:or at node shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/node/pattern-001 | approved | Test of sh:pattern at node shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/node/pattern-002 | approved | Test of sh:pattern at node shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/node/qualified-001 | approved | Test of qualified parameters allowed in node shapes | passed | passed | no data | passed | passed | passed | passed |
core/node/xone-001 | approved | Test of sh:xone at node shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/node/xone-duplicate | approved | Test of validation report for shape xone-duplicate by property constraints | passed | passed | no data | passed | failed | passed | passed |
core/path/path-alternative-001 | approved | Test of path sh:alternativePath 001 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-complex-001 | approved | Test of path complex (rdf:type/rdfs:subClassOf*) 001 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-complex-002 | approved | Test of complex path validation results | passed | passed | no data | passed | partial | passed | passed |
core/path/path-inverse-001 | approved | Test of path sh:inversePath 001 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-oneOrMore-001 | approved | Test of path sh:oneOrMorePath 001 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-sequence-001 | approved | Test of path sequence 001 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-sequence-002 | approved | Test of path sequence 002 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-sequence-duplicate-001 | approved | Test of path sequence with duplicate 001 | passed | passed | failed | passed | partial | passed | passed |
core/path/path-strange-001 | approved | Test of strange path 001 two valid paths together | passed | passed | no data | passed | passed | passed | passed |
core/path/path-strange-002 | approved | Test of strange path 002 valid and invalid paths together | passed | passed | no data | passed | passed | passed | passed |
core/path/path-unused-001 | approved | Test with unused ill-formed path | passed | passed | no data | passed | passed | passed | passed |
core/path/path-zeroOrMore-001 | approved | Test of path sh:zeroOrMorePath 001 | passed | passed | failed | passed | passed | passed | passed |
core/path/path-zeroOrOne-001 | approved | Test of path sh:zeroOrOnePath 001 | passed | passed | failed | passed | passed | passed | passed |
core/property/and-001 | approved | Test of sh:and at property shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/property/class-001 | approved | Test of sh:class at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/datatype-001 | approved | Test of sh:datatype at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/datatype-002 | approved | Test of sh:datatype at property shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/property/datatype-003 | approved | Test of sh:datatype at property shape 003 | passed | passed | passed | passed | failed | passed | passed |
core/property/datatype-ill-formed | approved | Test of validation report for ill-formed literals | passed | passed | passed | failed | passed | passed | passed |
core/property/disjoint-001 | approved | Test of sh:disjoint at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/equals-001 | approved | Test of sh:equals at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/hasValue-001 | approved | Test of sh:hasValue at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/in-001 | approved | Test of sh:in at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/languageIn-001 | approved | Test of sh:languageIn at property shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/property/lessThan-001 | approved | Test of sh:lessThan at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/lessThan-002 | approved | Test of sh:lessThan at property shape 002 | passed | passed | passed | passed | partial | passed | passed |
core/property/lessThanOrEquals-001 | approved | Test of sh:lessThanOrEquals at property shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/property/maxCount-001 | approved | Test of sh:maxCount at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/maxCount-002 | approved | Test of sh:maxCount at property shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/property/maxExclusive-001 | approved | Test of sh:maxExclusive at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/maxInclusive-001 | approved | Test of sh:maxInclusive at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/maxLength-001 | approved | Test of sh:maxLength at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/minCount-001 | approved | Test of sh:minCount at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/minCount-002 | approved | Test of sh:minCount at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/minExclusive-001 | approved | Test of sh:minExclusive at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/minExclusive-002 | approved | Test of sh:minExclusive at property shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/property/minLength-001 | approved | Test of sh:minLength at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/node-001 | approved | Test of sh:node at property shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/property/node-002 | approved | Test of sh:node at property shape 002 | passed | passed | passed | passed | partial | passed | passed |
core/property/nodeKind-001 | approved | Test of sh:nodeKind at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/not-001 | approved | Test of sh:not at property shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/property/or-001 | approved | Test of sh:or at property shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/property/or-datatypes-001 | approved | Test of sh:or of sh:datatypes at property shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/property/pattern-001 | approved | Test of sh:pattern at property shape 001 | passed | passed | passed | passed | passed | passed | passed |
core/property/pattern-002 | approved | Test of sh:pattern at property shape 002 | passed | passed | passed | passed | passed | passed | passed |
core/property/property-001 | approved | Test of sh:property at property shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/property/qualifiedMinCountDisjoint-001 | approved | Test of sh:qualifiedMinCount with disjoint shapes at property shape 001 | passed | passed | failed | passed | failed | passed | passed |
core/property/qualifiedValueShape-001 | approved | Test of sh:qualifiedValueShape at property shape 001 | passed | passed | passed | passed | failed | passed | passed |
core/property/qualifiedValueShapesDisjoint-001 | approved | Test of sh:qualifiedValueShapesDisjoint at property shape 001 | passed | passed | failed | passed | failed | passed | passed |
core/property/uniqueLang-001 | approved | Test of sh:uniqueLang at property shape 001 | passed | passed | passed | passed | partial | passed | passed |
core/property/uniqueLang-002 | approved | Test uniqueLang with other boolean literal for true | passed | passed | passed | passed | passed | passed | passed |
core/targets/multipleTargets-001 | approved | Test of multiple targets 001 | passed | passed | passed | passed | passed | passed | passed |
core/targets/targetClass-001 | approved | Test of sh:targetClass 001 | passed | passed | passed | passed | passed | passed | passed |
core/targets/targetClassImplicit-001 | approved | Test of implicit sh:targetClass 001 | passed | passed | passed | passed | passed | passed | passed |
core/targets/targetNode-001 | approved | Test of sh:targetNode 001 | passed | passed | passed | passed | passed | passed | passed |
core/targets/targetObjectsOf-001 | approved | Test of sh:targetObjectsOf 001 | passed | passed | passed | passed | passed | passed | passed |
core/targets/targetSubjectsOf-001 | approved | Test of sh:targetSubjectsOf 001 | passed | passed | passed | passed | passed | passed | passed |
core/targets/targetSubjectsOf-002 | approved | Test of sh:targetSubjectsOf 002 | passed | passed | passed | passed | partial | passed | passed |
core/validation-reports/shared | approved | Test of validation report for shape shared by property constraints | passed | passed | passed | passed | passed | passed | passed |
sparql/component/nodeValidator-001 | proposed | Test of sh:nodeValidator 001 | no data | passed | no data | passed | no data | no data | passed |
sparql/component/optional-001 | approved | Test of sh:optional 001 | no data | passed | passed | passed | passed | no data | passed |
sparql/component/propertyValidator-select-001 | approved | Test of sh:propertyValidator with SELECT 001 | no data | passed | passed | passed | passed | no data | passed |
sparql/component/validator-001 | approved | Test of sh:validator 001 | no data | passed | passed | passed | passed | no data | passed |
sparql/node/prefixes-001 | approved | Test of sh:prefixes 001 | no data | passed | passed | passed | passed | no data | passed |
sparql/node/sparql-001 | approved | Test of sh:sparql at node shape 001 | no data | passed | passed | passed | passed | no data | passed |
sparql/node/sparql-002 | approved | Test of sh:sparql at node shape 002 | no data | passed | passed | passed | partial | no data | passed |
sparql/node/sparql-003 | approved | Test of sh:sparql at node shape 003 | no data | passed | passed | passed | partial | no data | passed |
sparql/pre-binding/pre-binding-001 | approved | Test of pre-binding in FILTER | no data | passed | passed | passed | partial | no data | passed |
sparql/pre-binding/pre-binding-002 | approved | Test of pre-binding in UNION | no data | passed | passed | passed | failed | no data | passed |
sparql/pre-binding/pre-binding-003 | approved | Test of pre-binding in inner {...} blocks | no data | passed | passed | passed | failed | no data | passed |
sparql/pre-binding/pre-binding-004 | approved | Test of pre-binding in BIND expressions | no data | passed | passed | passed | partial | no data | passed |
sparql/pre-binding/pre-binding-005 | approved | Test of pre-binding in BGP and FILTER | no data | passed | passed | passed | failed | no data | passed |
sparql/pre-binding/pre-binding-006 | approved | Test of pre-binding in nested SELECT | no data | passed | passed | passed | failed | no data | passed |
sparql/pre-binding/pre-binding-007 | approved | Test of pre-binding in nested SELECT | no data | passed | passed | passed | failed | no data | passed |
sparql/pre-binding/shapesGraph-001 | approved | Test of $shapesGraph and $currentShape | no data | passed | passed | failed | failed | no data | passed |
sparql/pre-binding/unsupported-sparql-001 | approved | Test of unsupported MINUS | no data | passed | passed | passed | passed | no data | passed |
sparql/pre-binding/unsupported-sparql-002 | approved | Test of unsupported VALUES | no data | passed | passed | passed | passed | no data | passed |
sparql/pre-binding/unsupported-sparql-003 | approved | Test of unsupported SERVICE | no data | passed | passed | passed | passed | no data | passed |
sparql/pre-binding/unsupported-sparql-004 | approved | Test of unsupported SELECT | no data | passed | passed | passed | failed | no data | passed |
sparql/pre-binding/unsupported-sparql-005 | approved | Test of unsupported AS ?prebound | no data | passed | passed | passed | passed | no data | passed |
sparql/pre-binding/unsupported-sparql-006 | approved | Test of ASK trying to reassign ?value | no data | passed | passed | passed | passed | no data | passed |
sparql/property/sparql-001 | approved | Test of sh:sparql at property shape 001 | no data | passed | passed | passed | passed | no data | passed |