PYTHON
This commit is contained in:
@@ -10,7 +10,7 @@ from src import ai_client
|
|||||||
|
|
||||||
def test_agent_capabilities_listing() -> None:
|
def test_agent_capabilities_listing() -> None:
|
||||||
# Mock credentials
|
# Mock credentials
|
||||||
with patch("ai_client._load_credentials") as mock_creds:
|
with patch("src.ai_client._load_credentials") as mock_creds:
|
||||||
mock_creds.return_value = {"gemini": {"api_key": "fake-key"}}
|
mock_creds.return_value = {"gemini": {"api_key": "fake-key"}}
|
||||||
|
|
||||||
# Mock the google-genai Client and models.list
|
# Mock the google-genai Client and models.list
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ def test_event_emission() -> None:
|
|||||||
|
|
||||||
def test_send_emits_events_proper() -> None:
|
def test_send_emits_events_proper() -> None:
|
||||||
ai_client.reset_session()
|
ai_client.reset_session()
|
||||||
with patch("ai_client._ensure_gemini_client"), \
|
with patch("src.ai_client._ensure_gemini_client"), \
|
||||||
patch("ai_client._gemini_client") as mock_client:
|
patch("src.ai_client._gemini_client") as mock_client:
|
||||||
mock_chat = MagicMock()
|
mock_chat = MagicMock()
|
||||||
mock_client.chats.create.return_value = mock_chat
|
mock_client.chats.create.return_value = mock_chat
|
||||||
mock_response = MagicMock()
|
mock_response = MagicMock()
|
||||||
@@ -57,9 +57,9 @@ def test_send_emits_events_proper() -> None:
|
|||||||
|
|
||||||
def test_send_emits_tool_events() -> None:
|
def test_send_emits_tool_events() -> None:
|
||||||
ai_client.reset_session() # Clear caches and chats to avoid test pollution
|
ai_client.reset_session() # Clear caches and chats to avoid test pollution
|
||||||
with patch("ai_client._ensure_gemini_client"), \
|
with patch("src.ai_client._ensure_gemini_client"), \
|
||||||
patch("ai_client._gemini_client") as mock_client, \
|
patch("src.ai_client._gemini_client") as mock_client, \
|
||||||
patch("mcp_client.dispatch") as mock_dispatch:
|
patch("src.mcp_client.dispatch") as mock_dispatch:
|
||||||
mock_chat = MagicMock()
|
mock_chat = MagicMock()
|
||||||
mock_client.chats.create.return_value = mock_chat
|
mock_client.chats.create.return_value = mock_chat
|
||||||
# 1. Setup mock response with a tool call
|
# 1. Setup mock response with a tool call
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def test_telemetry_data_updates_correctly(app_instance: Any) -> None:
|
|||||||
"percentage": 75.0,
|
"percentage": 75.0,
|
||||||
}
|
}
|
||||||
# 3. Patch the dependencies
|
# 3. Patch the dependencies
|
||||||
with patch('ai_client.get_token_stats', return_value=mock_stats) as mock_get_stats:
|
with patch('src.ai_client.get_token_stats', return_value=mock_stats) as mock_get_stats:
|
||||||
# 4. Call the method under test
|
# 4. Call the method under test
|
||||||
app_instance._refresh_api_metrics({}, md_content="test content")
|
app_instance._refresh_api_metrics({}, md_content="test content")
|
||||||
# 5. Assert the results
|
# 5. Assert the results
|
||||||
@@ -41,7 +41,7 @@ def test_performance_history_updates(app_instance: Any) -> None:
|
|||||||
def test_gui_updates_on_event(app_instance: App) -> None:
|
def test_gui_updates_on_event(app_instance: App) -> None:
|
||||||
mock_stats = {"percentage": 50.0, "current": 500, "limit": 1000}
|
mock_stats = {"percentage": 50.0, "current": 500, "limit": 1000}
|
||||||
app_instance.last_md = "mock_md"
|
app_instance.last_md = "mock_md"
|
||||||
with patch('ai_client.get_token_stats', return_value=mock_stats):
|
with patch('src.ai_client.get_token_stats', return_value=mock_stats):
|
||||||
app_instance._on_api_event(payload={"text": "test"})
|
app_instance._on_api_event(payload={"text": "test"})
|
||||||
app_instance._process_pending_gui_tasks()
|
app_instance._process_pending_gui_tasks()
|
||||||
assert app_instance._token_stats["percentage"] == 50.0
|
assert app_instance._token_stats["percentage"] == 50.0
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ history = []
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def app_instance(mock_config: Path, mock_project: Path, monkeypatch: pytest.MonkeyPatch) -> App:
|
def app_instance(mock_config: Path, mock_project: Path, monkeypatch: pytest.MonkeyPatch) -> App:
|
||||||
monkeypatch.setattr("gui_2.CONFIG_PATH", mock_config)
|
monkeypatch.setattr("src.models.CONFIG_PATH", mock_config)
|
||||||
with patch("project_manager.load_project") as mock_load, \
|
with patch("src.project_manager.load_project") as mock_load, \
|
||||||
patch("session_logger.open_session"):
|
patch("src.session_logger.open_session"):
|
||||||
mock_load.return_value = {
|
mock_load.return_value = {
|
||||||
"project": {"name": "test"},
|
"project": {"name": "test"},
|
||||||
"discussion": {"roles": ["User", "AI"], "active": "main", "discussions": {"main": {"history": []}}},
|
"discussion": {"roles": ["User", "AI"], "active": "main", "discussions": {"main": {"history": []}}},
|
||||||
@@ -63,19 +63,19 @@ def test_render_log_management_logic(app_instance: App) -> None:
|
|||||||
app = app_instance
|
app = app_instance
|
||||||
app.show_windows["Log Management"] = True
|
app.show_windows["Log Management"] = True
|
||||||
# Mock LogRegistry
|
# Mock LogRegistry
|
||||||
with patch("gui_2.LogRegistry") as MockRegistry, \
|
with patch("src.log_registry.LogRegistry") as MockRegistry, \
|
||||||
patch("gui_2.imgui.begin") as mock_begin, \
|
patch("src.gui_2.imgui.begin") as mock_begin, \
|
||||||
patch("gui_2.imgui.begin_table") as mock_begin_table, \
|
patch("src.gui_2.imgui.begin_table") as mock_begin_table, \
|
||||||
patch("gui_2.imgui.text") as mock_text, \
|
patch("src.gui_2.imgui.text") as mock_text, \
|
||||||
patch("gui_2.imgui.end_table"), \
|
patch("src.gui_2.imgui.end_table"), \
|
||||||
patch("gui_2.imgui.end"), \
|
patch("src.gui_2.imgui.end"), \
|
||||||
patch("gui_2.imgui.push_style_color"), \
|
patch("src.gui_2.imgui.push_style_color"), \
|
||||||
patch("gui_2.imgui.pop_style_color"), \
|
patch("src.gui_2.imgui.pop_style_color"), \
|
||||||
patch("gui_2.imgui.table_setup_column"), \
|
patch("src.gui_2.imgui.table_setup_column"), \
|
||||||
patch("gui_2.imgui.table_headers_row"), \
|
patch("src.gui_2.imgui.table_headers_row"), \
|
||||||
patch("gui_2.imgui.table_next_row"), \
|
patch("src.gui_2.imgui.table_next_row"), \
|
||||||
patch("gui_2.imgui.table_next_column"), \
|
patch("src.gui_2.imgui.table_next_column"), \
|
||||||
patch("gui_2.imgui.button"):
|
patch("src.gui_2.imgui.button"):
|
||||||
mock_reg = MockRegistry.return_value
|
mock_reg = MockRegistry.return_value
|
||||||
mock_reg.data = {
|
mock_reg.data = {
|
||||||
"session_1": {
|
"session_1": {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from pathlib import Path
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from src import session_logger
|
from src import session_logger
|
||||||
from src.log_registry import LogRegistry
|
from src.log_registry import LogRegistry
|
||||||
from log_pruner import LogPruner
|
from src.log_pruner import LogPruner
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def e2e_setup(tmp_path: Path, monkeypatch: Any) -> Any:
|
def e2e_setup(tmp_path: Path, monkeypatch: Any) -> Any:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from src import mcp_client
|
|||||||
def test_mcp_perf_tool_retrieval() -> None:
|
def test_mcp_perf_tool_retrieval() -> None:
|
||||||
mock_metrics = {"fps": 60, "last_frame_time_ms": 16.6}
|
mock_metrics = {"fps": 60, "last_frame_time_ms": 16.6}
|
||||||
# Simulate tool call by patching the callback
|
# Simulate tool call by patching the callback
|
||||||
with patch('mcp_client.perf_monitor_callback', return_value=mock_metrics):
|
with patch('src.mcp_client.perf_monitor_callback', return_value=mock_metrics):
|
||||||
result = mcp_client.get_ui_performance()
|
result = mcp_client.get_ui_performance()
|
||||||
assert "60" in result
|
assert "60" in result
|
||||||
assert "16.6" in result
|
assert "16.6" in result
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class TestMMAApprovalIndicators:
|
|||||||
_pending_ask_dialog=False,
|
_pending_ask_dialog=False,
|
||||||
)
|
)
|
||||||
imgui_mock = _make_imgui_mock()
|
imgui_mock = _make_imgui_mock()
|
||||||
with patch("gui_2.imgui", imgui_mock):
|
with patch("src.gui_2.imgui", imgui_mock):
|
||||||
App._render_mma_dashboard(app)
|
App._render_mma_dashboard(app)
|
||||||
combined = _collect_text_colored_args(imgui_mock)
|
combined = _collect_text_colored_args(imgui_mock)
|
||||||
assert "APPROVAL PENDING" not in combined, (
|
assert "APPROVAL PENDING" not in combined, (
|
||||||
@@ -81,7 +81,7 @@ class TestMMAApprovalIndicators:
|
|||||||
"""'APPROVAL PENDING' badge must appear when _pending_mma_spawn is set."""
|
"""'APPROVAL PENDING' badge must appear when _pending_mma_spawn is set."""
|
||||||
app = _make_app(_pending_mma_spawn={"ticket_id": "T-001"})
|
app = _make_app(_pending_mma_spawn={"ticket_id": "T-001"})
|
||||||
imgui_mock = _make_imgui_mock()
|
imgui_mock = _make_imgui_mock()
|
||||||
with patch("gui_2.imgui", imgui_mock), patch("gui_2.math") as mock_math:
|
with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.math") as mock_math:
|
||||||
mock_math.sin.return_value = 0.8
|
mock_math.sin.return_value = 0.8
|
||||||
App._render_mma_dashboard(app)
|
App._render_mma_dashboard(app)
|
||||||
combined = _collect_text_colored_args(imgui_mock)
|
combined = _collect_text_colored_args(imgui_mock)
|
||||||
@@ -93,7 +93,7 @@ class TestMMAApprovalIndicators:
|
|||||||
"""'APPROVAL PENDING' badge must appear when _pending_mma_approval is set."""
|
"""'APPROVAL PENDING' badge must appear when _pending_mma_approval is set."""
|
||||||
app = _make_app(_pending_mma_approval={"step": "test"})
|
app = _make_app(_pending_mma_approval={"step": "test"})
|
||||||
imgui_mock = _make_imgui_mock()
|
imgui_mock = _make_imgui_mock()
|
||||||
with patch("gui_2.imgui", imgui_mock), patch("gui_2.math") as mock_math:
|
with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.math") as mock_math:
|
||||||
mock_math.sin.return_value = 0.8
|
mock_math.sin.return_value = 0.8
|
||||||
App._render_mma_dashboard(app)
|
App._render_mma_dashboard(app)
|
||||||
combined = _collect_text_colored_args(imgui_mock)
|
combined = _collect_text_colored_args(imgui_mock)
|
||||||
@@ -105,7 +105,7 @@ class TestMMAApprovalIndicators:
|
|||||||
"""'APPROVAL PENDING' badge must appear when _pending_ask_dialog is True."""
|
"""'APPROVAL PENDING' badge must appear when _pending_ask_dialog is True."""
|
||||||
app = _make_app(_pending_ask_dialog=True)
|
app = _make_app(_pending_ask_dialog=True)
|
||||||
imgui_mock = _make_imgui_mock()
|
imgui_mock = _make_imgui_mock()
|
||||||
with patch("gui_2.imgui", imgui_mock), patch("gui_2.math") as mock_math:
|
with patch("src.gui_2.imgui", imgui_mock), patch("src.gui_2.math") as mock_math:
|
||||||
mock_math.sin.return_value = 0.8
|
mock_math.sin.return_value = 0.8
|
||||||
App._render_mma_dashboard(app)
|
App._render_mma_dashboard(app)
|
||||||
combined = _collect_text_colored_args(imgui_mock)
|
combined = _collect_text_colored_args(imgui_mock)
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ from src.gui_2 import App
|
|||||||
def app_instance() -> Any:
|
def app_instance() -> Any:
|
||||||
with (
|
with (
|
||||||
patch("src.models.load_config", return_value={"ai": {}, "projects": {}}),
|
patch("src.models.load_config", return_value={"ai": {}, "projects": {}}),
|
||||||
patch("gui_2.save_config"),
|
patch("src.gui_2.save_config"),
|
||||||
patch("gui_2.project_manager"),
|
patch("src.gui_2.project_manager"),
|
||||||
patch("app_controller.project_manager") as mock_pm,
|
patch("src.app_controller.project_manager") as mock_pm,
|
||||||
patch("gui_2.session_logger"),
|
patch("src.gui_2.session_logger"),
|
||||||
patch("gui_2.immapp.run"),
|
patch("src.gui_2.immapp.run"),
|
||||||
patch("src.app_controller.AppController._load_active_project"),
|
patch("src.app_controller.AppController._load_active_project"),
|
||||||
patch("src.app_controller.AppController._fetch_models"),
|
patch("src.app_controller.AppController._fetch_models"),
|
||||||
patch.object(App, "_load_fonts"),
|
patch.object(App, "_load_fonts"),
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class TestMMADashboardStreams:
|
|||||||
app = _make_app(mma_streams={"Tier 1": "hello"})
|
app = _make_app(mma_streams={"Tier 1": "hello"})
|
||||||
imgui_mock = _make_imgui_mock()
|
imgui_mock = _make_imgui_mock()
|
||||||
imgui_mock.begin_child.return_value = True
|
imgui_mock.begin_child.return_value = True
|
||||||
with patch("gui_2.imgui", imgui_mock):
|
with patch("src.gui_2.imgui", imgui_mock):
|
||||||
App._render_tier_stream_panel(app, "Tier 1", "Tier 1")
|
App._render_tier_stream_panel(app, "Tier 1", "Tier 1")
|
||||||
text_wrapped_args = " ".join(str(c) for c in imgui_mock.text_wrapped.call_args_list)
|
text_wrapped_args = " ".join(str(c) for c in imgui_mock.text_wrapped.call_args_list)
|
||||||
assert "hello" in text_wrapped_args, "text_wrapped not called with stream content 'hello'"
|
assert "hello" in text_wrapped_args, "text_wrapped not called with stream content 'hello'"
|
||||||
@@ -69,7 +69,7 @@ class TestMMADashboardStreams:
|
|||||||
})
|
})
|
||||||
imgui_mock = _make_imgui_mock()
|
imgui_mock = _make_imgui_mock()
|
||||||
imgui_mock.begin_child.return_value = True
|
imgui_mock.begin_child.return_value = True
|
||||||
with patch("gui_2.imgui", imgui_mock):
|
with patch("src.gui_2.imgui", imgui_mock):
|
||||||
App._render_tier_stream_panel(app, "Tier 3", None)
|
App._render_tier_stream_panel(app, "Tier 3", None)
|
||||||
text_args = " ".join(str(c) for c in imgui_mock.text.call_args_list)
|
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"
|
assert "T-001" in text_args, "imgui.text not called with 'T-001' worker sub-header"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from src import mma_prompts
|
|||||||
|
|
||||||
class TestOrchestratorPM(unittest.TestCase):
|
class TestOrchestratorPM(unittest.TestCase):
|
||||||
|
|
||||||
@patch('summarize.build_summary_markdown')
|
@patch('src.summarize.build_summary_markdown')
|
||||||
@patch('ai_client.send')
|
@patch('src.ai_client.send')
|
||||||
def test_generate_tracks_success(self, mock_send: Any, mock_summarize: Any) -> None:
|
def test_generate_tracks_success(self, mock_send: Any, mock_summarize: Any) -> None:
|
||||||
# Setup mocks
|
# Setup mocks
|
||||||
mock_summarize.return_value = "REPO_MAP_CONTENT"
|
mock_summarize.return_value = "REPO_MAP_CONTENT"
|
||||||
@@ -43,8 +43,8 @@ class TestOrchestratorPM(unittest.TestCase):
|
|||||||
# Verify result
|
# Verify result
|
||||||
self.assertEqual(result[0]['id'], mock_response_data[0]['id'])
|
self.assertEqual(result[0]['id'], mock_response_data[0]['id'])
|
||||||
|
|
||||||
@patch('summarize.build_summary_markdown')
|
@patch('src.summarize.build_summary_markdown')
|
||||||
@patch('ai_client.send')
|
@patch('src.ai_client.send')
|
||||||
def test_generate_tracks_markdown_wrapped(self, mock_send: Any, mock_summarize: Any) -> None:
|
def test_generate_tracks_markdown_wrapped(self, mock_send: Any, mock_summarize: Any) -> None:
|
||||||
mock_summarize.return_value = "REPO_MAP"
|
mock_summarize.return_value = "REPO_MAP"
|
||||||
mock_response_data = [{"id": "track_1"}]
|
mock_response_data = [{"id": "track_1"}]
|
||||||
@@ -58,8 +58,8 @@ class TestOrchestratorPM(unittest.TestCase):
|
|||||||
result = orchestrator_pm.generate_tracks("req", {}, [])
|
result = orchestrator_pm.generate_tracks("req", {}, [])
|
||||||
self.assertEqual(result, expected_result)
|
self.assertEqual(result, expected_result)
|
||||||
|
|
||||||
@patch('summarize.build_summary_markdown')
|
@patch('src.summarize.build_summary_markdown')
|
||||||
@patch('ai_client.send')
|
@patch('src.ai_client.send')
|
||||||
def test_generate_tracks_malformed_json(self, mock_send: Any, mock_summarize: Any) -> None:
|
def test_generate_tracks_malformed_json(self, mock_send: Any, mock_summarize: Any) -> None:
|
||||||
mock_summarize.return_value = "REPO_MAP"
|
mock_summarize.return_value = "REPO_MAP"
|
||||||
mock_send.return_value = "NOT A JSON"
|
mock_send.return_value = "NOT A JSON"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class TestOrchestratorPMHistory(unittest.TestCase):
|
|||||||
with open(track_path / "spec.md", "w") as f:
|
with open(track_path / "spec.md", "w") as f:
|
||||||
f.write(spec_content)
|
f.write(spec_content)
|
||||||
|
|
||||||
@patch('orchestrator_pm.CONDUCTOR_PATH', Path("test_conductor"))
|
@patch('src.orchestrator_pm.CONDUCTOR_PATH', Path("test_conductor"))
|
||||||
def test_get_track_history_summary(self) -> None:
|
def test_get_track_history_summary(self) -> None:
|
||||||
self.create_track(self.archive_dir, "track_001", "Initial Setup", "completed", "Setting up the project structure.")
|
self.create_track(self.archive_dir, "track_001", "Initial Setup", "completed", "Setting up the project structure.")
|
||||||
self.create_track(self.tracks_dir, "track_002", "Feature A", "in_progress", "Implementing Feature A.")
|
self.create_track(self.tracks_dir, "track_002", "Feature A", "in_progress", "Implementing Feature A.")
|
||||||
@@ -40,7 +40,7 @@ class TestOrchestratorPMHistory(unittest.TestCase):
|
|||||||
self.assertIn("in_progress", summary)
|
self.assertIn("in_progress", summary)
|
||||||
self.assertIn("Implementing Feature A.", summary)
|
self.assertIn("Implementing Feature A.", summary)
|
||||||
|
|
||||||
@patch('orchestrator_pm.CONDUCTOR_PATH', Path("test_conductor"))
|
@patch('src.orchestrator_pm.CONDUCTOR_PATH', Path("test_conductor"))
|
||||||
def test_get_track_history_summary_missing_files(self) -> None:
|
def test_get_track_history_summary_missing_files(self) -> None:
|
||||||
track_path = self.tracks_dir / "track_003"
|
track_path = self.tracks_dir / "track_003"
|
||||||
track_path.mkdir(exist_ok=True)
|
track_path.mkdir(exist_ok=True)
|
||||||
@@ -51,8 +51,8 @@ class TestOrchestratorPMHistory(unittest.TestCase):
|
|||||||
self.assertIn("pending", summary)
|
self.assertIn("pending", summary)
|
||||||
self.assertIn("No overview available", summary)
|
self.assertIn("No overview available", summary)
|
||||||
|
|
||||||
@patch('orchestrator_pm.summarize.build_summary_markdown')
|
@patch('src.orchestrator_pm.summarize.build_summary_markdown')
|
||||||
@patch('ai_client.send')
|
@patch('src.ai_client.send')
|
||||||
def test_generate_tracks_with_history(self, mock_send: MagicMock, mock_summarize: MagicMock) -> None:
|
def test_generate_tracks_with_history(self, mock_send: MagicMock, mock_summarize: MagicMock) -> None:
|
||||||
mock_summarize.return_value = "REPO_MAP"
|
mock_summarize.return_value = "REPO_MAP"
|
||||||
mock_send.return_value = "[]"
|
mock_send.return_value = "[]"
|
||||||
|
|||||||
Reference in New Issue
Block a user