"""Wrapper-obliteration tests for result_migration_cruft_removal_20260620. Phase 3 (mcp_client._resolve_and_check): the legacy wrapper is DELETED; callers in dispatch_tool_call use _resolve_and_check_result(...).ok directly. The test mocks _resolve_and_check_result (the proper Result helper). """ import subprocess from pathlib import Path from unittest.mock import patch import pytest from src.mcp_client import dispatch @pytest.fixture def mock_resolve_result(): """Mock the proper Result helper to always succeed.""" from src import mcp_client original = mcp_client._resolve_and_check_result mcp_client._resolve_and_check_result = lambda path: __import__("src").mcp_client.Result( data=Path(path), errors=[], ) yield mcp_client._resolve_and_check_result = original def test_resolve_and_check_wrapper_obliterated(): """Phase 3 invariant: the legacy _resolve_and_check wrapper is DELETED.""" from src import mcp_client assert not hasattr(mcp_client, "_resolve_and_check"), ( "_resolve_and_check legacy wrapper must be OBLITERATED (deleted). " "Callers must use _resolve_and_check_result(...).ok directly." ) def test_dispatch_py_remove_def_uses_result_helper(mock_resolve_result, tmp_path): """dispatch_tool_call for py_remove_def uses _resolve_and_check_result(...).ok.""" from src import mcp_client c_file = tmp_path / "test.py" c_file.write_text("def foo(): pass\n") with patch("scripts.py_struct_tools.py_remove_def", return_value="removed") as mock_remove: # dispatch routes through _resolve_and_check_result now result = dispatch("py_remove_def", {"path": str(c_file), "name": "foo"}) assert result == "removed", f"expected 'removed', got {result!r}" def test_dispatch_py_move_def_uses_result_helper(mock_resolve_result, tmp_path): """dispatch_tool_call for py_move_def (multi-path) uses _resolve_and_check_result.""" from src import mcp_client src_file = tmp_path / "src.py" src_file.write_text("def foo(): pass\n") dest_file = tmp_path / "dest.py" dest_file.write_text("# dest\n") with patch("scripts.py_struct_tools.py_move_def", return_value="moved") as mock_move: result = dispatch( "py_move_def", { "src_path": str(src_file), "dest_path": str(dest_file), "name": "foo", "dest_name": "App", "anchor_type": "before", }, ) assert result == "moved", f"expected 'moved', got {result!r}" def test_audit_script_finds_zero_mcp_client_wrappers(): """Phase 3 invariant: scripts/audit_legacy_wrappers.py reports 0 wrappers in src/mcp_client.py.""" r = subprocess.run( ["uv", "run", "python", "scripts/audit_legacy_wrappers.py"], capture_output=True, text=True, ) assert "src\\mcp_client.py" not in r.stdout, ( f"expected 0 wrappers in src/mcp_client.py, but found:\n{r.stdout}" ) # ============ Phase 4 (ai_client wrappers) ============ def test_phase4_reread_file_items_wrapper_obliterated(): """Phase 4 invariant: the legacy _reread_file_items wrapper is DELETED.""" from src import ai_client assert not hasattr(ai_client, "_reread_file_items"), ( "_reread_file_items legacy wrapper must be OBLITERATED. " "Callers must use _reread_file_items_result(...).ok directly." ) def test_phase4_list_anthropic_models_wrapper_obliterated(): from src import ai_client assert not hasattr(ai_client, "_list_anthropic_models"), ( "_list_anthropic_models legacy wrapper must be OBLITERATED." ) def test_phase4_list_gemini_models_wrapper_obliterated(): from src import ai_client assert not hasattr(ai_client, "_list_gemini_models"), ( "_list_gemini_models legacy wrapper must be OBLITERATED." ) def test_phase4_extract_gemini_thoughts_wrapper_obliterated(): from src import ai_client assert not hasattr(ai_client, "_extract_gemini_thoughts"), ( "_extract_gemini_thoughts legacy wrapper must be OBLITERATED." ) def test_phase4_list_minimax_models_wrapper_obliterated(): from src import ai_client assert not hasattr(ai_client, "_list_minimax_models"), ( "_list_minimax_models legacy wrapper must be OBLITERATED." ) # ============ Phase 5 (rag_engine wrappers) ============ def test_phase5_chunk_code_wrapper_obliterated(): """Phase 5 invariant: the legacy RAGEngine._chunk_code wrapper is DELETED.""" from src.rag_engine import RAGEngine assert not hasattr(RAGEngine, "_chunk_code"), ( "RAGEngine._chunk_code legacy wrapper must be OBLITERATED." ) def test_phase5_chunk_code_caller_uses_result(): """The caller in index_file uses _chunk_code_result(...).ok directly.""" from src.rag_engine import RAGEngine import inspect src_text = inspect.getsource(RAGEngine.index_file) assert "_chunk_code_result" in src_text, "caller must use _chunk_code_result" # Check no bare _chunk_code( call (without _result suffix) import re bare_calls = re.findall(r"\b_chunk_code\(", src_text) bare_calls = [c for c in bare_calls if c == "_chunk_code("] assert len(bare_calls) == 0, ( f"caller should not call _chunk_code (legacy wrapper); " f"found {len(bare_calls)} bare calls" ) # ============ Phase 6 (gui_2 wrappers) ============ def test_phase6_detect_refresh_rate_wrapper_obliterated(): """Phase 6 invariant: the legacy _detect_refresh_rate_win32 wrapper is DELETED.""" from src import gui_2 assert not hasattr(gui_2, "_detect_refresh_rate_win32"), ( "_detect_refresh_rate_win32 wrapper must be OBLITERATED." ) def test_phase6_resolve_font_path_wrapper_obliterated(): """Phase 6 invariant: the legacy _resolve_font_path wrapper is DELETED.""" from src import gui_2 assert not hasattr(gui_2, "_resolve_font_path"), ( "_resolve_font_path wrapper must be OBLITERATED." ) def test_phase6_audit_finds_zero_wrappers_in_src(): """Phase 6 invariant: 0 legacy wrappers remain anywhere in src/.""" r = subprocess.run( ["uv", "run", "python", "scripts/audit_legacy_wrappers.py"], capture_output=True, text=True, ) assert "Found 0 legacy wrappers" in r.stdout, ( f"expected 0 legacy wrappers in src/, but audit found:\n{r.stdout[:500]}" ) # ============ Phase 9 (Patch Phase — corrective verification) ============ def test_phase9_audit_legacy_wrappers_finds_zero(): """Phase 9 invariant: scripts/audit_legacy_wrappers.py finds 0 legacy wrappers in src/. The 3 wrappers Tier 1 said were remaining in the tier-2-clone (_detect_refresh_rate_win32, _resolve_font_path, _chunk_code) are actually all gone in the merged branch state. """ r = subprocess.run( ["uv", "run", "python", "scripts/audit_legacy_wrappers.py"], capture_output=True, text=True, ) assert "Found 0 legacy wrappers" in r.stdout, ( f"Phase 9 invariant: expected 0 legacy wrappers; audit found:\n{r.stdout[:500]}" ) def test_phase9_baseline_tests_31_of_31_pass(): """Phase 9 invariant: the 7 originally-failing baseline tests all pass. Tier 1's spec said 7 tests were failing; the merged branch state has all 31 tests passing. The 7 scaffolding failures were fixed in Phase 1 (synthesized PHASE1_AUDIT_BASELINE.json from inventory docs). """ r = subprocess.run( ["uv", "run", "python", "-m", "pytest", "tests/test_baseline_result.py", "--tb=no", "-q"], capture_output=True, text=True, ) assert "31 passed" in r.stdout, ( f"Phase 9 invariant: expected 31/31 baseline tests to pass; got:\n{r.stdout[-500:]}" ) def test_phase9_gui_2_wrappers_gone(): """Phase 9 invariant: gui_2._detect_refresh_rate_win32 + _resolve_font_path are DELETED.""" from src import gui_2 assert not hasattr(gui_2, "_detect_refresh_rate_win32"), ( "_detect_refresh_rate_win32 wrapper STILL EXISTS (should be deleted)" ) assert not hasattr(gui_2, "_resolve_font_path"), ( "_resolve_font_path wrapper STILL EXISTS (should be deleted)" ) def test_phase9_rag_engine_chunk_code_gone(): """Phase 9 invariant: RAGEngine._chunk_code is DELETED.""" from src.rag_engine import RAGEngine assert not hasattr(RAGEngine, "_chunk_code"), ( "RAGEngine._chunk_code STILL EXISTS (should be deleted)" )