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, ts_cpp_get_definition, ts_cpp_update_definition 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 def test_exhaustive_gencpp_corpus(): base_dir = Path(__file__).parent / "assets" / "cpp_samples" files_to_test = { "base_component.h": [ "BaseComponent", "BaseComponent::Config", "BaseComponent::Config::Metadata" ], "complex_template.h": [ "MultiBuffer", "MultiBuffer::SetData", "MultiBuffer::Get", "TypeTraits", "Container::Wrapper" ], "component_registry.h": [ "ComponentRegistry", "ComponentRegistry::Iterator", "ComponentRegistry::Iterator::GetType", "ComponentRegistry::Instance" ], "component_registry.cpp": [ "ComponentRegistry::Instance", "ComponentRegistry::Register", "ComponentRegistry::Create" ] } from src import mcp_client original_resolve = mcp_client._resolve_and_check mcp_client._resolve_and_check = lambda path: (Path(path), None) try: for filename, symbols in files_to_test.items(): path = base_dir / filename assert path.exists(), f"{path} does not exist" # 1. Verify skeleton executes without errors skeleton = ts_cpp_get_skeleton(str(path)) assert skeleton and "ERROR" not in skeleton # 2. Verify code outline executes without errors outline = ts_cpp_get_code_outline(str(path)) assert outline and "ERROR" not in outline # 3. Verify specific complex symbols can be retrieved via ts_cpp_get_definition for symbol in symbols: definition = ts_cpp_get_definition(str(path), symbol) assert definition and "ERROR" not in definition, f"Failed to get definition for {symbol} in {filename}: {definition}" # Basic check that the symbol name is in the definition (allowing for namespaces) simple_name = symbol.split("::")[-1] assert simple_name in definition finally: mcp_client._resolve_and_check = original_resolve def test_ts_cpp_update_definition(tmp_path): asset_path = Path(__file__).parent / "assets" / "cpp_samples" / "component_registry.cpp" cpp_content = asset_path.read_text(encoding="utf-8") cpp_file = tmp_path / "component_registry.cpp" cpp_file.write_text(cpp_content, encoding="utf-8") from src import mcp_client original_resolve = mcp_client._resolve_and_check mcp_client._resolve_and_check = lambda path: (Path(path), None) try: new_register_body = """void ComponentRegistry::Register(const std::string& type, ComponentCreator creator) { // Updated body std::cout << "DEBUG: Registering " << type << std::endl; m_creators[type] = creator; if (type == "secret") { std::cout << "Special component" << std::endl; } }""" result = ts_cpp_update_definition(str(cpp_file), "ComponentRegistry::Register", new_register_body) assert "Successfully updated" in result updated_content = cpp_file.read_text(encoding="utf-8") assert "// Updated body" in updated_content assert "DEBUG: Registering" in updated_content # Verify it still parses by getting definition again definition = ts_cpp_get_definition(str(cpp_file), "ComponentRegistry::Register") assert "// Updated body" in definition assert "DEBUG: Registering" in definition finally: mcp_client._resolve_and_check = original_resolve def test_exhaustive_gencpp_samples(): base_dir = Path(__file__).parent / "assets" / "gencpp_samples" files_to_test = { "ast.hpp": [ "AST", "AST_Body", "AST_Class", "AST_Fn", "AST_Struct" ], "parser.cpp": [ "parser_push", "parser_pop", "parser_to_strbuilder", "lex__eat" ], "types.hpp": [ "LogLevel", "loglevel_to_str", "AccessSpec", "access_spec_to_str", "ModuleFlag" ] } from src import mcp_client original_resolve = mcp_client._resolve_and_check mcp_client._resolve_and_check = lambda path: (Path(path), None) try: for filename, symbols in files_to_test.items(): path = base_dir / filename assert path.exists(), f"{path} does not exist" # 1. Verify skeleton executes without errors skeleton = ts_cpp_get_skeleton(str(path)) assert skeleton and not skeleton.startswith("ERROR") # 2. Verify code outline executes without errors outline = ts_cpp_get_code_outline(str(path)) assert outline and not outline.startswith("ERROR") # 3. Verify specific complex symbols can be retrieved via ts_cpp_get_definition for symbol in symbols: definition = ts_cpp_get_definition(str(path), symbol) assert definition and not definition.startswith("ERROR"), f"Failed for {symbol} in {filename}: {definition}" simple_name = symbol.split("::")[-1] assert simple_name in definition finally: mcp_client._resolve_and_check = original_resolve def test_ts_cpp_update_definition_gencpp(tmp_path): asset_path = Path(__file__).parent / "assets" / "gencpp_samples" / "parser.cpp" cpp_content = asset_path.read_text(encoding="utf-8") cpp_file = tmp_path / "parser.cpp" cpp_file.write_text(cpp_content, encoding="utf-8") from src import mcp_client original_resolve = mcp_client._resolve_and_check mcp_client._resolve_and_check = lambda path: (Path(path), None) try: # Update parser_pop new_pop_body = """void parser_pop(ParseContext* ctx) { #if 0 && GEN_BUILD_DEBUG log_fmt("\\tPopping parser: %.*s\\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); #endif // HELLO FROM TEST ctx->scope = ctx->scope->prev; }""" result = ts_cpp_update_definition(str(cpp_file), "parser_pop", new_pop_body) assert "Successfully updated" in result updated_content = cpp_file.read_text(encoding="utf-8") assert "// HELLO FROM TEST" in updated_content # Verify retrieval definition = ts_cpp_get_definition(str(cpp_file), "parser_pop") assert "// HELLO FROM TEST" in definition finally: mcp_client._resolve_and_check = original_resolve