From 5c398428c3c871a900dcc5d823bcd47ca5be09b0 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 1 Apr 2024 12:12:19 +0500 Subject: [PATCH] ifctester.Specification.set_usage convenience method sets minOccurs and maxOccurs according to the agreement mentioned in the latest ids.xsd https://github.com/buildingSMART/IDS/blob/6d71cdf3547a0383c6cfbbead81a7cef7521ac3a/Development/ids.xsd#L67-L72 --- src/ifctester/ifctester/ids.py | 19 +++++++++++++++---- src/ifctester/test/test_ids.py | 25 ++++++++++--------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/ifctester/ifctester/ids.py b/src/ifctester/ifctester/ids.py index 98062eb872..ce2b7acc47 100644 --- a/src/ifctester/ifctester/ids.py +++ b/src/ifctester/ifctester/ids.py @@ -264,11 +264,11 @@ class Specification: is_pass = bool(result) if facet.cardinality == "prohibited": is_pass = not is_pass - if self.maxOccurs != 0: # This is a required or optional specification + if self.maxOccurs != 0: # This is a required or optional specification if not is_pass: self.failed_entities.add(element) facet.failures.append({"element": element, "reason": str(result)}) - else: # This is a prohibited specification + else: # This is a prohibited specification if is_pass: self.failed_entities.add(element) facet.failures.append({"element": element, "reason": str(result)}) @@ -279,12 +279,12 @@ class Specification: if not facet.status: self.status = False - if self.minOccurs != 0: # Required specification + if self.minOccurs != 0: # Required specification if not self.applicable_entities: self.status = False for facet in self.requirements: facet.status = False - elif self.maxOccurs == 0: # Prohibited specification + elif self.maxOccurs == 0: # Prohibited specification if self.applicable_entities and not self.requirements: self.status = False @@ -295,3 +295,14 @@ class Specification: return "optional" elif self.maxOccurs == 0: return "prohibited" + + def set_usage(self, usage: Cardinality) -> None: + if usage == "optional": + self.minOccurs = 0 + self.maxOccurs = "unbounded" + elif usage == "prohibited": + self.minOccurs = 0 + self.maxOccurs = 0 + else: # required + self.minOccurs = 1 + self.maxOccurs = "unbounded" diff --git a/src/ifctester/test/test_ids.py b/src/ifctester/test/test_ids.py index 52fcaafb7a..0d68c2af7d 100644 --- a/src/ifctester/test/test_ids.py +++ b/src/ifctester/test/test_ids.py @@ -146,7 +146,7 @@ class TestIds: ) spec.ifcVersion = [] - spec.minOccurs = 1 + spec.set_usage("required") model = ifcopenshell.file() waldo = model.createIfcWall(Name="Waldo") run("Required specifications need at least one applicable entity 1/2", specs, model, True, [waldo]) @@ -154,13 +154,12 @@ class TestIds: waldo = model.createIfcSlab(Name="Waldo") run("Required specifications need at least one applicable entity 2/2", specs, model, False) - spec.minOccurs = 0 + spec.set_usage("optional") model = ifcopenshell.file() waldo = model.createIfcSlab(Name="Waldo") run("Optional specifications may still pass if nothing is applicable", specs, model, True) - spec.minOccurs = 0 - spec.maxOccurs = 0 + spec.set_usage("prohibited") model = ifcopenshell.file() wall = model.createIfcSlab(Name="Waldo") run("Prohibited specifications fail if at least one entity passes all requirements 1/3", specs, model, True) @@ -185,8 +184,7 @@ class TestIds: [wall], ) - spec.minOccurs = 0 - spec.maxOccurs = "unbounded" + spec.set_usage("optional") model = ifcopenshell.file() wall = model.createIfcWall(Name="Waldo") spec.requirements.append(description_attr := ids.Attribute(name="Description", value="Foobar")) @@ -201,8 +199,7 @@ class TestIds: # run("Specification optionality and facet optionality can be combined", specs, model, True, [wall]) # double negative / required attributes - # spec.minOccurs = 0 - # spec.maxOccurs = 0 + # spec.set_usage("prohibited") # name_attr.minOccurs = 0 # name_attr.maxOccurs = 0 # description_attr.minOccurs = 0 @@ -292,7 +289,7 @@ class TestSpecification: spec = ids.Specification(name="Name") spec.applicability.append(ids.Entity(name="IFCWALL")) test_ids.specifications.append(spec) - spec.minOccurs = 1 + spec.set_usage("required") run( "A specification that is required and has at least one applicable entity but no requirements shall pass", test_ids, @@ -305,7 +302,7 @@ class TestSpecification: test_ids = ids.Ids(title="Title") spec = ids.Specification(name="Name") test_ids.specifications.append(spec) - spec.minOccurs = 1 + spec.set_usage("required") run( "A specification that is required but has no applicable entities or requirements shall fail", test_ids, @@ -319,7 +316,7 @@ class TestSpecification: spec = ids.Specification(name="Name") spec.applicability.append(ids.Entity(name="IFCWALL")) test_ids.specifications.append(spec) - spec.minOccurs = 0 + spec.set_usage("optional") run( "A specification that is optional and has at least one applicable entity but no requirements shall pass", test_ids, @@ -333,8 +330,7 @@ class TestSpecification: spec = ids.Specification(name="Name") spec.applicability.append(ids.Entity(name="IFCWALL")) test_ids.specifications.append(spec) - spec.minOccurs = 0 - spec.maxOccurs = 0 + spec.set_usage("prohibited") run( "A specification that is prohibited and has at least one applicable entity but no requirements shall fail", test_ids, @@ -347,8 +343,7 @@ class TestSpecification: test_ids = ids.Ids(title="Title") spec = ids.Specification(name="Name") test_ids.specifications.append(spec) - spec.minOccurs = 0 - spec.maxOccurs = 0 + spec.set_usage("prohibited") run( "A specification that is prohibited but has no applicable entities or requirements shall pass", test_ids,