BIMTester now operates on single feature files, which heavily improves usability

This commit is contained in:
Dion Moult
2021-02-02 12:34:14 +11:00
parent 1f4df32d04
commit ac95fb1aa2
20 changed files with 401 additions and 978 deletions
@@ -1,3 +0,0 @@
# dummy file to be able to run the command to get a list of all steps
# the command has to be run in the parent directory of this one
# behave --steps-catalog
@@ -1,28 +1,28 @@
import os
from behave.model import Scenario
from logfile import create_logfile
from logfile import append_logfile
from zoom_smart_view import append_zoom_smartview
from zoom_smart_view import create_zoom_smartview
from bimtester.ifc import IfcStore
from bimtester.lang import switch_locale
this_path = os.path.dirname(os.path.realpath(__file__))
def before_all(context):
# get from userdata
userdata = context.config.userdata
context.localedir = userdata.get("localedir")
context.ifcfile = userdata["ifcfile"]
context.ifcbasename = os.path.basename(
os.path.splitext(context.ifcfile)[0]
if context.config.lang:
switch_locale(userdata.get("localedir"), context.config.lang)
context.ifc_path = userdata["ifc"]
context.ifc_basename = os.path.basename(
os.path.splitext(context.ifc_path)[0]
)
# do not break after a failed scenario
# https://community.osarch.org/discussion/comment/3328/#Comment_3328
continue_after_failed = userdata.getbool(
"runner.continue_after_failed_step", True
)
@@ -37,21 +37,21 @@ def before_all(context):
# set up log file
context.thelogfile = os.path.join(
context.outpath,
context.ifcbasename + ".log"
context.ifc_basename + ".log"
)
create_logfile(
context.thelogfile,
context.ifcbasename,
context.ifc_basename,
)
# set up smart view file
context.smview_file = os.path.join(
context.outpath,
context.ifcbasename + ".bcsv"
context.ifc_basename + ".bcsv"
)
create_zoom_smartview(
context.smview_file,
context.ifcbasename,
context.ifc_basename,
)
@@ -1,20 +1,16 @@
import gettext # noqa
import gettext
from behave import given
from behave import step
import ifcdata_methods as idm
from utils import IfcFile
from utils import switch_locale
the_lang = "en"
from bimtester.ifc import IfcStore
from bimtester.lang import _
@step('The IFC schema "{schema}" must be provided')
def step_impl(context, schema):
try:
if context.config.userdata.get('path'):
schema = os.path.join(context.config.userdata.get('path'), schema)
if context.config.userdata.get("path"):
schema = os.path.join(context.config.userdata.get("path"), schema)
IfcFile.load_schema(schema)
except:
assert False, f"The schema {schema} could not be loaded"
@@ -28,25 +24,11 @@ def step_impl(context, file):
assert False, f"The file {file} could not be loaded"
@given("The IFC file has been provided through an argument")
def step_impl(context):
switch_locale(context.localedir, the_lang)
idm.provide_ifcfile_by_argument(context)
@given('A file path has been provided through an argument')
def step_impl(context):
try:
assert context.config.userdata.get("path")
except:
assert False, f"The path {context.config.userdata.get('path')} could not be loaded"
@step("IFC data must use the {schema} schema")
def step_impl(context, schema):
switch_locale(context.localedir, the_lang)
idm.has_ifcdata_specific_schema(context, schema)
real_schema = IfcStore.file.schema
assert real_schema == schema, _("We expected a schema of {} but instead got {}").format(schema, real_schema)
@step('The IFC file "{file}" is exempt from being provided')
def step_impl(context, file):
@@ -61,41 +43,43 @@ def step_impl(context, reason):
@step("The IFC file must be exported by application full name {fullname}")
def step_impl(context, fullname):
real_fullname = IfcFile.get().by_type("IfcApplication")[0].ApplicationFullName
assert real_fullname == fullname , (
real_fullname = IfcStore.file.by_type("IfcApplication")[0].ApplicationFullName
assert real_fullname == fullname, (
"The IFC file was not exported by application full name {} "
"instead it was exported by application full name {}"
.format(fullname, real_fullname)
"instead it was exported by application full name {}".format(fullname, real_fullname)
)
@step("The IFC file must be exported by application identifier {identifier}")
def step_impl(context, identifier):
real_identifier = IfcFile.get().by_type("IfcApplication")[0].ApplicationIdentifier
assert real_identifier == identifier , (
"The IFC file was not exported by application identifier {} "
"instead it was exported by identifier {}"
.format(identifier, real_identifier)
real_identifier = IfcStore.file.by_type("IfcApplication")[0].ApplicationIdentifier
assert (
real_identifier == identifier
), "The IFC file was not exported by application identifier {} " "instead it was exported by identifier {}".format(
identifier, real_identifier
)
@step("The IFC file must be exported by the application version {version}")
def step_impl(context, version):
real_version = IfcFile.get().by_type("IfcApplication")[0].Version
assert real_version == version , (
"The IFC file was not exported by application version {} "
"instead it was exported by version {}"
.format(version, real_version)
real_version = IfcStore.file.by_type("IfcApplication")[0].Version
assert (
real_version == version
), "The IFC file was not exported by application version {} " "instead it was exported by version {}".format(
version, real_version
)
@step("IFC data header must have a file description of {header_file_description} such as the new Allplan IFC exporter creates it")
@step(
"IFC data header must have a file description of {header_file_description} such as the new Allplan IFC exporter creates it"
)
def step_impl(context, header_file_description):
is_header_file_description = IfcFile.get().wrapped_data.header.file_description.description
assert str(is_header_file_description) == header_file_description , (
"The file was not exported by the new ifc exporter in Allplan. File description header: {}"
.format(is_header_file_description)
is_header_file_description = IfcStore.file.wrapped_data.header.file_description.description
assert (
str(is_header_file_description) == header_file_description
), "The file was not exported by the new ifc exporter in Allplan. File description header: {}".format(
is_header_file_description
)
@@ -1,19 +1,6 @@
from behave import step
import ifcdata_methods as idm
from utils import switch_locale
the_lang = "de"
@given("Die IFC-Datei wurde durch einen Startparameter zur Verfügung gestellt")
def step_impl(context):
switch_locale(context.localedir, the_lang)
idm.provide_ifcfile_by_argument(context)
@step("Die IFC-Daten müssen das {schema} Schema benutzen")
def step_impl(context, schema):
switch_locale(context.localedir, the_lang)
idm.has_ifcdata_specific_schema(context, schema)
context.execute_steps(f"* IFC data must use the {schema} schema")
@@ -1,22 +1,6 @@
from behave import step
import ifcdata_methods as idm
from utils import switch_locale
the_lang = "fr"
"""
# TODO the next line needs translation
@given("The IFC file has been provided through an argument")
def step_impl(context):
switch_locale(context.localedir, the_lang)
idm.provide_ifcfile_by_argument(context)
"""
@step("Les données IFC doivent utiliser le schéma {schema}")
def step_impl(context, schema):
switch_locale(context.localedir, the_lang)
idm.has_ifcdata_specific_schema(context, schema)
context.execute_steps(f"* IFC data must use the {schema} schema")
@@ -1,19 +1,6 @@
from behave import step
import ifcdata_methods as idm
from utils import switch_locale
the_lang = "it"
@given("Il file IFC è stato fornito attraverso un argumento")
def step_impl(context):
switch_locale(context.localedir, the_lang)
idm.provide_ifcfile_by_argument(context)
@step("I dati IFC devono seguire lo schema {schema}")
def step_impl(context, schema):
switch_locale(context.localedir, the_lang)
idm.has_ifcdata_specific_schema(context, schema)
context.execute_steps(f"* IFC data must use the {schema} schema")
@@ -1,19 +0,0 @@
from utils import IfcFile
def provide_ifcfile_by_argument(context):
try:
IfcFile.load(context.config.userdata.get("ifcfile"))
except:
assert False, (
_("The IFC {} file could not be loaded")
.format(context.config.userdata.get('ifcfile'))
)
def has_ifcdata_specific_schema(context, target_schema):
real_schema = IfcFile.get().schema
assert real_schema == target_schema, (
_("We expected a schema of {} but instead got {}")
.format(target_schema, real_schema)
)
@@ -1,22 +1,6 @@
from behave import step
import ifcdata_methods as idm
from utils import switch_locale
the_lang = "nl"
"""
# TODO the next line needs translation
@given("The IFC file has been provided through an argument")
def step_impl(context):
switch_locale(context.localedir, the_lang)
idm.provide_ifcfile_by_argument(context)
"""
@step("IFC-gegevens moeten het {schema} -schema gebruiken")
def step_impl(context, schema):
switch_locale(context.localedir, the_lang)
idm.has_ifcdata_specific_schema(context, schema)
context.execute_steps(f"* IFC data must use the {schema} schema")
@@ -2,36 +2,37 @@ from behave import step
from utils import assert_attribute
from utils import IfcFile
from bimtester.ifc import IfcStore
@step("The project must have an identifier of {guid}")
def step_impl(context, guid):
assert_attribute(IfcFile.get().by_type("IfcProject")[0], "GlobalId", guid)
assert_attribute(IfcStore.file.by_type("IfcProject")[0], "GlobalId", guid)
@step('The project name, code, or short identifier must be "{value}"')
def step_impl(context, value):
assert_attribute(IfcFile.get().by_type("IfcProject")[0], "Name", value)
assert_attribute(IfcStore.file.by_type("IfcProject")[0], "Name", value)
@step('The project must have a longer form name of "{value}"')
def step_impl(context, value):
assert_attribute(IfcFile.get().by_type("IfcProject")[0], "LongName", value)
assert_attribute(IfcStore.file.by_type("IfcProject")[0], "LongName", value)
@step('The project must be described as "{value}"')
def step_impl(context, value):
assert_attribute(IfcFile.get().by_type("IfcProject")[0], "Description", value)
assert_attribute(IfcStore.file.by_type("IfcProject")[0], "Description", value)
@step('The project must be categorised under "{value}"')
def step_impl(context, value):
assert_attribute(IfcFile.get().by_type("IfcProject")[0], "ObjectType", value)
assert_attribute(IfcStore.file.by_type("IfcProject")[0], "ObjectType", value)
@step('The project must contain information about the "{value}" phase')
def step_impl(context, value):
assert_attribute(IfcFile.get().by_type("IfcProject")[0], "Phase", value)
assert_attribute(IfcStore.file.by_type("IfcProject")[0], "Phase", value)
@step("The project must contain 3D geometry representing the shape of objects")
@@ -4,7 +4,6 @@ import ifcopenshell.express
import ifcopenshell.util
import ifcopenshell.util.element
class IfcFile(object):
file = None
bookmarks = {}
@@ -14,7 +13,7 @@ class IfcFile(object):
cls.file = ifcopenshell.open(path)
if not cls.file:
assert False
@classmethod
def load_schema(cls, path=None):
schema = ifcopenshell.express.parse(path)
@@ -32,7 +31,7 @@ class IfcFile(object):
return cls.get().by_guid(guid)
except:
assert False, "An element with the ID {} could not be found.".format(guid)
@classmethod
def by_type(cls, ifc_type):
return cls.get().by_type(ifc_type.strip())
@@ -108,60 +107,36 @@ def assert_elements(
message_all_falseelems,
message_some_falseelems,
message_no_elems,
parameter=None
parameter=None,
):
if elemcount > 0 and falsecount == 0:
return # Test OK
elif elemcount == 0:
assert False, (
message_no_elems.format(
ifc_class=ifc_class
)
)
assert False, message_no_elems.format(ifc_class=ifc_class)
elif falsecount == elemcount:
if parameter is None:
assert False, (
message_all_falseelems.format(
elemcount=elemcount,
ifc_class=ifc_class
)
)
assert False, message_all_falseelems.format(elemcount=elemcount, ifc_class=ifc_class)
else:
assert False, (
message_all_falseelems.format(
elemcount=elemcount,
ifc_class=ifc_class,
parameter=parameter
)
)
assert False, message_all_falseelems.format(elemcount=elemcount, ifc_class=ifc_class, parameter=parameter)
elif falsecount > 0 and falsecount < elemcount:
if parameter is None:
assert False, (
message_some_falseelems.format(
falsecount=falsecount,
elemcount=elemcount,
ifc_class=ifc_class,
falseelems=falseelems,
)
assert False, message_some_falseelems.format(
falsecount=falsecount,
elemcount=elemcount,
ifc_class=ifc_class,
falseelems=falseelems,
)
else:
assert False, (
message_some_falseelems.format(
falsecount=falsecount,
elemcount=elemcount,
ifc_class=ifc_class,
falseelems=falseelems,
parameter=parameter
)
assert False, message_some_falseelems.format(
falsecount=falsecount,
elemcount=elemcount,
ifc_class=ifc_class,
falseelems=falseelems,
parameter=parameter,
)
else:
assert False, _("Error in falsecount, something went wrong.")
def switch_locale(locale_dir, locale_id="en"):
newlang = gettext.translation(
"messages",
localedir=locale_dir,
languages=[locale_id]
)
newlang.install()
pass