diff --git a/rocrate_validator/profiles/five-safes-crate/may/8_disclosure_phase.ttl b/rocrate_validator/profiles/five-safes-crate/may/8_disclosure_phase.ttl index 2ad58813..46943191 100644 --- a/rocrate_validator/profiles/five-safes-crate/may/8_disclosure_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/may/8_disclosure_phase.ttl @@ -52,8 +52,7 @@ five-safes-crate:DisclosureObjectHasStartTimeIfBegun sh:path schema:startTime ; sh:minCount 1 ; sh:maxCount 1 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|[+-][0-9]{2}:[0-9]{2})$" ; sh:severity sh:Info ; - sh:description "Disclosure object MAY have startTime property with RFC 3339 full datetime string if action began." ; - sh:message "Disclosure object MAY have startTime property with RFC 3339 full datetime string if action began." ; + sh:description "`DisclosureCheck` MAY have the `startTime` property if `actionStatus` is either ActiveActionStatus, CompletedActionStatus or FailedActionStatus." ; + sh:message "`DisclosureCheck` MAY have the `startTime` property if `actionStatus` is either ActiveActionStatus, CompletedActionStatus or FailedActionStatus." ; ] . \ No newline at end of file diff --git a/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl index e371203d..d46e38ca 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl @@ -44,30 +44,31 @@ five-safes-crate:DisclosureObjectHasDescriptiveNameAndIsAssessAction sh:property [ a sh:PropertyShape ; sh:name "AssessAction" ; - sh:description "DisclosureCheck MUST be a `schema:AssessAction`." ; + sh:description "`DisclosureCheck` MUST be a `schema:AssessAction`." ; sh:path rdf:type ; sh:minCount 1 ; sh:hasValue schema:AssessAction; sh:severity sh:Violation ; - sh:message "DisclosureCheck MUST be a `schema:AssessAction`." ; + sh:message "`DisclosureCheck` MUST be a `schema:AssessAction`." ; ] ; sh:property [ a sh:PropertyShape ; sh:name "name" ; - sh:description "DisclosureCheck MUST have a name string of at least 20 characters." ; + sh:description "`DisclosureCheck` MUST have a name string of at least 10 characters." ; + sh:minCount 1 ; sh:path schema:name ; sh:datatype xsd:string ; - sh:minLength 20 ; + sh:minLength 10 ; sh:severity sh:Violation ; - sh:message "DisclosureCheck MUST have a name string of at least 20 characters." ; + sh:message "`DisclosureCheck` MUST have a name string of at least 10 characters." ; ] . -five-safes-crate:DisclosureObjectHasActionStatus +five-safes-crate:DisclosureObjectHasActionStatusWithAcceptedValue a sh:NodeShape ; sh:name "DisclosureCheck" ; - sh:description "DisclosureCheck" ; + sh:description "`DisclosureCheck` MUST have an actionStatus with an allowed value (see https://schema.org/ActionStatusType)." ; sh:target [ a sh:SPARQLTarget ; @@ -86,7 +87,7 @@ five-safes-crate:DisclosureObjectHasActionStatus sh:property [ a sh:PropertyShape ; sh:name "actionStatus" ; - sh:description "The value of actionStatus MUST be one of the allowed values." ; + sh:description "`DisclosureCheck` MUST have an actionStatus with an allowed value (see https://schema.org/ActionStatusType)." ; sh:path schema:actionStatus ; sh:in ( "http://schema.org/PotentialActionStatus" @@ -95,5 +96,63 @@ five-safes-crate:DisclosureObjectHasActionStatus "http://schema.org/FailedActionStatus" ) ; sh:severity sh:Violation ; - sh:message "The value of actionStatus MUST be one of the allowed values." ; + sh:message "`DisclosureCheck` MUST have an actionStatus with an allowed value (see https://schema.org/ActionStatusType)." ; + ] . + + +five-safes-crate:DisclosureObjectHasCompliantStartTimeFormat + a sh:NodeShape ; + sh:name "DisclosureCheck" ; + sh:description "`DisclosureCheck` --> `startTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + + SELECT ?this + WHERE { + ?this schema:additionalType shp:DisclosureCheck ; + schema:startTime ?o + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:name "StartTime" ; + sh:path schema:startTime ; + sh:minCount 0 ; + sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; + sh:severity sh:Violation ; + sh:message "`DisclosureCheck` --> `startTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + ] . + + +five-safes-crate:DisclosureObjectHasCompliantEndTimeFormat + a sh:NodeShape ; + sh:name "DisclosureCheck" ; + sh:description "`DisclosureCheck` --> `endTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + sh:target [ + a sh:SPARQLTarget ; + sh:select """ + PREFIX schema: + PREFIX shp: + + SELECT ?this + WHERE { + ?this schema:additionalType shp:DisclosureCheck ; + schema:endTime ?o + } + """ ; + ] ; + + sh:property [ + a sh:PropertyShape ; + sh:name "EndTime" ; + sh:path schema:endTime ; + sh:minCount 0 ; + sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; + sh:severity sh:Violation ; + sh:message "`DisclosureCheck` --> `endTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; ] . diff --git a/rocrate_validator/profiles/five-safes-crate/should/8_disclosure_phase.ttl b/rocrate_validator/profiles/five-safes-crate/should/8_disclosure_phase.ttl index a070de95..1d466251 100644 --- a/rocrate_validator/profiles/five-safes-crate/should/8_disclosure_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/should/8_disclosure_phase.ttl @@ -32,7 +32,7 @@ five-safes-crate:RootDataEntityShouldMentionDisclosureObject sh:sparql [ a sh:SPARQLConstraint ; sh:name "mentions" ; - sh:description "RootDataEntity SHOULD mention a disclosure object." ; + sh:description "`RootDataEntity` SHOULD mention a disclosure object." ; sh:select """ PREFIX schema: PREFIX shp: @@ -46,14 +46,14 @@ five-safes-crate:RootDataEntityShouldMentionDisclosureObject } """ ; sh:severity sh:Warning ; - sh:message "RootDataEntity SHOULD mention a disclosure object." ; + sh:message "`RootDataEntity` SHOULD mention a disclosure object." ; ] . five-safes-crate:DisclosureObjectHasActionStatus a sh:NodeShape ; sh:name "DisclosureCheck" ; - sh:description "DisclosureCheck" ; + sh:description "The `DisclosureCheck` SHOULD have `actionStatus` property." ; sh:target [ a sh:SPARQLTarget ; @@ -71,11 +71,11 @@ five-safes-crate:DisclosureObjectHasActionStatus sh:property [ a sh:PropertyShape ; sh:name "ActionStatus" ; - sh:description "The DisclosureCheck SHOULD have actionStatus property." ; + sh:description "The `DisclosureCheck` SHOULD have `actionStatus` property." ; sh:path schema:actionStatus ; sh:minCount 1 ; sh:severity sh:Warning ; - sh:message "The DisclosureCheck SHOULD have actionStatus property." ; + sh:message "The `DisclosureCheck` SHOULD have `actionStatus` property." ; ] . @@ -108,8 +108,7 @@ five-safes-crate:DisclosureObjectHasEndTimeIfcompletedOrFailed sh:path schema:endTime ; sh:minCount 1 ; sh:maxCount 1 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|[+-][0-9]{2}:[0-9]{2})$" ; sh:severity sh:Warning ; - sh:description "Disclosure object SHOULD have endTime property with a valid datetetime if action completed of failed." ; - sh:message "Disclosure object SHOULD have endTime property with a valid datetime if action completed of failed." ; + sh:description "`DisclosureCheck` SHOULD have the `endTime` property if `actionStatus` is either CompletedActionStatus or FailedActionStatus." ; + sh:message "`DisclosureCheck` SHOULD have the `endTime` property if `actionStatus` is either CompletedActionStatus or FailedActionStatus." ; ] . \ No newline at end of file diff --git a/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py index 07fecf21..1d3310c8 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py @@ -16,7 +16,7 @@ from rocrate_validator.models import Severity from tests.ro_crates import ValidROC -from tests.shared import do_entity_test +from tests.shared import do_entity_test, SPARQL_PREFIXES # set up logging logger = logging.getLogger(__name__) @@ -26,10 +26,9 @@ def test_5src_disclosure_object_with_no_name(): - sparql = """ - PREFIX schema: - PREFIX shp: - + sparql = ( + SPARQL_PREFIXES + + """ DELETE { ?this schema:name ?name . } @@ -39,23 +38,25 @@ def test_5src_disclosure_object_with_no_name(): <./> schema:mentions ?this . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + "`DisclosureCheck` MUST have a name string of at least 10 characters." + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) def test_5src_disclosure_object_with_name_not_string(): - sparql = """ - PREFIX schema: - PREFIX shp: - + sparql = ( + SPARQL_PREFIXES + + """ DELETE { ?this schema:name ?name . } @@ -68,28 +69,30 @@ def test_5src_disclosure_object_with_name_not_string(): <./> schema:mentions ?this . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + "`DisclosureCheck` MUST have a name string of at least 10 characters." + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) def test_5src_disclosure_object_with_not_long_enough_name(): - sparql = """ - PREFIX schema: - PREFIX shp: - + sparql = ( + SPARQL_PREFIXES + + """ DELETE { ?this schema:name ?name . } INSERT { - ?this schema:name "Too short" . + ?this schema:name "Short" . } WHERE { ?this schema:additionalType shp:DisclosureCheck ; @@ -97,26 +100,27 @@ def test_5src_disclosure_object_with_not_long_enough_name(): <./> schema:mentions ?this . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + "`DisclosureCheck` MUST have a name string of at least 10 characters." + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) def test_5src_disclosure_object_not_an_assess_action(): - sparql = """ - PREFIX schema: - PREFIX shp: - PREFIX rdf: - + sparql = ( + SPARQL_PREFIXES + + """ DELETE { - ?this rdf:type ?o . + ?this rdf:type schema:AssessAction . } INSERT { ?this rdf:type "Not an AssessAction type" . @@ -126,173 +130,186 @@ def test_5src_disclosure_object_not_an_assess_action(): schema:additionalType shp:DisclosureCheck . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + "`DisclosureCheck` MUST be a `schema:AssessAction`." + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) def test_5src_disclosure_object_with_no_proper_action_status(): - sparql = """ - PREFIX schema: - PREFIX shp: - PREFIX rdf: - + sparql = ( + SPARQL_PREFIXES + + """ DELETE { - ?this schema:actionStatus ?o . + ?s schema:actionStatus ?o . } INSERT { - ?this schema:actionStatus "This is not a proper actionStatus" . + ?s schema:actionStatus "This is not a proper actionStatus" . } WHERE { - ?this schema:actionStatus ?o ; - schema:additionalType shp:DisclosureCheck . + ?s schema:actionStatus ?o ; + schema:additionalType shp:DisclosureCheck . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + ( + "`DisclosureCheck` MUST have an actionStatus with an allowed value " + "(see https://schema.org/ActionStatusType)." + ) + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) -# ----- SHOULD fails tests - - -def test_5src_disclosure_object_not_mentioned_by_root_data_entity(): - sparql = """ - PREFIX schema: - PREFIX shp: - +def test_5src_disclosure_object_has_no_properly_formatted_start_time(): + sparql = ( + SPARQL_PREFIXES + + """ DELETE { - <./> schema:mentions ?o . + ?s schema:startTime ?time . + } + INSERT { + ?s schema:startTime "1st Dec '25 @ 10:00:00" . } WHERE { - ?o schema:additionalType shp:DisclosureCheck . + ?s schema:additionalType shp:DisclosureCheck ; + schema:startTime ?time . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, - requirement_severity=Severity.RECOMMENDED, + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + ( + "`DisclosureCheck` --> `startTime` MUST follow the RFC 3339 standard " + "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." + ) + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) -def test_5src_disclosure_object_with_no_action_status(): - sparql = """ - PREFIX schema: - PREFIX shp: - +def test_5src_disclosure_object_has_no_properly_formatted_end_time(): + sparql = ( + SPARQL_PREFIXES + + """ DELETE { - ?s schema:actionStatus ?o . + ?s schema:endTime ?time . + } + INSERT { + ?s schema:endTime "1st Dec '25 @ 10:00:00" . } WHERE { - ?s schema:additionalType shp:DisclosureCheck . + ?s schema:additionalType shp:DisclosureCheck ; + schema:endTime ?time . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, - requirement_severity=Severity.RECOMMENDED, + rocrate_path=ValidROC().five_safes_crate_result, + requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + ( + "`DisclosureCheck` --> `endTime` MUST follow the RFC 3339 standard " + "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." + ) + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) -def test_5src_disclosure_object_has_no_properly_formatted_start_time_if_begun(): - sparql = """ - PREFIX schema: - PREFIX shp: +# ----- SHOULD fails tests + +def test_5src_disclosure_object_not_mentioned_by_root_data_entity(): + sparql = ( + SPARQL_PREFIXES + + """ DELETE { - ?s schema:startTime ?o . - } - INSERT { - ?s schema:startTime "1st Dec '25 @ 10:00:00" . + <./> schema:mentions ?o . } WHERE { - ?s schema:additionalType shp:DisclosureCheck ; - schema:actionStatus ?status . - FILTER(?status IN ( - "http://schema.org/CompletedActionStatus", - "http://schema.org/FailedActionStatus", - "http://schema.org/ActiveActionStatus" - )) + ?o schema:additionalType shp:DisclosureCheck . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.RECOMMENDED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["RootDataEntity"], + expected_triggered_issues=[ + "`RootDataEntity` SHOULD mention a disclosure object." + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) -def test_5src_disclosure_object_has_no_end_time_if_ended(): - sparql = """ - PREFIX schema: - PREFIX shp: - +def test_5src_disclosure_object_with_no_action_status(): + sparql = ( + SPARQL_PREFIXES + + """ DELETE { - ?s schema:endTime ?o . + ?s schema:actionStatus ?o . } WHERE { ?s schema:additionalType shp:DisclosureCheck ; - schema:actionStatus ?status . - FILTER(?status IN ( - "http://schema.org/CompletedActionStatus", - "http://schema.org/FailedActionStatus" - )) + schema:actionStatus ?o . } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.RECOMMENDED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + "The `DisclosureCheck` SHOULD have `actionStatus` property." + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) -def test_5src_disclosure_object_has_no_properly_formatted_end_time_if_ended(): - sparql = """ - PREFIX schema: - PREFIX shp: - +def test_5src_disclosure_object_has_no_end_time_if_ended(): + sparql = ( + SPARQL_PREFIXES + + """ DELETE { ?s schema:endTime ?o . } - INSERT { - ?s schema:endTime "1st Dec '25 @ 10:00:00" . - } WHERE { ?s schema:additionalType shp:DisclosureCheck ; + schema:endTime ?o ; schema:actionStatus ?status . FILTER(?status IN ( "http://schema.org/CompletedActionStatus", @@ -300,13 +317,19 @@ def test_5src_disclosure_object_has_no_properly_formatted_end_time_if_ended(): )) } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.RECOMMENDED, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + ( + "`DisclosureCheck` SHOULD have the `endTime` property if `actionStatus` " + "is either CompletedActionStatus or FailedActionStatus." + ) + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) @@ -316,15 +339,15 @@ def test_5src_disclosure_object_has_no_properly_formatted_end_time_if_ended(): def test_5src_disclosure_object_has_no_start_time_if_begun(): - sparql = """ - PREFIX schema: - PREFIX shp: - + sparql = ( + SPARQL_PREFIXES + + """ DELETE { ?s schema:startTime ?o . } WHERE { ?s schema:additionalType shp:DisclosureCheck ; + schema:startTime ?o ; schema:actionStatus ?status . FILTER(?status IN ( "http://schema.org/CompletedActionStatus", @@ -333,13 +356,19 @@ def test_5src_disclosure_object_has_no_start_time_if_begun(): )) } """ + ) do_entity_test( - rocrate_path=ValidROC().five_safes_crate_request, + rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.OPTIONAL, expected_validation_result=False, - expected_triggered_requirements=None, - expected_triggered_issues=None, + expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_issues=[ + ( + "`DisclosureCheck` MAY have the `startTime` property if `actionStatus` " + "is either ActiveActionStatus, CompletedActionStatus or FailedActionStatus." + ) + ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, )