- Add cost tracking with new cost_tracker.py module - Enhance Track Proposal modal with editable titles and goals - Add Conductor Setup summary and New Track creation form to MMA Dashboard - Implement Task DAG editing (add/delete tickets) and track-scoped discussion - Add visual polish: color-coded statuses, tinted progress bars, and node indicators - Support live worker streaming from AI providers to GUI panels - Fix numerous integration test regressions and stabilize headless service
116 lines
4.4 KiB
Python
116 lines
4.4 KiB
Python
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"
|
|
)
|