From 43289a505d5ea396fc8a632942695530758b48f6 Mon Sep 17 00:00:00 2001 From: EttoreM Date: Tue, 28 Apr 2026 15:38:05 +0100 Subject: [PATCH 1/3] Added CHACL code and corresponding tests about RootDataEntity conforming to the appropriate ro-crate profile. --- .../should/5_profile_conformance.ttl | 80 +++++++++++++++ .../test_5src_5_profile_conformance.py | 97 +++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl create mode 100644 tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py diff --git a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl new file mode 100644 index 00000000..8c2287ec --- /dev/null +++ b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl @@ -0,0 +1,80 @@ +# 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 dct: . +@prefix sh: . +@prefix validator: . +@prefix xsd: . +@prefix shp: . + + +# Root Dataset SHOULD declare conformsTo Five Safes profile +five-safes-crate:RootDatasetConformsToFiveSafes + a sh:NodeShape ; + sh:name "RootDataEntity" ; + sh:targetClass ro-crate:RootDataEntity ; + + sh:property [ + a sh:PropertyShape ; + sh:name "conformsTo Five Safes profile" ; + sh:path dct:conformsTo ; + sh:hasValue ; + sh:severity sh:Warning ; + sh:message "Root Dataset SHOULD include `conformsTo` https://w3id.org/5s-crate/0.4" ; + ] . + +# five-safes-crate:RootDatasetDatePublishedWhenPublished +# a sh:NodeShape ; +# sh:name "datePublished present on published crates" ; +# sh:description "If the root dataset is published (has schema:publisher), it SHOULD have schema:datePublished." ; +# sh:targetNode ro: ; +# sh:severity sh:Warning ; +# sh:message "Published crates SHOULD include schema:datePublished." ; +# sh:or ( +# # datePublished not required if no publisher: +# [ sh:not [ sh:property [ +# sh:path schema:publisher ; +# sh:minCount 1 ; +# ]]] +# # datePublished required if publisher present: +# [ sh:property [ +# sh:path schema:datePublished ; +# sh:minCount 1 ; +# ]] +# ) . + +# five-safes-crate:RootDatasetLicenseWhenPublished +# a sh:NodeShape ; +# sh:name "License present on published crates" ; +# sh:description "If the root dataset is published (has schema:publisher), it SHOULD declare a license." ; +# sh:targetNode ro: ; +# sh:severity sh:Warning ; +# sh:message "Profile Conformance: Published crates SHOULD include a license." ; +# sh:or ( +# # license not required if no publisher: +# [ sh:not [ sh:property [ +# sh:path schema:publisher ; +# sh:minCount 1 ; +# ]]] +# # license required if publisher present: +# [ sh:property [ +# sh:path schema:license ; +# sh:minCount 1 ; +# ]] +# ) . diff --git a/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py b/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py new file mode 100644 index 00000000..efa2d548 --- /dev/null +++ b/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py @@ -0,0 +1,97 @@ +# Copyright (c) 2024-2025 CRS4 +# Copyright (c) 2025-2026 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. + +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 + + +# ----- SHOULD fails tests + + +def test_5src_root_data_entity_missing_conformsto_property(): + """ + Test a Five Safes Crate where the RootDataEntity does not have the conformsTo property. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?rootdataentity dct:conformsTo ?profile . + } + WHERE { + ?metadatafile a schema:CreativeWork ; + schema:about ?rootdataentity . + ?rootdataentity dct:conformsTo ?profile . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_request, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["RootDataEntity"], + expected_triggered_issues=[ + "Root Dataset SHOULD include `conformsTo` https://w3id.org/5s-crate/0.4" + ], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +def test_5src_root_data_entity_conforms_to_wrong_profile(): + """ + Test a Five Safes Crate where the RootDataEntity does not conform to the expected profile. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?rootdataentity dct:conformsTo ?profile . + } + INSERT { + ?rootdataentity dct:conformsTo "This is not the IRI to the 5sc profile" + } + WHERE { + ?metadatafile a schema:CreativeWork ; + schema:about ?rootdataentity . + ?rootdataentity dct:conformsTo ?profile . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_request, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["RootDataEntity"], + expected_triggered_issues=[ + "Root Dataset SHOULD include `conformsTo` https://w3id.org/5s-crate/0.4" + ], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + +# ----- MAY fails tests From 36f495a92a2284fc6a015a98aa58cf839ae23bbb Mon Sep 17 00:00:00 2001 From: EttoreM Date: Tue, 28 Apr 2026 16:02:23 +0100 Subject: [PATCH 2/3] Added SHACL code and corresponding tests about RootDataEntity having a publishedDate if it has a publisher. --- .../should/5_profile_conformance.ttl | 38 +++++++++---------- .../test_5src_5_profile_conformance.py | 32 ++++++++++++++++ 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl index 8c2287ec..e6964d3e 100644 --- a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl +++ b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl @@ -39,25 +39,25 @@ five-safes-crate:RootDatasetConformsToFiveSafes sh:message "Root Dataset SHOULD include `conformsTo` https://w3id.org/5s-crate/0.4" ; ] . -# five-safes-crate:RootDatasetDatePublishedWhenPublished -# a sh:NodeShape ; -# sh:name "datePublished present on published crates" ; -# sh:description "If the root dataset is published (has schema:publisher), it SHOULD have schema:datePublished." ; -# sh:targetNode ro: ; -# sh:severity sh:Warning ; -# sh:message "Published crates SHOULD include schema:datePublished." ; -# sh:or ( -# # datePublished not required if no publisher: -# [ sh:not [ sh:property [ -# sh:path schema:publisher ; -# sh:minCount 1 ; -# ]]] -# # datePublished required if publisher present: -# [ sh:property [ -# sh:path schema:datePublished ; -# sh:minCount 1 ; -# ]] -# ) . +five-safes-crate:RootDatasetDatePublishedWhenPublished + a sh:NodeShape ; + sh:name "datePublished present on published crates" ; + sh:description "If the root dataset is published (has schema:publisher), it SHOULD have schema:datePublished." ; + sh:targetClass ro-crate:RootDataEntity ; + sh:severity sh:Warning ; + sh:message "Published crates SHOULD include schema:datePublished." ; + sh:or ( + # datePublished not required if no publisher: + [ sh:not [ sh:property [ + sh:path schema:publisher ; + sh:minCount 1 ; + ]]] + # datePublished required if publisher present: + [ sh:property [ + sh:path schema:datePublished ; + sh:minCount 1 ; + ]] + ) . # five-safes-crate:RootDatasetLicenseWhenPublished # a sh:NodeShape ; diff --git a/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py b/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py index efa2d548..a32c593d 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py @@ -94,4 +94,36 @@ def test_5src_root_data_entity_conforms_to_wrong_profile(): ) +def test_5src_root_data_entity_has_publisher_but_not_date_published(): + """ + Test a Five Safes Crate where the RootDataEntity has published but not date published. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?rootdataentity schema:datePublished ?datePublished . + } + WHERE { + ?metadatafile a schema:CreativeWork ; + schema:about ?rootdataentity . + ?rootdataentity schema:publisher ?publisher ; + schema:datePublished ?datePublished . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["datePublished present on published crates"], + expected_triggered_issues=[ + "Published crates SHOULD include schema:datePublished." + ], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + # ----- MAY fails tests From 95ecd302c1f9a1621bd781ae62f86f2b9b3d45a0 Mon Sep 17 00:00:00 2001 From: EttoreM Date: Wed, 29 Apr 2026 08:57:40 +0100 Subject: [PATCH 3/3] Added SHACL code and corresponding tests for licencing information in the ro-crate --- .../should/5_profile_conformance.ttl | 38 +++++++++---------- .../test_5src_5_profile_conformance.py | 32 ++++++++++++++++ 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl index e6964d3e..1dad6d9b 100644 --- a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl +++ b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl @@ -59,22 +59,22 @@ five-safes-crate:RootDatasetDatePublishedWhenPublished ]] ) . -# five-safes-crate:RootDatasetLicenseWhenPublished -# a sh:NodeShape ; -# sh:name "License present on published crates" ; -# sh:description "If the root dataset is published (has schema:publisher), it SHOULD declare a license." ; -# sh:targetNode ro: ; -# sh:severity sh:Warning ; -# sh:message "Profile Conformance: Published crates SHOULD include a license." ; -# sh:or ( -# # license not required if no publisher: -# [ sh:not [ sh:property [ -# sh:path schema:publisher ; -# sh:minCount 1 ; -# ]]] -# # license required if publisher present: -# [ sh:property [ -# sh:path schema:license ; -# sh:minCount 1 ; -# ]] -# ) . +five-safes-crate:RootDatasetLicenseWhenPublished + a sh:NodeShape ; + sh:name "License present on published crates" ; + sh:description "If the root dataset is published (has schema:publisher), it SHOULD declare a license." ; + sh:targetNode ro: ; + sh:severity sh:Warning ; + sh:message "Profile Conformance: Published crates SHOULD include a license." ; + sh:or ( + # license not required if no publisher: + [ sh:not [ sh:property [ + sh:path schema:publisher ; + sh:minCount 1 ; + ]]] + # license required if publisher present: + [ sh:property [ + sh:path schema:license ; + sh:minCount 1 ; + ]] + ) . diff --git a/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py b/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py index a32c593d..58e7fd0a 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_5_profile_conformance.py @@ -126,4 +126,36 @@ def test_5src_root_data_entity_has_publisher_but_not_date_published(): ) +def test_5src_root_data_entity_has_publisher_but_not_license(): + """ + Test a Five Safes Crate where the RootDataEntity has publisher but not license. + """ + sparql = ( + SPARQL_PREFIXES + + """ + DELETE { + ?rootdataentity schema:license ?license . + } + WHERE { + ?metadatafile a schema:CreativeWork ; + schema:about ?rootdataentity . + ?rootdataentity schema:publisher ?publisher ; + schema:license ?license . + } + """ + ) + + do_entity_test( + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.RECOMMENDED, + expected_validation_result=False, + expected_triggered_requirements=["License present on published crates"], + expected_triggered_issues=[ + "Profile Conformance: Published crates SHOULD include a license." + ], + profile_identifier="five-safes-crate", + rocrate_entity_mod_sparql=sparql, + ) + + # ----- MAY fails tests