More Qto tests and you can now spy on UILists and enum items

This commit is contained in:
Dion Moult
2024-08-24 21:39:41 +10:00
parent daa6b31c5d
commit c7a8fd9309
3 changed files with 121 additions and 31 deletions
+46 -15
View File
@@ -5,29 +5,33 @@ Scenario: Calculate circle radius
Given an empty Blender session
And I add a cube
And the object "Cube" is selected
When I press "bim.calculate_circle_radius"
Then "scene.BIMQtoProperties.qto_result" is "1.732"
And I look at the "Simple Quantity Calculator" panel
When I click "Calculate Circle Radius"
Then I see the "Results" property is "1.732"
Scenario: Calculate edge lengths
Given an empty Blender session
And I add a cube
And the object "Cube" is selected
When I press "bim.calculate_edge_lengths"
Then "scene.BIMQtoProperties.qto_result" is "24.0"
And I look at the "Simple Quantity Calculator" panel
When I click "Calculate Edge Lengths"
Then I see the "Results" property is "24.0"
Scenario: Calculate face areas
Given an empty Blender session
And I add a cube
And the object "Cube" is selected
When I press "bim.calculate_face_areas"
Then "scene.BIMQtoProperties.qto_result" is "24.0"
And I look at the "Simple Quantity Calculator" panel
When I click "Calculate Face Areas"
Then I see the "Results" property is "24.0"
Scenario: Calculate object volumes
Given an empty Blender session
And I add a cube
And the object "Cube" is selected
When I press "bim.calculate_object_volumes"
Then "scene.BIMQtoProperties.qto_result" is "8.0"
And I look at the "Simple Quantity Calculator" panel
When I click "Calculate Object Volumes"
Then I see the "Results" property is "8.0"
Scenario: Execute qto method - formwork areas
Given an empty Blender session
@@ -45,13 +49,40 @@ Scenario: Execute qto method - side formwork areas
When I press "bim.calculate_side_formwork_area"
Then "scene.BIMQtoProperties.qto_result" is "16.0"
Scenario: Calculate all quantities
Scenario: Perform quantity take-off - no objects
Given an empty IFC project
When I look at the "Quantity Take-off" panel
Then I see "Quantifying All Objects"
When I click "Perform Quantity Take-off"
Then nothing happens
Scenario: Perform quantity take-off
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I press "bim.assign_class(ifc_class='IfcWall', predefined_type='SOLIDWALL')"
When I press "bim.perform_quantity_take_off"
And the variable "qset_id" is "{ifc}.by_type('IfcElementQuantity')[0].id()"
And I press "bim.enable_pset_editing(pset_id={qset_id}, obj='IfcWall/Cube', obj_type='Object')"
Then "active_object.PsetProperties.active_pset_name" is "Qto_WallBaseQuantities"
And "active_object.PsetProperties.properties['Length'].metadata.float_value" is roughly "2000.0"
And I look at the "Class" panel
And I set the "Products" property to "IfcElement"
And I set the "Class" property to "IfcWall"
And I click "Assign IFC Class"
And I look at the "Quantity Take-off" panel
When I see "Quantifying 1 Selected Objects"
And I click "Perform Quantity Take-off"
When I look at the "Quantity Sets" panel
Then I see "Qto_WallBaseQuantities"
And I see "NetVolume"
Scenario: Perform quantity take-off - using Blender engine
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I look at the "Class" panel
And I set the "Products" property to "IfcElement"
And I set the "Class" property to "IfcWall"
And I click "Assign IFC Class"
And I look at the "Quantity Take-off" panel
When I set the "qto_rule" property to "IFC4 Base Quantities - Blender"
And I see "Quantifying 1 Selected Objects"
And I click "Perform Quantity Take-off"
When I look at the "Quantity Sets" panel
Then I see "Qto_WallBaseQuantities"
And I see "NetVolume"
+3 -3
View File
@@ -26,21 +26,21 @@ Scenario: Colour by property - default class query
Given an empty IFC project
When I look at the "Colour By Property" panel
And I click "Colour by Property"
Then nothing happens
Then the "BIM_UL_colourscheme" list has 4 items
Scenario: Colour by property - no query
Given an empty IFC project
When I look at the "Colour By Property" panel
And I set the "Query" property to " "
And I click "Colour by Property" and expect error "Error: No Query Provided"
Then nothing happens
Then I don't see the "BIM_UL_colourscheme" list
Scenario: Reset colours
Given an empty IFC project
And I look at the "Colour By Property" panel
And I click "Colour by Property"
When I click "Reset Colours"
Then nothing happens
Then I don't see the "BIM_UL_colourscheme" list
Scenario: Flat colours
Given an empty IFC project
+72 -13
View File
@@ -60,6 +60,7 @@ class PanelSpy:
self.spied_labels = []
self.spied_props = []
self.spied_operators = []
self.spied_lists = []
self.panel.draw(self, bpy.context)
def __getattr__(self, attr):
@@ -72,7 +73,17 @@ class PanelSpy:
if self.spied_attr in ("row", "column", "box"):
return self
elif self.spied_attr == "template_list":
return lambda *args, **kwargs: None # Handle UI list spies
listtype_name, list_id, dataptr, propname, active_dataptr, active_propname = args
spied_data = {
"listtype_name": listtype_name,
"list_id": list_id,
"dataptr": dataptr,
"propname": propname,
"active_dataptr": active_dataptr,
"active_propname": active_propname,
}
self.spied_lists.append(spied_data)
return TemplateListSpy(spied_data)
elif self.spied_attr == "context_pointer_set":
return lambda *args, **kwargs: None
elif self.spied_attr == "label":
@@ -82,10 +93,29 @@ class PanelSpy:
props, name = args
text = kwargs.get("text", props.bl_rna.properties[name].name)
icon = kwargs.get("icon", None)
prop_type = props.bl_rna.properties[name].type
enum_items = []
if prop_type == "ENUM":
prop_keywords = props.__annotations__[name].keywords
items = prop_keywords.get("items")
if items is not None:
if isinstance(items, (list, tuple)):
enum_items = items
else:
# items are retrieved through a callback, not a static list / tuple :
enum_items = items(props, bpy.context)
value = getattr(props, name)
if text:
self.spied_labels.append(text)
spied_prop = {"props": props, "name": name, "text": text, "icon": icon, "value": value}
spied_prop = {
"props": props,
"name": name,
"text": text,
"icon": icon,
"value": value,
"prop_type": prop_type,
"enum_items": enum_items,
}
self.spied_props.append(spied_prop)
elif self.spied_attr == "operator":
operator = args[0]
@@ -116,6 +146,11 @@ class OperatorSpy:
self.spied_data["kwargs"][name] = value
class TemplateListSpy:
def __init__(self, spied_data):
self.spied_data = spied_data
panel_name_cache = {}
panel_spy = None
@@ -215,6 +250,14 @@ def i_dont_see_text(text):
assert not [l for l in panel_spy.spied_labels if text in l], f"Text {text} found in {panel_spy.spied_labels}"
@given(parsers.parse('I don\'t see the "{name}" list'))
@when(parsers.parse('I don\'t see the "{name}" list'))
@then(parsers.parse('I don\'t see the "{name}" list'))
def i_dont_see_the_name_list(name):
panel_spy.refresh_spy()
assert name not in [l["listtype_name"] for l in panel_spy.spied_lists]
@given(parsers.parse('I see the "{prop}" property'))
@when(parsers.parse('I see the "{prop}" property'))
@then(parsers.parse('I see the "{prop}" property'))
@@ -257,23 +300,39 @@ def i_set_the_prop_property_to_value(prop, value):
panel_spy.refresh_spy()
for spied_prop in panel_spy.spied_props:
if prop in (spied_prop["name"], spied_prop["text"], spied_prop["icon"]):
if value == "TRUE":
setattr(spied_prop["props"], spied_prop["name"], True)
elif value == "FALSE":
setattr(spied_prop["props"], spied_prop["name"], False)
if spied_prop["prop_type"] == "BOOLEAN":
if value == "TRUE":
setattr(spied_prop["props"], spied_prop["name"], True)
elif value == "FALSE":
setattr(spied_prop["props"], spied_prop["name"], False)
elif spied_prop["prop_type"] == "FLOAT":
setattr(spied_prop["props"], spied_prop["name"], float(value))
elif spied_prop["prop_type"] == "INTEGER":
setattr(spied_prop["props"], spied_prop["name"], int(value))
elif spied_prop["prop_type"] == "ENUM":
enum_identifier = [i for i in spied_prop["enum_items"] if i[1] == value]
if not enum_identifier:
assert False, f"Could not find value {value} in enum {spied_prop['enum_items']}"
setattr(spied_prop["props"], spied_prop["name"], enum_identifier[0][0])
else:
try:
setattr(spied_prop["props"], spied_prop["name"], value)
except:
try:
setattr(spied_prop["props"], spied_prop["name"], int(value))
except:
setattr(spied_prop["props"], spied_prop["name"], float(value))
setattr(spied_prop["props"], spied_prop["name"], value)
panel_spy.is_spy_dirty = True
return
assert False, f"Property {prop} not found in {panel_spy.spied_props}"
@then(parsers.parse('The "{name}" list has {total} items'))
def the_name_list_has_total_items(name, total):
total = int(total)
panel_spy.refresh_spy()
for spied_list in panel_spy.spied_lists:
if name == spied_list["listtype_name"]:
actual_total = len(getattr(spied_list["dataptr"], spied_list["propname"]))
assert actual_total == total, f"The actual number of items in {name} is {actual_total} not {total}"
return
assert False, f"List {name} not found in {panel_spy.spied_lists}"
@when("I load a new pset template file")
def i_load_a_new_pset_template_file():
IfcStore.pset_template_path = bpy.context.scene.BIMPsetTemplateProperties.pset_template_files