Files
IfcOpenShell/src/ifcbimtester/bimtester.py
T

147 lines
4.9 KiB
Python
Raw Normal View History

# 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
import pystache
import os
import sys
import json
import argparse
import csv
import re
from pathlib import Path
def run_tests(args):
behave_args = [args.feature, '--junit', '--junit-directory', args.junit_directory]
if args.advanced_arguments:
behave_args = args.advanced_arguments.split()
behave_main(behave_args)
print('# All tests are finished.')
2020-01-17 12:52:55 +11:00
def generate_report(args):
print('# Generating HTML reports now.')
if not os.path.exists('report'):
os.mkdir('report')
2020-01-17 12:52:55 +11:00
if not os.path.exists(args.junit_directory):
os.mkdir(args.junit_directory)
for file in os.listdir(args.junit_directory):
if not file.endswith('.xml'):
continue
print(f'Processing {file} ...')
2020-01-17 14:13:11 +11:00
root = ET.parse('{}{}'.format(args.junit_directory, 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:4] in ['Give', 'Then', 'When', 'And ']:
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
})
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': 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:
out.write(pystache.render(template.read(), data))
class TestPurger:
def __init__(self):
self.file = None
def purge(self):
for filename in Path('features/').glob('*.feature'):
with open(filename, 'r') as feature_file:
old_file = feature_file.readlines()
with open(filename, 'w') as new_file:
for line in old_file:
is_purged = False
if 'Given the IFC file ' in line and 'exists' not in line:
filename = line.split('"')[1]
print('Loading file {} ...'.format(filename))
self.file = ifcopenshell.open(filename)
if line.strip()[0:4] == 'Then':
words = line.strip().split()
for word in words:
if self.is_a_global_id(word):
if not self.does_global_id_exist(word):
print('Test for {} purged ...'.format(word))
is_purged = True
if not is_purged:
new_file.write(line)
def is_a_global_id(self, word):
return word[0] in ['0', '1', '2', '3'] and len(word) == 22
def does_global_id_exist(self, global_id):
try:
self.file.by_guid(global_id)
return True
except:
return False
parser = argparse.ArgumentParser(
description='Runs unit tests for BIM data')
parser.add_argument(
'-p',
'--purge',
action='store_true',
help='Purge tests of deleted elements')
parser.add_argument(
'-r',
'--report',
action='store_true',
help='Generate a HTML report')
2020-01-17 12:52:55 +11:00
parser.add_argument(
'-j',
'--junit-directory',
type=str,
help='Specify your own JUnit directory',
default='junit/')
parser.add_argument(
'-f',
'--feature',
type=str,
help='Specify a feature to test',
default='features')
parser.add_argument(
'-a',
'--advanced-arguments',
type=str,
help='Specify your own arguments to Python\'s Behave',
default='')
args = parser.parse_args()
if not os.path.exists('features'):
2020-01-10 18:24:05 +11:00
sys.exit('''
BIMTester requires a features folder to exist within the current folder.
Visit https://blenderbim.org/ to learn more about how to use BIMTester.
''')
if args.purge:
TestPurger().purge()
elif args.report:
generate_report(args)
else:
run_tests(args)
print('# All tasks are complete :-)')