Skip to content

Commit 5beb3dc

Browse files
committed
Show percentage results in BIMTester, add tests for element existance, attributes from a list, and more generic attribute checking
1 parent e44221c commit 5beb3dc

4 files changed

Lines changed: 44 additions & 34 deletions

File tree

src/ifcbimtester/bimtester.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import sys
1010
import json
1111
import argparse
12+
import csv
13+
import re
1214
from pathlib import Path
1315

1416
def run_tests(args):
@@ -45,13 +47,17 @@ def generate_report(args):
4547
'time': line.strip().split(' ... ')[1],
4648
'is_success': is_success
4749
})
50+
total_passes = len([s for s in steps if s['is_success'] == True])
51+
total_steps = len(steps)
52+
pass_rate = round((total_passes / total_steps) * 100)
4853
data['testcases'].append({
4954
'name': testcase.get('name'),
5055
'is_success': testcase.get('status') == 'passed',
5156
'time': testcase.get('time'),
5257
'steps': steps,
53-
'total_passes': len([s for s in steps if s['is_success'] == True]),
54-
'total_steps': len(steps)
58+
'total_passes': total_passes,
59+
'total_steps': total_steps,
60+
'pass_rate': pass_rate
5561
})
5662
with open('report/{}.html'.format(file[0:-4]), 'w') as out:
5763
with open('features/template.html') as template:

src/ifcbimtester/features/steps/steps.py

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@ def step_impl(context, file):
4141
pass
4242

4343

44-
@given('that an IFC file is loaded')
45-
def step_impl(context):
46-
assert IfcFile.get()
47-
48-
4944
@then('the file should be an {schema} file')
5045
def step_impl(context, schema):
5146
assert IfcFile.get().schema == schema
@@ -62,10 +57,15 @@ def step_impl(context, id, reason):
6257

6358

6459
@then('the file is exempt from auditing because {reason}')
65-
def step_impl(context, id, reason):
60+
def step_impl(context, reason):
6661
pass
6762

6863

64+
@given(u'there is at least one {ifc_class} element')
65+
def step_impl(context, ifc_class):
66+
assert len(IfcFile.get().by_type(ifc_class)) >= 1
67+
68+
6969
@then('all {ifc_class} elements have a name matching the pattern "{pattern}"')
7070
def step_impl(context, ifc_class, pattern):
7171
import re
@@ -147,6 +147,25 @@ def step_impl(context, ifc_class, attribute, pattern):
147147
assert re.search(pattern, value)
148148

149149

150+
@then('all (?P<ifc_class>.*) elements have an? (?P<attributes>.*) taken from the list in "(?P<list_file>.*)"')
151+
def step_impl(context, ifc_class, attributes, list_file):
152+
import csv
153+
values = []
154+
with open(list_file) as csvfile:
155+
reader = csv.reader(csvfile)
156+
for row in reader:
157+
values.append(row)
158+
elements = IfcFile.get().by_type(ifc_class)
159+
for element in elements:
160+
attribute_values = []
161+
for attribute in attributes.split(','):
162+
if not hasattr(element, attribute):
163+
assert False, f'Failed at element {element.GlobalId}'
164+
attribute_values.append(getattr(element, attribute))
165+
if attribute_values not in values:
166+
assert False, f'Failed at element {element.GlobalId}'
167+
168+
150169
use_step_matcher('parse')
151170
@then('all {ifc_class} elements have a {qto_name}.{quantity_name} quantity')
152171
def step_impl(context, ifc_class, qto_name, quantity_name):
@@ -201,29 +220,19 @@ def step_impl(context, attribute, value):
201220

202221

203222
use_step_matcher('parse')
204-
@then(u'the project name is "{name}"')
205-
def step_impl(context, name):
206-
project_name = IfcFile.get().by_type('IfcProject')[0].Name
207-
assert project_name == name, f'The name was {project_name}'
208-
209-
210-
@then(u'there is a site named "{name}"')
211-
def step_impl(context, name):
223+
@then(u'the project has a {attribute_name} attribute with a value of "{attribute_value}"')
224+
def step_impl(context, attribute_name, attribute_value):
212225
project = IfcFile.get().by_type('IfcProject')[0]
213-
if not project.IsDecomposedBy:
214-
assert False
215-
for relationship in project.IsDecomposedBy:
216-
for part in relationship.RelatedObjects:
217-
if part.is_a('IfcSite'):
218-
assert part.Name == name, f'The name was {part.Name}'
226+
assert getattr(project, attribute_name) == attribute_value
219227

220228

221-
@then(u'there is a building named "{name}"')
222-
def step_impl(context, name):
223-
for building in IfcFile.get().by_type('IfcBuilding'):
224-
if building.Name == name:
229+
@then(u'there is an {ifc_class} element with a {attribute_name} attribute with a value of "{attribute_value}"')
230+
def step_impl(context, ifc_class, attribute_name, attribute_value):
231+
elements = IfcFile.get().by_type(ifc_class)
232+
for element in elements:
233+
if hasattr(element, attribute_name) \
234+
and getattr(element, attribute_name) == attribute_value:
225235
return
226-
print(f'A building named {building.Name} was found.')
227236
assert False
228237

229238

@@ -232,8 +241,3 @@ def step_impl(context):
232241
for building in IfcFile.get().by_type('IfcBuilding'):
233242
if not building.BuildingAddress:
234243
assert False, f'The building "{building.Name}" has no address.'
235-
236-
237-
@then(u'all the IFC files have the same building storeys')
238-
def step_impl(context):
239-
raise NotImplementedError(u'STEP: Then all the IFC files have the same building storeys')

src/ifcbimtester/features/template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ <h1>IFC QA Report: {{report_name}}</h1>
2727
<h2>{{name}}</h2>
2828
<p>
2929
<span class="{{#is_success}}success{{/is_success}}{{^is_success}}failure{{/is_success}}">{{#is_success}}Success{{/is_success}}{{^is_success}}Failure{{/is_success}}</span>
30-
Tests passed: <strong>{{total_passes}} / {{total_steps}}</strong>
30+
Tests passed: <strong>{{total_passes}} / {{total_steps}}</strong> ({{pass_rate}}%)
3131
<span class="time">
3232
Time taken: {{time}} seconds
3333
</span>

src/ifcdiff/ifcdiff.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/python
2-
# This can be packaged with `pyinstaller --onefile --clean --icon=icon.ico diff.py`
2+
# This can be packaged with `pyinstaller --onefile --clean --icon=icon.ico ifcdiff.py`
33

44
import ifcopenshell
55
from deepdiff import DeepDiff

0 commit comments

Comments
 (0)