Skip to content
This repository was archived by the owner on Nov 24, 2024. It is now read-only.

Commit c0b4115

Browse files
authored
Merge pull request #1 from engisis-com/v0.6.0
Apply changes done under Engisis to the IFCRail fork
2 parents d5e6721 + 34174dd commit c0b4115

File tree

5 files changed

+149
-1
lines changed

5 files changed

+149
-1
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from behave import step, given, when, then, use_step_matcher
2+
3+
from utils import IfcFile
4+
5+
use_step_matcher("parse")
6+
@step(u"There must be exactly {number} {ifc_class} element")
7+
@step(u"There must be exactly {number} {ifc_class} elements")
8+
def step_impl(context, number, ifc_class):
9+
num = len(IfcFile.get().by_type(ifc_class))
10+
assert num == int(number), "Could not find {} elements of {}. Found {} element(s).".format(number, ifc_class, num)
11+
12+
@given(u'a set of specific related elements')
13+
def step_impl(context):
14+
model = getattr(context, "model", None)
15+
if not model:
16+
context.model = TableModel()
17+
for row in context.table:
18+
context.model.add_row(row["RelatedObjects"], row["RelatingGroup"])
19+
20+
@given(u'a set of specific related elements taken from the file "{path_file}"')
21+
def step_impl(context, path_file):
22+
import csv
23+
model = getattr(context, "model", None)
24+
if not model:
25+
context.model = TableModel()
26+
with open(path_file, encoding="utf-8") as csvfile:
27+
reader = csv.DictReader(csvfile)
28+
for row in reader:
29+
context.model.add_row(row["RelatedObjects"], row["RelatingGroup"])
30+
31+
@then(u'there must be exactly a number of {ifc_class} equals to the number of distinct row value')
32+
def step_impl(context, ifc_class):
33+
try:
34+
context.execute_steps(u"""
35+
then There must be exactly {number} {ifc_class} elements
36+
""".format(ifc_class=ifc_class, number=context.model.get_count_distinct_values()))
37+
except AssertionError as error:
38+
str_error = str(error)
39+
assert False, str_error[:str_error.find("Traceback")]
40+
assert True
41+
42+
@then(u'there is a relationship {ifc_class} with {left_attribute} and {right_attribute} between the two elements of each row')
43+
def step_impl(context, ifc_class, left_attribute, right_attribute):
44+
rows = context.model.rows
45+
elements = IfcFile.by_type(ifc_class)
46+
errors = []
47+
for key, value in rows.items():
48+
found = False
49+
for element in elements:
50+
if any(x.Name == key for x in getattr(element, left_attribute))\
51+
and getattr(element, right_attribute).Name == value:
52+
found = True
53+
if not found:
54+
errors.append(f'The row ({key}, {value}) does not have the relationship.')
55+
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
56+
57+
use_step_matcher("re")
58+
@step("all IfcGroup must be linked to a type in the list (?P<linked_ifc_classes>.*)")
59+
def step_impl(context, linked_ifc_classes):
60+
groups = IfcFile.by_type("IfcGroup")
61+
errors = []
62+
for group in groups:
63+
if not hasattr(group, "IsGroupedBy"):
64+
errors.append(f'The element "{group.Name}" has no "IsGroupedBy" attribute.')
65+
else:
66+
for grouped_by in getattr(group, "IsGroupedBy"):
67+
if not hasattr(grouped_by, "RelatedObjects"):
68+
errors.append(f'The element "{grouped_by.Name}" has no "RelatedObjects" attribute.')
69+
else:
70+
for related_object in getattr(grouped_by, "RelatedObjects"):
71+
found = False
72+
for linked_ifc_class in linked_ifc_classes.split(","):
73+
if(related_object.is_a(linked_ifc_class)):
74+
found = True
75+
if not found:
76+
errors.append(f'The element "{related_object.Name}" does not have the right associated type.')
77+
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
78+
79+
@then(u'there is an element of type (?P<ifc_types>.*) with a (?P<attribute_name>.*) attribute for each row key')
80+
def step_impl(context, ifc_types, attribute_name):
81+
check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, context.model.rows.keys())
82+
83+
@then(u'there is an element of type (?P<ifc_types>.*) with a (?P<attribute_name>.*) attribute for each row value')
84+
def step_impl(context, ifc_types, attribute_name):
85+
values = set(context.model.rows.values())
86+
check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, values)
87+
88+
def check_if_element_exists_by_types_with_attribute_name(ifc_types, attribute_name, attribute_values):
89+
errors = []
90+
# retrieve all elements of that type
91+
elements = IfcFile.by_types(ifc_types)
92+
# loop
93+
for attribute_value in attribute_values:
94+
found = False
95+
for element in elements:
96+
if hasattr(element, attribute_name) and getattr(element, attribute_name) == attribute_value:
97+
found = True
98+
if not found:
99+
errors.append(f'An element with {attribute_name} attribute "{attribute_value}" was not found.')
100+
assert not errors, "Errors occured:\n{}".format("\n".join(errors))
101+
102+
class TableModel(object):
103+
"""This class represents a table of data."""
104+
def __init__(self):
105+
self.rows = dict()
106+
107+
def add_row(self, related, relating):
108+
self.rows[related] = relating
109+
110+
def get_count(self):
111+
return len(self.rows)
112+
113+
def get_count_distinct_values(self):
114+
return len(set(self.rows.values()))

