feat(sdm): inject structural dependency mapping tags across codebase
Adds [C: caller] tags to functions/methods and [M: mutation] / [U: usage] tags to class variables based on cross-module call analysis.
This commit is contained in:
+15
-10
@@ -36,7 +36,7 @@ class VerificationLogger:
|
||||
|
||||
def log_state(self, field: str, before: Any, after: Any) -> None:
|
||||
"""
|
||||
[C: tests/test_ai_style_formatter.py:test_multiple_top_level_definitions, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_conductor_tech_lead.py:test_topological_sort_vlog, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_failure, tests/test_vlogger_availability.py:test_vlogger_available]
|
||||
[C: tests/test_ai_style_formatter.py:test_multiple_top_level_definitions, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_conductor_tech_lead.py:test_topological_sort_vlog, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_failure, tests/test_vlogger_availability.py:test_vlogger_available]
|
||||
"""
|
||||
delta = ""
|
||||
if isinstance(before, (int, float)) and isinstance(after, (int, float)):
|
||||
@@ -51,7 +51,7 @@ class VerificationLogger:
|
||||
|
||||
def finalize(self, title: str, status: str, result_msg: str) -> None:
|
||||
"""
|
||||
[C: tests/test_ai_style_formatter.py:test_multiple_top_level_definitions, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_conductor_tech_lead.py:test_topological_sort_vlog, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_tier4_interceptor.py:test_end_to_end_tier4_integration, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_failure, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_stderr_only, tests/test_vlogger_availability.py:test_vlogger_available]
|
||||
[C: tests/test_ai_style_formatter.py:test_multiple_top_level_definitions, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_conductor_tech_lead.py:test_topological_sort_vlog, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_tier4_interceptor.py:test_end_to_end_tier4_integration, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_failure, tests/test_tier4_interceptor.py:test_run_powershell_qa_callback_on_stderr_only, tests/test_vlogger_availability.py:test_vlogger_available]
|
||||
"""
|
||||
round(time.time() - self.start_time, 2)
|
||||
log_file = self.logs_dir / f"{self.script_name}.txt"
|
||||
@@ -71,7 +71,8 @@ class VerificationLogger:
|
||||
def reset_paths() -> Generator[None, None, None]:
|
||||
"""
|
||||
|
||||
Autouse fixture that resets the paths global state before each test.
|
||||
|
||||
Autouse fixture that resets the paths global state before each test.
|
||||
"""
|
||||
from src import paths
|
||||
paths.reset_resolved()
|
||||
@@ -82,8 +83,9 @@ def reset_paths() -> Generator[None, None, None]:
|
||||
def reset_ai_client() -> Generator[None, None, None]:
|
||||
"""
|
||||
|
||||
Autouse fixture that resets the ai_client global state before each test.
|
||||
This is critical for preventing state pollution between tests.
|
||||
|
||||
Autouse fixture that resets the ai_client global state before each test.
|
||||
This is critical for preventing state pollution between tests.
|
||||
"""
|
||||
from src import ai_client
|
||||
from src import mcp_client
|
||||
@@ -131,7 +133,8 @@ def kill_process_tree(pid: int | None) -> None:
|
||||
def mock_app() -> Generator[App, None, None]:
|
||||
"""
|
||||
|
||||
Mock version of the App for simple unit tests that don't need a loop.
|
||||
|
||||
Mock version of the App for simple unit tests that don't need a loop.
|
||||
"""
|
||||
with (
|
||||
patch('src.models.load_config', return_value={
|
||||
@@ -163,8 +166,9 @@ def mock_app() -> Generator[App, None, None]:
|
||||
def app_instance() -> Generator[App, None, None]:
|
||||
"""
|
||||
|
||||
Centralized App instance with all external side effects mocked.
|
||||
Matches the pattern used in test_token_viz.py and test_gui_phase4.py.
|
||||
|
||||
Centralized App instance with all external side effects mocked.
|
||||
Matches the pattern used in test_token_viz.py and test_gui_phase4.py.
|
||||
[C: tests/test_gui2_events.py:test_app_subscribes_to_events]
|
||||
"""
|
||||
with (
|
||||
@@ -199,8 +203,9 @@ def app_instance() -> Generator[App, None, None]:
|
||||
def live_gui() -> Generator[tuple[subprocess.Popen, str], None, None]:
|
||||
"""
|
||||
|
||||
Session-scoped fixture that starts sloppy.py with --enable-test-hooks.
|
||||
Includes high-signal environment telemetry and workspace isolation.
|
||||
|
||||
Session-scoped fixture that starts sloppy.py with --enable-test-hooks.
|
||||
Includes high-signal environment telemetry and workspace isolation.
|
||||
"""
|
||||
gui_script = os.path.abspath("sloppy.py")
|
||||
diag = VerificationLogger("live_gui_startup", "live_gui_diag")
|
||||
|
||||
@@ -10,7 +10,8 @@ from src.api_hook_client import ApiHookClient
|
||||
|
||||
def wait_for_value(client, field, expected, timeout=5):
|
||||
"""
|
||||
Polls the GUI state until a field matches the expected value.
|
||||
|
||||
Polls the GUI state until a field matches the expected value.
|
||||
[C: tests/test_live_workflow.py:test_full_live_workflow]
|
||||
"""
|
||||
start = time.time()
|
||||
|
||||
@@ -3,8 +3,9 @@ from src import ai_client
|
||||
def test_list_models_gemini_cli() -> None:
|
||||
"""
|
||||
|
||||
Verifies that 'ai_client.list_models' correctly returns a list of models
|
||||
for the 'gemini_cli' provider.
|
||||
|
||||
Verifies that 'ai_client.list_models' correctly returns a list of models
|
||||
for the 'gemini_cli' provider.
|
||||
"""
|
||||
models = ai_client.list_models("gemini_cli")
|
||||
assert "gemini-3.1-pro-preview" in models
|
||||
|
||||
@@ -37,7 +37,8 @@ def app_controller(tmp_session_dir):
|
||||
def test_on_comms_entry_tool_result_offloading(app_controller, tmp_session_dir):
|
||||
"""
|
||||
|
||||
Test that _on_comms_entry offloads tool_result output to a separate file.
|
||||
|
||||
Test that _on_comms_entry offloads tool_result output to a separate file.
|
||||
"""
|
||||
output_content = "This is a large tool output that should be offloaded."
|
||||
entry = {
|
||||
@@ -83,7 +84,8 @@ def test_on_comms_entry_tool_result_offloading(app_controller, tmp_session_dir):
|
||||
def test_on_tool_log_offloading(app_controller, tmp_session_dir):
|
||||
"""
|
||||
|
||||
Test that _on_tool_log calls session_logger.log_tool_call and log_tool_output.
|
||||
|
||||
Test that _on_tool_log calls session_logger.log_tool_call and log_tool_output.
|
||||
"""
|
||||
script = "Get-Process"
|
||||
result = "Process list..."
|
||||
|
||||
@@ -323,4 +323,4 @@ public:
|
||||
assert 'void myMethod() {' in updated
|
||||
assert 'int y = 2;' in updated
|
||||
assert 'int x = 1;' not in updated
|
||||
assert 'class MyClass {' in updated
|
||||
assert 'class MyClass {' in updated
|
||||
@@ -9,8 +9,9 @@ from src import mcp_client
|
||||
async def test_execute_tool_calls_concurrently_timing():
|
||||
"""
|
||||
|
||||
Verifies that _execute_tool_calls_concurrently runs tools in parallel.
|
||||
Total time should be approx 0.5s for 3 tools each taking 0.5s.
|
||||
|
||||
Verifies that _execute_tool_calls_concurrently runs tools in parallel.
|
||||
Total time should be approx 0.5s for 3 tools each taking 0.5s.
|
||||
"""
|
||||
# 1. Setup mock tool calls (Gemini style)
|
||||
class MockGeminiCall:
|
||||
@@ -67,8 +68,9 @@ async def test_execute_tool_calls_concurrently_timing():
|
||||
async def test_execute_tool_calls_concurrently_exception_handling():
|
||||
"""
|
||||
|
||||
Verifies that if one tool call fails, it doesn't crash the whole group if caught,
|
||||
but currently gather is used WITHOUT return_exceptions=True, so it should re-raise.
|
||||
|
||||
Verifies that if one tool call fails, it doesn't crash the whole group if caught,
|
||||
but currently gather is used WITHOUT return_exceptions=True, so it should re-raise.
|
||||
"""
|
||||
class MockGeminiCall:
|
||||
def __init__(self, name, args):
|
||||
|
||||
@@ -22,8 +22,9 @@ class TestCliToolBridgeMapping(unittest.TestCase):
|
||||
def test_mapping_from_api_format(self, mock_request: MagicMock, mock_stdout: MagicMock, mock_stdin: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verify that bridge correctly maps 'id', 'name', 'input' (Gemini API format)
|
||||
into tool_name and tool_input for the hook client.
|
||||
|
||||
Verify that bridge correctly maps 'id', 'name', 'input' (Gemini API format)
|
||||
into tool_name and tool_input for the hook client.
|
||||
"""
|
||||
api_tool_call = {
|
||||
'id': 'call123',
|
||||
|
||||
@@ -7,7 +7,8 @@ import threading
|
||||
def test_conductor_abort_event_populated():
|
||||
"""
|
||||
|
||||
Test that ConductorEngine populates _abort_events when spawning a worker.
|
||||
|
||||
Test that ConductorEngine populates _abort_events when spawning a worker.
|
||||
"""
|
||||
# 1. Mock WorkerPool.spawn to return a mock thread
|
||||
with patch('src.multi_agent_conductor.WorkerPool.spawn') as mock_spawn:
|
||||
|
||||
@@ -4,7 +4,8 @@ from src.api_hook_client import ApiHookClient
|
||||
def simulate_conductor_phase_completion(client: ApiHookClient, track_id: str, phase_name: str) -> bool:
|
||||
"""
|
||||
|
||||
Simulates the Conductor agent's logic for phase completion using ApiHookClient.
|
||||
|
||||
Simulates the Conductor agent's logic for phase completion using ApiHookClient.
|
||||
"""
|
||||
try:
|
||||
# 1. Poll for state
|
||||
@@ -24,8 +25,9 @@ def simulate_conductor_phase_completion(client: ApiHookClient, track_id: str, ph
|
||||
|
||||
def test_conductor_integrates_api_hook_client_for_verification(live_gui) -> None:
|
||||
"""
|
||||
Verify that Conductor's simulated phase completion logic properly integrates
|
||||
with the ApiHookClient and the live Hook Server.
|
||||
|
||||
Verify that Conductor's simulated phase completion logic properly integrates
|
||||
with the ApiHookClient and the live Hook Server.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=10)
|
||||
|
||||
@@ -8,7 +8,8 @@ from src.models import Track
|
||||
def test_conductor_engine_initializes_empty_worker_and_abort_dicts() -> None:
|
||||
"""
|
||||
|
||||
Test that ConductorEngine correctly initializes _active_workers and _abort_events as empty dictionaries.
|
||||
|
||||
Test that ConductorEngine correctly initializes _active_workers and _abort_events as empty dictionaries.
|
||||
"""
|
||||
# Mock the track object
|
||||
mock_track = MagicMock(spec=Track)
|
||||
@@ -24,8 +25,9 @@ def test_conductor_engine_initializes_empty_worker_and_abort_dicts() -> None:
|
||||
def test_kill_worker_sets_abort_and_joins_thread() -> None:
|
||||
"""
|
||||
|
||||
Test kill_worker: mock a running thread in _active_workers, call kill_worker,
|
||||
assert abort_event is set and thread is joined.
|
||||
|
||||
Test kill_worker: mock a running thread in _active_workers, call kill_worker,
|
||||
assert abort_event is set and thread is joined.
|
||||
"""
|
||||
mock_track = MagicMock(spec=Track)
|
||||
mock_track.tickets = []
|
||||
@@ -38,7 +40,7 @@ def test_kill_worker_sets_abort_and_joins_thread() -> None:
|
||||
# Create a thread that waits for the abort event
|
||||
def worker():
|
||||
"""
|
||||
[C: tests/test_symbol_parsing.py:test_handle_generate_send_appends_definitions, tests/test_symbol_parsing.py:test_handle_generate_send_no_symbols]
|
||||
[C: tests/test_symbol_parsing.py:test_handle_generate_send_appends_definitions, tests/test_symbol_parsing.py:test_handle_generate_send_no_symbols]
|
||||
"""
|
||||
abort_event.wait(timeout=2.0)
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ from src import ai_client
|
||||
def test_conductor_engine_initialization() -> None:
|
||||
"""
|
||||
|
||||
Test that ConductorEngine can be initialized with a Track.
|
||||
|
||||
Test that ConductorEngine can be initialized with a Track.
|
||||
"""
|
||||
track = Track(id="test_track", description="Test Track")
|
||||
from src.multi_agent_conductor import ConductorEngine
|
||||
@@ -20,7 +21,8 @@ def test_conductor_engine_initialization() -> None:
|
||||
def test_conductor_engine_run_executes_tickets_in_order(monkeypatch: pytest.MonkeyPatch, vlogger) -> None:
|
||||
"""
|
||||
|
||||
Test that run iterates through executable tickets and calls the worker lifecycle.
|
||||
|
||||
Test that run iterates through executable tickets and calls the worker lifecycle.
|
||||
"""
|
||||
ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
ticket2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="worker2", depends_on=["T1"])
|
||||
@@ -67,7 +69,8 @@ def test_conductor_engine_run_executes_tickets_in_order(monkeypatch: pytest.Monk
|
||||
def test_run_worker_lifecycle_calls_ai_client_send(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle triggers the AI client and updates ticket status on success.
|
||||
|
||||
Test that run_worker_lifecycle triggers the AI client and updates ticket status on success.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
@@ -88,7 +91,8 @@ def test_run_worker_lifecycle_calls_ai_client_send(monkeypatch: pytest.MonkeyPat
|
||||
def test_run_worker_lifecycle_context_injection(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle can take a context_files list and injects AST views into the prompt.
|
||||
|
||||
Test that run_worker_lifecycle can take a context_files list and injects AST views into the prompt.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
@@ -134,7 +138,8 @@ def test_run_worker_lifecycle_context_injection(monkeypatch: pytest.MonkeyPatch)
|
||||
def test_run_worker_lifecycle_handles_blocked_response(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle marks the ticket as blocked if the AI indicates it cannot proceed.
|
||||
|
||||
Test that run_worker_lifecycle marks the ticket as blocked if the AI indicates it cannot proceed.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
@@ -151,9 +156,10 @@ def test_run_worker_lifecycle_handles_blocked_response(monkeypatch: pytest.Monke
|
||||
def test_run_worker_lifecycle_step_mode_confirmation(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle passes confirm_execution to ai_client.send when step_mode is True.
|
||||
Verify that if confirm_execution is called (simulated by mocking ai_client.send to call its callback),
|
||||
the flow works as expected.
|
||||
|
||||
Test that run_worker_lifecycle passes confirm_execution to ai_client.send when step_mode is True.
|
||||
Verify that if confirm_execution is called (simulated by mocking ai_client.send to call its callback),
|
||||
the flow works as expected.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1", step_mode=True)
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
@@ -188,8 +194,9 @@ def test_run_worker_lifecycle_step_mode_confirmation(monkeypatch: pytest.MonkeyP
|
||||
def test_run_worker_lifecycle_step_mode_rejection(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Verify that if confirm_execution returns False, the logic (in ai_client, which we simulate here)
|
||||
would prevent execution. In run_worker_lifecycle, we just check if it's passed.
|
||||
|
||||
Verify that if confirm_execution returns False, the logic (in ai_client, which we simulate here)
|
||||
would prevent execution. In run_worker_lifecycle, we just check if it's passed.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1", step_mode=True)
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
@@ -213,7 +220,8 @@ def test_run_worker_lifecycle_step_mode_rejection(monkeypatch: pytest.MonkeyPatc
|
||||
def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytest.MonkeyPatch, vlogger) -> None:
|
||||
"""
|
||||
|
||||
Test that parse_json_tickets correctly populates the track and run executes them in dependency order.
|
||||
|
||||
Test that parse_json_tickets correctly populates the track and run executes them in dependency order.
|
||||
"""
|
||||
import json
|
||||
from src.multi_agent_conductor import ConductorEngine
|
||||
@@ -281,8 +289,9 @@ def test_conductor_engine_dynamic_parsing_and_execution(monkeypatch: pytest.Monk
|
||||
def test_run_worker_lifecycle_pushes_response_via_queue(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle pushes a 'response' event with the correct stream_id
|
||||
via _queue_put when event_queue is provided.
|
||||
|
||||
Test that run_worker_lifecycle pushes a 'response' event with the correct stream_id
|
||||
via _queue_put when event_queue is provided.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
@@ -307,8 +316,9 @@ def test_run_worker_lifecycle_pushes_response_via_queue(monkeypatch: pytest.Monk
|
||||
def test_run_worker_lifecycle_token_usage_from_comms_log(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle reads token usage from the comms log and
|
||||
updates engine.tier_usage['Tier 3'] with real input/output token counts.
|
||||
|
||||
Test that run_worker_lifecycle reads token usage from the comms log and
|
||||
updates engine.tier_usage['Tier 3'] with real input/output token counts.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
context = WorkerContext(ticket_id="T1", model_name="test-model", messages=[])
|
||||
|
||||
+19
-10
@@ -10,7 +10,8 @@ from src.dag_engine import TrackDAG
|
||||
def test_get_ready_tasks_linear():
|
||||
"""
|
||||
|
||||
Verifies ready tasks detection in a simple linear dependency chain.
|
||||
|
||||
Verifies ready tasks detection in a simple linear dependency chain.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -22,8 +23,9 @@ def test_get_ready_tasks_linear():
|
||||
def test_get_ready_tasks_branching():
|
||||
"""
|
||||
|
||||
Verifies ready tasks detection in a branching dependency graph where multiple tasks
|
||||
are unlocked simultaneously after a prerequisite is met.
|
||||
|
||||
Verifies ready tasks detection in a branching dependency graph where multiple tasks
|
||||
are unlocked simultaneously after a prerequisite is met.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="completed", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -38,7 +40,8 @@ def test_get_ready_tasks_branching():
|
||||
def test_has_cycle_no_cycle():
|
||||
"""
|
||||
|
||||
Validates that an acyclic graph is correctly identified as not having cycles.
|
||||
|
||||
Validates that an acyclic graph is correctly identified as not having cycles.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -48,7 +51,8 @@ def test_has_cycle_no_cycle():
|
||||
def test_has_cycle_direct_cycle():
|
||||
"""
|
||||
|
||||
Validates that a direct cycle (A depends on B, B depends on A) is correctly detected.
|
||||
|
||||
Validates that a direct cycle (A depends on B, B depends on A) is correctly detected.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1", depends_on=["T2"])
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -58,7 +62,8 @@ def test_has_cycle_direct_cycle():
|
||||
def test_has_cycle_indirect_cycle():
|
||||
"""
|
||||
|
||||
Validates that an indirect cycle (A->B->C->A) is correctly detected.
|
||||
|
||||
Validates that an indirect cycle (A->B->C->A) is correctly detected.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1", depends_on=["T3"])
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -69,7 +74,8 @@ def test_has_cycle_indirect_cycle():
|
||||
def test_has_cycle_complex_no_cycle():
|
||||
"""
|
||||
|
||||
Validates cycle detection in a complex graph that merges branches but remains acyclic.
|
||||
|
||||
Validates cycle detection in a complex graph that merges branches but remains acyclic.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -81,7 +87,8 @@ def test_has_cycle_complex_no_cycle():
|
||||
def test_get_ready_tasks_multiple_deps():
|
||||
"""
|
||||
|
||||
Validates that a task is not marked ready until ALL of its dependencies are completed.
|
||||
|
||||
Validates that a task is not marked ready until ALL of its dependencies are completed.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="completed", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1")
|
||||
@@ -95,7 +102,8 @@ def test_get_ready_tasks_multiple_deps():
|
||||
def test_topological_sort():
|
||||
"""
|
||||
|
||||
Verifies that tasks are correctly ordered by dependencies regardless of input order.
|
||||
|
||||
Verifies that tasks are correctly ordered by dependencies regardless of input order.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -107,7 +115,8 @@ def test_topological_sort():
|
||||
def test_topological_sort_cycle():
|
||||
"""
|
||||
|
||||
Verifies that topological sorting safely aborts and raises ValueError when a cycle is present.
|
||||
|
||||
Verifies that topological sorting safely aborts and raises ValueError when a cycle is present.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="desc", status="todo", assigned_to="worker1", depends_on=["T2"])
|
||||
t2 = Ticket(id="T2", description="desc", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
|
||||
@@ -13,8 +13,9 @@ from src import project_manager
|
||||
def test_credentials_error_mentions_deepseek(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""
|
||||
|
||||
Verify that the error message shown when credentials.toml is missing
|
||||
includes deepseek instructions.
|
||||
|
||||
Verify that the error message shown when credentials.toml is missing
|
||||
includes deepseek instructions.
|
||||
"""
|
||||
# Monkeypatch SLOP_CREDENTIALS to a non-existent file
|
||||
monkeypatch.setenv("SLOP_CREDENTIALS", "non_existent_credentials_file.toml")
|
||||
@@ -27,8 +28,9 @@ def test_credentials_error_mentions_deepseek(monkeypatch: pytest.MonkeyPatch) ->
|
||||
def test_default_project_includes_reasoning_role() -> None:
|
||||
"""
|
||||
|
||||
Verify that 'Reasoning' is included in the default discussion roles
|
||||
to support DeepSeek-R1 reasoning traces.
|
||||
|
||||
Verify that 'Reasoning' is included in the default discussion roles
|
||||
to support DeepSeek-R1 reasoning traces.
|
||||
"""
|
||||
proj = project_manager.default_project("test")
|
||||
roles = proj["discussion"]["roles"]
|
||||
@@ -37,7 +39,8 @@ def test_default_project_includes_reasoning_role() -> None:
|
||||
def test_gui_providers_list() -> None:
|
||||
"""
|
||||
|
||||
Check if 'deepseek' is in the GUI's provider list.
|
||||
|
||||
Check if 'deepseek' is in the GUI's provider list.
|
||||
"""
|
||||
from src.models import PROVIDERS
|
||||
assert "deepseek" in PROVIDERS
|
||||
@@ -45,7 +48,8 @@ def test_gui_providers_list() -> None:
|
||||
def test_deepseek_model_listing() -> None:
|
||||
"""
|
||||
|
||||
Verify that list_models for deepseek returns expected models.
|
||||
|
||||
Verify that list_models for deepseek returns expected models.
|
||||
"""
|
||||
models = ai_client.list_models("deepseek")
|
||||
assert "deepseek-chat" in models
|
||||
@@ -54,7 +58,8 @@ def test_deepseek_model_listing() -> None:
|
||||
def test_gui_provider_list_via_hooks(live_gui: Any) -> None:
|
||||
"""
|
||||
|
||||
Verify 'deepseek' is present in the GUI provider list using API hooks.
|
||||
|
||||
Verify 'deepseek' is present in the GUI provider list using API hooks.
|
||||
"""
|
||||
from api_hook_client import ApiHookClient
|
||||
import time
|
||||
|
||||
@@ -5,7 +5,8 @@ from src import ai_client
|
||||
def test_deepseek_model_selection() -> None:
|
||||
"""
|
||||
|
||||
Verifies that ai_client.set_provider('deepseek', 'deepseek-chat') correctly updates the internal state.
|
||||
|
||||
Verifies that ai_client.set_provider('deepseek', 'deepseek-chat') correctly updates the internal state.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-chat")
|
||||
assert ai_client._provider == "deepseek"
|
||||
@@ -15,7 +16,8 @@ def test_deepseek_model_selection() -> None:
|
||||
def test_deepseek_completion_logic(mock_post: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verifies that ai_client.send() correctly calls the DeepSeek API and returns content.
|
||||
|
||||
Verifies that ai_client.send() correctly calls the DeepSeek API and returns content.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-chat")
|
||||
with patch("src.ai_client._load_credentials", return_value={"deepseek": {"api_key": "test-key"}}):
|
||||
@@ -34,7 +36,8 @@ def test_deepseek_completion_logic(mock_post: MagicMock) -> None:
|
||||
def test_deepseek_reasoning_logic(mock_post: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verifies that reasoning_content is captured and wrapped in <thinking> tags.
|
||||
|
||||
Verifies that reasoning_content is captured and wrapped in <thinking> tags.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-reasoner")
|
||||
with patch("src.ai_client._load_credentials", return_value={"deepseek": {"api_key": "test-key"}}):
|
||||
@@ -56,7 +59,8 @@ def test_deepseek_reasoning_logic(mock_post: MagicMock) -> None:
|
||||
def test_deepseek_tool_calling(mock_post: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verifies that DeepSeek provider correctly identifies and executes tool calls.
|
||||
|
||||
Verifies that DeepSeek provider correctly identifies and executes tool calls.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-chat")
|
||||
with patch("src.ai_client._load_credentials", return_value={"deepseek": {"api_key": "test-key"}}), \
|
||||
@@ -98,7 +102,8 @@ def test_deepseek_tool_calling(mock_post: MagicMock) -> None:
|
||||
def test_deepseek_streaming(mock_post: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verifies that DeepSeek provider correctly aggregates streaming chunks.
|
||||
|
||||
Verifies that DeepSeek provider correctly aggregates streaming chunks.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-chat")
|
||||
with patch("src.ai_client._load_credentials", return_value={"deepseek": {"api_key": "test-key"}}):
|
||||
@@ -121,7 +126,8 @@ def test_deepseek_streaming(mock_post: MagicMock) -> None:
|
||||
def test_deepseek_payload_verification(mock_post: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the correct JSON payload (tools, history, params) is sent to DeepSeek.
|
||||
|
||||
Verifies that the correct JSON payload (tools, history, params) is sent to DeepSeek.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-chat")
|
||||
ai_client.reset_session()
|
||||
@@ -149,7 +155,8 @@ def test_deepseek_payload_verification(mock_post: MagicMock) -> None:
|
||||
def test_deepseek_reasoner_payload_verification(mock_post: MagicMock) -> None:
|
||||
"""
|
||||
|
||||
Verifies that deepseek-reasoner payload excludes tools and temperature.
|
||||
|
||||
Verifies that deepseek-reasoner payload excludes tools and temperature.
|
||||
"""
|
||||
ai_client.set_provider("deepseek", "deepseek-reasoner")
|
||||
ai_client.reset_session()
|
||||
|
||||
@@ -69,4 +69,4 @@ def test_execution_sim_live(live_gui: Any) -> None:
|
||||
client.set_value('auto_add_history', True)
|
||||
sim.run()
|
||||
time.sleep(2)
|
||||
sim.teardown()
|
||||
sim.teardown()
|
||||
@@ -55,4 +55,4 @@ def test_file_item_from_dict_defaults():
|
||||
assert item.view_mode == "full"
|
||||
assert item.ast_mask == {}
|
||||
assert item.custom_slices == []
|
||||
assert item.injected_at is None
|
||||
assert item.injected_at is None
|
||||
@@ -12,8 +12,9 @@ from src.ai_client import get_gemini_cache_stats, reset_session
|
||||
def test_get_gemini_cache_stats_with_mock_client() -> None:
|
||||
"""
|
||||
|
||||
Test that get_gemini_cache_stats correctly processes cache lists
|
||||
from a mocked client instance.
|
||||
|
||||
Test that get_gemini_cache_stats correctly processes cache lists
|
||||
from a mocked client instance.
|
||||
"""
|
||||
# Ensure a clean state before the test by resetting the session
|
||||
reset_session()
|
||||
|
||||
@@ -12,8 +12,9 @@ def app_instance(monkeypatch: pytest.MonkeyPatch) -> type[App]:
|
||||
def test_app_subscribes_to_events(app_instance: type[App]) -> None:
|
||||
"""
|
||||
|
||||
This test checks that the App's __init__ method subscribes the necessary
|
||||
event handlers to the ai_client.events emitter.
|
||||
|
||||
This test checks that the App's __init__ method subscribes the necessary
|
||||
event handlers to the ai_client.events emitter.
|
||||
"""
|
||||
with patch.object(ai_client.events, 'on') as mock_on:
|
||||
app = app_instance()
|
||||
|
||||
@@ -3,8 +3,9 @@ from src.gui_2 import App
|
||||
def test_gui2_hubs_exist_in_show_windows(app_instance: App) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the new consolidated Hub windows are defined in the App's show_windows.
|
||||
This ensures they will be available in the 'Windows' menu.
|
||||
|
||||
Verifies that the new consolidated Hub windows are defined in the App's show_windows.
|
||||
This ensures they will be available in the 'Windows' menu.
|
||||
"""
|
||||
expected_hubs = [
|
||||
"Project Settings",
|
||||
@@ -20,8 +21,9 @@ def test_gui2_hubs_exist_in_show_windows(app_instance: App) -> None:
|
||||
def test_gui2_old_windows_removed_from_show_windows(app_instance: App) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the old fragmented windows are removed from show_windows.
|
||||
Note: Message, Response, and Tool Calls are kept as they are now optional standalone windows.
|
||||
|
||||
Verifies that the old fragmented windows are removed from show_windows.
|
||||
Note: Message, Response, and Tool Calls are kept as they are now optional standalone windows.
|
||||
"""
|
||||
old_windows = [
|
||||
"Projects", "Files", "Screenshots",
|
||||
|
||||
@@ -6,9 +6,10 @@ from src import ai_client
|
||||
def test_mcp_tool_call_is_dispatched(app_instance: App) -> None:
|
||||
"""
|
||||
|
||||
This test verifies that when the AI returns a tool call for an MCP function,
|
||||
the ai_client correctly dispatches it to mcp_client.
|
||||
This will fail until mcp_client is properly integrated.
|
||||
|
||||
This test verifies that when the AI returns a tool call for an MCP function,
|
||||
the ai_client correctly dispatches it to mcp_client.
|
||||
This will fail until mcp_client is properly integrated.
|
||||
"""
|
||||
# 1. Define the mock tool call from the AI
|
||||
mock_fc = MagicMock()
|
||||
|
||||
@@ -26,7 +26,8 @@ def cleanup_callback_file() -> None:
|
||||
def test_gui2_set_value_hook_works(live_gui: Any) -> None:
|
||||
"""
|
||||
|
||||
Tests that the 'set_value' GUI hook is correctly implemented.
|
||||
|
||||
Tests that the 'set_value' GUI hook is correctly implemented.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=10)
|
||||
@@ -42,7 +43,8 @@ def test_gui2_set_value_hook_works(live_gui: Any) -> None:
|
||||
def test_gui2_click_hook_works(live_gui: Any) -> None:
|
||||
"""
|
||||
|
||||
Tests that the 'click' GUI hook for the 'Reset' button is implemented.
|
||||
|
||||
Tests that the 'click' GUI hook for the 'Reset' button is implemented.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=10)
|
||||
@@ -60,7 +62,8 @@ def test_gui2_click_hook_works(live_gui: Any) -> None:
|
||||
def test_gui2_custom_callback_hook_works(live_gui: Any) -> None:
|
||||
"""
|
||||
|
||||
Tests that the 'custom_callback' GUI hook is correctly implemented.
|
||||
|
||||
Tests that the 'custom_callback' GUI hook is correctly implemented.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=10)
|
||||
@@ -78,4 +81,4 @@ def test_gui2_custom_callback_hook_works(live_gui: Any) -> None:
|
||||
assert temp_workspace_file.exists(), f"Custom callback was NOT executed, or file path is wrong! Expected: {temp_workspace_file}"
|
||||
with open(temp_workspace_file, "r") as f:
|
||||
content = f.read()
|
||||
assert content == test_data, "Callback executed, but file content is incorrect."
|
||||
assert content == test_data, "Callback executed, but file content is incorrect."
|
||||
@@ -20,8 +20,9 @@ _shared_metrics = {}
|
||||
def test_performance_benchmarking(live_gui: tuple) -> None:
|
||||
"""
|
||||
|
||||
Collects performance metrics for the current GUI script over a 5-second window.
|
||||
Ensures the application does not lock up and can report its internal state.
|
||||
|
||||
Collects performance metrics for the current GUI script over a 5-second window.
|
||||
Ensures the application does not lock up and can report its internal state.
|
||||
"""
|
||||
process, gui_script = live_gui
|
||||
client = ApiHookClient()
|
||||
@@ -67,8 +68,9 @@ def test_performance_benchmarking(live_gui: tuple) -> None:
|
||||
def test_performance_baseline_check() -> None:
|
||||
"""
|
||||
|
||||
Verifies that we have successfully collected performance metrics for sloppy.py
|
||||
and that they meet the minimum 30 FPS baseline.
|
||||
|
||||
Verifies that we have successfully collected performance metrics for sloppy.py
|
||||
and that they meet the minimum 30 FPS baseline.
|
||||
"""
|
||||
# Key is full path, find it by basename
|
||||
gui_key = next((k for k in _shared_metrics if "sloppy.py" in k), None)
|
||||
|
||||
@@ -15,9 +15,10 @@ def test_diagnostics_panel_initialization(app_instance: Any) -> None:
|
||||
def test_diagnostics_history_updates(app_instance: Any) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the internal performance history is updated correctly.
|
||||
This logic is inside the render loop in gui_2.py, but we can test
|
||||
the data structure and initialization.
|
||||
|
||||
Verifies that the internal performance history is updated correctly.
|
||||
This logic is inside the render loop in gui_2.py, but we can test
|
||||
the data structure and initialization.
|
||||
"""
|
||||
assert "fps" in app_instance.perf_history
|
||||
assert len(app_instance.perf_history["fps"]) == 100
|
||||
@@ -60,4 +60,4 @@ def test_render_files_and_media_fast(app_instance: App):
|
||||
try:
|
||||
app_instance._render_files_and_media()
|
||||
except Exception as e:
|
||||
pytest.fail(f"_render_files_and_media raised an exception: {e}")
|
||||
pytest.fail(f"_render_files_and_media raised an exception: {e}")
|
||||
@@ -13,7 +13,7 @@ class MockApp:
|
||||
|
||||
def init_state(self):
|
||||
"""
|
||||
[C: tests/test_system_prompt_exposure.py:TestSystemPromptExposure.test_app_controller_init_state_loads_prompts]
|
||||
[C: tests/test_system_prompt_exposure.py:TestSystemPromptExposure.test_app_controller_init_state_loads_prompts]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ from api_hook_client import ApiHookClient
|
||||
def test_idle_performance_requirements(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Requirement: GUI must maintain stable performance on idle.
|
||||
|
||||
Requirement: GUI must maintain stable performance on idle.
|
||||
"""
|
||||
# Warmup to ensure GUI is ready
|
||||
time.sleep(5.0)
|
||||
|
||||
@@ -12,8 +12,9 @@ from src import paths
|
||||
def test_track_proposal_editing(app_instance):
|
||||
"""
|
||||
|
||||
Verifies the structural integrity of track proposal items.
|
||||
Ensures that track proposals can be edited and removed from the active list.
|
||||
|
||||
Verifies the structural integrity of track proposal items.
|
||||
Ensures that track proposals can be edited and removed from the active list.
|
||||
"""
|
||||
app_instance.proposed_tracks = [
|
||||
{"title": "Old Title", "goal": "Old Goal"},
|
||||
@@ -35,8 +36,9 @@ def test_track_proposal_editing(app_instance):
|
||||
def test_conductor_setup_scan(app_instance, tmp_path, monkeypatch):
|
||||
"""
|
||||
|
||||
Verifies that the conductor setup scan properly iterates through the conductor directory,
|
||||
counts files and lines, and identifies active tracks.
|
||||
|
||||
Verifies that the conductor setup scan properly iterates through the conductor directory,
|
||||
counts files and lines, and identifies active tracks.
|
||||
"""
|
||||
old_cwd = os.getcwd()
|
||||
os.chdir(tmp_path)
|
||||
@@ -63,8 +65,9 @@ def test_conductor_setup_scan(app_instance, tmp_path, monkeypatch):
|
||||
def test_create_track(app_instance, tmp_path):
|
||||
"""
|
||||
|
||||
Verifies that _cb_create_track properly creates the track folder
|
||||
and populates the necessary boilerplate files (spec.md, plan.md, metadata.json).
|
||||
|
||||
Verifies that _cb_create_track properly creates the track folder
|
||||
and populates the necessary boilerplate files (spec.md, plan.md, metadata.json).
|
||||
"""
|
||||
old_cwd = os.getcwd()
|
||||
os.chdir(tmp_path)
|
||||
@@ -91,4 +94,4 @@ def test_create_track(app_instance, tmp_path):
|
||||
assert data['type'] == "feature"
|
||||
assert data['id'] == track_dir.name
|
||||
finally:
|
||||
os.chdir(old_cwd)
|
||||
os.chdir(old_cwd)
|
||||
@@ -3,7 +3,8 @@ import time
|
||||
def test_gui_startup_smoke(live_gui):
|
||||
"""
|
||||
|
||||
Smoke test to ensure the GUI starts and remains running.
|
||||
|
||||
Smoke test to ensure the GUI starts and remains running.
|
||||
"""
|
||||
proc, _ = live_gui
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ from src.api_hook_client import ApiHookClient
|
||||
def test_text_viewer_state_update(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Verifies that we can set text viewer state and it is reflected in GUI state.
|
||||
|
||||
Verifies that we can set text viewer state and it is reflected in GUI state.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
client.click("btn_reset")
|
||||
@@ -32,4 +33,4 @@ def test_text_viewer_state_update(live_gui) -> None:
|
||||
assert state is not None
|
||||
assert state.get('show_text_viewer') == True
|
||||
assert state.get('text_viewer_title') == label
|
||||
assert state.get('text_viewer_type') == text_type
|
||||
assert state.get('text_viewer_type') == text_type
|
||||
@@ -17,9 +17,10 @@ from src.gui_2 import App
|
||||
def test_telemetry_data_updates_correctly(app_instance: Any) -> None:
|
||||
"""
|
||||
|
||||
Tests that the _refresh_api_metrics method correctly updates
|
||||
the internal state for display by querying the ai_client.
|
||||
Verifies the boundary between GUI state and API state.
|
||||
|
||||
Tests that the _refresh_api_metrics method correctly updates
|
||||
the internal state for display by querying the ai_client.
|
||||
Verifies the boundary between GUI state and API state.
|
||||
"""
|
||||
# 1. Set the provider to anthropic
|
||||
app_instance._current_provider = "anthropic"
|
||||
@@ -43,9 +44,10 @@ def test_telemetry_data_updates_correctly(app_instance: Any) -> None:
|
||||
def test_performance_history_updates(app_instance: Any) -> None:
|
||||
"""
|
||||
|
||||
Verify the data structure that feeds the sparkline.
|
||||
This ensures that the rolling buffer for performance telemetry maintains
|
||||
the correct size and default initialization to prevent GUI rendering crashes.
|
||||
|
||||
Verify the data structure that feeds the sparkline.
|
||||
This ensures that the rolling buffer for performance telemetry maintains
|
||||
the correct size and default initialization to prevent GUI rendering crashes.
|
||||
"""
|
||||
# ANTI-SIMPLIFICATION: Verifying exactly 100 elements ensures the sparkline won't overflow
|
||||
assert len(app_instance.perf_history["frame_time"]) == 100
|
||||
@@ -54,9 +56,10 @@ def test_performance_history_updates(app_instance: Any) -> None:
|
||||
def test_gui_updates_on_event(app_instance: App) -> None:
|
||||
"""
|
||||
|
||||
Verifies that when an API event is received (e.g. from ai_client),
|
||||
the _on_api_event handler correctly updates internal metrics and
|
||||
queues the update to be processed by the GUI event loop.
|
||||
|
||||
Verifies that when an API event is received (e.g. from ai_client),
|
||||
the _on_api_event handler correctly updates internal metrics and
|
||||
queues the update to be processed by the GUI event loop.
|
||||
"""
|
||||
mock_stats = {"percentage": 50.0, "current": 500, "limit": 1000}
|
||||
app_instance.last_md = "mock_md"
|
||||
|
||||
@@ -6,10 +6,11 @@ from src.api_hook_client import ApiHookClient
|
||||
async def test_mma_track_lifecycle_simulation():
|
||||
"""
|
||||
|
||||
This test simulates the sequence of API calls an external orchestrator
|
||||
would make to manage an MMA track lifecycle via the Hook API.
|
||||
It verifies that ApiHookClient correctly routes requests to the
|
||||
corresponding endpoints in src/api_hooks.py.
|
||||
|
||||
This test simulates the sequence of API calls an external orchestrator
|
||||
would make to manage an MMA track lifecycle via the Hook API.
|
||||
It verifies that ApiHookClient correctly routes requests to the
|
||||
corresponding endpoints in src/api_hooks.py.
|
||||
"""
|
||||
|
||||
client = ApiHookClient("http://localhost:8999")
|
||||
|
||||
@@ -10,10 +10,11 @@ from src import ai_client
|
||||
async def test_headless_verification_full_run(vlogger) -> None:
|
||||
"""
|
||||
|
||||
1. Initialize a ConductorEngine with a Track containing multiple dependent Tickets.
|
||||
2. Simulate a full execution run using engine.run().
|
||||
3. Mock ai_client.send to simulate successful tool calls and final responses.
|
||||
4. Specifically verify that 'Context Amnesia' is maintained.
|
||||
|
||||
1. Initialize a ConductorEngine with a Track containing multiple dependent Tickets.
|
||||
2. Simulate a full execution run using engine.run().
|
||||
3. Mock ai_client.send to simulate successful tool calls and final responses.
|
||||
4. Specifically verify that 'Context Amnesia' is maintained.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="worker1")
|
||||
t2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="worker1", depends_on=["T1"])
|
||||
@@ -49,8 +50,9 @@ async def test_headless_verification_full_run(vlogger) -> None:
|
||||
async def test_headless_verification_error_and_qa_interceptor(vlogger) -> None:
|
||||
"""
|
||||
|
||||
5. Simulate a shell error and verify that the Tier 4 QA interceptor is triggered
|
||||
and its summary is injected into the worker's history for the next retry.
|
||||
|
||||
5. Simulate a shell error and verify that the Tier 4 QA interceptor is triggered
|
||||
and its summary is injected into the worker's history for the next retry.
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="Task with error", status="todo", assigned_to="worker1")
|
||||
track = Track(id="track_error", description="Error Track", tickets=[t1])
|
||||
|
||||
@@ -12,8 +12,9 @@ from src.gui_2 import App
|
||||
def test_new_hubs_defined_in_show_windows(mock_app: App) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the new consolidated Hub windows are defined in the App's show_windows.
|
||||
This ensures they will be available in the 'Windows' menu.
|
||||
|
||||
Verifies that the new consolidated Hub windows are defined in the App's show_windows.
|
||||
This ensures they will be available in the 'Windows' menu.
|
||||
"""
|
||||
expected_hubs = [
|
||||
"Project Settings",
|
||||
@@ -27,7 +28,8 @@ def test_new_hubs_defined_in_show_windows(mock_app: App) -> None:
|
||||
def test_old_windows_removed_from_gui2(app_instance_simple: Any) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the old fragmented windows are removed or renamed.
|
||||
|
||||
Verifies that the old fragmented windows are removed or renamed.
|
||||
"""
|
||||
old_tags = [
|
||||
"win_projects", "win_files", "win_screenshots",
|
||||
@@ -54,7 +56,8 @@ def app_instance_simple() -> Any:
|
||||
def test_hub_windows_exist_in_gui2(app_instance_simple: Any) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the new Hub windows are present in the show_windows dictionary.
|
||||
|
||||
Verifies that the new Hub windows are present in the show_windows dictionary.
|
||||
"""
|
||||
hubs = ["Project Settings", "AI Settings", "Discussion Hub", "Operations Hub"]
|
||||
for hub in hubs:
|
||||
@@ -63,7 +66,8 @@ def test_hub_windows_exist_in_gui2(app_instance_simple: Any) -> None:
|
||||
def test_indicators_logic_exists(app_instance_simple: Any) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the status indicators logic exists in the App.
|
||||
|
||||
Verifies that the status indicators logic exists in the App.
|
||||
"""
|
||||
assert hasattr(app_instance_simple, 'ai_status')
|
||||
assert hasattr(app_instance_simple, 'mma_status')
|
||||
@@ -14,11 +14,12 @@ from src.api_hook_client import ApiHookClient
|
||||
def test_user_request_integration_flow(mock_app: App) -> None:
|
||||
"""
|
||||
|
||||
Verifies that pushing a UserRequestEvent to the event_queue:
|
||||
1. Triggers ai_client.send
|
||||
2. Results in a 'response' event back to the queue
|
||||
3. Eventually updates the UI state (ai_response, ai_status) after processing GUI tasks.
|
||||
ANTI-SIMPLIFICATION: This verifies the full cross-thread boundary.
|
||||
|
||||
Verifies that pushing a UserRequestEvent to the event_queue:
|
||||
1. Triggers ai_client.send
|
||||
2. Results in a 'response' event back to the queue
|
||||
3. Eventually updates the UI state (ai_response, ai_status) after processing GUI tasks.
|
||||
ANTI-SIMPLIFICATION: This verifies the full cross-thread boundary.
|
||||
"""
|
||||
app = mock_app
|
||||
# Mock all ai_client methods called during _handle_request_event
|
||||
@@ -76,7 +77,8 @@ def test_user_request_integration_flow(mock_app: App) -> None:
|
||||
def test_user_request_error_handling(mock_app: App) -> None:
|
||||
"""
|
||||
|
||||
Verifies that if ai_client.send raises an exception, the UI is updated with the error state.
|
||||
|
||||
Verifies that if ai_client.send raises an exception, the UI is updated with the error state.
|
||||
"""
|
||||
app = mock_app
|
||||
with (
|
||||
|
||||
@@ -16,7 +16,8 @@ from src.api_hook_client import ApiHookClient
|
||||
def wait_for_value(client, field, expected, timeout=10):
|
||||
"""
|
||||
|
||||
Helper to poll the GUI state until a field matches the expected value.
|
||||
|
||||
Helper to poll the GUI state until a field matches the expected value.
|
||||
"""
|
||||
start = time.time()
|
||||
while time.time() - start < timeout:
|
||||
@@ -31,9 +32,10 @@ def wait_for_value(client, field, expected, timeout=10):
|
||||
def test_full_live_workflow(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Integration test that drives the GUI through a full workflow.
|
||||
ANTI-SIMPLIFICATION: Asserts exact AI behavior, thinking state tracking,
|
||||
and response logging in discussion history.
|
||||
|
||||
Integration test that drives the GUI through a full workflow.
|
||||
ANTI-SIMPLIFICATION: Asserts exact AI behavior, thinking state tracking,
|
||||
and response logging in discussion history.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=10)
|
||||
|
||||
@@ -6,7 +6,7 @@ from src.gui_2 import App
|
||||
|
||||
def _make_app(**kwargs):
|
||||
"""
|
||||
[C: tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier1_renders_stream_content, tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier3_renders_worker_subheaders]
|
||||
[C: tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier1_renders_stream_content, tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier3_renders_worker_subheaders]
|
||||
"""
|
||||
app = MagicMock()
|
||||
app.mma_streams = kwargs.get("mma_streams", {})
|
||||
@@ -65,7 +65,7 @@ def _make_app(**kwargs):
|
||||
|
||||
def _make_imgui_mock():
|
||||
"""
|
||||
[C: tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier1_renders_stream_content, tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier3_renders_worker_subheaders]
|
||||
[C: tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier1_renders_stream_content, tests/test_mma_dashboard_streams.py:TestMMADashboardStreams.test_tier3_renders_worker_subheaders]
|
||||
"""
|
||||
m = MagicMock()
|
||||
m.begin_table.return_value = False
|
||||
|
||||
@@ -11,7 +11,8 @@ from src import api_hook_client
|
||||
|
||||
def _poll_mma_status(client, timeout, condition, label):
|
||||
"""
|
||||
Poll get_mma_status() until condition(status) is True or timeout.
|
||||
|
||||
Poll get_mma_status() until condition(status) is True or timeout.
|
||||
[C: tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow]
|
||||
"""
|
||||
last_status = {}
|
||||
@@ -28,9 +29,10 @@ def _poll_mma_status(client, timeout, condition, label):
|
||||
def test_mma_concurrent_tracks_execution(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Stress test for concurrent MMA track execution.
|
||||
Verifies that starting multiple tracks simultaneously doesn't cause crashes
|
||||
and that workers from both tracks are processed.
|
||||
|
||||
Stress test for concurrent MMA track execution.
|
||||
Verifies that starting multiple tracks simultaneously doesn't cause crashes
|
||||
and that workers from both tracks are processed.
|
||||
"""
|
||||
client = api_hook_client.ApiHookClient()
|
||||
assert client.wait_for_server(timeout=15), "Hook server did not start"
|
||||
|
||||
@@ -25,8 +25,9 @@ def _poll_mma_workers(client: api_hook_client.ApiHookClient, timeout: int, condi
|
||||
def test_mma_concurrent_tracks_stress(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Stress test: Start two tracks concurrently and verify they both progress
|
||||
without crashing the GUI or losing state.
|
||||
|
||||
Stress test: Start two tracks concurrently and verify they both progress
|
||||
without crashing the GUI or losing state.
|
||||
"""
|
||||
client = api_hook_client.ApiHookClient()
|
||||
assert client.wait_for_server(timeout=15), "Hook server did not start"
|
||||
|
||||
+26
-17
@@ -3,8 +3,9 @@ from src.models import Ticket, Track, WorkerContext
|
||||
def test_ticket_instantiation() -> None:
|
||||
"""
|
||||
|
||||
Verifies that a Ticket can be instantiated with its required fields:
|
||||
id, description, status, assigned_to.
|
||||
|
||||
Verifies that a Ticket can be instantiated with its required fields:
|
||||
id, description, status, assigned_to.
|
||||
"""
|
||||
ticket_id = "T1"
|
||||
description = "Implement surgical code changes"
|
||||
@@ -25,7 +26,8 @@ def test_ticket_instantiation() -> None:
|
||||
def test_ticket_with_dependencies() -> None:
|
||||
"""
|
||||
|
||||
Verifies that a Ticket can store dependencies.
|
||||
|
||||
Verifies that a Ticket can store dependencies.
|
||||
"""
|
||||
ticket = Ticket(
|
||||
id="T2",
|
||||
@@ -39,8 +41,9 @@ def test_ticket_with_dependencies() -> None:
|
||||
def test_track_instantiation() -> None:
|
||||
"""
|
||||
|
||||
Verifies that a Track can be instantiated with its required fields:
|
||||
id, description, and a list of Tickets.
|
||||
|
||||
Verifies that a Track can be instantiated with its required fields:
|
||||
id, description, and a list of Tickets.
|
||||
"""
|
||||
ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a")
|
||||
ticket2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="b")
|
||||
@@ -61,7 +64,8 @@ def test_track_instantiation() -> None:
|
||||
def test_track_can_handle_empty_tickets() -> None:
|
||||
"""
|
||||
|
||||
Verifies that a Track can be instantiated with an empty list of tickets.
|
||||
|
||||
Verifies that a Track can be instantiated with an empty list of tickets.
|
||||
"""
|
||||
track = Track(id="TRACK-2", description="Empty Track", tickets=[])
|
||||
assert track.tickets == []
|
||||
@@ -69,8 +73,9 @@ def test_track_can_handle_empty_tickets() -> None:
|
||||
def test_worker_context_instantiation() -> None:
|
||||
"""
|
||||
|
||||
Verifies that a WorkerContext can be instantiated with ticket_id,
|
||||
model_name, and messages.
|
||||
|
||||
Verifies that a WorkerContext can be instantiated with ticket_id,
|
||||
model_name, and messages.
|
||||
"""
|
||||
ticket_id = "T1"
|
||||
model_name = "gemini-2.0-flash-lite"
|
||||
@@ -90,8 +95,9 @@ def test_worker_context_instantiation() -> None:
|
||||
def test_ticket_mark_blocked() -> None:
|
||||
"""
|
||||
|
||||
Verifies that ticket.mark_blocked(reason) sets the status to 'blocked'.
|
||||
Note: The reason field might need to be added to the Ticket class.
|
||||
|
||||
Verifies that ticket.mark_blocked(reason) sets the status to 'blocked'.
|
||||
Note: The reason field might need to be added to the Ticket class.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a")
|
||||
ticket.mark_blocked("Waiting for API key")
|
||||
@@ -100,7 +106,8 @@ def test_ticket_mark_blocked() -> None:
|
||||
def test_ticket_mark_complete() -> None:
|
||||
"""
|
||||
|
||||
Verifies that ticket.mark_complete() sets the status to 'completed'.
|
||||
|
||||
Verifies that ticket.mark_complete() sets the status to 'completed'.
|
||||
"""
|
||||
ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a")
|
||||
ticket.mark_complete()
|
||||
@@ -109,8 +116,9 @@ def test_ticket_mark_complete() -> None:
|
||||
def test_track_get_executable_tickets() -> None:
|
||||
"""
|
||||
|
||||
Verifies that track.get_executable_tickets() returns only 'todo' tickets
|
||||
whose dependencies are all 'completed'.
|
||||
|
||||
Verifies that track.get_executable_tickets() returns only 'todo' tickets
|
||||
whose dependencies are all 'completed'.
|
||||
"""
|
||||
# T1: todo, no deps -> executable
|
||||
t1 = Ticket(id="T1", description="T1", status="todo", assigned_to="a")
|
||||
@@ -134,10 +142,11 @@ def test_track_get_executable_tickets() -> None:
|
||||
def test_track_get_executable_tickets_complex() -> None:
|
||||
"""
|
||||
|
||||
Verifies executable tickets with complex dependency chains.
|
||||
Chain: T1 (comp) -> T2 (todo) -> T3 (todo)
|
||||
T4 (comp) -> T3
|
||||
T5 (todo) -> T3
|
||||
|
||||
Verifies executable tickets with complex dependency chains.
|
||||
Chain: T1 (comp) -> T2 (todo) -> T3 (todo)
|
||||
T4 (comp) -> T3
|
||||
T5 (todo) -> T3
|
||||
"""
|
||||
t1 = Ticket(id="T1", description="T1", status="completed", assigned_to="a")
|
||||
t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="a", depends_on=["T1"])
|
||||
|
||||
@@ -24,7 +24,8 @@ def _poll_mma_status(client: api_hook_client.ApiHookClient, timeout: int, condit
|
||||
def test_mma_step_mode_approval_flow(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Verify that we can manually approve a ticket in Step Mode and it proceeds.
|
||||
|
||||
Verify that we can manually approve a ticket in Step Mode and it proceeds.
|
||||
"""
|
||||
client = api_hook_client.ApiHookClient()
|
||||
assert client.wait_for_server(timeout=15), "Hook server did not start"
|
||||
|
||||
@@ -13,8 +13,9 @@ from src import api_hook_client
|
||||
def test_patch_modal_appears_on_trigger(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Test that triggering a patch shows the modal in the GUI.
|
||||
Uses live_gui fixture to start the GUI with test hooks enabled.
|
||||
|
||||
Test that triggering a patch shows the modal in the GUI.
|
||||
Uses live_gui fixture to start the GUI with test hooks enabled.
|
||||
"""
|
||||
proc, _ = live_gui
|
||||
client = api_hook_client.ApiHookClient()
|
||||
@@ -51,7 +52,8 @@ def test_patch_modal_appears_on_trigger(live_gui) -> None:
|
||||
def test_patch_apply_modal_workflow(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Test the full patch apply workflow: trigger -> apply -> verify modal closes.
|
||||
|
||||
Test the full patch apply workflow: trigger -> apply -> verify modal closes.
|
||||
"""
|
||||
proc, _ = live_gui
|
||||
client = api_hook_client.ApiHookClient()
|
||||
|
||||
@@ -65,4 +65,4 @@ def test_process_pending_gui_tasks_right_click(app_instance: App) -> None:
|
||||
{"action": "right_click", "item": "item_id"}
|
||||
]
|
||||
app_instance.controller._process_pending_gui_tasks()
|
||||
mock_callback.assert_called_once()
|
||||
mock_callback.assert_called_once()
|
||||
@@ -25,7 +25,8 @@ def mock_project():
|
||||
def test_rag_integration(mock_project):
|
||||
"""
|
||||
|
||||
Integration test verifying the flow from AppController through RAGEngine to ai_client.
|
||||
|
||||
Integration test verifying the flow from AppController through RAGEngine to ai_client.
|
||||
"""
|
||||
# 1. Initializes a mock project and AppController.
|
||||
# We patch several components to avoid side effects during initialization.
|
||||
|
||||
@@ -10,8 +10,9 @@ class TestRunWorkerLifecycleAbort(unittest.TestCase):
|
||||
def test_run_worker_lifecycle_returns_early_on_abort(self):
|
||||
"""
|
||||
|
||||
Test that run_worker_lifecycle returns early and marks ticket as 'killed'
|
||||
if the abort event is set for the ticket.
|
||||
|
||||
Test that run_worker_lifecycle returns early and marks ticket as 'killed'
|
||||
if the abort event is set for the ticket.
|
||||
"""
|
||||
# Mock ai_client.send
|
||||
with patch('src.ai_client.send') as mock_send:
|
||||
|
||||
@@ -13,8 +13,9 @@ from src.gui_2 import App
|
||||
def test_selectable_label_stability(live_gui) -> None:
|
||||
"""
|
||||
|
||||
Verifies that the application starts correctly with --enable-test-hooks
|
||||
and that the selectable label infrastructure is present and stable.
|
||||
|
||||
Verifies that the application starts correctly with --enable-test-hooks
|
||||
and that the selectable label infrastructure is present and stable.
|
||||
"""
|
||||
client = ApiHookClient()
|
||||
assert client.wait_for_server(timeout=20), "Hook server failed to start"
|
||||
|
||||
@@ -16,8 +16,9 @@ from simulation.sim_ai_settings import AISettingsSimulation
|
||||
def test_ai_settings_simulation_run() -> None:
|
||||
"""
|
||||
|
||||
Verifies that AISettingsSimulation correctly cycles through models
|
||||
to test the settings UI components.
|
||||
|
||||
Verifies that AISettingsSimulation correctly cycles through models
|
||||
to test the settings UI components.
|
||||
"""
|
||||
mock_client = MagicMock()
|
||||
mock_client.wait_for_server.return_value = True
|
||||
|
||||
@@ -16,7 +16,8 @@ from simulation.sim_base import BaseSimulation
|
||||
def test_base_simulation_init() -> None:
|
||||
"""
|
||||
|
||||
Verifies that the BaseSimulation initializes the ApiHookClient correctly.
|
||||
|
||||
Verifies that the BaseSimulation initializes the ApiHookClient correctly.
|
||||
"""
|
||||
with patch('simulation.sim_base.ApiHookClient') as mock_client_class:
|
||||
mock_client = MagicMock()
|
||||
@@ -29,8 +30,9 @@ def test_base_simulation_init() -> None:
|
||||
def test_base_simulation_setup() -> None:
|
||||
"""
|
||||
|
||||
Verifies that the setup routine correctly resets the GUI state
|
||||
and initializes a clean temporary project for simulation.
|
||||
|
||||
Verifies that the setup routine correctly resets the GUI state
|
||||
and initializes a clean temporary project for simulation.
|
||||
"""
|
||||
mock_client = MagicMock()
|
||||
mock_client.wait_for_server.return_value = True
|
||||
|
||||
@@ -16,8 +16,9 @@ from simulation.sim_context import ContextSimulation
|
||||
def test_context_simulation_run() -> None:
|
||||
"""
|
||||
|
||||
Verifies that the ContextSimulation runs the correct sequence of user actions:
|
||||
discussion switching, context building (md_only), and history truncation.
|
||||
|
||||
Verifies that the ContextSimulation runs the correct sequence of user actions:
|
||||
discussion switching, context building (md_only), and history truncation.
|
||||
"""
|
||||
mock_client = MagicMock()
|
||||
mock_client.wait_for_server.return_value = True
|
||||
|
||||
@@ -16,8 +16,9 @@ from simulation.sim_execution import ExecutionSimulation
|
||||
def test_execution_simulation_run() -> None:
|
||||
"""
|
||||
|
||||
Verifies that ExecutionSimulation handles script confirmation modals.
|
||||
Ensures that it waits for the modal and clicks the approve button.
|
||||
|
||||
Verifies that ExecutionSimulation handles script confirmation modals.
|
||||
Ensures that it waits for the modal and clicks the approve button.
|
||||
"""
|
||||
mock_client = MagicMock()
|
||||
mock_client.wait_for_server.return_value = True
|
||||
|
||||
@@ -16,8 +16,9 @@ from simulation.sim_tools import ToolsSimulation
|
||||
def test_tools_simulation_run() -> None:
|
||||
"""
|
||||
|
||||
Verifies that ToolsSimulation requests specific tool executions
|
||||
and verifies they appear in the resulting session history.
|
||||
|
||||
Verifies that ToolsSimulation requests specific tool executions
|
||||
and verifies they appear in the resulting session history.
|
||||
"""
|
||||
mock_client = MagicMock()
|
||||
mock_client.wait_for_server.return_value = True
|
||||
|
||||
@@ -7,13 +7,14 @@ import os
|
||||
def test_system_prompt_sim(live_gui):
|
||||
"""
|
||||
|
||||
Simulation test for system prompt settings.
|
||||
1. Wait for server.
|
||||
2. Verify initial state.
|
||||
3. Modify settings via API.
|
||||
4. Verify updates.
|
||||
5. Use 'Reset to Default' button via API.
|
||||
6. Verify restoration to default text.
|
||||
|
||||
Simulation test for system prompt settings.
|
||||
1. Wait for server.
|
||||
2. Verify initial state.
|
||||
3. Modify settings via API.
|
||||
4. Verify updates.
|
||||
5. Use 'Reset to Default' button via API.
|
||||
6. Verify restoration to default text.
|
||||
"""
|
||||
_, gui_script = live_gui
|
||||
client = ApiHookClient()
|
||||
@@ -68,4 +69,4 @@ def test_system_prompt_sim(live_gui):
|
||||
|
||||
# Close it
|
||||
client.set_value('show_base_prompt_diff_modal', False)
|
||||
assert client.get_value('show_base_prompt_diff_modal') is False
|
||||
assert client.get_value('show_base_prompt_diff_modal') is False
|
||||
@@ -62,9 +62,10 @@ def test_run_powershell_optional_qa_callback() -> None:
|
||||
|
||||
def test_end_to_end_tier4_integration(vlogger) -> None:
|
||||
"""
|
||||
1. Start a task that triggers a tool failure.
|
||||
2. Ensure Tier 4 QA analysis is run.
|
||||
3. Verify the analysis is merged into the next turn's prompt.
|
||||
|
||||
1. Start a task that triggers a tool failure.
|
||||
2. Ensure Tier 4 QA analysis is run.
|
||||
3. Verify the analysis is merged into the next turn's prompt.
|
||||
"""
|
||||
# Trigger a send that results in a tool failure
|
||||
# (In reality, the tool loop handles this)
|
||||
|
||||
@@ -8,11 +8,12 @@ from src.project_manager import save_track_state, load_track_state
|
||||
def test_track_state_persistence(tmp_path) -> None:
|
||||
"""
|
||||
|
||||
Tests saving and loading a TrackState object to/from a TOML file.
|
||||
1. Create a TrackState object with sample metadata, discussion, and tasks.
|
||||
2. Call save_track_state('test_track', state, base_dir).
|
||||
3. Verify that base_dir/conductor/tracks/test_track/state.toml exists.
|
||||
4. Call load_track_state('test_track', base_dir) and verify it returns an identical TrackState object.
|
||||
|
||||
Tests saving and loading a TrackState object to/from a TOML file.
|
||||
1. Create a TrackState object with sample metadata, discussion, and tasks.
|
||||
2. Call save_track_state('test_track', state, base_dir).
|
||||
3. Verify that base_dir/conductor/tracks/test_track/state.toml exists.
|
||||
4. Call load_track_state('test_track', base_dir) and verify it returns an identical TrackState object.
|
||||
"""
|
||||
base_dir = tmp_path
|
||||
track_id = "test-track-999" # Metadata internal ID
|
||||
|
||||
@@ -4,8 +4,9 @@ from tree_sitter import Language, Parser
|
||||
def test_tree_sitter_python_setup() -> None:
|
||||
"""
|
||||
|
||||
Verifies that tree-sitter and tree-sitter-python are correctly installed
|
||||
and can parse a simple Python function string.
|
||||
|
||||
Verifies that tree-sitter and tree-sitter-python are correctly installed
|
||||
and can parse a simple Python function string.
|
||||
"""
|
||||
# Initialize the Python language and parser
|
||||
PY_LANGUAGE = Language(tspython.language())
|
||||
|
||||
@@ -56,9 +56,10 @@ def _poll(client: api_hook_client.ApiHookClient, timeout: int, condition, label:
|
||||
def test_mma_complete_lifecycle(live_gui) -> None:
|
||||
"""
|
||||
|
||||
End-to-end MMA lifecycle using real Gemini API (gemini-2.5-flash-lite).
|
||||
Incorporates frame-sync sleeps and explicit state-transition waits per
|
||||
simulation_hardening_20260301 spec (Issues 2 & 3).
|
||||
|
||||
End-to-end MMA lifecycle using real Gemini API (gemini-2.5-flash-lite).
|
||||
Incorporates frame-sync sleeps and explicit state-transition waits per
|
||||
simulation_hardening_20260301 spec (Issues 2 & 3).
|
||||
"""
|
||||
client = api_hook_client.ApiHookClient()
|
||||
assert client.wait_for_server(timeout=15), "Hook server did not start"
|
||||
|
||||
@@ -14,12 +14,13 @@ from src import api_hook_client
|
||||
def test_workspace_profiles_restoration(live_gui):
|
||||
"""
|
||||
|
||||
Verifies that workspace profiles can save and restore UI state.
|
||||
1. Sets a field (ui_separate_tier1) to True.
|
||||
2. Saves a workspace profile.
|
||||
3. Resets the field to False.
|
||||
4. Loads the workspace profile.
|
||||
5. Verifies the field is restored to True.
|
||||
|
||||
Verifies that workspace profiles can save and restore UI state.
|
||||
1. Sets a field (ui_separate_tier1) to True.
|
||||
2. Saves a workspace profile.
|
||||
3. Resets the field to False.
|
||||
4. Loads the workspace profile.
|
||||
5. Verifies the field is restored to True.
|
||||
"""
|
||||
client = api_hook_client.ApiHookClient()
|
||||
assert client.wait_for_server(timeout=20), "Hook server did not start"
|
||||
|
||||
Reference in New Issue
Block a user