diff --git a/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl new file mode 100644 index 00000000..1e582607 --- /dev/null +++ b/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl @@ -0,0 +1,94 @@ +# Copyright (c) 2025 eScience Lab, The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix five-safes-crate: . +@prefix rdf: . +@prefix schema: . +@prefix purl: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +five-safes-crate:ValidationCheckObjectHasDescriptiveNameAndIsAssessAction + a sh:NodeShape ; + sh:name "ValidationCheck" ; + sh:description "" ; + + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + + SELECT ?this + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """ ; + ] ; + + sh:property [ + sh:path rdf:type ; + sh:minCount 1 ; + sh:hasValue schema:AssessAction; + sh:severity sh:Violation ; + sh:message "ValidationCheck MUST be a `schema:AssessAction`." ; + ] ; + + sh:property [ + sh:a sh:PropertyShape ; + sh:name "name" ; + sh:description "ValidationCheck MUST have a human readable name string of at least 10 characters." ; + sh:path schema:name ; + sh:datatype xsd:string ; + sh:minLength 10 ; + sh:severity sh:Violation ; + sh:message "ValidationCheck MUST have a human readable name string of at least 10 characters." ; + ] . + + +five-safes-crate:ValidationCheckActionStatusMustHaveAllowedValue + a sh:NodeShape ; + sh:name "ValidationCheck" ; + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + + SELECT ?this + WHERE { + ?this schema:additionalType shp:ValidationCheck ; + schema:actionStatus ?status . + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:name "actionStatus" ; + sh:description "The `actionStatus` of ValidationCheck MUST have an allowed value (see https://schema.org/ActionStatusType)." ; + sh:path schema:actionStatus ; + sh:in ( + "http://schema.org/PotentialActionStatus" + "http://schema.org/ActiveActionStatus" + "http://schema.org/CompletedActionStatus" + "http://schema.org/FailedActionStatus" + ) ; + sh:severity sh:Violation ; + sh:message "The `actionStatus` of ValidationCheck MUST have an allowed value (see https://schema.org/ActionStatusType)." ; + ] . \ No newline at end of file diff --git a/rocrate_validator/profiles/five-safes-crate/should/13_validation_phase.ttl b/rocrate_validator/profiles/five-safes-crate/should/13_validation_phase.ttl new file mode 100644 index 00000000..eb8ea458 --- /dev/null +++ b/rocrate_validator/profiles/five-safes-crate/should/13_validation_phase.ttl @@ -0,0 +1,167 @@ +# Copyright (c) 2025 eScience Lab, The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +@prefix ro: <./> . +@prefix ro-crate: . +@prefix five-safes-crate: . +@prefix rdf: . +@prefix schema: . +@prefix purl: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . + + +five-safes-crate:RootDataEntityShouldMentionValidationCheckObject + a sh:NodeShape ; + sh:name "RootDataEntity" ; + sh:targetClass ro-crate:RootDataEntity ; + sh:description "" ; + + sh:sparql [ + a sh:SPARQLConstraint ; + sh:name "mentions" ; + sh:description "RootDataEntity SHOULD mention a ValidationCheck object." ; + sh:select """ + PREFIX schema: + PREFIX shp: + SELECT $this + WHERE { + FILTER NOT EXISTS{ + $this schema:mentions ?action . + ?action schema:additionalType shp:ValidationCheck . + } + } + """ ; + sh:severity sh:Warning ; + sh:message "RootDataEntity SHOULD mention a ValidationCheck object." ; + ] . + + +five-safes-crate:ValidationCheckObjectShouldPointToRootDataEntity + a sh:NodeShape ; + sh:name "ValidationCheck" ; + sh:description "" ; + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + SELECT ?this + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:name "object" ; + sh:path schema:object ; + sh:minCount 1 ; + sh:hasValue <./> ; + sh:severity sh:Warning ; + sh:message "`ValidationCheck` --> `object` SHOULD point to the root of the RO-Crate" ; + ] . + + +five-safes-crate:ValidationCheckInstrumentShouldPointToEntityWithSpecificId + a sh:NodeShape ; + sh:name "ValidationCheck" ; + sh:description "" ; + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + SELECT ?this + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:name "instrument" ; + sh:description "" ; + sh:path schema:instrument ; + sh:minCount 1 ; + sh:nodeKind sh:IRI ; + sh:hasValue ; + sh:severity sh:Warning ; + sh:message "`ValidationCheck` --> `instrument` SHOULD point to an entity with @id https://w3id.org/5s-crate/0.4" ; + ] . + + +five-safes-crate:ValidationCheckShouldHaveActionStatus + a sh:NodeShape ; + sh:name "ValidationCheck" ; + sh:description "" ; + + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + + SELECT ?this + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:name "ActionStatus" ; + sh:path schema:actionStatus ; + sh:minCount 1 ; + sh:severity sh:Warning ; + sh:message "ValidationCheck SHOULD have actionStatus property." ; + ] . + + + +five-safes-crate:ValidationCheckShouldHaveActionStatus + a sh:NodeShape ; + sh:name "ValidationCheck" ; + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + + SELECT ?this + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:minCount 1 ; + sh:name "actionStatus" ; + sh:description "ValidationCheck SHOULD have the `actionStatus` property." ; + sh:path schema:actionStatus ; + sh:in ( + "http://schema.org/PotentialActionStatus" + "http://schema.org/ActiveActionStatus" + "http://schema.org/CompletedActionStatus" + "http://schema.org/FailedActionStatus" + ) ; + sh:severity sh:Warning ; + sh:message "ValidationCheck SHOULD have the `actionStatus` property." ; + ] . diff --git a/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py new file mode 100644 index 00000000..12761783 --- /dev/null +++ b/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py @@ -0,0 +1,220 @@ +# Copyright (c) 2024-2025 CRS4 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rocrate_validator.models import Severity +from tests.ro_crates import ValidROC +from tests.shared import do_entity_test, SPARQL_PREFIXES + +# set up logging +logger = logging.getLogger(__name__) + + +# ----- MUST fails tests + +# TO BE CHECKED AGAIN +def test_5src_validation_check_not_of_type_assess_action(): + sparql = ( + SPARQL_PREFIXES + """ + DELETE { + ?this rdf:type schema:AssessAction . + } + INSERT { + ?this rdf:type . + } + WHERE { + ?this rdf:type schema:AssessAction ; + schema:additionalType shp:ValidationCheck . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=["ValidationCheck MUST be a `schema:AssessAction`."], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_validation_check_name_not_a_string(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + ?this schema:name ?name . + } + INSERT { + ?this schema:name 123 . + } + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=["ValidationCheck MUST have a human readable name string of at least 10 characters."], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_validation_check_name_not_long_enough(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + ?this schema:name ?name . + } + INSERT { + ?this schema:name "Short" . + } + WHERE { + ?this schema:additionalType shp:ValidationCheck . + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=["ValidationCheck MUST have a human readable name string of at least 10 characters."], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_validation_check_has_action_status_with_not_allowed_value(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + ?s schema:actionStatus ?o . + } + INSERT { + ?s schema:actionStatus "Not a good action status" . + } + WHERE { + ?s schema:additionalType . + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.REQUIRED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=[( + "The `actionStatus` of ValidationCheck MUST have an allowed value " + "(see https://schema.org/ActionStatusType)." + )], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +# # ----- SHOULD fails tests + +def test_5src_root_data_entity_does_not_mention_validation_check_entity(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + <./> schema:mentions ?o . + } + WHERE { + ?o schema:additionalType shp:ValidationCheck ; + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["RootDataEntity"], + expected_triggered_issues=["RootDataEntity SHOULD mention a ValidationCheck object."], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_validation_check_object_does_not_point_to_root_data_entity(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + ?s schema:object <./> . + } + INSERT { + ?s schema:object "not the RootDataEntity" . + } + WHERE { + ?s schema:additionalType shp:ValidationCheck ; + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=["`ValidationCheck` --> `object` SHOULD point to the root of the RO-Crate"], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_validation_check_instrument_does_not_point_to_5scrate_0p4(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + ?s schema:instrument . + } + WHERE { + ?s schema:additionalType shp:ValidationCheck ; + schema:instrument . + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=[ + "`ValidationCheck` --> `instrument` SHOULD point to an entity with @id https://w3id.org/5s-crate/0.4" + ], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_Validation_check_does_not_have_action_status_property(): + sparql = (SPARQL_PREFIXES + """ + DELETE { + ?s schema:actionStatus ?o . + } + WHERE { + ?s schema:additionalType shp:ValidationCheck ; + schema:actionStatus ?o . + } + """) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["ValidationCheck"], + expected_triggered_issues=["ValidationCheck SHOULD have actionStatus property."], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) diff --git a/tests/shared.py b/tests/shared.py index 978f60e4..b82d4ade 100644 --- a/tests/shared.py +++ b/tests/shared.py @@ -34,7 +34,10 @@ T = TypeVar("T") -SPARQL_PREFIXES = """PREFIX schema: +SPARQL_PREFIXES = """ +PREFIX schema: +PREFIX shp: +PREFIX rdf: """