File size: 7,908 Bytes
985c397
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
"""GUI tests for ArchReport features that require a running FreeCAD GUI.

These tests inherit from the GUI test base `TestArchBaseGui` which skips
the whole class when `FreeCAD.GuiUp` is False.
"""

import FreeCAD
import Arch
import FreeCADGui
import ArchReport

from bimtests.TestArchBaseGui import TestArchBaseGui


class TestArchReportGui(TestArchBaseGui):
    """GUI-enabled tests ported from TestArchReport.

    These tests rely on Qt widgets and the BIM workbench UI panels.
    """

    def setUp(self):
        super().setUp()
        self.doc = self.document
        self.panel = None

        # Recreate the same minimal scene that TestArchReport.setUp creates
        self.wall_ext = Arch.makeWall(length=1000, name="Exterior Wall")
        self.wall_ext.IfcType = "Wall"
        self.wall_ext.Height = FreeCAD.Units.Quantity(3000, "mm")

        self.wall_int = Arch.makeWall(length=500, name="Interior partition wall")
        self.wall_int.IfcType = "Wall"
        self.wall_int.Height = FreeCAD.Units.Quantity(2500, "mm")

        self.column = Arch.makeStructure(length=300, width=330, height=2000, name="Main Column")
        self.column.IfcType = "Column"

        self.beam = Arch.makeStructure(length=2000, width=200, height=400, name="Main Beam")
        self.beam.IfcType = "Beam"

        self.window = Arch.makeWindow(name="Living Room Window")
        self.window.IfcType = "Window"

        self.part_box = self.doc.addObject("Part::Box", "Generic Box")

        # Spreadsheet used by some report features
        self.spreadsheet = self.doc.addObject("Spreadsheet::Sheet", "ReportTarget")
        self.doc.recompute()

    def tearDown(self):
        # This method is automatically called after EACH test function.
        if self.panel:
            # If a panel was created, ensure it is closed.
            FreeCADGui.Control.closeDialog()
            self.panel = None  # Clear the reference
        super().tearDown()

    def test_cheatsheet_dialog_creation(self):
        """Tests that the Cheatsheet dialog can be created without errors."""
        api_data = Arch.getSqlApiDocumentation()
        dialog = ArchReport.CheatsheetDialog(api_data)
        self.assertIsNotNone(dialog)

    def DISABLED_test_preview_pane_toggle_and_refresh(self):
        """
        Tests the user workflow for the preview pane: toggling visibility,
        refreshing with a valid query, and checking the results.
        This replaces the obsolete test_task_panel_on_demand_preview.
        """
        # 1. Arrange: Create a report object and the task panel.
        report_obj = Arch.makeReport(name="PreviewToggleTestReport")
        self.panel = ArchReport.ReportTaskPanel(report_obj)
        # Open the editor for the first (default) statement.
        self.panel._start_edit_session(row_index=0)

        # 2. Assert Initial State: The preview pane should be hidden.
        self.assertFalse(
            self.panel.preview_pane.isVisible(), "Preview pane should be hidden by default."
        )

        # 3. Act: Toggle the preview pane to show it.
        # A user click on a checkable button toggles its checked state.
        self.panel.btn_toggle_preview.setChecked(True)
        self.pump_gui_events()

        # 4. Assert Visibility: The pane and its contents should now be visible.
        self.assertTrue(
            self.panel.preview_pane.isVisible(),
            "Preview pane should be visible after toggling it on.",
        )
        self.assertEqual(
            self.panel.btn_toggle_preview.text(),
            "Hide Preview",
            "Button text should update to 'Hide Preview'.",
        )
        self.assertTrue(
            self.panel.btn_refresh_preview.isVisible(),
            "Refresh button should be visible when pane is open.",
        )

        # 5. Act: Set a valid query and refresh the preview.
        query = "SELECT Label, IfcType FROM document WHERE IfcType = 'Wall' ORDER BY Label"
        self.panel.sql_query_edit.setPlainText(query)
        self.panel.btn_refresh_preview.click()
        self.pump_gui_events()

        # 6. Assert Correctness: The preview table should be populated correctly.
        self.assertEqual(
            self.panel.table_preview_results.columnCount(),
            2,
            "Preview table should have 2 columns for the valid query.",
        )
        self.assertEqual(
            self.panel.table_preview_results.rowCount(),
            2,
            "Preview table should have 2 rows for the two wall objects.",
        )
        # Check cell content to confirm the query ran correctly.
        self.assertEqual(self.panel.table_preview_results.item(0, 0).text(), self.wall_ext.Label)
        self.assertEqual(self.panel.table_preview_results.item(1, 1).text(), self.wall_int.IfcType)

        # 7. Act: Toggle the preview pane to hide it again.
        self.panel.btn_toggle_preview.setChecked(False)
        self.pump_gui_events()

        # 8. Assert Final State: The pane should be hidden.
        self.assertFalse(
            self.panel.preview_pane.isVisible(),
            "Preview pane should be hidden after toggling it off.",
        )
        self.assertEqual(
            self.panel.btn_toggle_preview.text(),
            "Show Preview",
            "Button text should revert to 'Show Preview'.",
        )

    def DISABLED_test_preview_pane_displays_errors_gracefully(self):
        """
        Tests that the preview pane displays a user-friendly error message when
        the query is invalid, instead of raising an exception.
        This replaces the obsolete test_preview_button_handles_errors_gracefully_in_ui.
        """
        # 1. Arrange: Create the report and panel, then open the editor and preview.
        report_obj = Arch.makeReport(name="PreviewErrorTestReport")
        self.panel = ArchReport.ReportTaskPanel(report_obj)
        self.panel._start_edit_session(row_index=0)
        self.panel.btn_toggle_preview.setChecked(True)
        self.pump_gui_events()

        # 2. Act: Set an invalid query and click the refresh button.
        invalid_query = "SELECT Label FRM document"  # Deliberate syntax error
        self.panel.sql_query_edit.setPlainText(invalid_query)
        self.panel.btn_refresh_preview.click()
        self.pump_gui_events()

        # 3. Assert: The preview table should be visible and display the error.
        self.assertTrue(
            self.panel.table_preview_results.isVisible(),
            "Preview table should remain visible to display the error.",
        )
        self.assertEqual(
            self.panel.table_preview_results.rowCount(),
            1,
            "Error display should occupy a single row.",
        )
        self.assertEqual(
            self.panel.table_preview_results.columnCount(),
            1,
            "Error display should occupy a single column.",
        )

        error_item = self.panel.table_preview_results.item(0, 0)
        self.assertIsNotNone(error_item, "An error item should have been placed in the table.")
        # Check for keywords that indicate a graceful error message.
        self.assertIn(
            "Syntax Error", error_item.text(), "The error message should indicate a syntax error."
        )
        self.assertIn(
            "❌", error_item.text(), "The error message should contain a visual error indicator."
        )

    def test_hover_tooltips(self):
        """Tests that the SQL editor can generate tooltips."""
        editor = ArchReport.SqlQueryEditor()
        api_docs = Arch.getSqlApiDocumentation()
        editor.set_api_documentation(api_docs)

        func_tooltip = editor._get_tooltip_for_word("CONVERT")
        self.assertIn("CONVERT(quantity, 'unit')", func_tooltip)
        self.assertIn("Utility", func_tooltip)

        clause_tooltip = editor._get_tooltip_for_word("SELECT")
        self.assertIn("SQL Clause", clause_tooltip)