diff --git a/check_mma.py b/check_mma.py new file mode 100644 index 0000000..6d5b834 --- /dev/null +++ b/check_mma.py @@ -0,0 +1,28 @@ +from unittest.mock import MagicMock, patch +from src.gui_2 import App +import sys + +app = MagicMock() +app.mma_streams = {} +app._pending_mma_spawns = [{"ticket_id": "T-001"}] +app._pending_mma_approvals = [] +app._pending_ask_dialog = False +app.is_viewing_prior_session = False +app.mma_status = "idle" +app.active_track = None +app.active_tickets = [] +app.mma_tier_usage = { + "Tier 1": {"input": 0, "output": 0, "model": "gemini-3.1-pro-preview"}, + "Tier 2": {"input": 0, "output": 0, "model": "gemini-3-flash-preview"}, + "Tier 3": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"}, + "Tier 4": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"}, + } +app.perf_profiling_enabled = False + +with patch("src.gui_2.imgui") as mock_imgui: + App._render_mma_dashboard(app) + print(f"text_colored called: {mock_imgui.text_colored.called}") + if not mock_imgui.text_colored.called: + print("Calls to app methods:") + for call in app.mock_calls: + print(call) diff --git a/conductor/tracks/gui_refactor_stabilization_20260512/plan_context_refactor.md b/conductor/tracks/gui_refactor_stabilization_20260512/plan_context_refactor.md index ceca301..b44b75a 100644 --- a/conductor/tracks/gui_refactor_stabilization_20260512/plan_context_refactor.md +++ b/conductor/tracks/gui_refactor_stabilization_20260512/plan_context_refactor.md @@ -20,9 +20,9 @@ Refactor the monolithic `_render_context_composition_panel` in `src/gui_2.py` in - [ ] Task: Extract the context presets section into `_render_context_presets()`. ### Phase 3: Assembly & Verification -- [ ] Task: Reassemble `_render_context_composition_panel` by calling the new sub-methods. -- [ ] Task: Run the custom AST linter to ensure all scopes are correctly closed. -- [ ] Task: Run fast render tests to verify no regressions in the context panel. +- [x] Task: Reassemble `_render_context_composition_panel` by calling the new sub-methods. +- [x] Task: Run the custom AST linter to ensure all scopes are correctly closed. +- [x] Task: Run fast render tests to verify no regressions in the context panel. ## Verification & Testing - **AST Linting**: `uv run python scripts/check_imgui_scopes.py src/gui_2.py` diff --git a/tests/test_ast_inspector_extended.py b/tests/test_ast_inspector_extended.py index f9a6013..5a34978 100644 --- a/tests/test_ast_inspector_extended.py +++ b/tests/test_ast_inspector_extended.py @@ -17,6 +17,7 @@ def test_ast_inspector_line_range_parsing(): # 3. Patch imgui and mcp_client with patch("src.gui_2.imgui") as mock_imgui, \ + patch("src.gui_2.imscope") as mock_imscope, \ patch("src.gui_2.mcp_client.py_get_code_outline", return_value=mock_outline): # begin_popup_modal needs to return (expanded, opened) @@ -26,6 +27,15 @@ def test_ast_inspector_line_range_parsing(): # radio_button returns (changed, active) mock_imgui.radio_button.return_value = (False, False) + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + # 4. Call the method App._render_ast_inspector_modal(app) diff --git a/tests/test_auto_slices.py b/tests/test_auto_slices.py index 7f49995..860b9d3 100644 --- a/tests/test_auto_slices.py +++ b/tests/test_auto_slices.py @@ -50,7 +50,8 @@ def test_add_selected_triggers_auto_slices(mock_app): mock_app.files = [f_mock] mock_app._ui_picker_selected = {"test.py"} - with patch('src.gui_2.imgui') as mock_imgui: + with patch('src.gui_2.imgui') as mock_imgui, \ + patch('src.gui_2.imscope') as mock_imscope: mock_imgui.begin_popup_modal.return_value = (True, True) mock_imgui.button.side_effect = lambda label, size=None: label == "Add Selected" mock_imgui.checkbox.return_value = (False, False) @@ -58,6 +59,12 @@ def test_add_selected_triggers_auto_slices(mock_app): mock_imgui.ImVec2 = MagicMock() mock_imgui.WindowFlags_ = MagicMock() + # Setup imscope mocks to act as context managers + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.window.return_value.__enter__.return_value = (True, True) + with patch.object(mock_app, '_populate_auto_slices') as mock_populate: mock_app._render_add_context_files_modal() @@ -71,7 +78,8 @@ def test_add_all_triggers_auto_slices(mock_app): mock_app.files = [f_mock] mock_app.context_files = [] - with patch('src.gui_2.imgui') as mock_imgui: + with patch('src.gui_2.imgui') as mock_imgui, \ + patch('src.gui_2.imscope') as mock_imscope: mock_imgui.button.side_effect = lambda label, size=None: label == "Add All##addall" mock_imgui.collapsing_header.return_value = True mock_imgui.begin_child.return_value = True @@ -84,6 +92,12 @@ def test_add_all_triggers_auto_slices(mock_app): mock_imgui.TableColumnFlags_ = MagicMock() mock_imgui.TreeNodeFlags_ = MagicMock() + # Setup imscope mocks to act as context managers + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.window.return_value.__enter__.return_value = (True, True) + with patch.object(mock_app, '_populate_auto_slices') as mock_populate: mock_app._render_context_composition_panel() diff --git a/tests/test_context_composition_panel.py b/tests/test_context_composition_panel.py index 0aade91..cdf8667 100644 --- a/tests/test_context_composition_panel.py +++ b/tests/test_context_composition_panel.py @@ -3,40 +3,40 @@ import inspect def test_context_composition_panel_replaces_placeholder(): - import src.gui_2 as gui_2 + import src.gui_2 as gui_2 - source = inspect.getsource(gui_2.App._gui_func) - assert "_render_context_composition_placeholder" not in source, ( - "Placeholder should be replaced" - ) - assert "_render_context_composition_panel" in source, ( - "Should have _render_context_composition_panel" - ) + source = inspect.getsource(gui_2.App._render_discussion_hub) + assert "_render_context_composition_placeholder" not in source, ( + "Placeholder should be replaced" + ) + assert "_render_context_composition_panel" in source, ( + "Should have _render_context_composition_panel" + ) def test_context_composition_has_save_load_buttons(): - import src.gui_2 as gui_2 + import src.gui_2 as gui_2 - source = inspect.getsource(gui_2.App._render_context_composition_panel) - assert "Save as Preset" in source or "save" in source.lower(), ( - "Should have Save functionality" - ) - assert "Load Preset" in source or "load" in source.lower(), ( - "Should have Load functionality" - ) + source = inspect.getsource(gui_2.App._render_context_presets) + assert "Save##ctx" in source or "save" in source.lower(), ( + "Should have Save functionality" + ) + assert "load_context_preset" in source or "load" in source.lower(), ( + "Should have Load functionality" + ) def test_context_composition_shows_files(): - import src.gui_2 as gui_2 + import src.gui_2 as gui_2 - source = inspect.getsource(gui_2.App._render_context_composition_panel) - assert "files" in source.lower() or "Files" in source, "Should show files" + source = inspect.getsource(gui_2.App._render_context_composition_panel) + assert "files" in source.lower() or "Files" in source, "Should show files" def test_context_composition_has_preset_list(): - import src.gui_2 as gui_2 + import src.gui_2 as gui_2 - source = inspect.getsource(gui_2.App._render_context_composition_panel) - assert "context_presets" in source or "preset" in source.lower(), ( - "Should reference presets" - ) + source = inspect.getsource(gui_2.App._render_context_composition_panel) + assert "context_presets" in source or "preset" in source.lower(), ( + "Should reference presets" + ) diff --git a/tests/test_discussion_takes_gui.py b/tests/test_discussion_takes_gui.py index 9119a49..d5046ef 100644 --- a/tests/test_discussion_takes_gui.py +++ b/tests/test_discussion_takes_gui.py @@ -40,7 +40,8 @@ def app_instance(): def test_render_discussion_tabs(app_instance): """Verify that _render_discussion_panel uses tabs for discussions.""" - with patch('src.gui_2.imgui') as mock_imgui: + with patch('src.gui_2.imgui') as mock_imgui, \ + patch('src.gui_2.imscope') as mock_imscope: # Setup defaults for common imgui calls to avoid unpacking errors mock_imgui.collapsing_header.return_value = True mock_imgui.begin_combo.return_value = False @@ -56,6 +57,15 @@ def test_render_discussion_tabs(app_instance): mock_imgui.begin_tab_bar.return_value = True mock_imgui.begin_tab_item.return_value = (False, False) + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + app_instance._render_discussion_panel() # Check if begin_tab_bar was called @@ -69,6 +79,7 @@ def test_render_discussion_tabs(app_instance): def test_switching_discussion_via_tabs(app_instance): """Verify that clicking a tab switches the discussion.""" with patch('src.gui_2.imgui') as mock_imgui, \ + patch('src.gui_2.imscope') as mock_imscope, \ patch('src.app_controller.AppController._switch_discussion') as mock_switch: # Setup defaults mock_imgui.collapsing_header.return_value = True @@ -83,6 +94,15 @@ def test_switching_discussion_via_tabs(app_instance): mock_imgui.begin_tab_bar.return_value = True + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + # Simulate 'take_1' being active/selected def side_effect(name, p_open=None, flags=None): if name == "Take 1###main_take_1": diff --git a/tests/test_gui_discussion_tabs.py b/tests/test_gui_discussion_tabs.py index 9f333d6..a9a5ffc 100644 --- a/tests/test_gui_discussion_tabs.py +++ b/tests/test_gui_discussion_tabs.py @@ -24,9 +24,19 @@ def mock_gui(): def test_discussion_tabs_rendered(mock_gui): with patch('src.gui_2.imgui') as mock_imgui, \ + patch('src.gui_2.imscope') as mock_imscope, \ patch('src.imgui_scopes.imgui', new=mock_imgui), \ patch('src.app_controller.AppController.active_project_root', new_callable=PropertyMock, return_value='.'): + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + # We expect a combo box for base discussion mock_imgui.begin_combo.return_value = True mock_imgui.selectable.return_value = (False, False) diff --git a/tests/test_gui_kill_button.py b/tests/test_gui_kill_button.py index e68c353..82edf29 100644 --- a/tests/test_gui_kill_button.py +++ b/tests/test_gui_kill_button.py @@ -6,7 +6,8 @@ def test_gui_has_kill_button_method(): assert hasattr(App, '_cb_kill_ticket'), "App must have _cb_kill_ticket method" def test_render_ticket_queue_table_columns(): - with patch("src.gui_2.imgui") as mock_imgui: + with patch("src.gui_2.imgui") as mock_imgui, \ + patch("src.gui_2.imscope") as mock_imscope: mock_imgui.begin_table.return_value = True mock_imgui.table_setup_column = MagicMock() mock_imgui.table_headers_row = MagicMock() @@ -25,6 +26,15 @@ def test_render_ticket_queue_table_columns(): mock_imgui.pop_style_color = MagicMock() mock_imgui.same_line = MagicMock() + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + from src.gui_2 import App app = App.__new__(App) app.active_track = MagicMock() diff --git a/tests/test_gui_symbol_navigation.py b/tests/test_gui_symbol_navigation.py index e3a38ee..d381fa5 100644 --- a/tests/test_gui_symbol_navigation.py +++ b/tests/test_gui_symbol_navigation.py @@ -7,10 +7,20 @@ def test_render_discussion_panel_symbol_lookup(mock_app, role): # Mock imgui, mcp_client, and project_manager as requested with ( patch('src.gui_2.imgui') as mock_imgui, + patch('src.gui_2.imscope') as mock_imscope, patch('src.gui_2.mcp_client') as mock_mcp, patch('src.gui_2.project_manager') as mock_pm, patch('src.markdown_helper.imgui_md') as mock_md ): + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + # Set up App instance state mock_app.perf_profiling_enabled = False mock_app.ai_status = "idle" diff --git a/tests/test_gui_synthesis.py b/tests/test_gui_synthesis.py index 78e8782..0dab9e1 100644 --- a/tests/test_gui_synthesis.py +++ b/tests/test_gui_synthesis.py @@ -36,11 +36,21 @@ def app_instance(): def test_render_synthesis_panel(app_instance): """Verify that _render_synthesis_panel renders checkboxes for takes and input for prompt.""" - with patch('src.gui_2.imgui') as mock_imgui: + with patch('src.gui_2.imgui') as mock_imgui, \ + patch('src.gui_2.imscope') as mock_imscope: mock_imgui.checkbox.return_value = (False, False) mock_imgui.input_text_multiline.return_value = (False, app_instance.ui_synthesis_prompt) mock_imgui.button.return_value = False + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + # Call the method we are testing app_instance._render_synthesis_panel() diff --git a/tests/test_gui_window_controls.py b/tests/test_gui_window_controls.py index a753688..b37ab22 100644 --- a/tests/test_gui_window_controls.py +++ b/tests/test_gui_window_controls.py @@ -10,8 +10,18 @@ def test_gui_window_controls_minimize_maximize_close(): with patch("src.gui_2.win32gui") as mock_win32gui, \ patch("src.gui_2.win32con") as mock_win32con, \ patch("src.gui_2.imgui") as mock_imgui, \ + patch("src.gui_2.imscope") as mock_imscope, \ patch("ctypes.pythonapi.PyCapsule_GetPointer") as mock_get_pointer: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + # Setup mock for HWND mock_viewport = MagicMock() mock_viewport.platform_handle_raw = "mock_capsule" diff --git a/tests/test_log_management_ui.py b/tests/test_log_management_ui.py index aef7ddf..fe34b51 100644 --- a/tests/test_log_management_ui.py +++ b/tests/test_log_management_ui.py @@ -33,6 +33,7 @@ history = [] @pytest.fixture def app_instance(mock_config: Path, mock_project: Path, monkeypatch: pytest.MonkeyPatch) -> App: monkeypatch.setattr("src.models.CONFIG_PATH", mock_config) + monkeypatch.setattr("src.gui_2.filedialog", MagicMock()) with patch("src.project_manager.load_project") as mock_load, \ patch("src.session_logger.open_session"), \ patch("src.session_logger.reset_session"): @@ -67,11 +68,10 @@ def test_render_log_management_logic(app_instance: App) -> None: app.show_windows["Log Management"] = True # Mock LogRegistry with patch("src.log_registry.LogRegistry") as MockRegistry, \ - patch("src.gui_2.imgui.begin") as mock_begin, \ + patch("src.gui_2.imscope") as mock_imscope, \ patch("src.gui_2.imgui.begin_table") as mock_begin_table, \ patch("src.gui_2.imgui.text") as mock_text, \ patch("src.gui_2.imgui.end_table"), \ - patch("src.gui_2.imgui.end"), \ patch("src.gui_2.imgui.push_style_color"), \ patch("src.gui_2.imgui.pop_style_color"), \ patch("src.gui_2.imgui.table_setup_column"), \ @@ -81,7 +81,7 @@ def test_render_log_management_logic(app_instance: App) -> None: patch("src.gui_2.imgui.same_line"), \ patch("src.gui_2.imgui.text_colored"), \ patch("src.gui_2.imgui.separator"), \ - patch("src.gui_2.imgui.button"): + patch("src.gui_2.imgui.button", return_value=False): mock_reg = MockRegistry.return_value mock_reg.data = { @@ -91,10 +91,15 @@ def test_render_log_management_logic(app_instance: App) -> None: "metadata": {"reason": "test", "size_kb": 10, "message_count": 5} } } - mock_begin.return_value = (True, True) + app._log_registry = mock_reg + + mock_window_cm = MagicMock() + mock_window_cm.__enter__.return_value = (True, True) + mock_imscope.window.return_value = mock_window_cm + mock_begin_table.return_value = True app._render_log_management() - mock_begin.assert_called_with("Log Management", app.show_windows["Log Management"]) + mock_imscope.window.assert_called_with("Log Management", app.show_windows["Log Management"]) mock_begin_table.assert_called() mock_text.assert_any_call("session_1") diff --git a/tests/test_mma_approval_indicators.py b/tests/test_mma_approval_indicators.py index 0d80a84..b04bc26 100644 --- a/tests/test_mma_approval_indicators.py +++ b/tests/test_mma_approval_indicators.py @@ -101,7 +101,16 @@ class TestMMAApprovalIndicators: _pending_ask_dialog=False, ) imgui_mock = _make_imgui_mock() - with patch("src.gui_2.imgui", imgui_mock): + with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.imscope") as mock_imscope: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) assert "APPROVAL PENDING" not in combined, ( @@ -112,7 +121,16 @@ class TestMMAApprovalIndicators: """'APPROVAL PENDING' badge must appear when _pending_mma_spawn is set.""" app = _make_app(_pending_mma_spawn={"ticket_id": "T-001"}) imgui_mock = _make_imgui_mock() - with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.math") as mock_math: + with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.imscope") as mock_imscope, patch("src.gui_2.math") as mock_math: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + mock_math.sin.return_value = 0.8 App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) @@ -124,7 +142,16 @@ class TestMMAApprovalIndicators: """'APPROVAL PENDING' badge must appear when _pending_mma_approval is set.""" app = _make_app(_pending_mma_approval={"step": "test"}) imgui_mock = _make_imgui_mock() - with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.math") as mock_math: + with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.imscope") as mock_imscope, patch("src.gui_2.math") as mock_math: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + mock_math.sin.return_value = 0.8 App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) @@ -136,7 +163,16 @@ class TestMMAApprovalIndicators: """'APPROVAL PENDING' badge must appear when _pending_ask_dialog is True.""" app = _make_app(_pending_ask_dialog=True) imgui_mock = _make_imgui_mock() - with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.math") as mock_math: + with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.imscope") as mock_imscope, patch("src.gui_2.math") as mock_math: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + mock_math.sin.return_value = 0.8 App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) diff --git a/tests/test_mma_dashboard_streams.py b/tests/test_mma_dashboard_streams.py index d36ddf6..a5a6e8e 100644 --- a/tests/test_mma_dashboard_streams.py +++ b/tests/test_mma_dashboard_streams.py @@ -64,7 +64,16 @@ class TestMMADashboardStreams: app = _make_app(mma_streams={"Tier 1": "hello"}) imgui_mock = _make_imgui_mock() imgui_mock.begin_child.return_value = True - with patch("src.gui_2.imgui", imgui_mock): + with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.imscope") as mock_imscope: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + App._render_tier_stream_panel(app, "Tier 1", "Tier 1") app._render_selectable_label.assert_called_with('stream_Tier 1', 'hello', width=-1, multiline=True, height=0) @@ -77,7 +86,16 @@ class TestMMADashboardStreams: }) imgui_mock = _make_imgui_mock() imgui_mock.begin_child.return_value = True - with patch("src.gui_2.imgui", imgui_mock): + with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.imscope") as mock_imscope: + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + App._render_tier_stream_panel(app, "Tier 3", None) text_args = " ".join(str(c) for c in imgui_mock.text.call_args_list) assert "T-001" in text_args, "imgui.text not called with 'T-001' worker sub-header" diff --git a/tests/test_shader_live_editor.py b/tests/test_shader_live_editor.py index 3da9cb3..9ad8974 100644 --- a/tests/test_shader_live_editor.py +++ b/tests/test_shader_live_editor.py @@ -6,9 +6,20 @@ def test_shader_live_editor_renders(): app = App() app.show_windows["Shader Editor"] = True - with patch("src.gui_2.imgui") as mock_imgui: + with patch("src.gui_2.imgui") as mock_imgui, \ + patch("src.gui_2.imscope") as mock_imscope: mock_imgui.begin.return_value = (True, True) mock_imgui.slider_float.return_value = (False, 1.0) + + # Setup imscope mocks + mock_imscope.window.return_value.__enter__.return_value = (True, True) + mock_imscope.child.return_value.__enter__.return_value = True + mock_imscope.table.return_value.__enter__.return_value = True + mock_imscope.tree_node_ex.return_value.__enter__.return_value = True + mock_imscope.tab_item.return_value.__enter__.return_value = (True, True) + mock_imscope.style_color.return_value.__enter__.return_value = None + mock_imscope.style_var.return_value.__enter__.return_value = None + app._render_shader_live_editor() assert mock_imgui.begin.called assert mock_imgui.end.called