From cd411e1f14dad8bc285275b35be3df6d2062ce63 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 24 Aug 2024 14:20:13 +1000 Subject: [PATCH] Add smoke tests for colour by property feature --- src/bonsai/bonsai/bim/module/search/data.py | 7 ++- .../bonsai/bim/module/search/operator.py | 1 + src/bonsai/test/bim/feature/search.feature | 57 ++++++++++++++++--- src/bonsai/test/bim/test_feature.py | 29 +++++++++- 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/search/data.py b/src/bonsai/bonsai/bim/module/search/data.py index f1985cb802..c82f26e7d6 100644 --- a/src/bonsai/bonsai/bim/module/search/data.py +++ b/src/bonsai/bonsai/bim/module/search/data.py @@ -84,12 +84,13 @@ class ColourByPropertyData: @classmethod def colourscheme_key(cls): + default = [("QUERY", "Custom Query", "Specify a custom query to colour by"), None] obj = bpy.context.active_object if not obj: - return [] + return default element = tool.Ifc.get_entity(obj) if not element: - return [] + return default keys = [a.name() for a in element.wrapped_data.declaration().as_entity().all_attributes()] psets = ifcopenshell.util.element.get_psets(element) for pset, properties in psets.items(): @@ -100,7 +101,7 @@ class ColourByPropertyData: else: keys.extend([f"{pset}.{name}" for name in properties.keys() if name != "id"]) results = [(k, k, "") for k in keys] - return [("QUERY", "Custom Query", "Specify a custom query to colour by"), None] + results + return default + results class SelectSimilarData: diff --git a/src/bonsai/bonsai/bim/module/search/operator.py b/src/bonsai/bonsai/bim/module/search/operator.py index af0df4148c..7b7b90db38 100644 --- a/src/bonsai/bonsai/bim/module/search/operator.py +++ b/src/bonsai/bonsai/bim/module/search/operator.py @@ -124,6 +124,7 @@ class EditFilterQuery(Operator, tool.Ifc.Operator): bl_description = "Edit the underlying filter query for advanced users" bl_options = {"REGISTER", "UNDO"} query: StringProperty(name="Query") + old_query: StringProperty(name="Old Query") module: StringProperty() def _execute(self, context): diff --git a/src/bonsai/test/bim/feature/search.feature b/src/bonsai/test/bim/feature/search.feature index 18bef26f3f..6d40e71e1a 100644 --- a/src/bonsai/test/bim/feature/search.feature +++ b/src/bonsai/test/bim/feature/search.feature @@ -5,12 +5,53 @@ Scenario: Select all walls Given an empty IFC project And I add a cube And the object "Cube" is selected - And I set "scene.BIMRootProperties.ifc_product" to "IfcElement" - And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" - And I press "bim.assign_class" - And I press "bim.add_filter_group(module='search')" - And I set "scene.BIMSearchProperties.facet" to "entity" - And I press "bim.add_filter(index=0, type='entity', module='search')" - And I set "scene.BIMSearchProperties.filter_groups[0].filters[0].value" to "IfcWall" - When I press "bim.search(property_group='BIMSearchProperties')" + 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" + When I look at the "Search" panel + And I click "Add Search Group" + And I click "Add Filter" + And I set the "FILE_3D" property to "IfcWall" + And I click "Search" Then the object "IfcWall/Cube" is selected + +Scenario: Edit filter query + Given an empty IFC project + When I look at the "Search" panel + And I click "FILTER" + Then nothing happens + +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 + +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 + +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 + +Scenario: Flat colours + Given an empty IFC project + And I look at the "Colour By Property" panel + And I click "Colour by Property" + When I click "SHADING_RENDERED" + Then nothing happens + +Scenario: Select by property + Given an empty IFC project + And I look at the "Colour By Property" panel + And I click "Colour by Property" + When I click "RESTRICT_SELECT_OFF" + Then nothing happens diff --git a/src/bonsai/test/bim/test_feature.py b/src/bonsai/test/bim/test_feature.py index 8d476ab80b..5ef289d1a7 100644 --- a/src/bonsai/test/bim/test_feature.py +++ b/src/bonsai/test/bim/test_feature.py @@ -71,6 +71,10 @@ class PanelSpy: def __call__(self, *args, **kwargs): 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 + elif self.spied_attr == "context_pointer_set": + return lambda *args, **kwargs: None elif self.spied_attr == "label": self.spied_labels.append(kwargs["text"]) return self @@ -105,7 +109,10 @@ class OperatorSpy: self.spied_data = spied_data def __setattr__(self, name, value): - if name != "spied_data": + if name == "spied_data": + # Allow direct setting of spied_data only during initialization + super().__setattr__(name, value) + else: self.spied_data["kwargs"][name] = value @@ -186,6 +193,8 @@ def i_look_at_the_panel_panel(panel): panel_name_cache[panel_type.bl_label] = panel_type.bl_idname except: pass + if panel not in panel_name_cache: + assert False, f"Panel {panel} not found in {panel_name_cache}" panel_spy = PanelSpy(getattr(bpy.types, panel_name_cache[panel])) panel_spy.refresh_spy() @@ -244,6 +253,7 @@ def i_see_the_prop_property_is_value(prop, value): @when(parsers.parse('I set the "{prop}" property to "{value}"')) @then(parsers.parse('I set the "{prop}" property to "{value}"')) def i_set_the_prop_property_to_value(prop, value): + value = value.strip() panel_spy.refresh_spy() for spied_prop in panel_spy.spied_props: if prop in (spied_prop["name"], spied_prop["text"], spied_prop["icon"]): @@ -390,7 +400,7 @@ def i_click_button(button): panel_spy.refresh_spy() for spied_operator in panel_spy.spied_operators: if spied_operator["text"] == button or spied_operator["icon"] == button: - spied_operator["operator"](**spied_operator["kwargs"]) + spied_operator["operator"]("INVOKE_DEFAULT", **spied_operator["kwargs"]) panel_spy.is_spy_dirty = True return # Users can also "click" on booleans to toggle them @@ -402,6 +412,21 @@ def i_click_button(button): assert False, f"Could not find {button} in {panel_spy.spied_operators}" +@given(parsers.parse('I click "{button}" and expect error "{error_msg}"')) +@when(parsers.parse('I click "{button}" and expect error "{error_msg}"')) +def i_click_button_and_expect_error_error_msg(button, error_msg): + try: + i_click_button(button) + except Exception as e: + actual_error_msg = str(e).strip() + if str(e).strip() != error_msg: + traceback.print_exc() + msg = f"Got different exception clickign {button} - '{actual_error_msg}' instead of '{error_msg}'" + assert False, msg + return + assert False, f"No error message {error_msg} raised when I pressed {button}" + + @given(parsers.parse('I evaluate expression "{expression}"')) @when(parsers.parse('I evaluate expression "{expression}"')) def i_evaluate_expression(expression):