src/ifcbimtester/bimtester/features/steps/ifcdata.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
from utils import IfcFile
44

5+
@step('The IFC schema "{schema}" must be provided')
6+
def step_impl(context, schema):
7+
try:
8+
IfcFile.load_schema(schema)
9+
except:
10+
assert False
11+
512

613
@step('The IFC file "{file}" must be provided')
714
def step_impl(context, file):

src/ifcbimtester/bimtester/features/steps/utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ifcopenshell
2+
import ifcopenshell.express
23
import ifcopenshell.util
34
import ifcopenshell.util.element
45

@@ -10,6 +11,13 @@ class IfcFile(object):
1011
@classmethod
1112
def load(cls, path=None):
1213
cls.file = ifcopenshell.open(path)
14+
if not cls.file:
15+
assert False
16+
17+
@classmethod
18+
def load_schema(cls, path=None):
19+
schema = ifcopenshell.express.parse(path)
20+
ifcopenshell.register_schema(schema)
1321

1422
@classmethod
1523
def get(cls):
@@ -23,6 +31,17 @@ def by_guid(cls, guid):
2331
return cls.get().by_guid(guid)
2432
except:
2533
assert False, "An element with the ID {} could not be found.".format(guid)
34+
35+
@classmethod
36+
def by_type(cls, ifc_type):
37+
return cls.get().by_type(ifc_type.strip())
38+
39+
@classmethod
40+
def by_types(cls, ifc_types):
41+
elements = []
42+
for ifc_type in ifc_types.split(","):
43+
elements += cls.by_type(ifc_type.strip())
44+
return elements
2645

2746

2847
def assert_number(number):

src/ifcbimtester/bimtester/reports.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,6 @@ def generate_report(adir="."):
9494
data["pass_rate"] = round((data["total_passes"] / data["total_steps"]) * 100)
9595

9696
html_report_file = os.path.join(report_dir, "{}.html".format(file_name))
97-
with open(html_report_file, "w") as out:
97+
with open(html_report_file, "w", encoding="utf-8") as out:
9898
with open(html_template_file) as template:
9999
out.write(pystache.render(template.read(), data))

src/ifcbimtester/startbimtester.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ def show_widget(features="", ifcfile=""):
4242
action="store_true",
4343
help="Generate a HTML report"
4444
)
45+
parser.add_argument(
46+
"-rr",
47+
"--report_after_run",
48+
action="store_true",
49+
help="Generate a HTML report after running the tests"
50+
)
4551
parser.add_argument(
4652
"-c",
4753
"--console",
@@ -103,4 +109,6 @@ def show_widget(features="", ifcfile=""):
103109
show_widget(args["featuresdir"], args["ifcfile"])
104110
else:
105111
run.run_tests(args)
112+
if args["report_after_run"]:
113+
reports.generate_report()
106114
print("# All tasks are complete :-)")

0 commit comments

Comments
 (0)