diff --git a/src/file_cache.py b/src/file_cache.py index 9b664e4..57d06ef 100644 --- a/src/file_cache.py +++ b/src/file_cache.py @@ -117,15 +117,21 @@ class ASTParser: if child.type != "comment": first_stmt = child break + initializer = None + for child in node.children: + if child.type == "field_initializer_list": + initializer = child + break if first_stmt and is_docstring(first_stmt): start_byte = first_stmt.end_byte end_byte = body.end_byte if end_byte > start_byte: edits.append((start_byte, end_byte, f"\n{indent}...")) else: - start_byte = body.start_byte + start_byte = initializer.start_byte if initializer else body.start_byte end_byte = body.end_byte - edits.append((start_byte, end_byte, "...")) + repl = "..." + edits.append((start_byte, end_byte, repl)) for child in node.children: walk(child) walk(tree.root_node) diff --git a/tests/test_mcp_ts_integration.py b/tests/test_mcp_ts_integration.py new file mode 100644 index 0000000..da712e2 --- /dev/null +++ b/tests/test_mcp_ts_integration.py @@ -0,0 +1,88 @@ +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 + mcp_client._resolve_and_check = lambda path: (Path(path), None) + yield + mcp_client._resolve_and_check = 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 diff --git a/tests/test_ts_c_tools.py b/tests/test_ts_c_tools.py new file mode 100644 index 0000000..909c296 --- /dev/null +++ b/tests/test_ts_c_tools.py @@ -0,0 +1,65 @@ +import pytest +from pathlib import Path +import os +import sys + +# 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 ts_c_get_skeleton, ts_c_get_code_outline + +def test_ts_c_get_skeleton(tmp_path): + c_code = """#include + +void hello() { + printf("Hello, World!\\n"); +} + +int add(int a, int b) { + return a + b; +} + +struct Point { + int x; + int y; +}; +""" + c_file = tmp_path / "test.c" + c_file.write_text(c_code) + + # Mock _resolve_and_check to allow tmp_path + from src import mcp_client + original_resolve = mcp_client._resolve_and_check + mcp_client._resolve_and_check = lambda path: (Path(path), None) + + try: + skeleton = ts_c_get_skeleton(str(c_file)) + assert "void hello() ..." in skeleton + assert "int add(int a, int b) ..." in skeleton + assert "struct Point" in skeleton + assert "printf" not in skeleton + finally: + mcp_client._resolve_and_check = original_resolve + +def test_ts_c_get_code_outline(tmp_path): + c_code = """ +void func1() { +} + +int func2(int x) { + return x * 2; +} +""" + c_file = tmp_path / "test.c" + c_file.write_text(c_code) + + from src import mcp_client + original_resolve = mcp_client._resolve_and_check + mcp_client._resolve_and_check = lambda path: (Path(path), None) + + try: + outline = ts_c_get_code_outline(str(c_file)) + assert "[Func] func1 (Lines 2-3)" in outline + assert "[Func] func2 (Lines 5-7)" in outline + finally: + mcp_client._resolve_and_check = original_resolve diff --git a/tests/test_ts_cpp_tools.py b/tests/test_ts_cpp_tools.py new file mode 100644 index 0000000..edd9ae9 --- /dev/null +++ b/tests/test_ts_cpp_tools.py @@ -0,0 +1,71 @@ +import pytest +from pathlib import Path +import os +import sys + +# 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 ts_cpp_get_skeleton, ts_cpp_get_code_outline + +def test_ts_cpp_get_skeleton(tmp_path): + cpp_code = """#include +#include + +template +class Box { +public: + Box(T val) : value(val) {} + T getValue() { + return value; + } +private: + T value; +}; + +void globalFunc() { + std::cout << "Global" << std::endl; +} +""" + cpp_file = tmp_path / "test.cpp" + cpp_file.write_text(cpp_code) + + from src import mcp_client + original_resolve = mcp_client._resolve_and_check + mcp_client._resolve_and_check = lambda path: (Path(path), None) + + try: + skeleton = ts_cpp_get_skeleton(str(cpp_file)) + assert "class Box" in skeleton + assert "Box(T val) ..." in skeleton + assert "T getValue() ..." in skeleton + assert "void globalFunc() ..." in skeleton + assert "std::cout" not in skeleton + finally: + mcp_client._resolve_and_check = original_resolve + +def test_ts_cpp_get_code_outline(tmp_path): + cpp_code = """ +class MyClass { + void method1() { + } +}; + +template +void templateFunc(T t) { +} +""" + cpp_file = tmp_path / "test.cpp" + cpp_file.write_text(cpp_code) + + from src import mcp_client + original_resolve = mcp_client._resolve_and_check + mcp_client._resolve_and_check = lambda path: (Path(path), None) + + try: + outline = ts_cpp_get_code_outline(str(cpp_file)) + assert "[Class] MyClass (Lines 2-5)" in outline + assert "[Method] method1 (Lines 3-4)" in outline + assert "[Func] templateFunc (Lines 8-9)" in outline + finally: + mcp_client._resolve_and_check = original_resolve