c5a119d63f
Phase 4 (5 of 9 cruft sites obliterated): OBLITERATED wrappers: 1. _reread_file_items (4 callers in _send_gemini + _send_gemini_cli + 2 others) 2. _list_anthropic_models (1 caller in list_models) 3. _list_gemini_models (1 caller in list_models) 4. _extract_gemini_thoughts (1 caller in _send_gemini) 5. _list_minimax_models (2 callers in _set_minimax_provider_result + set_provider) Migration: each caller now uses the _result sibling directly with .ok check + .data extraction. The Result[T] error context (structured ErrorInfo) is now propagated instead of dropped. _send_gemini gets .data with explicit .ok check. Updated tests to assert OBLITERATED state (5 sub-track 5 tests inverted from '_legacy_preserved' to '_legacy_obliterated'): - tests/test_baseline_result.py: test_phase9_redo_modules_import_cleanly - tests/tier2/phase10_invariant_test.py: _list_gemini_models removed from list - tests/tier2/phase10_site1_test.py: _legacy_unchanged -> _legacy_obliterated - tests/tier2/phase11_invariant_test.py: _extract/_list_minimax moved to obliterated - tests/tier2/phase11_sites78_test.py: _legacy_preserved -> _legacy_obliterated - tests/tier2/phase12_invariant_test.py: _list_anthropic moved to obliterated - tests/tier2/phase12_site4_test.py: _legacy_preserved -> _legacy_obliterated - tests/test_gemini_thinking_format.py: helper uses _result directly - tests/test_cruft_removal.py: 5 new obliterated-wrappers invariant tests Test result: 122/122 pass (31 baseline + 16 heuristic + 9 cruft + 5 thinking + 61 tier2). Audit gate: src/ai_client.py --strict exits 0 (no new violations introduced). Wrapper count: 9 -> 3 (Phase 5-6 remaining: rag_engine 1, gui_2 2).
123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
"""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("src.mcp_client.py_struct_tools") as mock_struct:
|
|
mock_struct.py_remove_def.return_value = "removed"
|
|
# 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("src.mcp_client.py_struct_tools") as mock_struct:
|
|
mock_struct.py_move_def.return_value = "moved"
|
|
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."
|
|
) |