from __future__ import annotations import math import pytest from unittest.mock import patch, MagicMock, call from gui_2 import App def _make_app(**kwargs): app = MagicMock(spec=App) app.mma_streams = kwargs.get("mma_streams", {}) app.mma_tier_usage = kwargs.get("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.tracks = kwargs.get("tracks", []) app.active_track = kwargs.get("active_track", None) app.active_tickets = kwargs.get("active_tickets", []) app.mma_status = kwargs.get("mma_status", "idle") app.active_tier = kwargs.get("active_tier", None) app.mma_step_mode = kwargs.get("mma_step_mode", False) app._pending_mma_spawn = kwargs.get("_pending_mma_spawn", None) app._pending_mma_approval = kwargs.get("_pending_mma_approval", None) app._pending_ask_dialog = kwargs.get("_pending_ask_dialog", False) app.ui_new_track_name = "" app.ui_new_track_desc = "" app.ui_new_track_type = "feature" app.ui_conductor_setup_summary = "" app.ui_epic_input = "" app._show_add_ticket_form = False app.ui_new_ticket_id = "" app.ui_new_ticket_desc = "" app.ui_new_ticket_target = "" app.ui_new_ticket_deps = "" return app def _make_imgui_mock(): m = MagicMock() m.begin_table.return_value = False m.begin_child.return_value = False m.checkbox.return_value = (False, False) m.input_text.side_effect = lambda label, value, *args, **kwargs: (False, value) m.input_text_multiline.side_effect = lambda label, value, *args, **kwargs: (False, value) m.combo.side_effect = lambda label, current_item, items, *args, **kwargs: (False, current_item) m.collapsing_header.return_value = False m.ImVec2.return_value = MagicMock() m.ImVec4.return_value = MagicMock() return m def _collect_text_colored_args(imgui_mock): """Return a single joined string of all text_colored second-arg strings.""" parts = [] for c in imgui_mock.text_colored.call_args_list: args = c.args if len(args) >= 2: parts.append(str(args[1])) return " ".join(parts) class TestMMAApprovalIndicators: def test_no_approval_badge_when_idle(self): """No 'APPROVAL PENDING' badge when all pending attrs are None/False.""" app = _make_app( _pending_mma_spawn=None, _pending_mma_approval=None, _pending_ask_dialog=False, ) imgui_mock = _make_imgui_mock() with patch("gui_2.imgui", imgui_mock): App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) assert "APPROVAL PENDING" not in combined, ( "text_colored called with 'APPROVAL PENDING' when no approval is pending" ) def test_approval_badge_shown_when_spawn_pending(self): """'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("gui_2.imgui", imgui_mock), patch("gui_2.math") as mock_math: mock_math.sin.return_value = 0.8 App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) assert "APPROVAL PENDING" in combined, ( "text_colored not called with 'APPROVAL PENDING' when _pending_mma_spawn is set" ) def test_approval_badge_shown_when_mma_approval_pending(self): """'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("gui_2.imgui", imgui_mock), patch("gui_2.math") as mock_math: mock_math.sin.return_value = 0.8 App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) assert "APPROVAL PENDING" in combined, ( "text_colored not called with 'APPROVAL PENDING' when _pending_mma_approval is set" ) def test_approval_badge_shown_when_ask_dialog_pending(self): """'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("gui_2.imgui", imgui_mock), patch("gui_2.math") as mock_math: mock_math.sin.return_value = 0.8 App._render_mma_dashboard(app) combined = _collect_text_colored_args(imgui_mock) assert "APPROVAL PENDING" in combined, ( "text_colored not called with 'APPROVAL PENDING' when _pending_ask_dialog is True" )