diff --git a/src/dsp_tools/commands/validate_data/models/validation.py b/src/dsp_tools/commands/validate_data/models/validation.py index 15e2243485..fcf0d64c81 100644 --- a/src/dsp_tools/commands/validate_data/models/validation.py +++ b/src/dsp_tools/commands/validate_data/models/validation.py @@ -31,20 +31,35 @@ class ValidationReport: @dataclass -class ResourceValidationReportIdentifiers: +class UnexpectedComponent: + component_type: str + + +@dataclass +class QueryInfo: validation_bn: Node - focus_node_iri: Node + focus_iri: Node + focus_rdf_type: Node + + +@dataclass +class ValidationResultBaseInfo: + result_bn: Node + source_constraint_component: Node + resource_iri: Node res_class_type: Node - detail_node: Node | None = None + result_path: Node + detail: DetailBaseInfo | None = None @dataclass -class UnexpectedComponent: - component_type: str +class DetailBaseInfo: + detail_bn: Node + source_constraint_component: Node @dataclass -class ResultWithoutDetail: +class ExtractedResultWithoutDetail: source_constraint_component: Node res_iri: Node res_class: Node @@ -54,16 +69,16 @@ class ResultWithoutDetail: @dataclass -class ResultWithDetail: +class ExtractedResultWithDetail: source_constraint_component: Node res_iri: Node res_class: Node property: Node - detail: ResultDetail + detail: ExtractedResultDetail @dataclass -class ResultDetail: +class ExtractedResultDetail: component: Node results_message: str result_path: Node | None diff --git a/src/dsp_tools/commands/validate_data/reformat_validaton_result.py b/src/dsp_tools/commands/validate_data/reformat_validaton_result.py index 253dd8b866..40eb58973e 100644 --- a/src/dsp_tools/commands/validate_data/reformat_validaton_result.py +++ b/src/dsp_tools/commands/validate_data/reformat_validaton_result.py @@ -1,3 +1,5 @@ +from typing import cast + import regex from rdflib import RDF from rdflib import SH @@ -16,12 +18,14 @@ from dsp_tools.commands.validate_data.models.input_problems import NonExistentCardinalityViolation from dsp_tools.commands.validate_data.models.input_problems import UnexpectedResults from dsp_tools.commands.validate_data.models.input_problems import ValueTypeViolation -from dsp_tools.commands.validate_data.models.validation import ResourceValidationReportIdentifiers -from dsp_tools.commands.validate_data.models.validation import ResultDetail -from dsp_tools.commands.validate_data.models.validation import ResultWithDetail -from dsp_tools.commands.validate_data.models.validation import ResultWithoutDetail +from dsp_tools.commands.validate_data.models.validation import DetailBaseInfo +from dsp_tools.commands.validate_data.models.validation import ExtractedResultDetail +from dsp_tools.commands.validate_data.models.validation import ExtractedResultWithDetail +from dsp_tools.commands.validate_data.models.validation import ExtractedResultWithoutDetail +from dsp_tools.commands.validate_data.models.validation import QueryInfo from dsp_tools.commands.validate_data.models.validation import UnexpectedComponent from dsp_tools.commands.validate_data.models.validation import ValidationReport +from dsp_tools.commands.validate_data.models.validation import ValidationResultBaseInfo DASH = Namespace("http://datashapes.org/dash#") KNORA_API = Namespace("http://api.knora.org/ontology/knora-api/v2#") @@ -63,92 +67,101 @@ def reformat_validation_graph(report: ValidationReport) -> AllProblems: def _separate_result_types( results_and_onto: Graph, data_onto_graph: Graph -) -> tuple[list[ResultWithoutDetail], list[ResultWithDetail]]: - identifiers = _extract_identifiers_of_resource_results(results_and_onto, data_onto_graph) - no_details = [x for x in identifiers if not x.detail_node] +) -> tuple[list[ExtractedResultWithoutDetail], list[ExtractedResultWithDetail]]: + all_base_info = _extract_base_info_of_resource_results(results_and_onto, data_onto_graph) + no_details = [x for x in all_base_info if not x.detail] no_detail_results = [_query_without_detail(x, results_and_onto) for x in no_details] - with_details = [x for x in identifiers if x.detail_node] + with_details = [x for x in all_base_info if x.detail] details_results = [_query_with_detail(x, results_and_onto, data_onto_graph) for x in with_details] return no_detail_results, details_results -def _extract_identifiers_of_resource_results( +def _extract_base_info_of_resource_results( results_and_onto: Graph, data_onto_graph: Graph -) -> list[ResourceValidationReportIdentifiers]: +) -> list[ValidationResultBaseInfo]: focus_nodes = list(results_and_onto.subject_objects(SH.focusNode)) resource_classes = list(data_onto_graph.subjects(KNORA_API.canBeInstantiated, Literal(True))) all_res_focus_nodes = [] for nd in focus_nodes: - validation_bn = nd[0] focus_iri = nd[1] res_type = next(data_onto_graph.objects(focus_iri, RDF.type)) if res_type in resource_classes: - detail_bn = None - if detail_bn_list := list(results_and_onto.objects(validation_bn, SH.detail)): - detail_bn = detail_bn_list[0] - all_res_focus_nodes.append( - ResourceValidationReportIdentifiers( - validation_bn=validation_bn, - focus_node_iri=focus_iri, - res_class_type=res_type, - detail_node=detail_bn, - ) + info = QueryInfo( + validation_bn=nd[0], + focus_iri=focus_iri, + focus_rdf_type=res_type, ) + all_res_focus_nodes.append(_extract_one_base_info(info, results_and_onto)) return all_res_focus_nodes -def _query_without_detail( - identifiers: ResourceValidationReportIdentifiers, results_and_onto: Graph -) -> ResultWithoutDetail: - path = next(results_and_onto.objects(identifiers.validation_bn, SH.resultPath)) - component = next(results_and_onto.objects(identifiers.validation_bn, SH.sourceConstraintComponent)) - msg = str(next(results_and_onto.objects(identifiers.validation_bn, SH.resultMessage))) +def _extract_one_base_info(info: QueryInfo, results_and_onto: Graph) -> ValidationResultBaseInfo: + path = next(results_and_onto.objects(info.validation_bn, SH.resultPath)) + main_component_type = next(results_and_onto.objects(info.validation_bn, SH.sourceConstraintComponent)) + detail = None + if detail_bn_list := list(results_and_onto.objects(info.validation_bn, SH.detail)): + detail_bn = detail_bn_list[0] + detail_component = next(results_and_onto.objects(detail_bn, SH.sourceConstraintComponent)) + detail = DetailBaseInfo( + detail_bn=detail_bn, + source_constraint_component=detail_component, + ) + return ValidationResultBaseInfo( + result_bn=info.validation_bn, + source_constraint_component=main_component_type, + resource_iri=info.focus_iri, + res_class_type=info.focus_rdf_type, + result_path=path, + detail=detail, + ) + + +def _query_without_detail(base_info: ValidationResultBaseInfo, results_and_onto: Graph) -> ExtractedResultWithoutDetail: + msg = str(next(results_and_onto.objects(base_info.result_bn, SH.resultMessage))) res_value: str | None = None - if val := list(results_and_onto.objects(identifiers.validation_bn, SH.value)): + if val := list(results_and_onto.objects(base_info.result_bn, SH.value)): res_value = str(val[0]) - return ResultWithoutDetail( - source_constraint_component=component, - res_iri=identifiers.focus_node_iri, - res_class=identifiers.res_class_type, - property=path, + return ExtractedResultWithoutDetail( + source_constraint_component=base_info.source_constraint_component, + res_iri=base_info.resource_iri, + res_class=base_info.res_class_type, + property=base_info.result_path, results_message=msg, value=res_value, ) def _query_with_detail( - identifiers: ResourceValidationReportIdentifiers, results_and_onto: Graph, data_graph: Graph -) -> ResultWithDetail: - path = next(results_and_onto.objects(identifiers.validation_bn, SH.resultPath)) - value_iri = next(results_and_onto.objects(identifiers.validation_bn, SH.value)) + base_info: ValidationResultBaseInfo, results_and_onto: Graph, data_graph: Graph +) -> ExtractedResultWithDetail: + detail_info = cast(DetailBaseInfo, base_info.detail) + value_iri = next(results_and_onto.objects(base_info.result_bn, SH.value)) value_type = next(data_graph.objects(value_iri, RDF.type)) - component = next(results_and_onto.objects(identifiers.validation_bn, SH.sourceConstraintComponent)) - detail_component = next(results_and_onto.objects(identifiers.detail_node, SH.sourceConstraintComponent)) detail_path: None | Node = None - if path_found := list(results_and_onto.objects(identifiers.detail_node, SH.resultPath)): + if path_found := list(results_and_onto.objects(detail_info.detail_bn, SH.resultPath)): detail_path = path_found[0] val = None - if node_value := list(results_and_onto.objects(identifiers.detail_node, SH.value)): + if node_value := list(results_and_onto.objects(detail_info.detail_bn, SH.value)): val = str(node_value[0]) - msg = str(next(results_and_onto.objects(identifiers.detail_node, SH.resultMessage))) - detail = ResultDetail( - component=detail_component, + msg = str(next(results_and_onto.objects(detail_info.detail_bn, SH.resultMessage))) + detail = ExtractedResultDetail( + component=detail_info.source_constraint_component, results_message=msg, result_path=detail_path, value_type=value_type, value=val, ) - return ResultWithDetail( - source_constraint_component=component, - res_iri=identifiers.focus_node_iri, - res_class=identifiers.res_class_type, - property=path, + return ExtractedResultWithDetail( + source_constraint_component=base_info.source_constraint_component, + res_iri=base_info.resource_iri, + res_class=base_info.res_class_type, + property=base_info.result_path, detail=detail, ) def _reformat_without_detail( - validation_results: list[ResultWithoutDetail], + validation_results: list[ExtractedResultWithoutDetail], ) -> tuple[list[InputProblem], list[UnexpectedComponent]]: input_problems: list[InputProblem] = [] unexpected_components: list[UnexpectedComponent] = [] @@ -162,7 +175,7 @@ def _reformat_without_detail( return input_problems, unexpected_components -def _reformat_one_without_detail(violation: ResultWithoutDetail) -> InputProblem | UnexpectedComponent: +def _reformat_one_without_detail(violation: ExtractedResultWithoutDetail) -> InputProblem | UnexpectedComponent: subject_id = _reformat_data_iri(str(violation.res_iri)) prop_name = _reformat_onto_iri(str(violation.property)) res_type = _reformat_onto_iri(str(violation.res_class)) @@ -200,7 +213,7 @@ def _reformat_one_without_detail(violation: ResultWithoutDetail) -> InputProblem def _reformat_with_detail( - validation_results: list[ResultWithDetail], + validation_results: list[ExtractedResultWithDetail], ) -> tuple[list[InputProblem], list[UnexpectedComponent]]: input_problems: list[InputProblem] = [] unexpected_components: list[UnexpectedComponent] = [] @@ -214,7 +227,7 @@ def _reformat_with_detail( return input_problems, unexpected_components -def _reformat_one_with_detail(val_result: ResultWithDetail) -> InputProblem | UnexpectedComponent: +def _reformat_one_with_detail(val_result: ExtractedResultWithDetail) -> InputProblem | UnexpectedComponent: subject_id = _reformat_data_iri(str(val_result.res_iri)) prop_name = _reformat_onto_iri(str(val_result.property)) res_type = _reformat_onto_iri(str(val_result.res_class)) @@ -245,7 +258,7 @@ def _reformat_one_with_detail(val_result: ResultWithDetail) -> InputProblem | Un return UnexpectedComponent(str(val_result.source_constraint_component)) -def _reformat_detail_class_constraint_component(val_result: ResultWithDetail) -> InputProblem: +def _reformat_detail_class_constraint_component(val_result: ExtractedResultWithDetail) -> InputProblem: subject_id = _reformat_data_iri(str(val_result.res_iri)) prop_name = _reformat_onto_iri(str(val_result.property)) res_type = _reformat_onto_iri(str(val_result.res_class)) diff --git a/test/e2e_validate_data/test_validate_data.py b/test/e2e_validate_data/test_validate_data.py index 839a7479e9..eac2229e3e 100644 --- a/test/e2e_validate_data/test_validate_data.py +++ b/test/e2e_validate_data/test_validate_data.py @@ -15,8 +15,9 @@ from dsp_tools.commands.validate_data.models.input_problems import MinCardinalityViolation from dsp_tools.commands.validate_data.models.input_problems import NonExistentCardinalityViolation from dsp_tools.commands.validate_data.models.input_problems import ValueTypeViolation +from dsp_tools.commands.validate_data.models.validation import DetailBaseInfo from dsp_tools.commands.validate_data.models.validation import ValidationReport -from dsp_tools.commands.validate_data.reformat_validaton_result import _extract_identifiers_of_resource_results +from dsp_tools.commands.validate_data.reformat_validaton_result import _extract_base_info_of_resource_results from dsp_tools.commands.validate_data.reformat_validaton_result import reformat_validation_graph from dsp_tools.commands.validate_data.validate_data import _get_validation_result from test.e2e_validate_data.setup_testcontainers import get_containers @@ -90,8 +91,8 @@ def value_type_violation(_create_project: None) -> ValidationReport: def test_extract_identifiers_of_resource_results(every_combination_once: ValidationReport) -> None: report_and_onto = every_combination_once.validation_graph + every_combination_once.onto_graph data_and_onto = every_combination_once.data_graph + every_combination_once.onto_graph - result = _extract_identifiers_of_resource_results(report_and_onto, data_and_onto) - result_sorted = sorted(result, key=lambda x: str(x.focus_node_iri)) + result = _extract_base_info_of_resource_results(report_and_onto, data_and_onto) + result_sorted = sorted(result, key=lambda x: str(x.resource_iri)) expected_iris = [ (URIRef("http://data/empty_label"), None), (URIRef("http://data/geoname_not_number"), BNode), @@ -101,12 +102,14 @@ def test_extract_identifiers_of_resource_results(every_combination_once: Validat (URIRef("http://data/id_simpletext"), BNode), (URIRef("http://data/id_uri"), BNode), ] - for result_iri, expected_iri in zip(result_sorted, expected_iris): - assert result_iri.focus_node_iri == expected_iri[0] + for result_info, expected_iri in zip(result_sorted, expected_iris): + assert result_info.resource_iri == expected_iri[0] if expected_iri[1] is None: - assert not result_iri.detail_node + assert not result_info.detail else: - assert isinstance(result_iri.detail_node, expected_iri[1]) + detail_base_info = result_info.detail + assert isinstance(detail_base_info, DetailBaseInfo) + assert isinstance(detail_base_info.detail_bn, expected_iri[1]) class TestCheckConforms: diff --git a/test/unittests/commands/validate_data/fixtures_validation_result.py b/test/unittests/commands/validate_data/fixtures_validation_result.py index 0193e4cd7a..9f8638f515 100644 --- a/test/unittests/commands/validate_data/fixtures_validation_result.py +++ b/test/unittests/commands/validate_data/fixtures_validation_result.py @@ -5,12 +5,12 @@ from rdflib import RDFS from rdflib import SH from rdflib import Graph -from rdflib import URIRef -from dsp_tools.commands.validate_data.models.validation import ResourceValidationReportIdentifiers -from dsp_tools.commands.validate_data.models.validation import ResultDetail -from dsp_tools.commands.validate_data.models.validation import ResultWithDetail -from dsp_tools.commands.validate_data.models.validation import ResultWithoutDetail +from dsp_tools.commands.validate_data.models.validation import DetailBaseInfo +from dsp_tools.commands.validate_data.models.validation import ExtractedResultDetail +from dsp_tools.commands.validate_data.models.validation import ExtractedResultWithDetail +from dsp_tools.commands.validate_data.models.validation import ExtractedResultWithoutDetail +from dsp_tools.commands.validate_data.models.validation import ValidationResultBaseInfo from dsp_tools.commands.validate_data.reformat_validaton_result import API_SHAPES from test.unittests.commands.validate_data.constants import DASH from test.unittests.commands.validate_data.constants import DATA @@ -28,7 +28,34 @@ def onto_graph() -> Graph: @pytest.fixture -def report_min_card(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_not_resource(onto_graph: Graph) -> tuple[Graph, Graph]: + validation_str = f"""{PREFIXES} + _:bn_id_simpletext a sh:ValidationResult ; + sh:focusNode ; + sh:resultMessage "TextValue without formatting" ; + sh:resultPath knora-api:valueAsString ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MinCountConstraintComponent ; + sh:sourceShape api-shapes:SimpleTextValue_PropShape . + """ + validation_g = Graph() + validation_g.parse(data=validation_str, format="ttl") + data_str = f"""{PREFIXES} + a onto:ClassWithEverything ; + rdfs:label "Simpletext"^^xsd:string ; + onto:testTextarea . + + a knora-api:TextValue ; + knora-api:textValueAsXml "Text"^^xsd:string . + """ + onto_data_g = Graph() + onto_data_g += onto_graph + onto_data_g.parse(data=data_str, format="ttl") + return validation_g, onto_data_g + + +@pytest.fixture +def report_min_card(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:focusNode ; @@ -48,15 +75,19 @@ def report_min_card(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidation onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, URIRef("http://data/id_card_one"), ONTO.ClassInheritedCardinalityOverwriting + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.MinCountConstraintComponent, + resource_iri=DATA.id_card_one, + res_class_type=ONTO.ClassInheritedCardinalityOverwriting, + result_path=ONTO.testBoolean, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_min_card() -> ResultWithoutDetail: - return ResultWithoutDetail( +def extracted_min_card() -> ExtractedResultWithoutDetail: + return ExtractedResultWithoutDetail( source_constraint_component=SH.MinCountConstraintComponent, res_iri=DATA.id_card_one, res_class=ONTO.ClassInheritedCardinalityOverwriting, @@ -66,7 +97,7 @@ def extracted_min_card() -> ResultWithoutDetail: @pytest.fixture -def report_value_type_simpletext(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_value_type_simpletext(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:detail _:bn_id_simpletext ; @@ -86,8 +117,8 @@ def report_value_type_simpletext(onto_graph: Graph) -> tuple[Graph, Graph, Resou sh:sourceConstraintComponent sh:MinCountConstraintComponent ; sh:sourceShape api-shapes:SimpleTextValue_PropShape . """ # noqa: E501 (Line too long) - valiation_g = Graph() - valiation_g.parse(data=validation_str, format="ttl") + validation_g = Graph() + validation_g.parse(data=validation_str, format="ttl") data_str = f"""{PREFIXES} a onto:ClassWithEverything ; rdfs:label "Simpletext"^^xsd:string ; @@ -99,24 +130,33 @@ def report_value_type_simpletext(onto_graph: Graph) -> tuple[Graph, Graph, Resou onto_data_g = Graph() onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") - val_bn = next(valiation_g.subjects(RDF.type, SH.ValidationResult)) - detail_bn = next(valiation_g.objects(predicate=SH.detail)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, URIRef("http://data/id_simpletext"), ONTO.ClassWithEverything, detail_bn + val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) + detail_bn = next(validation_g.objects(val_bn, SH.detail)) + detail = DetailBaseInfo( + detail_bn=detail_bn, + source_constraint_component=SH.MinCountConstraintComponent, + ) + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + result_path=ONTO.testTextarea, + source_constraint_component=SH.NodeConstraintComponent, + resource_iri=DATA.id_simpletext, + res_class_type=ONTO.ClassWithEverything, + detail=detail, ) - return valiation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_value_type_simpletext() -> ResultWithDetail: - detail = ResultDetail( +def extracted_value_type_simpletext() -> ExtractedResultWithDetail: + detail = ExtractedResultDetail( component=SH.MinCountConstraintComponent, results_message="TextValue without formatting", result_path=KNORA_API.textValueAsXml, value_type=KNORA_API.TextValue, value=None, ) - return ResultWithDetail( + return ExtractedResultWithDetail( source_constraint_component=SH.NodeConstraintComponent, res_iri=DATA.id_simpletext, res_class=ONTO.ClassWithEverything, @@ -126,7 +166,7 @@ def extracted_value_type_simpletext() -> ResultWithDetail: @pytest.fixture -def report_value_type(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_value_type(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:detail _:bn_id_uri ; @@ -160,23 +200,33 @@ def report_value_type(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidati onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - detail_bn = next(validation_g.objects(predicate=SH.detail)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, URIRef("http://data/id_uri"), ONTO.ClassWithEverything, detail_bn + detail_bn = next(validation_g.objects(val_bn, SH.detail)) + detail_component = next(validation_g.objects(detail_bn, SH.sourceConstraintComponent)) + detail = DetailBaseInfo( + detail_bn=detail_bn, + source_constraint_component=detail_component, + ) + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.NodeConstraintComponent, + resource_iri=DATA.id_uri, + res_class_type=ONTO.ClassWithEverything, + result_path=ONTO.testUriValue, + detail=detail, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_value_type() -> ResultWithDetail: - detail = ResultDetail( +def extracted_value_type() -> ExtractedResultWithDetail: + detail = ExtractedResultDetail( component=SH.ClassConstraintComponent, results_message="UriValue", result_path=None, value_type=KNORA_API.TextValue, value=None, ) - return ResultWithDetail( + return ExtractedResultWithDetail( source_constraint_component=SH.NodeConstraintComponent, res_iri=DATA.id_uri, res_class=ONTO.ClassWithEverything, @@ -186,7 +236,7 @@ def extracted_value_type() -> ResultWithDetail: @pytest.fixture -def report_regex(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_regex(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:detail _:bn_geoname_not_number ; @@ -221,23 +271,33 @@ def report_regex(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationRep onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - detail_bn = next(validation_g.objects(predicate=SH.detail)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, URIRef("http://data/geoname_not_number"), ONTO.ClassWithEverything, detail_bn + detail_bn = next(validation_g.objects(val_bn, SH.detail)) + detail_component = next(validation_g.objects(detail_bn, SH.sourceConstraintComponent)) + detail = DetailBaseInfo( + detail_bn=detail_bn, + source_constraint_component=detail_component, + ) + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.NodeConstraintComponent, + resource_iri=DATA.geoname_not_number, + res_class_type=ONTO.ClassWithEverything, + result_path=ONTO.testGeoname, + detail=detail, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_regex() -> ResultWithDetail: - detail = ResultDetail( +def extracted_regex() -> ExtractedResultWithDetail: + detail = ExtractedResultDetail( component=SH.PatternConstraintComponent, results_message="The value must be a valid geoname code", result_path=KNORA_API.geonameValueAsGeonameCode, value_type=KNORA_API.GeonameValue, value="this-is-not-a-valid-code", ) - return ResultWithDetail( + return ExtractedResultWithDetail( source_constraint_component=SH.NodeConstraintComponent, res_iri=DATA.geoname_not_number, res_class=ONTO.ClassWithEverything, @@ -247,7 +307,7 @@ def extracted_regex() -> ResultWithDetail: @pytest.fixture -def report_link_target_non_existent(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_link_target_non_existent(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:detail _:bn_link_target_non_existent ; @@ -282,26 +342,33 @@ def report_link_target_non_existent(onto_graph: Graph) -> tuple[Graph, Graph, Re onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - detail_bn = next(validation_g.objects(predicate=SH.detail)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, - URIRef("http://data/link_target_non_existent"), - ONTO.ClassWithEverything, - detail_bn, + detail_bn = next(validation_g.objects(val_bn, SH.detail)) + detail_component = next(validation_g.objects(detail_bn, SH.sourceConstraintComponent)) + detail = DetailBaseInfo( + detail_bn=detail_bn, + source_constraint_component=detail_component, + ) + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.NodeConstraintComponent, + resource_iri=DATA.link_target_non_existent, + res_class_type=ONTO.ClassWithEverything, + result_path=ONTO.testHasLinkTo, + detail=detail, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_link_target_non_existent() -> ResultWithDetail: - detail = ResultDetail( +def extracted_link_target_non_existent() -> ExtractedResultWithDetail: + detail = ExtractedResultDetail( component=SH.ClassConstraintComponent, results_message="Resource", result_path=API_SHAPES.linkValueHasTargetID, value_type=KNORA_API.LinkValue, - value=URIRef("http://data/other"), + value=DATA.other, ) - return ResultWithDetail( + return ExtractedResultWithDetail( source_constraint_component=SH.NodeConstraintComponent, res_iri=DATA.link_target_non_existent, res_class=ONTO.ClassWithEverything, @@ -311,7 +378,7 @@ def extracted_link_target_non_existent() -> ResultWithDetail: @pytest.fixture -def report_link_target_wrong_class(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_link_target_wrong_class(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:detail _:bn_link_target_wrong_class ; @@ -349,26 +416,33 @@ def report_link_target_wrong_class(onto_graph: Graph) -> tuple[Graph, Graph, Res onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - detail_bn = next(validation_g.objects(predicate=SH.detail)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, - URIRef("http://data/link_target_wrong_class"), - ONTO.ClassWithEverything, - detail_bn, + detail_bn = next(validation_g.objects(val_bn, SH.detail)) + detail_component = next(validation_g.objects(detail_bn, SH.sourceConstraintComponent)) + detail = DetailBaseInfo( + detail_bn=detail_bn, + source_constraint_component=detail_component, + ) + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.NodeConstraintComponent, + resource_iri=DATA.link_target_wrong_class, + res_class_type=ONTO.ClassWithEverything, + result_path=ONTO.testHasLinkToCardOneResource, + detail=detail, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_link_target_wrong_class() -> ResultWithDetail: - detail = ResultDetail( +def extracted_link_target_wrong_class() -> ExtractedResultWithDetail: + detail = ExtractedResultDetail( component=SH.ClassConstraintComponent, results_message="CardOneResource", result_path=API_SHAPES.linkValueHasTargetID, value_type=KNORA_API.LinkValue, - value=URIRef("http://data/id_9_target"), + value=DATA.id_9_target, ) - return ResultWithDetail( + return ExtractedResultWithDetail( source_constraint_component=SH.NodeConstraintComponent, res_iri=DATA.link_target_wrong_class, res_class=ONTO.ClassWithEverything, @@ -378,7 +452,7 @@ def extracted_link_target_wrong_class() -> ResultWithDetail: @pytest.fixture -def report_closed_constraint(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_closed_constraint(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:focusNode ; @@ -402,15 +476,19 @@ def report_closed_constraint(onto_graph: Graph) -> tuple[Graph, Graph, ResourceV onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, URIRef("http://data/id_closed_constraint"), ONTO.CardOneResource + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=DASH.ClosedByTypesConstraintComponent, + resource_iri=DATA.id_closed_constraint, + res_class_type=ONTO.CardOneResource, + result_path=ONTO.testIntegerSimpleText, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_closed_constraint() -> ResultWithoutDetail: - return ResultWithoutDetail( +def extracted_closed_constraint() -> ExtractedResultWithoutDetail: + return ExtractedResultWithoutDetail( source_constraint_component=DASH.ClosedByTypesConstraintComponent, res_iri=DATA.id_closed_constraint, res_class=ONTO.CardOneResource, @@ -420,7 +498,7 @@ def extracted_closed_constraint() -> ResultWithoutDetail: @pytest.fixture -def report_max_card(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_max_card(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:focusNode ; @@ -446,13 +524,19 @@ def report_max_card(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidation onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - identifiers = ResourceValidationReportIdentifiers(val_bn, URIRef("http://data/id_max_card"), ONTO.ClassMixedCard) - return validation_g, onto_data_g, identifiers + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.MaxCountConstraintComponent, + resource_iri=DATA.id_max_card, + res_class_type=ONTO.ClassMixedCard, + result_path=ONTO.testHasLinkToCardOneResource, + ) + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_max_card() -> ResultWithoutDetail: - return ResultWithoutDetail( +def extracted_max_card() -> ExtractedResultWithoutDetail: + return ExtractedResultWithoutDetail( source_constraint_component=SH.MaxCountConstraintComponent, res_iri=DATA.id_max_card, res_class=ONTO.ClassMixedCard, @@ -462,7 +546,7 @@ def extracted_max_card() -> ResultWithoutDetail: @pytest.fixture -def report_empty_label(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidationReportIdentifiers]: +def report_empty_label(onto_graph: Graph) -> tuple[Graph, Graph, ValidationResultBaseInfo]: validation_str = f"""{PREFIXES} [ a sh:ValidationResult ; sh:focusNode ; @@ -483,15 +567,19 @@ def report_empty_label(onto_graph: Graph) -> tuple[Graph, Graph, ResourceValidat onto_data_g += onto_graph onto_data_g.parse(data=data_str, format="ttl") val_bn = next(validation_g.subjects(RDF.type, SH.ValidationResult)) - identifiers = ResourceValidationReportIdentifiers( - val_bn, URIRef("http://data/empty_label"), ONTO.ClassWithEverything + base_info = ValidationResultBaseInfo( + result_bn=val_bn, + source_constraint_component=SH.PatternConstraintComponent, + resource_iri=DATA.empty_label, + res_class_type=ONTO.ClassWithEverything, + result_path=RDFS.label, ) - return validation_g, onto_data_g, identifiers + return validation_g, onto_data_g, base_info @pytest.fixture -def extracted_empty_label() -> ResultWithoutDetail: - return ResultWithoutDetail( +def extracted_empty_label() -> ExtractedResultWithoutDetail: + return ExtractedResultWithoutDetail( source_constraint_component=SH.PatternConstraintComponent, res_iri=DATA.empty_label, res_class=ONTO.ClassWithEverything, @@ -501,15 +589,15 @@ def extracted_empty_label() -> ResultWithoutDetail: @pytest.fixture -def extracted_unknown_component() -> ResultWithDetail: - detail = ResultDetail( +def extracted_unknown_component() -> ExtractedResultWithDetail: + detail = ExtractedResultDetail( component=SH.AndConstraintComponent, results_message="This is a constraint that is not checked in the data and should never appear.", result_path=KNORA_API.doesNotExist, value_type=KNORA_API.TextValue, value=None, ) - return ResultWithDetail( + return ExtractedResultWithDetail( source_constraint_component=SH.UniqueLangConstraintComponent, res_iri=DATA.id, res_class=ONTO.ClassMixedCard, diff --git a/test/unittests/commands/validate_data/test_reformat_validaton_result.py b/test/unittests/commands/validate_data/test_reformat_validaton_result.py index 156cda6707..b3c7ed8348 100644 --- a/test/unittests/commands/validate_data/test_reformat_validaton_result.py +++ b/test/unittests/commands/validate_data/test_reformat_validaton_result.py @@ -2,7 +2,6 @@ from rdflib import RDFS from rdflib import SH from rdflib import Graph -from rdflib import URIRef from dsp_tools.commands.validate_data.models.input_problems import ContentRegexViolation from dsp_tools.commands.validate_data.models.input_problems import LinkedResourceDoesNotExist @@ -11,94 +10,120 @@ from dsp_tools.commands.validate_data.models.input_problems import MinCardinalityViolation from dsp_tools.commands.validate_data.models.input_problems import NonExistentCardinalityViolation from dsp_tools.commands.validate_data.models.input_problems import ValueTypeViolation -from dsp_tools.commands.validate_data.models.validation import ResourceValidationReportIdentifiers -from dsp_tools.commands.validate_data.models.validation import ResultWithDetail -from dsp_tools.commands.validate_data.models.validation import ResultWithoutDetail +from dsp_tools.commands.validate_data.models.validation import DetailBaseInfo +from dsp_tools.commands.validate_data.models.validation import ExtractedResultWithDetail +from dsp_tools.commands.validate_data.models.validation import ExtractedResultWithoutDetail from dsp_tools.commands.validate_data.models.validation import UnexpectedComponent +from dsp_tools.commands.validate_data.models.validation import ValidationResultBaseInfo +from dsp_tools.commands.validate_data.reformat_validaton_result import _extract_base_info_of_resource_results from dsp_tools.commands.validate_data.reformat_validaton_result import _query_with_detail from dsp_tools.commands.validate_data.reformat_validaton_result import _query_without_detail from dsp_tools.commands.validate_data.reformat_validaton_result import _reformat_one_with_detail from dsp_tools.commands.validate_data.reformat_validaton_result import _reformat_one_without_detail from dsp_tools.commands.validate_data.reformat_validaton_result import _separate_result_types from test.unittests.commands.validate_data.constants import DASH +from test.unittests.commands.validate_data.constants import DATA from test.unittests.commands.validate_data.constants import KNORA_API from test.unittests.commands.validate_data.constants import ONTO +class TestExtractBaseInfo: + def test_not_resource(self, report_not_resource: tuple[Graph, Graph]) -> None: + validation_g, onto_data_g = report_not_resource + results = _extract_base_info_of_resource_results(validation_g, onto_data_g) + assert not results + + def test_no_detail(self, report_min_card: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: + validation_g, onto_data_g, _ = report_min_card + results = _extract_base_info_of_resource_results(validation_g, onto_data_g) + assert len(results) == 1 + found_result = results[0] + assert found_result.resource_iri == DATA.id_card_one + assert found_result.res_class_type == ONTO.ClassInheritedCardinalityOverwriting + assert found_result.result_path == ONTO.testBoolean + assert found_result.source_constraint_component == SH.MinCountConstraintComponent + assert not found_result.detail + + def test_with_detail(self, report_value_type_simpletext: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: + validation_g, onto_data_g, _ = report_value_type_simpletext + results = _extract_base_info_of_resource_results(validation_g, onto_data_g) + assert len(results) == 1 + found_result = results[0] + assert found_result.resource_iri == DATA.id_simpletext + assert found_result.res_class_type == ONTO.ClassWithEverything + assert found_result.result_path == ONTO.testTextarea + assert found_result.source_constraint_component == SH.NodeConstraintComponent + detail = found_result.detail + assert isinstance(detail, DetailBaseInfo) + assert detail.source_constraint_component == SH.MinCountConstraintComponent + + class TestSeparateResultTypes: - def test_result_id_card_one( - self, report_min_card: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_id_card_one(self, report_min_card: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res_g, onto_data_g, _ = report_min_card no_detail, with_detail = _separate_result_types(res_g, onto_data_g) assert len(no_detail) == 1 assert len(with_detail) == 0 - assert no_detail[0].res_iri == URIRef("http://data/id_card_one") + assert no_detail[0].res_iri == DATA.id_card_one def test_result_id_simpletext( - self, report_value_type_simpletext: tuple[Graph, Graph, ResourceValidationReportIdentifiers] + self, report_value_type_simpletext: tuple[Graph, Graph, ValidationResultBaseInfo] ) -> None: res_g, onto_data_g, _ = report_value_type_simpletext no_detail, with_detail = _separate_result_types(res_g, onto_data_g) assert len(no_detail) == 0 assert len(with_detail) == 1 - assert with_detail[0].res_iri == URIRef("http://data/id_simpletext") + assert with_detail[0].res_iri == DATA.id_simpletext - def test_result_id_uri(self, report_value_type: tuple[Graph, Graph, ResourceValidationReportIdentifiers]) -> None: + def test_result_id_uri(self, report_value_type: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res_g, onto_data_g, _ = report_value_type no_detail, with_detail = _separate_result_types(res_g, onto_data_g) assert len(no_detail) == 0 assert len(with_detail) == 1 - assert with_detail[0].res_iri == URIRef("http://data/id_uri") + assert with_detail[0].res_iri == DATA.id_uri - def test_result_geoname_not_number( - self, report_regex: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_geoname_not_number(self, report_regex: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res_g, onto_data_g, _ = report_regex no_detail, with_detail = _separate_result_types(res_g, onto_data_g) assert len(no_detail) == 0 assert len(with_detail) == 1 - assert with_detail[0].res_iri == URIRef("http://data/geoname_not_number") + assert with_detail[0].res_iri == DATA.geoname_not_number def test_result_id_closed_constraint( - self, report_closed_constraint: tuple[Graph, Graph, ResourceValidationReportIdentifiers] + self, report_closed_constraint: tuple[Graph, Graph, ValidationResultBaseInfo] ) -> None: res_g, onto_data_g, _ = report_closed_constraint no_detail, with_detail = _separate_result_types(res_g, onto_data_g) assert len(no_detail) == 1 assert len(with_detail) == 0 - assert no_detail[0].res_iri == URIRef("http://data/id_closed_constraint") + assert no_detail[0].res_iri == DATA.id_closed_constraint - def test_result_id_max_card( - self, report_max_card: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_id_max_card(self, report_max_card: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res_g, onto_data_g, _ = report_max_card no_detail, with_detail = _separate_result_types(res_g, onto_data_g) assert len(no_detail) == 1 assert len(with_detail) == 0 - assert no_detail[0].res_iri == URIRef("http://data/id_max_card") + assert no_detail[0].res_iri == DATA.id_max_card class TestQueryWithoutDetail: - def test_result_id_card_one( - self, report_min_card: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_id_card_one(self, report_min_card: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res, _, ids = report_min_card result = _query_without_detail(ids, res) assert result.source_constraint_component == SH.MinCountConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testBoolean assert result.results_message == "1" assert not result.value def test_result_id_closed_constraint( - self, report_closed_constraint: tuple[Graph, Graph, ResourceValidationReportIdentifiers] + self, report_closed_constraint: tuple[Graph, Graph, ValidationResultBaseInfo] ) -> None: res, _, ids = report_closed_constraint result = _query_without_detail(ids, res) assert result.source_constraint_component == DASH.ClosedByTypesConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testIntegerSimpleText assert ( @@ -107,25 +132,21 @@ def test_result_id_closed_constraint( ) assert result.value == "http://data/value_id_closed_constraint" - def test_result_id_max_card( - self, report_max_card: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_id_max_card(self, report_max_card: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res, _, ids = report_max_card result = _query_without_detail(ids, res) assert result.source_constraint_component == SH.MaxCountConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testHasLinkToCardOneResource assert result.results_message == "1" assert not result.value - def test_result_empty_label( - self, report_empty_label: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_empty_label(self, report_empty_label: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res, _, ids = report_empty_label result = _query_without_detail(ids, res) assert result.source_constraint_component == SH.PatternConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == RDFS.label assert result.results_message == "The label must be a non-empty string" @@ -134,12 +155,12 @@ def test_result_empty_label( class TestQueryWithDetail: def test_result_id_simpletext( - self, report_value_type_simpletext: tuple[Graph, Graph, ResourceValidationReportIdentifiers] + self, report_value_type_simpletext: tuple[Graph, Graph, ValidationResultBaseInfo] ) -> None: res, data, ids = report_value_type_simpletext result = _query_with_detail(ids, res, data) assert result.source_constraint_component == SH.NodeConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testTextarea assert result.detail.results_message == "TextValue without formatting" @@ -147,11 +168,11 @@ def test_result_id_simpletext( assert result.detail.value_type == KNORA_API.TextValue assert not result.detail.value - def test_result_id_uri(self, report_value_type: tuple[Graph, Graph, ResourceValidationReportIdentifiers]) -> None: + def test_result_id_uri(self, report_value_type: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res, data, ids = report_value_type result = _query_with_detail(ids, res, data) assert result.source_constraint_component == SH.NodeConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testUriValue assert result.detail.results_message == "UriValue" @@ -159,13 +180,11 @@ def test_result_id_uri(self, report_value_type: tuple[Graph, Graph, ResourceVali assert result.detail.value_type == KNORA_API.TextValue assert result.detail.value == "http://data/value_id_uri" - def test_result_geoname_not_number( - self, report_regex: tuple[Graph, Graph, ResourceValidationReportIdentifiers] - ) -> None: + def test_result_geoname_not_number(self, report_regex: tuple[Graph, Graph, ValidationResultBaseInfo]) -> None: res, data, ids = report_regex result = _query_with_detail(ids, res, data) assert result.source_constraint_component == SH.NodeConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testGeoname assert result.detail.results_message == "The value must be a valid geoname code" @@ -174,12 +193,12 @@ def test_result_geoname_not_number( assert result.detail.value == "this-is-not-a-valid-code" def test_link_target_non_existent( - self, report_link_target_non_existent: tuple[Graph, Graph, ResourceValidationReportIdentifiers] + self, report_link_target_non_existent: tuple[Graph, Graph, ValidationResultBaseInfo] ) -> None: res, data, ids = report_link_target_non_existent result = _query_with_detail(ids, res, data) assert result.source_constraint_component == SH.NodeConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testHasLinkTo assert result.detail.results_message == "Resource" @@ -188,12 +207,12 @@ def test_link_target_non_existent( assert result.detail.value == "http://data/other" def test_link_target_wrong_class( - self, report_link_target_wrong_class: tuple[Graph, Graph, ResourceValidationReportIdentifiers] + self, report_link_target_wrong_class: tuple[Graph, Graph, ValidationResultBaseInfo] ) -> None: res, data, ids = report_link_target_wrong_class result = _query_with_detail(ids, res, data) assert result.source_constraint_component == SH.NodeConstraintComponent - assert result.res_iri == ids.focus_node_iri + assert result.res_iri == ids.resource_iri assert result.res_class == ids.res_class_type assert result.property == ONTO.testHasLinkToCardOneResource assert result.detail.results_message == "CardOneResource" @@ -203,7 +222,7 @@ def test_link_target_wrong_class( class TestReformatWithoutDetail: - def test_min(self, extracted_min_card: ResultWithoutDetail) -> None: + def test_min(self, extracted_min_card: ExtractedResultWithoutDetail) -> None: result = _reformat_one_without_detail(extracted_min_card) assert isinstance(result, MinCardinalityViolation) assert result.res_id == "id_card_one" @@ -211,7 +230,7 @@ def test_min(self, extracted_min_card: ResultWithoutDetail) -> None: assert result.prop_name == "onto:testBoolean" assert result.expected_cardinality == "1" - def test_max(self, extracted_max_card: ResultWithoutDetail) -> None: + def test_max(self, extracted_max_card: ExtractedResultWithoutDetail) -> None: result = _reformat_one_without_detail(extracted_max_card) assert isinstance(result, MaxCardinalityViolation) assert result.res_id == "id_max_card" @@ -219,7 +238,7 @@ def test_max(self, extracted_max_card: ResultWithoutDetail) -> None: assert result.prop_name == "onto:testDecimalSimpleText" assert result.expected_cardinality == "0-1" - def test_violation_empty_label(self, extracted_empty_label: ResultWithoutDetail) -> None: + def test_violation_empty_label(self, extracted_empty_label: ExtractedResultWithoutDetail) -> None: result = _reformat_one_without_detail(extracted_empty_label) assert isinstance(result, ContentRegexViolation) assert result.res_id == "empty_label" @@ -228,7 +247,7 @@ def test_violation_empty_label(self, extracted_empty_label: ResultWithoutDetail) assert result.expected_format == "The label must be a non-empty string" assert not result.actual_content - def test_closed(self, extracted_closed_constraint: ResultWithoutDetail) -> None: + def test_closed(self, extracted_closed_constraint: ExtractedResultWithoutDetail) -> None: result = _reformat_one_without_detail(extracted_closed_constraint) assert isinstance(result, NonExistentCardinalityViolation) assert result.res_id == "id_closed_constraint" @@ -237,7 +256,7 @@ def test_closed(self, extracted_closed_constraint: ResultWithoutDetail) -> None: class TestReformatWithDetail: - def test_value_type_simpletext(self, extracted_value_type_simpletext: ResultWithDetail) -> None: + def test_value_type_simpletext(self, extracted_value_type_simpletext: ExtractedResultWithDetail) -> None: result = _reformat_one_with_detail(extracted_value_type_simpletext) assert isinstance(result, ValueTypeViolation) assert result.res_id == "id_simpletext" @@ -246,7 +265,7 @@ def test_value_type_simpletext(self, extracted_value_type_simpletext: ResultWith assert result.actual_type == "TextValue" assert result.expected_type == "TextValue without formatting" - def test_value_type(self, extracted_value_type: ResultWithDetail) -> None: + def test_value_type(self, extracted_value_type: ExtractedResultWithDetail) -> None: result = _reformat_one_with_detail(extracted_value_type) assert isinstance(result, ValueTypeViolation) assert result.res_id == "id_uri" @@ -255,7 +274,7 @@ def test_value_type(self, extracted_value_type: ResultWithDetail) -> None: assert result.actual_type == "TextValue" assert result.expected_type == "UriValue" - def test_violation_regex(self, extracted_regex: ResultWithDetail) -> None: + def test_violation_regex(self, extracted_regex: ExtractedResultWithDetail) -> None: result = _reformat_one_with_detail(extracted_regex) assert isinstance(result, ContentRegexViolation) assert result.res_id == "geoname_not_number" @@ -264,12 +283,12 @@ def test_violation_regex(self, extracted_regex: ResultWithDetail) -> None: assert result.expected_format == "The value must be a valid geoname code" assert result.actual_content == "this-is-not-a-valid-code" - def test_unknown(self, extracted_unknown_component: ResultWithDetail) -> None: + def test_unknown(self, extracted_unknown_component: ExtractedResultWithDetail) -> None: result = _reformat_one_with_detail(extracted_unknown_component) assert isinstance(result, UnexpectedComponent) assert result.component_type == str(SH.UniqueLangConstraintComponent) - def test_link_target_non_existent(self, extracted_link_target_non_existent: ResultWithDetail) -> None: + def test_link_target_non_existent(self, extracted_link_target_non_existent: ExtractedResultWithDetail) -> None: result = _reformat_one_with_detail(extracted_link_target_non_existent) assert isinstance(result, LinkedResourceDoesNotExist) assert result.res_id == "link_target_non_existent" @@ -277,7 +296,7 @@ def test_link_target_non_existent(self, extracted_link_target_non_existent: Resu assert result.prop_name == "onto:testHasLinkTo" assert result.link_target_id == "other" - def test_link_target_wrong_class(self, extracted_link_target_wrong_class: ResultWithDetail) -> None: + def test_link_target_wrong_class(self, extracted_link_target_wrong_class: ExtractedResultWithDetail) -> None: result = _reformat_one_with_detail(extracted_link_target_wrong_class) assert isinstance(result, LinkTargetTypeMismatch) assert result.res_id == "link_target_wrong_class" diff --git a/testdata/validate-data/validationResultTypes.csv b/testdata/validate-data/validationResultTypes.csv new file mode 100644 index 0000000000..d1787485fb --- /dev/null +++ b/testdata/validate-data/validationResultTypes.csv @@ -0,0 +1,10 @@ +Error Group,User Input Error Class,Main information from,Identifiable How?,sh:sourceConstraintComponent,sh:sourceShape,sh:detail - sh:sourceConstraintComponent,sh:detail - sh:sourceShape,sh:detail - sh:resultPath,res_id,res_type,prop_name,User message from,actual_type,actual_content +Link Target,LinkedResourceDoesNotExist,message with context,"detail, is Link value, target id no rdf:type",sh:NodeConstraintComponent,onto specific,sh:ClassConstraintComponent,bn,api-shapes:linkValueHasTargetID,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,-,sh:detail - sh:value IRI - rdf:type,sh:detail - sh:value IRI +Link Target,LinkTargetTypeMismatch,message with context,"detail, is Link value, target id has rdf:type",sh:NodeConstraintComponent,onto specific,sh:ClassConstraintComponent,bn,api-shapes:linkValueHasTargetID,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:detail - sh:resultMessage,sh:detail - sh:value IRI - rdf:type,sh:detail - sh:value IRI +Value Type,ValueTypeViolation,"message with detail, no value","detail, both constraint types, ends with class shape",sh:NodeConstraintComponent,onto specific,sh:ClassConstraintComponent,api-shapes:..._ClassShape,-,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:detail - sh:resultMessage,sh:value IRI - rdf:type, +Value Type,ValueTypeViolation,"message, with detail, no value","detail, with min count contraint (text value)",sh:NodeConstraintComponent,onto specific,sh:MinCountConstraintComponent,api-shapes:..._PropShape,knora-api:valueAsString / knora-api:textValueAsXml,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:detail - sh:resultMessage,, +Content,ContentRegexViolation,"message, with detail, with value","detail, sourceconstraintcomponent (wrong content)",sh:NodeConstraintComponent,onto specific,sh:PatternConstraintComponent,too diverse to be helpfull,too diverse to be helpfull,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:resultMessage,,sh:detail - sh:value Literal +Cardinality,NonExistentCardinalityViolation,sourceConstraintComponent,sourceConstraintComponent,dash:ClosedByTypesConstraintComponent,onto specific,,,,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,-,, +Cardinality,MaxCardinalityViolation,sourceConstraintComponent,sourceConstraintComponent,sh:MaxCountConstraintComponent,onto specific,,,,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:resultMessage,, +Cardinality,MinCardinalityViolation,sourceConstraintComponent,sourceConstraintComponent,sh:MinCountConstraintComponent,onto specific,,,,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:resultMessage,, +Content,ContentRegexViolation,"message, no detail, with value","sourceConstraintComponent, sourceShape (empty label)",sh:PatternConstraintComponent,api-shapes:rdfsLabel_Shape,,,,sh:focusNode,sh:focusNode - rdf:type,sh:resultPath,sh:resultMessage,,sh:value Literal \ No newline at end of file