WIP: fixing regressions in tests

This commit is contained in:
2026-05-12 21:04:50 -04:00
parent c0d106255b
commit 29de116233
15 changed files with 236 additions and 44 deletions
+28
View File
@@ -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)
@@ -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`
+10
View File
@@ -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)
+16 -2
View File
@@ -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()
+24 -24
View File
@@ -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"
)
+21 -1
View File
@@ -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":
+10
View File
@@ -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)
+11 -1
View File
@@ -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()
+10
View File
@@ -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"
+11 -1
View File
@@ -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()
+10
View File
@@ -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"
+10 -5
View File
@@ -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")
+40 -4
View File
@@ -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)
+20 -2
View File
@@ -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"
+12 -1
View File
@@ -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