Merge pull request #1 from engisis-com/v0.6.0

Apply changes done under Engisis to the IFCRail fork
This commit is contained in:
rbertucat
2020-12-11 15:48:56 +01:00
committed by GitHub
5 changed files with 149 additions and 1 deletions
@@ -0,0 +1,114 @@
from behave import step, given, when, then, use_step_matcher
from utils import IfcFile
use_step_matcher("parse")
@step(u"There must be exactly {number} {ifc_class} element")
@step(u"There must be exactly {number} {ifc_class} elements")
def step_impl(context, number, ifc_class):
num = len(IfcFile.get().by_type(ifc_class))
assert num == int(number), "Could not find {} elements of {}. Found {} element(s).".format(number, ifc_class, num)
@given(u'a set of specific related elements')
def step_impl(context):
model = getattr(context, "model", None)
if not model:
context.model = TableModel()
for row in context.table:
context.model.add_row(row["RelatedObjects"], row["RelatingGroup"])
@given(u'a set of specific related elements taken from the file "{path_file}"')
def step_impl(context, path_file):
import csv
model = getattr(context, "model", None)
if not model:
context.model = TableModel()
with open(path_file, encoding="utf-8") as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
context.model.add_row(row["RelatedObjects"], row["RelatingGroup"])
@then(u'there must be exactly a number of {ifc_class} equals to the number of distinct row value')
def step_impl(context, ifc_class):
try:
context.execute_steps(u"""
then There must be exactly {number} {ifc_class} elements
""".format(ifc_class=ifc_class, number=context.model.get_count_distinct_values()))
except AssertionError as error:
str_error = str(error)
assert False, str_error[:str_error.find("Traceback")]
assert True
@then(u'there is a relationship {ifc_class} with {left_attribute} and {right_attribute} between the two elements of each row')
def step_impl(context, ifc_class, left_attribute, right_attribute):
rows = context.model.rows
elements = IfcFile.by_type(ifc_class)
errors = []
for key, value in rows.items():
found = False
for element in elements:
if any(x.Name == key for x in getattr(element, left_attribute))\
and getattr(element, right_attribute).Name == value:
found = True
if not found:
errors.append(f'The row ({key}, {value}) does not have the relationship.')
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
use_step_matcher("re")
@step("all IfcGroup must be linked to a type in the list (?P<linked_ifc_classes>.*)")
def step_impl(context, linked_ifc_classes):
groups = IfcFile.by_type("IfcGroup")
errors = []
for group in groups:
if not hasattr(group, "IsGroupedBy"):
errors.append(f'The element "{group.Name}" has no "IsGroupedBy" attribute.')
else:
for grouped_by in getattr(group, "IsGroupedBy"):
if not hasattr(grouped_by, "RelatedObjects"):
errors.append(f'The element "{grouped_by.Name}" has no "RelatedObjects" attribute.')
else:
for related_object in getattr(grouped_by, "RelatedObjects"):
found = False
for linked_ifc_class in linked_ifc_classes.split(","):
if(related_object.is_a(linked_ifc_class)):
found = True
if not found:
errors.append(f'The element "{related_object.Name}" does not have the right associated type.')
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
@then(u'there is an element of type (?P<ifc_types>.*) with a (?P<attribute_name>.*) attribute for each row key')
def step_impl(context, ifc_types, attribute_name):
check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, context.model.rows.keys())
@then(u'there is an element of type (?P<ifc_types>.*) with a (?P<attribute_name>.*) attribute for each row value')
def step_impl(context, ifc_types, attribute_name):
values = set(context.model.rows.values())
check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, values)
def check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, attribute_values):
errors = []
# retrieve all elements of that type
elements = IfcFile.by_types(ifc_types)
# loop
for attribute_value in attribute_values:
found = False
for element in elements:
if hasattr(element, attribute_name) and getattr(element, attribute_name) == attribute_value:
found = True
if not found:
errors.append(f'An element with {attribute_name} attribute "{attribute_value}" was not found.')
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
class TableModel(object):
"""This class represents a table of data."""
def __init__(self):
self.rows = dict()
def add_row(self, related, relating):
self.rows[related] = relating
def get_count(self):
return len(self.rows)
def get_count_distinct_values(self):
return len(set(self.rows.values()))
@@ -2,6 +2,13 @@ from behave import step
from utils import IfcFile
@step('The IFC schema "{schema}" must be provided')
def step_impl(context, schema):
try:
IfcFile.load_schema(schema)
except:
assert False
@step('The IFC file "{file}" must be provided')
def step_impl(context, file):
@@ -1,4 +1,5 @@
import ifcopenshell
import ifcopenshell.express
import ifcopenshell.util
import ifcopenshell.util.element
@@ -10,6 +11,13 @@ class IfcFile(object):
@classmethod
def load(cls, path=None):
cls.file = ifcopenshell.open(path)
if not cls.file:
assert False
@classmethod
def load_schema(cls, path=None):
schema = ifcopenshell.express.parse(path)
ifcopenshell.register_schema(schema)
@classmethod
def get(cls):
@@ -23,6 +31,17 @@ class IfcFile(object):
return cls.get().by_guid(guid)
except:
assert False, "An element with the ID {} could not be found.".format(guid)
@classmethod
def by_type(cls, ifc_type):
return cls.get().by_type(ifc_type.strip())
@classmethod
def by_types(cls, ifc_types):
elements = []
for ifc_type in ifc_types.split(","):
elements += cls.by_type(ifc_type.strip())
return elements
def assert_number(number):
+1 -1
View File
@@ -94,6 +94,6 @@ def generate_report(adir="."):
data["pass_rate"] = round((data["total_passes"] / data["total_steps"]) * 100)
html_report_file = os.path.join(report_dir, "{}.html".format(file_name))
with open(html_report_file, "w") as out:
with open(html_report_file, "w", encoding="utf-8") as out:
with open(html_template_file) as template:
out.write(pystache.render(template.read(), data))
+8
View File
@@ -42,6 +42,12 @@ if __name__ == "__main__":
action="store_true",
help="Generate a HTML report"
)
parser.add_argument(
"-rr",
"--report_after_run",
action="store_true",
help="Generate a HTML report after running the tests"
)
parser.add_argument(
"-c",
"--console",
@@ -103,4 +109,6 @@ if __name__ == "__main__":
show_widget(args["featuresdir"], args["ifcfile"])
else:
run.run_tests(args)
if args["report_after_run"]:
reports.generate_report()
print("# All tasks are complete :-)")