5c871dacac
Phase 3 (1 of 9 cruft sites obliterated):
The legacy wrapper _resolve_and_check(raw_path) returned tuple[Path|None, str],
dropping the structured ErrorInfo from _resolve_and_check_result. Callers in
dispatch_tool_call (py_remove_def, py_add_def, py_move_def, py_region_wrap) used
the pattern 'p, err = _resolve_and_check(path); if err: return err' which is
exactly the false drain the user wants obliterated.
Migration:
- DELETED: _resolve_and_check wrapper (lines 175-188 in src/mcp_client.py)
- UPDATED: 5 callers in dispatch_tool_call now call _resolve_and_check_result
directly with .ok check + NilPath check + structured error routing
- UPDATED: 4 test files that monkey-patched _resolve_and_check to mock the
Result helper instead:
- test_mcp_ts_integration.py (1 mock)
- test_ts_c_tools.py (2 mocks)
- test_ts_cpp_tools.py (8 mocks)
- test_cruft_removal.py (NEW; 4 tests including the wrapper-obliterated
invariant + the audit-script-finds-zero invariant + 2 dispatch tests)
Test result: 51/51 pass (31 baseline + 16 heuristic + 4 cruft).
Audit gate: src/mcp_client.py --strict exits 0 (no new violations introduced).
Baseline audit: --include-baseline --strict exits 1 only due to 4 pre-existing
non-baseline INTERNAL_RETHROW sites in outline_tool.py / warmup.py /
vendor_capabilities.py (out of scope per spec).
The wrapper IS DELETED. No pass-through. No backward compat. The dead code dies.
179 lines
6.7 KiB
Python
179 lines
6.7 KiB
Python
import pytest
|
|
from pathlib import Path
|
|
import os
|
|
import sys
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
# Add project root to sys.path
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
|
|
from src.mcp_client import dispatch
|
|
|
|
@pytest.fixture
|
|
def mock_resolve():
|
|
from src import mcp_client
|
|
original_resolve = 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_resolve
|
|
|
|
def test_ts_c_get_skeleton_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_c_get_skeleton via dispatch
|
|
c_file = tmp_path / "test.c"
|
|
c_file.write_text("void main() { }")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_skeleton.return_value = "void main() { ... }"
|
|
|
|
result = dispatch("ts_c_get_skeleton", {"path": str(c_file)})
|
|
|
|
# Verify ASTParser called with correct language
|
|
mock_parser_cls.assert_called_once_with("c")
|
|
# Verify get_skeleton called
|
|
mock_instance.get_skeleton.assert_called_once()
|
|
# Verify non-empty result
|
|
assert result and len(result) > 0
|
|
assert "void main() { ... }" in result
|
|
|
|
def test_ts_cpp_get_skeleton_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_cpp_get_skeleton via dispatch
|
|
cpp_file = tmp_path / "test.cpp"
|
|
cpp_file.write_text("void main() { }")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_skeleton.return_value = "void main() { ... }"
|
|
|
|
result = dispatch("ts_cpp_get_skeleton", {"path": str(cpp_file)})
|
|
|
|
# Verify ASTParser called with correct language
|
|
mock_parser_cls.assert_called_once_with("cpp")
|
|
mock_instance.get_skeleton.assert_called_once()
|
|
assert result and len(result) > 0
|
|
assert "void main() { ... }" in result
|
|
|
|
def test_ts_c_get_code_outline_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_c_get_code_outline via dispatch
|
|
c_file = tmp_path / "test.c"
|
|
c_file.write_text("void main() { }")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_code_outline.return_value = "[Func] main (Lines 1-1)"
|
|
|
|
result = dispatch("ts_c_get_code_outline", {"path": str(c_file)})
|
|
|
|
# Verify ASTParser called with correct language
|
|
mock_parser_cls.assert_called_once_with("c")
|
|
mock_instance.get_code_outline.assert_called_once()
|
|
assert result and len(result) > 0
|
|
assert "[Func] main (Lines 1-1)" in result
|
|
|
|
def test_ts_cpp_get_code_outline_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_cpp_get_code_outline via dispatch
|
|
cpp_file = tmp_path / "test.cpp"
|
|
cpp_file.write_text("void main() { }")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_code_outline.return_value = "[Func] main (Lines 1-1)"
|
|
|
|
result = dispatch("ts_cpp_get_code_outline", {"path": str(cpp_file)})
|
|
|
|
# Verify ASTParser called with correct language
|
|
mock_parser_cls.assert_called_once_with("cpp")
|
|
mock_instance.get_code_outline.assert_called_once()
|
|
assert result and len(result) > 0
|
|
assert "[Func] main (Lines 1-1)" in result
|
|
|
|
def test_ts_c_get_definition_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_c_get_definition via dispatch
|
|
c_file = tmp_path / "test.c"
|
|
c_file.write_text("void foo() {}")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_definition.return_value = "void foo() {}"
|
|
|
|
result = dispatch("ts_c_get_definition", {"path": str(c_file), "name": "foo"})
|
|
|
|
mock_parser_cls.assert_called_once_with("c")
|
|
mock_instance.get_definition.assert_called_once()
|
|
assert "void foo() {}" in result
|
|
|
|
def test_ts_cpp_get_definition_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_cpp_get_definition via dispatch
|
|
cpp_file = tmp_path / "test.cpp"
|
|
cpp_file.write_text("void foo() {}")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_definition.return_value = "void foo() {}"
|
|
|
|
result = dispatch("ts_cpp_get_definition", {"path": str(cpp_file), "name": "foo"})
|
|
|
|
mock_parser_cls.assert_called_once_with("cpp")
|
|
mock_instance.get_definition.assert_called_once()
|
|
assert "void foo() {}" in result
|
|
|
|
def test_ts_c_get_signature_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_c_get_signature via dispatch
|
|
c_file = tmp_path / "test.c"
|
|
c_file.write_text("void foo() {}")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_signature.return_value = "void foo()"
|
|
|
|
result = dispatch("ts_c_get_signature", {"path": str(c_file), "name": "foo"})
|
|
|
|
mock_parser_cls.assert_called_once_with("c")
|
|
mock_instance.get_signature.assert_called_once()
|
|
assert "void foo()" in result
|
|
|
|
def test_ts_cpp_get_signature_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_cpp_get_signature via dispatch
|
|
cpp_file = tmp_path / "test.cpp"
|
|
cpp_file.write_text("void foo() {}")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.get_signature.return_value = "void foo()"
|
|
|
|
result = dispatch("ts_cpp_get_signature", {"path": str(cpp_file), "name": "foo"})
|
|
|
|
mock_parser_cls.assert_called_once_with("cpp")
|
|
mock_instance.get_signature.assert_called_once()
|
|
assert "void foo()" in result
|
|
|
|
def test_ts_c_update_definition_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_c_update_definition via dispatch
|
|
c_file = tmp_path / "test.c"
|
|
c_file.write_text("void foo() {}")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.update_definition.return_value = "void foo() { return; }"
|
|
|
|
result = dispatch("ts_c_update_definition", {"path": str(c_file), "name": "foo", "new_content": "void foo() { return; }"})
|
|
|
|
mock_parser_cls.assert_called_once_with("c")
|
|
mock_instance.update_definition.assert_called_once()
|
|
assert "Successfully updated" in result
|
|
|
|
def test_ts_cpp_update_definition_dispatch(tmp_path, mock_resolve):
|
|
# Verify ts_cpp_update_definition via dispatch
|
|
cpp_file = tmp_path / "test.cpp"
|
|
cpp_file.write_text("void foo() {}")
|
|
|
|
with patch("src.file_cache.ASTParser") as mock_parser_cls:
|
|
mock_instance = mock_parser_cls.return_value
|
|
mock_instance.update_definition.return_value = "void foo() { return; }"
|
|
|
|
result = dispatch("ts_cpp_update_definition", {"path": str(cpp_file), "name": "foo", "new_content": "void foo() { return; }"})
|
|
|
|
mock_parser_cls.assert_called_once_with("cpp")
|
|
mock_instance.update_definition.assert_called_once()
|
|
assert "Successfully updated" in result
|