diff --git a/rocrate_validator/profiles/five-safes-crate/must/15_metadata_file.py b/rocrate_validator/profiles/five-safes-crate/must/15_metadata_file.py
new file mode 100644
index 00000000..7fd46ccf
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/must/15_metadata_file.py
@@ -0,0 +1,64 @@
+# 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 re
+
+import rocrate_validator.log as logging
+from rocrate_validator.models import Severity, ValidationContext
+from rocrate_validator.requirements.python import PyFunctionCheck, check, requirement
+
+# set up logging
+logger = logging.getLogger(__name__)
+
+
+@requirement(name="RO-Crate context version")
+class FileDescriptorContextVersion(PyFunctionCheck):
+ """The RO-Crate metadata file MUST include the RO-Crate context version 1.2
+ (or later minor version) in `@context`"""
+
+ @check(name="RO-Crate context version", severity=Severity.REQUIRED)
+ def test_existence(self, context: ValidationContext) -> bool:
+ """
+ The RO-Crate metadata file MUST include the RO-Crate context version 1.2
+ (or later minor version) in `@context`
+ """
+ try:
+ json_dict = context.ro_crate.metadata.as_dict()
+ context_value = json_dict["@context"]
+ pattern = re.compile(
+ r"https://w3id\.org/ro/crate/1\.[2-9](-DRAFT)?/context"
+ )
+ passed = True
+ if isinstance(context_value, list):
+ if not any(
+ pattern.match(item)
+ for item in context_value
+ if isinstance(item, str)
+ ):
+ passed = False
+ else:
+ if not pattern.match(context_value):
+ passed = False
+ if not passed:
+ context.result.add_issue(
+ "The RO-Crate metadata file MUST include the RO-Crate context "
+ "version 1.2 (or later minor version) in `@context`",
+ self,
+ )
+ return passed
+
+ except Exception as e:
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.exception(e)
+ return True
diff --git a/rocrate_validator/profiles/five-safes-crate/must/15_metadata_file.ttl b/rocrate_validator/profiles/five-safes-crate/must/15_metadata_file.ttl
new file mode 100644
index 00000000..14d939f0
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/must/15_metadata_file.ttl
@@ -0,0 +1,41 @@
+# 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-crate: .
+@prefix five-safes-crate: .
+@prefix rdf: .
+@prefix schema: .
+@prefix purl: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+@prefix dct: .
+
+five-safes-crate:MetadataFileDescriptorProperties a sh:NodeShape ;
+ sh:name "RO-Crate conforms to 1.2 or later minor version" ;
+ sh:description """The RO-Crate metadata file descriptor MUST have a `conformsTo` property with RO-Crate specification version 1.2 or later minor version""";
+ sh:targetClass ro-crate:ROCrateMetadataFileDescriptor ;
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "RO-Crate conforms to 1.2 or later minor version" ;
+ sh:description "The RO-Crate metadata file descriptor MUST have a `conformsTo` property with RO-Crate specification version 1.2 or later minor version" ;
+ sh:minCount 1 ;
+ sh:nodeKind sh:IRI ;
+ sh:path dct:conformsTo ;
+ sh:pattern "https://w3id\\.org/ro/crate/(1\\.[2-9](-DRAFT)?)" ;
+ sh:severity sh:Violation;
+ sh:message "The RO-Crate metadata file descriptor MUST have a `conformsTo` property with RO-Crate specification version 1.2 or later minor version" ;
+ ] .
+
+ro-crate:conformsToROCrateSpec sh:deactivated true .
diff --git a/rocrate_validator/profiles/ro-crate/must/1_file-descriptor_metadata.ttl b/rocrate_validator/profiles/ro-crate/must/1_file-descriptor_metadata.ttl
index 075f5f21..fee8c135 100644
--- a/rocrate_validator/profiles/ro-crate/must/1_file-descriptor_metadata.ttl
+++ b/rocrate_validator/profiles/ro-crate/must/1_file-descriptor_metadata.ttl
@@ -89,13 +89,12 @@ ro-crate:ROCrateMetadataFileDescriptorRecommendedProperties a sh:NodeShape ;
sh:class schema_org:Dataset ;
sh:message "The RO-Crate metadata file descriptor MUST have an `about` property referencing the Root Data Entity" ;
] ;
- sh:property [
- a sh:PropertyShape ;
- sh:name "Metadata File Descriptor entity: `conformsTo` property" ;
- sh:description """Check if the RO-Crate Metadata File Descriptor has a `conformsTo` property which points to the RO-Crate specification version""" ;
- sh:minCount 1 ;
- sh:nodeKind sh:IRI ;
- sh:path dct:conformsTo ;
- sh:hasValue ;
- sh:message "The RO-Crate metadata file descriptor MUST have a `conformsTo` property with the RO-Crate specification version" ;
- ] .
+ sh:property ro-crate:conformsToROCrateSpec .
+
+ro-crate:conformsToROCrateSpec sh:name "Metadata File Descriptor entity: `conformsTo` property" ;
+ sh:description """Check if the RO-Crate Metadata File Descriptor has a `conformsTo` property which points to the RO-Crate specification version""" ;
+ sh:minCount 1 ;
+ sh:nodeKind sh:IRI ;
+ sh:path dct:conformsTo ;
+ sh:hasValue ;
+ sh:message "The RO-Crate metadata file descriptor MUST have a `conformsTo` property with the RO-Crate specification version" .
diff --git a/tests/data/crates/invalid/five_safes_crate/context_multiple_wrong_version/ro-crate-metadata.json b/tests/data/crates/invalid/five_safes_crate/context_multiple_wrong_version/ro-crate-metadata.json
new file mode 100644
index 00000000..79733fa7
--- /dev/null
+++ b/tests/data/crates/invalid/five_safes_crate/context_multiple_wrong_version/ro-crate-metadata.json
@@ -0,0 +1,169 @@
+{
+ "@context": ["https://w3id.org/ro/crate/1.1/context", "http://schema.org", {"test": "http://schema.org/test"}],
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate/1.2"
+ }
+ },
+ {
+ "@id": "./",
+ "@type": "Dataset",
+ "name": "5-Safe RO-Crate Request",
+ "description": "example 5-Safe RO-Crate request metadata for testing",
+ "license": "Apache-2.0",
+ "datePublished": "2025-09-20T14:38:00+00:00",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ }
+ ],
+ "mainEntity": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "mentions": {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538"
+ },
+ "sourceOrganization": {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ },
+ {
+ "@id": "https://w3id.org/5s-crate/0.4",
+ "@type": "Profile",
+ "name": "Five Safes RO-Crate profile"
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1",
+ "@type": "Dataset",
+ "name": "CWL Protein MD Setup tutorial with mutations",
+ "conformsTo": {
+ "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
+ },
+ "distribution": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ }
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1",
+ "@type": "DataDownload",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ },
+ "encodingFormat": "application/zip"
+ },
+ {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538",
+ "@type": "CreateAction",
+ "actionStatus": "http://schema.org/PotentialActionStatus",
+ "agent": {
+ "@id": "https://orcid.org/0000-0001-9842-9718"
+ },
+ "instrument": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "name": "Execute query 12389 on workflow ",
+ "object": [
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "#enableFastMode"
+ }
+ ]
+ },
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718",
+ "@type": "Person",
+ "name": "Stian Soiland-Reyes",
+ "affiliation": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "memberOf": [
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ ]
+ },
+ {
+ "@id": "https://ror.org/027m9bs27",
+ "@type": "Organization",
+ "name": "The University of Manchester"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58",
+ "@type": "Organization",
+ "name": "University of Nottingham"
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70",
+ "@type": "Project",
+ "name": "Investigation of cancer (TRE72 project 81)",
+ "identifier": [
+ {
+ "@id": "_:localid:tre72:project81"
+ }
+ ],
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961"
+ },
+ "member": [
+ {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58"
+ }
+ ]
+ },
+ {
+ "@id": "_:localid:tre72:project81",
+ "@type": "PropertyValue",
+ "name": "tre72",
+ "value": "project81"
+ },
+ {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961",
+ "@type": "Grant",
+ "name": "EOSC4Cancer"
+ },
+ {
+ "@id": "input1.txt",
+ "@type": "File",
+ "name": "input1",
+ "exampleOfWork": {
+ "@id": "#sequence"
+ }
+ },
+ {
+ "@id": "#enableFastMode",
+ "@type": "PropertyValue",
+ "name": "--fast-mode",
+ "value": "True",
+ "exampleOfWork": {
+ "@id": "#fast"
+ }
+ },
+ {
+ "@id": "#sequence",
+ "@type": "FormalParameter",
+ "name": "input-sequence"
+ },
+ {
+ "@id": "#fast",
+ "@type": "FormalParameter",
+ "name": "fast-mode"
+ }
+ ]
+}
diff --git a/tests/data/crates/invalid/five_safes_crate/context_single_wrong_version/ro-crate-metadata.json b/tests/data/crates/invalid/five_safes_crate/context_single_wrong_version/ro-crate-metadata.json
new file mode 100644
index 00000000..beba6839
--- /dev/null
+++ b/tests/data/crates/invalid/five_safes_crate/context_single_wrong_version/ro-crate-metadata.json
@@ -0,0 +1,169 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate/1.2"
+ }
+ },
+ {
+ "@id": "./",
+ "@type": "Dataset",
+ "name": "5-Safe RO-Crate Request",
+ "description": "example 5-Safe RO-Crate request metadata for testing",
+ "license": "Apache-2.0",
+ "datePublished": "2025-09-20T14:38:00+00:00",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ }
+ ],
+ "mainEntity": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "mentions": {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538"
+ },
+ "sourceOrganization": {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ },
+ {
+ "@id": "https://w3id.org/5s-crate/0.4",
+ "@type": "Profile",
+ "name": "Five Safes RO-Crate profile"
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1",
+ "@type": "Dataset",
+ "name": "CWL Protein MD Setup tutorial with mutations",
+ "conformsTo": {
+ "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
+ },
+ "distribution": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ }
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1",
+ "@type": "DataDownload",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ },
+ "encodingFormat": "application/zip"
+ },
+ {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538",
+ "@type": "CreateAction",
+ "actionStatus": "http://schema.org/PotentialActionStatus",
+ "agent": {
+ "@id": "https://orcid.org/0000-0001-9842-9718"
+ },
+ "instrument": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "name": "Execute query 12389 on workflow ",
+ "object": [
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "#enableFastMode"
+ }
+ ]
+ },
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718",
+ "@type": "Person",
+ "name": "Stian Soiland-Reyes",
+ "affiliation": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "memberOf": [
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ ]
+ },
+ {
+ "@id": "https://ror.org/027m9bs27",
+ "@type": "Organization",
+ "name": "The University of Manchester"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58",
+ "@type": "Organization",
+ "name": "University of Nottingham"
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70",
+ "@type": "Project",
+ "name": "Investigation of cancer (TRE72 project 81)",
+ "identifier": [
+ {
+ "@id": "_:localid:tre72:project81"
+ }
+ ],
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961"
+ },
+ "member": [
+ {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58"
+ }
+ ]
+ },
+ {
+ "@id": "_:localid:tre72:project81",
+ "@type": "PropertyValue",
+ "name": "tre72",
+ "value": "project81"
+ },
+ {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961",
+ "@type": "Grant",
+ "name": "EOSC4Cancer"
+ },
+ {
+ "@id": "input1.txt",
+ "@type": "File",
+ "name": "input1",
+ "exampleOfWork": {
+ "@id": "#sequence"
+ }
+ },
+ {
+ "@id": "#enableFastMode",
+ "@type": "PropertyValue",
+ "name": "--fast-mode",
+ "value": "True",
+ "exampleOfWork": {
+ "@id": "#fast"
+ }
+ },
+ {
+ "@id": "#sequence",
+ "@type": "FormalParameter",
+ "name": "input-sequence"
+ },
+ {
+ "@id": "#fast",
+ "@type": "FormalParameter",
+ "name": "fast-mode"
+ }
+ ]
+}
diff --git a/tests/data/crates/valid/five-safes-crate-multiple-context/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-multiple-context/ro-crate-metadata.json
new file mode 100644
index 00000000..89813ee6
--- /dev/null
+++ b/tests/data/crates/valid/five-safes-crate-multiple-context/ro-crate-metadata.json
@@ -0,0 +1,169 @@
+{
+ "@context": ["https://w3id.org/ro/crate/1.2/context", "https://w3id.org/ro/terms/workflow-run/context", {"test": "http://schema.org/test"}],
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate/1.2"
+ }
+ },
+ {
+ "@id": "./",
+ "@type": "Dataset",
+ "name": "5-Safe RO-Crate Request",
+ "description": "example 5-Safe RO-Crate request metadata for testing",
+ "license": "Apache-2.0",
+ "datePublished": "2025-09-20T14:38:00+00:00",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ }
+ ],
+ "mainEntity": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "mentions": {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538"
+ },
+ "sourceOrganization": {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ },
+ {
+ "@id": "https://w3id.org/5s-crate/0.4",
+ "@type": "Profile",
+ "name": "Five Safes RO-Crate profile"
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1",
+ "@type": "Dataset",
+ "name": "CWL Protein MD Setup tutorial with mutations",
+ "conformsTo": {
+ "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
+ },
+ "distribution": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ }
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1",
+ "@type": "DataDownload",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ },
+ "encodingFormat": "application/zip"
+ },
+ {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538",
+ "@type": "CreateAction",
+ "actionStatus": "http://schema.org/PotentialActionStatus",
+ "agent": {
+ "@id": "https://orcid.org/0000-0001-9842-9718"
+ },
+ "instrument": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "name": "Execute query 12389 on workflow ",
+ "object": [
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "#enableFastMode"
+ }
+ ]
+ },
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718",
+ "@type": "Person",
+ "name": "Stian Soiland-Reyes",
+ "affiliation": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "memberOf": [
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ ]
+ },
+ {
+ "@id": "https://ror.org/027m9bs27",
+ "@type": "Organization",
+ "name": "The University of Manchester"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58",
+ "@type": "Organization",
+ "name": "University of Nottingham"
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70",
+ "@type": "Project",
+ "name": "Investigation of cancer (TRE72 project 81)",
+ "identifier": [
+ {
+ "@id": "_:localid:tre72:project81"
+ }
+ ],
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961"
+ },
+ "member": [
+ {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58"
+ }
+ ]
+ },
+ {
+ "@id": "_:localid:tre72:project81",
+ "@type": "PropertyValue",
+ "name": "tre72",
+ "value": "project81"
+ },
+ {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961",
+ "@type": "Grant",
+ "name": "EOSC4Cancer"
+ },
+ {
+ "@id": "input1.txt",
+ "@type": "File",
+ "name": "input1",
+ "exampleOfWork": {
+ "@id": "#sequence"
+ }
+ },
+ {
+ "@id": "#enableFastMode",
+ "@type": "PropertyValue",
+ "name": "--fast-mode",
+ "value": "True",
+ "exampleOfWork": {
+ "@id": "#fast"
+ }
+ },
+ {
+ "@id": "#sequence",
+ "@type": "FormalParameter",
+ "name": "input-sequence"
+ },
+ {
+ "@id": "#fast",
+ "@type": "FormalParameter",
+ "name": "fast-mode"
+ }
+ ]
+}
diff --git a/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
index 73285401..a53902d4 100644
--- a/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
+++ b/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
@@ -1,5 +1,5 @@
{
- "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@context": "https://w3id.org/ro/crate/1.2/context",
"@graph": [
{
"@type": "CreativeWork",
@@ -8,7 +8,7 @@
"@id": "./"
},
"conformsTo": {
- "@id": "https://w3id.org/ro/crate/1.1"
+ "@id": "https://w3id.org/ro/crate/1.2"
}
},
{
@@ -166,4 +166,4 @@
"name": "fast-mode"
}
]
-}
\ No newline at end of file
+}
diff --git a/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
index e4aa7f03..38e74f08 100644
--- a/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
+++ b/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
@@ -1,5 +1,5 @@
{
- "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@context": "https://w3id.org/ro/crate/1.2/context",
"@graph": [
{
"@type": "CreativeWork",
@@ -8,7 +8,7 @@
"@id": "./"
},
"conformsTo": {
- "@id": "https://w3id.org/ro/crate/1.1"
+ "@id": "https://w3id.org/ro/crate/1.2"
}
},
{
@@ -406,4 +406,4 @@
"name": "sha-512 algorithm"
}
]
-}
\ No newline at end of file
+}
diff --git a/tests/integration/profiles/five-safes-crate/test_5src_15_metadata_file.py b/tests/integration/profiles/five-safes-crate/test_5src_15_metadata_file.py
new file mode 100644
index 00000000..52cdce45
--- /dev/null
+++ b/tests/integration/profiles/five-safes-crate/test_5src_15_metadata_file.py
@@ -0,0 +1,86 @@
+# 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, Invalid5sROC
+from tests.shared import do_entity_test, SPARQL_PREFIXES
+
+# set up logging
+logger = logging.getLogger(__name__)
+
+
+# ----- MUST fails tests
+
+
+def test_5src_conforms_to_old_version():
+ sparql = (
+ SPARQL_PREFIXES
+ + """
+ DELETE {
+ ?this dct:conformsTo ?version .
+ }
+ INSERT {
+ ?this dct:conformsTo .
+ }
+ WHERE {
+ ?this dct:conformsTo ?version ;
+ schema:about <./> .
+ }
+ """
+ )
+
+ do_entity_test(
+ rocrate_path=ValidROC().five_safes_crate_request,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=[
+ "RO-Crate conforms to 1.2 or later minor version"
+ ],
+ expected_triggered_issues=[
+ "The RO-Crate metadata file descriptor MUST have a `conformsTo` property with "
+ "RO-Crate specification version 1.2 or later minor version"
+ ],
+ profile_identifier="five-safes-crate",
+ rocrate_entity_mod_sparql=sparql,
+ )
+
+
+def test_5src_context_single_wrong_version():
+ do_entity_test(
+ rocrate_path=Invalid5sROC().context_single_wrong_version,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["RO-Crate context version"],
+ expected_triggered_issues=[
+ "The RO-Crate metadata file MUST include the RO-Crate context version 1.2 "
+ "(or later minor version) in `@context`"
+ ],
+ profile_identifier="five-safes-crate",
+ )
+
+
+def test_5src_context_multiple_wrong_version():
+ do_entity_test(
+ rocrate_path=Invalid5sROC().context_multiple_wrong_version,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["RO-Crate context version"],
+ expected_triggered_issues=[
+ "The RO-Crate metadata file MUST include the RO-Crate context version 1.2 "
+ "(or later minor version) in `@context`"
+ ],
+ profile_identifier="five-safes-crate",
+ )
diff --git a/tests/integration/profiles/five-safes-crate/test_valid_5src.py b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
index cfc5aa53..7de8c869 100644
--- a/tests/integration/profiles/five-safes-crate/test_valid_5src.py
+++ b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
@@ -30,7 +30,9 @@ def test_valid_five_safes_crate_request_required():
Severity.REQUIRED,
True,
profile_identifier="five-safes-crate",
- skip_checks=[SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER],
+ skip_checks=[
+ SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER,
+ ],
)
@@ -41,5 +43,20 @@ def test_valid_five_safes_crate_result_required():
Severity.REQUIRED,
True,
profile_identifier="five-safes-crate",
- skip_checks=[SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER],
+ skip_checks=[
+ SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER,
+ ],
+ )
+
+
+def test_valid_five_safes_crate_multiple_context():
+ """Test a valid Five Safes Crate representing a result."""
+ do_entity_test(
+ ValidROC().five_safes_crate_multiple_context,
+ Severity.REQUIRED,
+ True,
+ profile_identifier="five-safes-crate",
+ skip_checks=[
+ SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER,
+ ],
)
diff --git a/tests/ro_crates.py b/tests/ro_crates.py
index 53f77259..b78d9880 100644
--- a/tests/ro_crates.py
+++ b/tests/ro_crates.py
@@ -99,6 +99,10 @@ def five_safes_crate_request(self) -> Path:
def five_safes_crate_result(self) -> Path:
return VALID_CRATES_DATA_PATH / "five-safes-crate-result"
+ @property
+ def five_safes_crate_multiple_context(self) -> Path:
+ return VALID_CRATES_DATA_PATH / "five-safes-crate-multiple-context"
+
class InvalidFileDescriptor:
@@ -980,19 +984,15 @@ def propertyvalue_no_unitcode(self) -> Path:
class Invalid5sROC:
- base_path = INVALID_CRATES_DATA_PATH / "6_five_safes_crate/"
-
- @property
- def funding_project_no_name(self) -> Path:
- return self.base_path / "funding_project_no_name"
+ base_path = INVALID_CRATES_DATA_PATH / "five_safes_crate/"
@property
- def root_data_entity_no_source_organization(self) -> Path:
- return self.base_path / "root_data_entity_no_source_organization"
+ def context_multiple_wrong_version(self) -> Path:
+ return self.base_path / "context_multiple_wrong_version"
@property
- def root_data_entity_source_organization_not_entity(self) -> Path:
- return self.base_path / "root_data_entity_source_organization_not_entity"
+ def context_single_wrong_version(self) -> Path:
+ return self.base_path / "context_single_wrong_version"
class InvalidMultiProfileROC:
diff --git a/tests/shared.py b/tests/shared.py
index b82d4ade..7a9dca32 100644
--- a/tests/shared.py
+++ b/tests/shared.py
@@ -36,6 +36,7 @@
SPARQL_PREFIXES = """
PREFIX schema:
+PREFIX dct:
PREFIX shp:
PREFIX rdf:
"""