mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 15:08:51 +00:00
Show percentage results in BIMTester, add tests for element existance, attributes from a list, and more generic attribute checking
This commit is contained in:
@@ -9,6 +9,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import argparse
|
import argparse
|
||||||
|
import csv
|
||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
def run_tests(args):
|
def run_tests(args):
|
||||||
@@ -45,13 +47,17 @@ def generate_report(args):
|
|||||||
'time': line.strip().split(' ... ')[1],
|
'time': line.strip().split(' ... ')[1],
|
||||||
'is_success': is_success
|
'is_success': is_success
|
||||||
})
|
})
|
||||||
|
total_passes = len([s for s in steps if s['is_success'] == True])
|
||||||
|
total_steps = len(steps)
|
||||||
|
pass_rate = round((total_passes / total_steps) * 100)
|
||||||
data['testcases'].append({
|
data['testcases'].append({
|
||||||
'name': testcase.get('name'),
|
'name': testcase.get('name'),
|
||||||
'is_success': testcase.get('status') == 'passed',
|
'is_success': testcase.get('status') == 'passed',
|
||||||
'time': testcase.get('time'),
|
'time': testcase.get('time'),
|
||||||
'steps': steps,
|
'steps': steps,
|
||||||
'total_passes': len([s for s in steps if s['is_success'] == True]),
|
'total_passes': total_passes,
|
||||||
'total_steps': len(steps)
|
'total_steps': total_steps,
|
||||||
|
'pass_rate': pass_rate
|
||||||
})
|
})
|
||||||
with open('report/{}.html'.format(file[0:-4]), 'w') as out:
|
with open('report/{}.html'.format(file[0:-4]), 'w') as out:
|
||||||
with open('features/template.html') as template:
|
with open('features/template.html') as template:
|
||||||
|
|||||||
@@ -41,11 +41,6 @@ def step_impl(context, file):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@given('that an IFC file is loaded')
|
|
||||||
def step_impl(context):
|
|
||||||
assert IfcFile.get()
|
|
||||||
|
|
||||||
|
|
||||||
@then('the file should be an {schema} file')
|
@then('the file should be an {schema} file')
|
||||||
def step_impl(context, schema):
|
def step_impl(context, schema):
|
||||||
assert IfcFile.get().schema == schema
|
assert IfcFile.get().schema == schema
|
||||||
@@ -62,10 +57,15 @@ def step_impl(context, id, reason):
|
|||||||
|
|
||||||
|
|
||||||
@then('the file is exempt from auditing because {reason}')
|
@then('the file is exempt from auditing because {reason}')
|
||||||
def step_impl(context, id, reason):
|
def step_impl(context, reason):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@given(u'there is at least one {ifc_class} element')
|
||||||
|
def step_impl(context, ifc_class):
|
||||||
|
assert len(IfcFile.get().by_type(ifc_class)) >= 1
|
||||||
|
|
||||||
|
|
||||||
@then('all {ifc_class} elements have a name matching the pattern "{pattern}"')
|
@then('all {ifc_class} elements have a name matching the pattern "{pattern}"')
|
||||||
def step_impl(context, ifc_class, pattern):
|
def step_impl(context, ifc_class, pattern):
|
||||||
import re
|
import re
|
||||||
@@ -147,6 +147,25 @@ def step_impl(context, ifc_class, attribute, pattern):
|
|||||||
assert re.search(pattern, value)
|
assert re.search(pattern, value)
|
||||||
|
|
||||||
|
|
||||||
|
@then('all (?P<ifc_class>.*) elements have an? (?P<attributes>.*) taken from the list in "(?P<list_file>.*)"')
|
||||||
|
def step_impl(context, ifc_class, attributes, list_file):
|
||||||
|
import csv
|
||||||
|
values = []
|
||||||
|
with open(list_file) as csvfile:
|
||||||
|
reader = csv.reader(csvfile)
|
||||||
|
for row in reader:
|
||||||
|
values.append(row)
|
||||||
|
elements = IfcFile.get().by_type(ifc_class)
|
||||||
|
for element in elements:
|
||||||
|
attribute_values = []
|
||||||
|
for attribute in attributes.split(','):
|
||||||
|
if not hasattr(element, attribute):
|
||||||
|
assert False, f'Failed at element {element.GlobalId}'
|
||||||
|
attribute_values.append(getattr(element, attribute))
|
||||||
|
if attribute_values not in values:
|
||||||
|
assert False, f'Failed at element {element.GlobalId}'
|
||||||
|
|
||||||
|
|
||||||
use_step_matcher('parse')
|
use_step_matcher('parse')
|
||||||
@then('all {ifc_class} elements have a {qto_name}.{quantity_name} quantity')
|
@then('all {ifc_class} elements have a {qto_name}.{quantity_name} quantity')
|
||||||
def step_impl(context, ifc_class, qto_name, quantity_name):
|
def step_impl(context, ifc_class, qto_name, quantity_name):
|
||||||
@@ -201,29 +220,19 @@ def step_impl(context, attribute, value):
|
|||||||
|
|
||||||
|
|
||||||
use_step_matcher('parse')
|
use_step_matcher('parse')
|
||||||
@then(u'the project name is "{name}"')
|
@then(u'the project has a {attribute_name} attribute with a value of "{attribute_value}"')
|
||||||
def step_impl(context, name):
|
def step_impl(context, attribute_name, attribute_value):
|
||||||
project_name = IfcFile.get().by_type('IfcProject')[0].Name
|
|
||||||
assert project_name == name, f'The name was {project_name}'
|
|
||||||
|
|
||||||
|
|
||||||
@then(u'there is a site named "{name}"')
|
|
||||||
def step_impl(context, name):
|
|
||||||
project = IfcFile.get().by_type('IfcProject')[0]
|
project = IfcFile.get().by_type('IfcProject')[0]
|
||||||
if not project.IsDecomposedBy:
|
assert getattr(project, attribute_name) == attribute_value
|
||||||
assert False
|
|
||||||
for relationship in project.IsDecomposedBy:
|
|
||||||
for part in relationship.RelatedObjects:
|
|
||||||
if part.is_a('IfcSite'):
|
|
||||||
assert part.Name == name, f'The name was {part.Name}'
|
|
||||||
|
|
||||||
|
|
||||||
@then(u'there is a building named "{name}"')
|
@then(u'there is an {ifc_class} element with a {attribute_name} attribute with a value of "{attribute_value}"')
|
||||||
def step_impl(context, name):
|
def step_impl(context, ifc_class, attribute_name, attribute_value):
|
||||||
for building in IfcFile.get().by_type('IfcBuilding'):
|
elements = IfcFile.get().by_type(ifc_class)
|
||||||
if building.Name == name:
|
for element in elements:
|
||||||
|
if hasattr(element, attribute_name) \
|
||||||
|
and getattr(element, attribute_name) == attribute_value:
|
||||||
return
|
return
|
||||||
print(f'A building named {building.Name} was found.')
|
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
@@ -232,8 +241,3 @@ def step_impl(context):
|
|||||||
for building in IfcFile.get().by_type('IfcBuilding'):
|
for building in IfcFile.get().by_type('IfcBuilding'):
|
||||||
if not building.BuildingAddress:
|
if not building.BuildingAddress:
|
||||||
assert False, f'The building "{building.Name}" has no address.'
|
assert False, f'The building "{building.Name}" has no address.'
|
||||||
|
|
||||||
|
|
||||||
@then(u'all the IFC files have the same building storeys')
|
|
||||||
def step_impl(context):
|
|
||||||
raise NotImplementedError(u'STEP: Then all the IFC files have the same building storeys')
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<h2>{{name}}</h2>
|
<h2>{{name}}</h2>
|
||||||
<p>
|
<p>
|
||||||
<span class="{{#is_success}}success{{/is_success}}{{^is_success}}failure{{/is_success}}">{{#is_success}}Success{{/is_success}}{{^is_success}}Failure{{/is_success}}</span>
|
<span class="{{#is_success}}success{{/is_success}}{{^is_success}}failure{{/is_success}}">{{#is_success}}Success{{/is_success}}{{^is_success}}Failure{{/is_success}}</span>
|
||||||
Tests passed: <strong>{{total_passes}} / {{total_steps}}</strong>
|
Tests passed: <strong>{{total_passes}} / {{total_steps}}</strong> ({{pass_rate}}%)
|
||||||
<span class="time">
|
<span class="time">
|
||||||
Time taken: {{time}} seconds
|
Time taken: {{time}} seconds
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# This can be packaged with `pyinstaller --onefile --clean --icon=icon.ico diff.py`
|
# This can be packaged with `pyinstaller --onefile --clean --icon=icon.ico ifcdiff.py`
|
||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
from deepdiff import DeepDiff
|
from deepdiff import DeepDiff
|
||||||
|
|||||||
Reference in New Issue
Block a user