Fix incorrect handling of prohibited specifications

This commit is contained in:
Dion Moult
2024-03-30 00:13:02 +11:00
parent 1ab24e8362
commit 0065c5fba8
2 changed files with 27 additions and 24 deletions
+19 -19
View File
@@ -259,31 +259,31 @@ class Specification:
self.applicable_entities.append(element) self.applicable_entities.append(element)
for facet in self.requirements: for facet in self.requirements:
result = facet(element) result = facet(element)
if not bool(result): is_pass = bool(result)
self.failed_entities.add(element) if facet.cardinality == "prohibited":
facet.failures.append({"element": element, "reason": str(result)}) is_pass = not is_pass
if self.maxOccurs != 0: # This is a required or optional specification
for facet in self.requirements: if not is_pass:
if facet.cardinality == "required": self.failed_entities.add(element)
facet.status = not bool(facet.failures) facet.failures.append({"element": element, "reason": str(result)})
elif facet.cardinality == "optional": else: # This is a prohibited specification
facet.status = True if is_pass:
elif facet.cardinality == "prohibited": self.failed_entities.add(element)
facet.status = bool(facet.failures) facet.failures.append({"element": element, "reason": str(result)})
self.status = True self.status = True
if self.minOccurs != 0: for facet in self.requirements:
facet.status = not bool(facet.failures)
if not facet.status:
self.status = False
if self.minOccurs != 0: # Required specification
if not self.applicable_entities: if not self.applicable_entities:
self.status = False self.status = False
for facet in self.requirements: for facet in self.requirements:
facet.status = False facet.status = False
elif self.failed_entities: elif self.maxOccurs == 0: # Prohibited specification
self.status = False if self.applicable_entities and not self.requirements:
elif self.minOccurs == 0 and self.maxOccurs != 0:
if self.failed_entities:
self.status = False
elif self.maxOccurs == 0:
if (len(self.applicable_entities)) > 0:
self.status = False self.status = False
def get_usage(self): def get_usage(self):
+8 -5
View File
@@ -36,7 +36,7 @@ def run(name, ids, ifc, expected, applicable_entities=None, failed_entities=None
all_applicable.update(spec.applicable_entities) all_applicable.update(spec.applicable_entities)
for requirement in spec.requirements: for requirement in spec.requirements:
if requirement.status is False: if requirement.status is False:
all_failures.update(requirement.failed_entities) all_failures.update([f["element"] for f in requirement.failures])
assert set(all_applicable) == set(applicable_entities) assert set(all_applicable) == set(applicable_entities)
assert set(all_failures) == set(failed_entities) assert set(all_failures) == set(failed_entities)
@@ -162,9 +162,9 @@ class TestIds:
"Prohibited specifications fail if at least one entity passes all requirements 2/3", "Prohibited specifications fail if at least one entity passes all requirements 2/3",
specs, specs,
model, model,
False, True,
[wall],
[wall], [wall],
[],
) )
model = ifcopenshell.file() model = ifcopenshell.file()
wall = model.createIfcWall(Name="Waldo") wall = model.createIfcWall(Name="Waldo")
@@ -174,6 +174,7 @@ class TestIds:
model, model,
False, False,
[wall], [wall],
[wall],
) )
spec.minOccurs = 0 spec.minOccurs = 0
@@ -238,8 +239,10 @@ class TestIds:
assert spec.status == False assert spec.status == False
assert set(spec.applicable_entities) == {wall, waldo} assert set(spec.applicable_entities) == {wall, waldo}
assert spec.requirements[0].failed_entities == [wall] assert len(spec.requirements[0].failures) == 1
assert spec2.requirements[0].failed_entities == [wall] assert len(spec2.requirements[0].failures) == 1
assert spec.requirements[0].failures[0]["element"] == wall
assert spec2.requirements[0].failures[0]["element"] == wall
class TestSpecification: class TestSpecification: