diff --git a/src/ifcbimtester/bimtester.py b/src/ifcbimtester/bimtester.py index 28e5e0ad4d..e9577865a2 100644 --- a/src/ifcbimtester/bimtester.py +++ b/src/ifcbimtester/bimtester.py @@ -9,6 +9,8 @@ import os import sys import json import argparse +import csv +import re from pathlib import Path def run_tests(args): @@ -45,13 +47,17 @@ def generate_report(args): 'time': line.strip().split(' ... ')[1], '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({ 'name': testcase.get('name'), 'is_success': testcase.get('status') == 'passed', 'time': testcase.get('time'), 'steps': steps, - 'total_passes': len([s for s in steps if s['is_success'] == True]), - 'total_steps': len(steps) + 'total_passes': total_passes, + 'total_steps': total_steps, + 'pass_rate': pass_rate }) with open('report/{}.html'.format(file[0:-4]), 'w') as out: with open('features/template.html') as template: diff --git a/src/ifcbimtester/features/steps/steps.py b/src/ifcbimtester/features/steps/steps.py index 0f4e03ee6c..b3b68be5b7 100644 --- a/src/ifcbimtester/features/steps/steps.py +++ b/src/ifcbimtester/features/steps/steps.py @@ -41,11 +41,6 @@ def step_impl(context, file): pass -@given('that an IFC file is loaded') -def step_impl(context): - assert IfcFile.get() - - @then('the file should be an {schema} file') def step_impl(context, 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}') -def step_impl(context, id, reason): +def step_impl(context, reason): 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}"') def step_impl(context, ifc_class, pattern): import re @@ -147,6 +147,25 @@ def step_impl(context, ifc_class, attribute, pattern): assert re.search(pattern, value) +@then('all (?P.*) elements have an? (?P.*) taken from the list in "(?P.*)"') +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') @then('all {ifc_class} elements have a {qto_name}.{quantity_name} quantity') def step_impl(context, ifc_class, qto_name, quantity_name): @@ -201,29 +220,19 @@ def step_impl(context, attribute, value): use_step_matcher('parse') -@then(u'the project name is "{name}"') -def step_impl(context, name): - 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): +@then(u'the project has a {attribute_name} attribute with a value of "{attribute_value}"') +def step_impl(context, attribute_name, attribute_value): project = IfcFile.get().by_type('IfcProject')[0] - if not project.IsDecomposedBy: - 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}' + assert getattr(project, attribute_name) == attribute_value -@then(u'there is a building named "{name}"') -def step_impl(context, name): - for building in IfcFile.get().by_type('IfcBuilding'): - if building.Name == name: +@then(u'there is an {ifc_class} element with a {attribute_name} attribute with a value of "{attribute_value}"') +def step_impl(context, ifc_class, attribute_name, attribute_value): + elements = IfcFile.get().by_type(ifc_class) + for element in elements: + if hasattr(element, attribute_name) \ + and getattr(element, attribute_name) == attribute_value: return - print(f'A building named {building.Name} was found.') assert False @@ -232,8 +241,3 @@ def step_impl(context): for building in IfcFile.get().by_type('IfcBuilding'): if not building.BuildingAddress: 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') diff --git a/src/ifcbimtester/features/template.html b/src/ifcbimtester/features/template.html index 5a4b6ae2f9..5d90dd4f01 100644 --- a/src/ifcbimtester/features/template.html +++ b/src/ifcbimtester/features/template.html @@ -27,7 +27,7 @@

{{name}}

{{#is_success}}Success{{/is_success}}{{^is_success}}Failure{{/is_success}} - Tests passed: {{total_passes}} / {{total_steps}} + Tests passed: {{total_passes}} / {{total_steps}} ({{pass_rate}}%) Time taken: {{time}} seconds diff --git a/src/ifcdiff/ifcdiff.py b/src/ifcdiff/ifcdiff.py index 06e3fdcc96..25c1d8ba8d 100644 --- a/src/ifcdiff/ifcdiff.py +++ b/src/ifcdiff/ifcdiff.py @@ -1,5 +1,5 @@ #!/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 from deepdiff import DeepDiff