Validation Strategy#
Validation is done by round-tripping various IFC files and ensuring that the IFC content is 1:1 comparing the returned IFC with what was sent.
Different validation techniques have been tested, and so far the current strategy is using ifcopenshell to compare
two ifcopenshell.File
objects
A unittest procedure is added
import ifcopenshell
import logging
def compare_ifcopenshell_objects_element_by_element(f1: ifcopenshell.file, f2: ifcopenshell.file):
results = sorted(fingerprint(f1).symmetric_difference(fingerprint(f2)), key=lambda x: len(str(x)))
res = [set([name for name, value in result]) for result in results]
matches = []
i = 0
while i < len(res):
x = res[i]
for k, match_eval in enumerate(res):
if k == i or x != match_eval:
continue
found = tuple(sorted([i, k]))
if found not in matches:
matches.append(found)
break
i += 1
# Compare element by element
for a, b in matches:
m_a = {key: value for key, value in results[a]}
m_b = {key: value for key, value in results[b]}
ifc_class = m_a["type"]
for key, value in m_a.items():
other_val = m_b[key]
if isinstance(value, frozenset):
continue
if isinstance(value, tuple) and isinstance(value[0], frozenset):
continue
if other_val != value:
logging.error(f'Diff in Ifc Class "{ifc_class}" property: {key} := "{value}" != "{other_val}"')
def fingerprint(file: ifcopenshell.file):
get_info_props = dict(include_identifier=False, recursive=True, return_type=frozenset)
return frozenset(inst.get_info(**get_info_props) for inst in file)
def validate_ifc_objects(f1: ifcopenshell.file, f2: ifcopenshell.file):
compare_ifcopenshell_objects_element_by_element(f1, f2)
assert fingerprint(f1) == fingerprint(f2)