mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-20 20:22:09 +00:00
Resolve merge conflict. Still WIP IDS test cases.
This commit is contained in:
@@ -32,7 +32,6 @@ from dataclasses import dataclass
|
|||||||
from ifcopenshell import ids, template, validate
|
from ifcopenshell import ids, template, validate
|
||||||
from xml.dom.minidom import parseString
|
from xml.dom.minidom import parseString
|
||||||
|
|
||||||
TEST_PATH = os.path.join(tempfile.gettempdir(), "test.ifc")
|
|
||||||
IFC_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IFC/", "IFC4_Wall_3_with_properties.ifc")
|
IFC_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IFC/", "IFC4_Wall_3_with_properties.ifc")
|
||||||
IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_all_fields.xml")
|
IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_all_fields.xml")
|
||||||
|
|
||||||
@@ -48,9 +47,6 @@ os.remove(os.path.join(tempfile.gettempdir(), "test.ifc"))
|
|||||||
|
|
||||||
|
|
||||||
class TestIdsParsing(unittest.TestCase):
|
class TestIdsParsing(unittest.TestCase):
|
||||||
|
|
||||||
"""Parsing basic IDS files"""
|
|
||||||
|
|
||||||
def test_parse_basic_ids(self):
|
def test_parse_basic_ids(self):
|
||||||
IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_all_fields.xml")
|
IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_all_fields.xml")
|
||||||
ids_file = ids.ids.open(IDS_URL)
|
ids_file = ids.ids.open(IDS_URL)
|
||||||
@@ -90,11 +86,9 @@ class TestIdsParsing(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["system"]["simpleValue"], "Test_System")
|
self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["system"]["simpleValue"], "Test_System")
|
||||||
|
|
||||||
""" Parsing invalid IDS.xml """
|
def test_failing_on_opening_invalid_ids_data(self):
|
||||||
# TODO
|
with pytest.raises(xmlschema.validators.exceptions.XMLSchemaValidationError):
|
||||||
# def test_invalid_classification_facet(self):
|
ids.ids.open("""<?xml version="1.0" encoding="UTF-8"?><clearly_not_an_ids/>""")
|
||||||
# IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "Invalid_IDS_Wall_needs_classification.xml")
|
|
||||||
# self.assertRaises( XMLSchemaChildrenValidationError, ids.open(IDS_URL) )
|
|
||||||
|
|
||||||
""" Saving parsed IDS to IDS.xml """
|
""" Saving parsed IDS to IDS.xml """
|
||||||
|
|
||||||
@@ -238,19 +232,6 @@ case = spec_generator()
|
|||||||
|
|
||||||
|
|
||||||
class TestIdsAuthoring(unittest.TestCase):
|
class TestIdsAuthoring(unittest.TestCase):
|
||||||
def test_creating_a_minimal_ids_and_validating(self):
|
|
||||||
specs = ids.ids(title="Title")
|
|
||||||
spec = ids.specification(name="Name")
|
|
||||||
spec.add_applicability(ids.entity.create(name="IfcWall"))
|
|
||||||
spec.add_requirement(ids.attribute.create(name="Name", value="Waldo"))
|
|
||||||
specs.specifications.append(spec)
|
|
||||||
assert "http://standards.buildingsmart.org/IDS" in specs.to_string()
|
|
||||||
|
|
||||||
model = ifcopenshell.file()
|
|
||||||
model.createIfcWall(Name="Waldo")
|
|
||||||
specs.validate(model)
|
|
||||||
# TODO test this without resorting to hooking into logger output
|
|
||||||
|
|
||||||
def test_create_an_ids_with_minimal_information(self):
|
def test_create_an_ids_with_minimal_information(self):
|
||||||
specs = ids.ids()
|
specs = ids.ids()
|
||||||
assert specs.asdict() == {
|
assert specs.asdict() == {
|
||||||
@@ -351,23 +332,27 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
i.specifications[0].add_requirement(m)
|
i.specifications[0].add_requirement(m)
|
||||||
self.assertEqual(i.specifications[0].requirements.terms[1].value, "Test_Value")
|
self.assertEqual(i.specifications[0].requirements.terms[1].value, "Test_Value")
|
||||||
|
|
||||||
def test_create_an_entity_facet(self):
|
def test_creating_an_entity_facet(self):
|
||||||
facet = ids.entity.create(name="IfcName")
|
facet = ids.entity.create(name="IfcName")
|
||||||
assert facet.asdict() == {"name": {"simpleValue": "IfcName"}}
|
assert facet.asdict() == {"name": {"simpleValue": "IfcName"}}
|
||||||
facet = ids.entity.create(name="IfcName", predefinedType="predefinedType")
|
facet = ids.entity.create(name="IfcName", predefinedType="predefinedType", instructions="instructions")
|
||||||
assert facet.asdict() == {
|
assert facet.asdict() == {
|
||||||
"name": {"simpleValue": "IfcName"},
|
"name": {"simpleValue": "IfcName"},
|
||||||
"predefinedType": {"simpleValue": "predefinedType"},
|
"predefinedType": {"simpleValue": "predefinedType"},
|
||||||
|
"@instructions": "instructions",
|
||||||
}
|
}
|
||||||
|
|
||||||
def test_filtering_using_an_entity_facet(self):
|
def test_filtering_using_an_entity_facet(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
|
|
||||||
# Wrong IFC classes are never matched.
|
# Wrong IFC classes are never matched.
|
||||||
|
# TODO: Discuss about potential schema error checking
|
||||||
facet = ids.entity.create(name="IfcRabbit")
|
facet = ids.entity.create(name="IfcRabbit")
|
||||||
case("Non-existent entity name", facet=facet, inst=ifc.createIfcWall(), expected=False)
|
case("Non-existent entity name", facet=facet, inst=ifc.createIfcWall(), expected=False)
|
||||||
|
|
||||||
# IFC class is checked for an exact match. Subclasses should not match.
|
# IFC class is checked for an exact match. Subclasses should not match.
|
||||||
|
# TODO: Some votes to prefer inheritance (For: Moult, Evandro, Artur)
|
||||||
|
# Possible argument: CAD tools don't understand IFC
|
||||||
facet = ids.entity.create(name="IfcWall")
|
facet = ids.entity.create(name="IfcWall")
|
||||||
case("Entity matching", facet=facet, inst=ifc.createIfcWall(), expected=True)
|
case("Entity matching", facet=facet, inst=ifc.createIfcWall(), expected=True)
|
||||||
case(
|
case(
|
||||||
@@ -377,6 +362,7 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("Entity subtype", facet=facet, inst=ifc.createIfcWallStandardCase(), expected=False)
|
case("Entity subtype", facet=facet, inst=ifc.createIfcWallStandardCase(), expected=False)
|
||||||
|
|
||||||
# IFC class is case insensitive.
|
# IFC class is case insensitive.
|
||||||
|
# WRONG WRONG WRONG should be UPPERCASE
|
||||||
facet = ids.entity.create(name="IFCWALL")
|
facet = ids.entity.create(name="IFCWALL")
|
||||||
case("Entity case 0", facet=facet, inst=ifc.createIfcWall(), expected=True)
|
case("Entity case 0", facet=facet, inst=ifc.createIfcWall(), expected=True)
|
||||||
case("Entity case 1", facet=facet, inst=ifc.createIfcWall(PredefinedType="SOLIDWALL"), expected=True)
|
case("Entity case 1", facet=facet, inst=ifc.createIfcWall(PredefinedType="SOLIDWALL"), expected=True)
|
||||||
@@ -393,6 +379,10 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
expected=False,
|
expected=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Predefined Type must be uppercase, exactly the same as defined in the enumeration
|
||||||
|
facet = ids.entity.create(name="IfcWall", predefinedType="solidwall")
|
||||||
|
assert bool(facet(ifc.createIfcWall(PredefinedType="SOLIDWALL"))) is False
|
||||||
|
|
||||||
# Predefined types are checked from the object type field if not standard
|
# Predefined types are checked from the object type field if not standard
|
||||||
facet = ids.entity.create(name="IfcWall", predefinedType="WALDO")
|
facet = ids.entity.create(name="IfcWall", predefinedType="WALDO")
|
||||||
case(
|
case(
|
||||||
@@ -411,6 +401,9 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
expected=True,
|
expected=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Predefined types are checked from the process type field if not standard for processes
|
||||||
|
# TODO
|
||||||
|
|
||||||
# Userdefined is not an allowed filter because userdefined implies a specified object or element type
|
# Userdefined is not an allowed filter because userdefined implies a specified object or element type
|
||||||
facet = ids.entity.create(name="IfcWall", predefinedType="USERDEFINED")
|
facet = ids.entity.create(name="IfcWall", predefinedType="USERDEFINED")
|
||||||
case(
|
case(
|
||||||
@@ -444,6 +437,7 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("Entity enumeration 2", facet=facet, inst=ifc.createIfcBeam(), expected=False)
|
case("Entity enumeration 2", facet=facet, inst=ifc.createIfcBeam(), expected=False)
|
||||||
|
|
||||||
# Another example of how restrictions are allowed when matching the IFC class
|
# Another example of how restrictions are allowed when matching the IFC class
|
||||||
|
# Note: Regex patterns follow the XSD flavour
|
||||||
restriction = ids.restriction.create(options="Ifc.*Type", type="pattern")
|
restriction = ids.restriction.create(options="Ifc.*Type", type="pattern")
|
||||||
facet = ids.entity.create(name=restriction)
|
facet = ids.entity.create(name=restriction)
|
||||||
case("Entity pattern 0", facet=facet, inst=ifc.createIfcWall(), expected=False)
|
case("Entity pattern 0", facet=facet, inst=ifc.createIfcWall(), expected=False)
|
||||||
@@ -454,8 +448,10 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
facet = ids.entity.create(name="IfcWall", predefinedType=restriction)
|
facet = ids.entity.create(name="IfcWall", predefinedType=restriction)
|
||||||
wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall", predefined_type="FOOBAR")
|
wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall", predefined_type="FOOBAR")
|
||||||
wall2 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall", predefined_type="FOOBAZ")
|
wall2 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall", predefined_type="FOOBAZ")
|
||||||
|
wall3 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall", predefined_type="BAZFOO")
|
||||||
case("", facet=facet, inst=wall, expected=True)
|
case("", facet=facet, inst=wall, expected=True)
|
||||||
case("", facet=facet, inst=wall2, expected=True)
|
case("", facet=facet, inst=wall2, expected=True)
|
||||||
|
case("", facet=facet, inst=wall3, expected=False)
|
||||||
|
|
||||||
def test_creating_an_attribute_facet(self):
|
def test_creating_an_attribute_facet(self):
|
||||||
attribute = ids.attribute.create(name="name")
|
attribute = ids.attribute.create(name="name")
|
||||||
@@ -490,16 +486,51 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("", facet=facet, inst=ifc.createIfcWall(), expected=False)
|
case("", facet=facet, inst=ifc.createIfcWall(), expected=False)
|
||||||
case("", facet=facet, inst=ifc.createIfcWall(Name=""), expected=False)
|
case("", facet=facet, inst=ifc.createIfcWall(Name=""), expected=False)
|
||||||
case("", facet=facet, inst=ifc.createIfcWall(Name="Foobar"), expected=True)
|
case("", facet=facet, inst=ifc.createIfcWall(Name="Foobar"), expected=True)
|
||||||
|
# TODO write test case that evaluates empty list / set as False
|
||||||
|
# TODO write test case that evaluates logical UNKNOWN as False
|
||||||
|
# TODO write test case that evaluates any bool as True
|
||||||
|
|
||||||
|
# An object value is truthy
|
||||||
|
facet = ids.attribute.create(name="OwnerHistory")
|
||||||
|
assert bool(facet(ifc.createIfcWall())) is False
|
||||||
|
assert bool(facet(ifc.createIfcWall(OwnerHistory=ifc.createIfcOwnerHistory()))) is True
|
||||||
|
|
||||||
|
# Selects are only considered for truthy or falsey
|
||||||
|
facet = ids.attribute.create(name="DiffuseColour")
|
||||||
|
element = ifc.createIfcSurfaceStyleRendering()
|
||||||
|
assert bool(facet(element)) is False
|
||||||
|
assert bool(facet(ifc.createIfcSurfaceStyleRendering(DiffuseColour=ifc.createIfcColourRgb()))) is True
|
||||||
|
assert (
|
||||||
|
bool(facet(ifc.createIfcSurfaceStyleRendering(DiffuseColour=ifc.createIfcNormalisedRatioMeasure(0.5))))
|
||||||
|
is True
|
||||||
|
)
|
||||||
|
|
||||||
# When a value is specified, the value shall match case sensitively
|
# When a value is specified, the value shall match case sensitively
|
||||||
facet = ids.attribute.create(name="Name", value="Foobar")
|
facet = ids.attribute.create(name="Name", value="Foobar")
|
||||||
case("", facet=facet, inst=ifc.createIfcWall(Name="Foobar"), expected=True)
|
case("", facet=facet, inst=ifc.createIfcWall(Name="Foobar"), expected=True)
|
||||||
|
case("", facet=facet, inst=ifc.createIfcWall(Name="foobar"), expected=False)
|
||||||
case("", facet=facet, inst=ifc.createIfcWall(Name="Foobaz"), expected=False)
|
case("", facet=facet, inst=ifc.createIfcWall(Name="Foobaz"), expected=False)
|
||||||
|
|
||||||
# A value that is 0 is still considered a value, not "null-like", so it is matched
|
# A value that is 0 is still considered a value, not "null-like", so it is matched
|
||||||
facet = ids.attribute.create(name="Eastings")
|
facet = ids.attribute.create(name="Eastings")
|
||||||
case("", facet=facet, inst=ifc.createIfcMapConversion(Eastings=0), expected=True)
|
case("", facet=facet, inst=ifc.createIfcMapConversion(Eastings=0), expected=True)
|
||||||
|
|
||||||
|
# Value checks are meaningless for checking objects, selects, and lists so it always fails
|
||||||
|
facet = ids.attribute.create(name="OwnerHistory", value="Foobar")
|
||||||
|
assert bool(facet(ifc.createIfcWall(OwnerHistory=ifc.createIfcOwnerHistory()))) is False
|
||||||
|
|
||||||
|
# Selects
|
||||||
|
|
||||||
|
# Lists
|
||||||
|
|
||||||
|
# TODO continue from here
|
||||||
|
|
||||||
|
# TODO should we be allowed to check inverse attributes?
|
||||||
|
# Nope - always false
|
||||||
|
|
||||||
|
# TODO should we be allowed to check derived attributes?
|
||||||
|
# Nope - always false
|
||||||
|
|
||||||
# Simple values which must be strings are checked with strict typing. No type casting shall occur.
|
# Simple values which must be strings are checked with strict typing. No type casting shall occur.
|
||||||
facet = ids.attribute.create(name="Eastings", value="42")
|
facet = ids.attribute.create(name="Eastings", value="42")
|
||||||
case("", facet=facet, inst=ifc.createIfcMapConversion(Eastings=0), expected=False)
|
case("", facet=facet, inst=ifc.createIfcMapConversion(Eastings=0), expected=False)
|
||||||
@@ -909,7 +940,7 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("", facet=facet, inst=wall, expected=True)
|
case("", facet=facet, inst=wall, expected=True)
|
||||||
case("", facet=facet, inst=wall_type, expected=False)
|
case("", facet=facet, inst=wall_type, expected=False)
|
||||||
|
|
||||||
def test_material_create(self):
|
def test_creating_a_material_facet(self):
|
||||||
facet = ids.material.create()
|
facet = ids.material.create()
|
||||||
assert facet.asdict() == {"@location": "any"}
|
assert facet.asdict() == {"@location": "any"}
|
||||||
facet = ids.material.create(
|
facet = ids.material.create(
|
||||||
@@ -1095,6 +1126,7 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("", facet=facet, inst=subelement, expected=False)
|
case("", facet=facet, inst=subelement, expected=False)
|
||||||
|
|
||||||
# A nested subelement still passes so long as one of its parents is an IfcElementAssembly
|
# A nested subelement still passes so long as one of its parents is an IfcElementAssembly
|
||||||
|
# TODO nononono
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
|
||||||
subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSlab")
|
subelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSlab")
|
||||||
subsubelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBeam")
|
subsubelement = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcBeam")
|
||||||
@@ -1112,6 +1144,7 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("", facet=facet, inst=element, expected=True)
|
case("", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
# An IfcGroup can be passed by subtypes
|
# An IfcGroup can be passed by subtypes
|
||||||
|
# TODO: wrong, subtypes should not be matched
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
|
||||||
group = ifc.createIfcInventory()
|
group = ifc.createIfcInventory()
|
||||||
facet = ids.partOf.create(entity="IfcGroup")
|
facet = ids.partOf.create(entity="IfcGroup")
|
||||||
@@ -1127,6 +1160,7 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
case("", facet=facet, inst=element, expected=True)
|
case("", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
# An IfcSystem allows subtypes
|
# An IfcSystem allows subtypes
|
||||||
|
# TODO: wrong, subtypes should not be matched
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcElementAssembly")
|
||||||
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcDistributionSystem")
|
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcDistributionSystem")
|
||||||
ifcopenshell.api.run("system.assign_system", ifc, product=element, system=system)
|
ifcopenshell.api.run("system.assign_system", ifc, product=element, system=system)
|
||||||
@@ -1190,8 +1224,6 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
i.specifications[0].add_requirement(p)
|
i.specifications[0].add_requirement(p)
|
||||||
self.assertEqual(i.specifications[0].requirements.terms[0].value, "èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ")
|
self.assertEqual(i.specifications[0].requirements.terms[0].value, "èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ")
|
||||||
|
|
||||||
""" Saving created IDS to IDS.xml """
|
|
||||||
|
|
||||||
def test_created_ids_to_xml(self):
|
def test_created_ids_to_xml(self):
|
||||||
i = ids.ids(title="My IDS")
|
i = ids.ids(title="My IDS")
|
||||||
i.specifications.append(ids.specification(name="Test_Specification"))
|
i.specifications.append(ids.specification(name="Test_Specification"))
|
||||||
@@ -1213,10 +1245,10 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
i.specifications[0].add_applicability(m)
|
i.specifications[0].add_applicability(m)
|
||||||
i.specifications[0].add_requirement(c)
|
i.specifications[0].add_requirement(c)
|
||||||
i.specifications[0].add_requirement(p1)
|
i.specifications[0].add_requirement(p1)
|
||||||
# TODO i.specifications[0].add_requirement(p2)
|
i.specifications[0].add_requirement(p2)
|
||||||
i.specifications[0].add_requirement(p3)
|
i.specifications[0].add_requirement(p3)
|
||||||
i.specifications[0].add_requirement(p4)
|
i.specifications[0].add_requirement(p4)
|
||||||
# TODO i.specifications[0].add_requirement(p5)
|
i.specifications[0].add_requirement(p5)
|
||||||
fn = "TEST_FILE.xml"
|
fn = "TEST_FILE.xml"
|
||||||
result = i.to_xml(fn)
|
result = i.to_xml(fn)
|
||||||
os.remove(fn)
|
os.remove(fn)
|
||||||
@@ -1224,6 +1256,24 @@ class TestIdsAuthoring(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestIfcValidation(unittest.TestCase):
|
class TestIfcValidation(unittest.TestCase):
|
||||||
|
def test_creating_a_minimal_ids_and_validating(self):
|
||||||
|
specs = ids.ids(title="Title")
|
||||||
|
spec = ids.specification(name="Name")
|
||||||
|
spec.add_applicability(ids.entity.create(name="IfcWall"))
|
||||||
|
spec.add_requirement(ids.attribute.create(name="Name", value="Waldo"))
|
||||||
|
specs.specifications.append(spec)
|
||||||
|
assert "http://standards.buildingsmart.org/IDS" in specs.to_string()
|
||||||
|
assert spec.status == None
|
||||||
|
|
||||||
|
model = ifcopenshell.file()
|
||||||
|
wall = model.createIfcWall()
|
||||||
|
waldo = model.createIfcWall(Name="Waldo")
|
||||||
|
specs.validate2(model)
|
||||||
|
|
||||||
|
assert spec.status == False
|
||||||
|
assert set(spec.applicable_entities) == {wall, waldo}
|
||||||
|
assert spec.failed_entities == [wall]
|
||||||
|
|
||||||
def test_validate_simple(self):
|
def test_validate_simple(self):
|
||||||
# Same test as in reporting...
|
# Same test as in reporting...
|
||||||
ids_file = ids.ids.open(IDS_URL)
|
ids_file = ids.ids.open(IDS_URL)
|
||||||
|
|||||||
Reference in New Issue
Block a user