From f63caad95603a2fb032101ae776be1ba778d7d11 Mon Sep 17 00:00:00 2001 From: Alex Nelson Date: Tue, 17 Aug 2021 09:50:09 -0400 Subject: [PATCH] Add test for sh:datatype count validity References: * [OC-165] (CP-79) Several classes have multiple sh:datatypes and are invalid by SHACL spec Signed-off-by: Alex Nelson --- tests/Makefile | 4 +++ tests/test_uco_monolithic.py | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/test_uco_monolithic.py diff --git a/tests/Makefile b/tests/Makefile index f0caea52..ca25ff10 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -47,6 +47,10 @@ all: check: \ inheritance_review.ttl \ uco_monolithic.ttl + source venv/bin/activate \ + && pytest \ + --ignore examples \ + --log-level=DEBUG $(MAKE) \ --directory examples \ check diff --git a/tests/test_uco_monolithic.py b/tests/test_uco_monolithic.py new file mode 100644 index 00000000..1b70b548 --- /dev/null +++ b/tests/test_uco_monolithic.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# This software was developed at the National Institute of Standards +# and Technology by employees of the Federal Government in the course +# of their official duties. Pursuant to title 17 Section 105 of the +# United States Code this software is not subject to copyright +# protection and is in the public domain. NIST assumes no +# responsibility whatsoever for its use by other parties, and makes +# no guarantees, expressed or implied, about its quality, +# reliability, or any other characteristic. +# +# We would appreciate acknowledgement if the software is used. + +import os + +import rdflib.plugins.sparql + +def test_max_1_sh_datatype_per_property_shape(): + """ + This enforces the maximum sh:datatype count of 1, as specified here: + + "A shape has at most one value for sh:datatype." + https://www.w3.org/TR/shacl/#DatatypeConstraintComponent + + This is encoded in the SHACL ontology with the statement 'sh:DatatypeConstraintComponent-datatype sh:maxCount 1 .' + """ + expected = set() # This set is intentionally empty. + computed = set() + + graph = rdflib.Graph() + graph.parse(os.path.join(os.path.dirname(__file__), "uco_monolithic.ttl")) + assert len(graph) > 0, "Failed to load uco_monolithic.ttl." + + nsdict = { + "sh": rdflib.SH + } + + query_object = rdflib.plugins.sparql.prepareQuery("""\ +SELECT ?nClass ?nPath ?lConstraintDatatypeTally +WHERE { + { + SELECT ?nClass ?nPath (COUNT(DISTINCT ?nConstraintDatatype) AS ?lConstraintDatatypeTally) + WHERE { + ?nClass + sh:property ?nPropertyShape ; + . + + ?nPropertyShape + sh:datatype ?nConstraintDatatype ; + sh:path ?nPath ; + . + } GROUP BY ?nClass ?nPath + } + + FILTER (?lConstraintDatatypeTally > 1) +} +""", initNs=nsdict) + for result in graph.query(query_object): + computed.add(result) + assert expected == computed