Step 46 TDD test: Tree-sitter C++ integration
Tests parseCpp() produces real AST: Function with name and return type, typed Parameters, and memory pattern detection: unique_ptr->@Lifetime(RAII), shared_ptr->@Owner(Shared_ARC), raw new/delete->@Deallocate(Explicit). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -151,6 +151,9 @@ target_include_directories(step44_test PRIVATE src)
|
||||
add_executable(step45_test tests/step45_test.cpp)
|
||||
target_include_directories(step45_test PRIVATE src)
|
||||
|
||||
add_executable(step46_test tests/step46_test.cpp)
|
||||
target_include_directories(step46_test PRIVATE src)
|
||||
|
||||
add_executable(whetstone_editor src/main.cpp)
|
||||
target_include_directories(whetstone_editor PRIVATE src)
|
||||
# find_package(SDL2 REQUIRED) # Commented out for now to avoid build issues
|
||||
|
||||
189
editor/tests/step46_test.cpp
Normal file
189
editor/tests/step46_test.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
// Step 46 TDD Test: Tree-sitter C++ integration
|
||||
//
|
||||
// Tests that TreeSitterParser::parseCpp() actually parses real C++ source:
|
||||
// 1. Simple function → Function node with correct name and return type
|
||||
// 2. Parameters with types → Parameter nodes with PrimitiveType children
|
||||
// 3. Variable declarations → Variable nodes
|
||||
// 4. Detect unique_ptr → @Lifetime(RAII) annotation
|
||||
// 5. Detect shared_ptr → @Owner(Shared_ARC) annotation
|
||||
// 6. Detect raw new/delete → @Deallocate(Explicit) annotation
|
||||
// 7. Module targetLanguage is "cpp"
|
||||
//
|
||||
// Will fail until TreeSitterParser::parseCpp() is replaced with real
|
||||
// tree-sitter-cpp integration.
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include "ast/Parser.h"
|
||||
#include "ast/Annotation.h"
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
// --- Test 1: Parse simple C++ function ---
|
||||
{
|
||||
std::string source = "int f(int x) { return x + 1; }";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
assert(module != nullptr && "parseCpp should return a non-null module");
|
||||
assert(module->targetLanguage == "cpp" && "Module target language should be 'cpp'");
|
||||
|
||||
std::cout << "Test 1 PASS: parseCpp returns non-null module with cpp target" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 2: Parsed C++ function has correct name ---
|
||||
{
|
||||
std::string source = "int f(int x) { return x + 1; }";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
auto functions = module->getChildren("functions");
|
||||
assert(!functions.empty() && "Module should contain at least one function");
|
||||
|
||||
auto* fn = static_cast<Function*>(functions[0]);
|
||||
assert(fn->name == "f" && "Function name should be 'f'");
|
||||
|
||||
std::cout << "Test 2 PASS: Parsed C++ function has name 'f'" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 3: C++ function has typed parameter ---
|
||||
{
|
||||
std::string source = "int f(int x) { return x + 1; }";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
auto functions = module->getChildren("functions");
|
||||
auto* fn = static_cast<Function*>(functions[0]);
|
||||
|
||||
auto params = fn->getChildren("parameters");
|
||||
assert(!params.empty() && "Function should have parameters");
|
||||
|
||||
auto* param = static_cast<Parameter*>(params[0]);
|
||||
assert(param->name == "x" && "Parameter name should be 'x'");
|
||||
|
||||
auto* type = param->getChild("type");
|
||||
assert(type != nullptr && "Parameter should have a type");
|
||||
assert(type->conceptType == "PrimitiveType" && "Type should be PrimitiveType");
|
||||
|
||||
auto* primType = static_cast<PrimitiveType*>(type);
|
||||
assert(primType->kind == "int" && "Parameter type should be 'int'");
|
||||
|
||||
std::cout << "Test 3 PASS: C++ parameter has name 'x' with type 'int'" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 4: Function has return type ---
|
||||
{
|
||||
std::string source = "int f(int x) { return x + 1; }";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
auto functions = module->getChildren("functions");
|
||||
auto* fn = static_cast<Function*>(functions[0]);
|
||||
|
||||
auto* retType = fn->getChild("returnType");
|
||||
assert(retType != nullptr && "Function should have a return type");
|
||||
assert(retType->conceptType == "PrimitiveType" && "Return type should be PrimitiveType");
|
||||
|
||||
auto* primType = static_cast<PrimitiveType*>(retType);
|
||||
assert(primType->kind == "int" && "Return type should be 'int'");
|
||||
|
||||
std::cout << "Test 4 PASS: C++ function has return type 'int'" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 5: Detect unique_ptr → @Lifetime(RAII) ---
|
||||
{
|
||||
std::string source =
|
||||
"void createWidget() {\n"
|
||||
" std::unique_ptr<Widget> w = std::make_unique<Widget>();\n"
|
||||
"}\n";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
auto functions = module->getChildren("functions");
|
||||
assert(!functions.empty() && "Should parse the function");
|
||||
auto* fn = static_cast<Function*>(functions[0]);
|
||||
|
||||
// Look for @Lifetime(RAII) annotation inferred from unique_ptr usage
|
||||
auto annotations = fn->getChildren("annotations");
|
||||
bool hasLifetimeRAII = false;
|
||||
for (auto* anno : annotations) {
|
||||
if (anno->conceptType == "LifetimeAnnotation") {
|
||||
auto* lifetime = static_cast<LifetimeAnnotation*>(anno);
|
||||
if (lifetime->strategy == "RAII") {
|
||||
hasLifetimeRAII = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(hasLifetimeRAII &&
|
||||
"unique_ptr usage should be annotated with @Lifetime(RAII)");
|
||||
|
||||
std::cout << "Test 5 PASS: unique_ptr detected → @Lifetime(RAII)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 6: Detect shared_ptr → @Owner(Shared_ARC) ---
|
||||
{
|
||||
std::string source =
|
||||
"void shareWidget() {\n"
|
||||
" std::shared_ptr<Widget> w = std::make_shared<Widget>();\n"
|
||||
"}\n";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
auto functions = module->getChildren("functions");
|
||||
assert(!functions.empty() && "Should parse the function");
|
||||
auto* fn = static_cast<Function*>(functions[0]);
|
||||
|
||||
auto annotations = fn->getChildren("annotations");
|
||||
bool hasSharedARC = false;
|
||||
for (auto* anno : annotations) {
|
||||
if (anno->conceptType == "OwnerAnnotation") {
|
||||
auto* owner = static_cast<OwnerAnnotation*>(anno);
|
||||
if (owner->strategy == "Shared_ARC") {
|
||||
hasSharedARC = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(hasSharedARC &&
|
||||
"shared_ptr usage should be annotated with @Owner(Shared_ARC)");
|
||||
|
||||
std::cout << "Test 6 PASS: shared_ptr detected → @Owner(Shared_ARC)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 7: Detect raw new/delete → @Deallocate(Explicit) ---
|
||||
{
|
||||
std::string source =
|
||||
"void rawAlloc() {\n"
|
||||
" Widget* w = new Widget();\n"
|
||||
" delete w;\n"
|
||||
"}\n";
|
||||
auto module = TreeSitterParser::parseCpp(source);
|
||||
|
||||
auto functions = module->getChildren("functions");
|
||||
assert(!functions.empty() && "Should parse the function");
|
||||
auto* fn = static_cast<Function*>(functions[0]);
|
||||
|
||||
auto annotations = fn->getChildren("annotations");
|
||||
bool hasDeallocExplicit = false;
|
||||
for (auto* anno : annotations) {
|
||||
if (anno->conceptType == "DeallocateAnnotation") {
|
||||
auto* dealloc = static_cast<DeallocateAnnotation*>(anno);
|
||||
if (dealloc->strategy == "Explicit") {
|
||||
hasDeallocExplicit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(hasDeallocExplicit &&
|
||||
"raw new/delete should be annotated with @Deallocate(Explicit)");
|
||||
|
||||
std::cout << "Test 7 PASS: raw new/delete detected → @Deallocate(Explicit)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Summary ---
|
||||
std::cout << "\n=== Step 46 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user