From f78fb0a4f0ddbd632a0990c47af390380d6123ba Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 15 Oct 2019 11:19:44 +1100 Subject: [PATCH] Package up BIMTester - basically a super lightweight wrapper around Behave and a JUnit HTML formatter. --- src/ifcbimtester/bimtester.py | 64 ++++++++++++++++++++++++++++++++++ src/ifcbimtester/icon.ico | Bin 0 -> 106929 bytes 2 files changed, 64 insertions(+) create mode 100644 src/ifcbimtester/bimtester.py create mode 100644 src/ifcbimtester/icon.ico diff --git a/src/ifcbimtester/bimtester.py b/src/ifcbimtester/bimtester.py new file mode 100644 index 0000000000..b820869b77 --- /dev/null +++ b/src/ifcbimtester/bimtester.py @@ -0,0 +1,64 @@ +# This can be packaged with `pyinstaller --onefile --clean --icon=icon.ico bimtester.py` + +from behave.__main__ import main as behave_main +import behave.formatter.pretty # Needed for pyinstaller to package it +import xml.etree.ElementTree as ET +import ifcopenshell # Needed for pyinstaller to package it +import pystache +import os +import sys + +def run_tests(): + behave_main(['features', '--junit', '--junit-directory', 'junit/']) + print('# All tests have finished. Generating HTML reports now.') + with open('features/template.html') as template: + os.mkdir('report') + for file in os.listdir('junit/'): + if not file.endswith('.xml'): + continue + root = ET.parse('junit/{}'.format(file)).getroot() + data = { + 'report_name': root.get('name'), + 'testcases': [] + } + for testcase in root.findall('testcase'): + steps = [] + system_out = testcase.findall('system-out')[0].text.splitlines() + for line in system_out: + if line.strip()[0:5] in ['Given', 'Then ', 'When ']: + is_success = True if ' ... passed in ' in line else False + steps.append({ + 'name': line.strip().split(' ... ')[0], + 'time': line.strip().split(' ... ')[1], + 'is_success': is_success + }) + 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) + }) + with open('report/{}.html'.format(file[0:-4]), 'w') as out: + out.write(pystache.render(template.read(), data)) + + +print('# BIMTester') +print(''' +BIMTester is free software developed under the IfcOpenShell and BlenderBIM +projects. BIMTester allows advanced, fast, and human-readable BIM data analysis, +and can be run automatically on open-source BIM servers. To learn more, visit: + + - http://ifcopenshell.org + - https://blenderbim.org + +To run, a `features/` folder is required in the current folder. +''') + +value = input('Would you like to run the tests? [Y/n] ') +if value == 'n': + quit() +run_tests() +print('# All tests and reports are complete :-)') +input('Press to quit.') diff --git a/src/ifcbimtester/icon.ico b/src/ifcbimtester/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8b3af5ec6609be0fc4fde724ec3a11bc982fd9e4 GIT binary patch literal 106929 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 OA_U(iAN23QdH)amZZ<6d literal 0 HcmV?d00001