From 7a847c4f030452f6f895694d10a2081b25ea667f Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 7 Feb 2026 08:20:41 -0700 Subject: [PATCH] Step 44 TDD test: C++-specific idioms Tests FunctionCall, const reference parameters via LangSpecific annotation, #include directives, using namespace declarations, void return type, IndexAccess bracket notation, and MemberAccess dot/arrow notation. Co-Authored-By: Claude Opus 4.6 --- editor/CMakeLists.txt | 3 + editor/tests/step44_test.cpp | 207 +++++++++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 editor/tests/step44_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 8c0462c..3d067e0 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -145,6 +145,9 @@ target_include_directories(step42_test PRIVATE src) add_executable(step43_test tests/step43_test.cpp) target_include_directories(step43_test PRIVATE src) +add_executable(step44_test tests/step44_test.cpp) +target_include_directories(step44_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 diff --git a/editor/tests/step44_test.cpp b/editor/tests/step44_test.cpp new file mode 100644 index 0000000..3d22046 --- /dev/null +++ b/editor/tests/step44_test.cpp @@ -0,0 +1,207 @@ +// Step 44 TDD Test: C++-specific idioms +// +// Tests that CppGenerator handles C++-specific features: +// 1. FunctionCall with proper argument passing +// 2. const correctness in parameter declarations +// 3. Reference parameters (& and const&) +// 4. LangSpecific annotation for C++ → #include directives +// 5. LangSpecific annotation → using namespace declarations +// +// Will fail to compile until CppGenerator is fully implemented. + +#include +#include +#include +#include "ast/Generator.h" + +static bool contains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) != std::string::npos; +} + +int main() { + int passed = 0; + int failed = 0; + + // --- Test 1: FunctionCall generates proper C++ call syntax --- + { + FunctionCall call; + call.functionName = "std::sort"; + VariableReference* arg1 = new VariableReference("v1", "vec.begin()"); + VariableReference* arg2 = new VariableReference("v2", "vec.end()"); + call.addChild("arguments", arg1); + call.addChild("arguments", arg2); + + CppGenerator gen; + std::string output = gen.generate(&call); + + assert(contains(output, "std::sort") && "Should contain function name"); + assert(contains(output, "(") && "Should have opening paren"); + assert(contains(output, ")") && "Should have closing paren"); + + std::cout << "Test 1 PASS: FunctionCall generates proper C++ call" << std::endl; + ++passed; + + delete arg2; + delete arg1; + } + + // --- Test 2: const parameter in function --- + { + Function fn("f1", "printName"); + PrimitiveType* retType = new PrimitiveType("t0", "void"); + fn.setChild("returnType", retType); + + Parameter* param = new Parameter("p1", "name"); + PrimitiveType* paramType = new PrimitiveType("t1", "string"); + param->setChild("type", paramType); + + // Mark as const reference via LangSpecific annotation + LangSpecific* constAnno = new LangSpecific(); + constAnno->language = "cpp"; + constAnno->idiomType = "const_ref"; + param->addChild("annotations", constAnno); + + fn.addChild("parameters", param); + + CppGenerator gen; + std::string output = gen.generate(&fn); + + assert(contains(output, "printName") && "Should contain function name"); + assert(contains(output, "name") && "Should contain parameter name"); + // With const_ref annotation, should produce "const std::string&" + assert((contains(output, "const") || contains(output, "&")) && + "const_ref annotation should produce const reference parameter"); + + std::cout << "Test 2 PASS: const reference parameter annotation" << std::endl; + ++passed; + + delete constAnno; + delete paramType; + delete param; + delete retType; + } + + // --- Test 3: LangSpecific annotation for #include --- + { + Module mod("m1", "Sorter", "cpp"); + + LangSpecific* includeAnno = new LangSpecific(); + includeAnno->language = "cpp"; + includeAnno->idiomType = "include"; + includeAnno->rawSyntax = "#include "; + mod.addChild("annotations", includeAnno); + + Function* fn = new Function("f1", "sort"); + PrimitiveType* retType = new PrimitiveType("t1", "void"); + fn->setChild("returnType", retType); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert(contains(output, "#include") && "Should emit #include directive"); + assert(contains(output, "vector") && "Should include vector header"); + + std::cout << "Test 3 PASS: LangSpecific 'include' emits #include directive" << std::endl; + ++passed; + + delete retType; + delete fn; + delete includeAnno; + } + + // --- Test 4: LangSpecific annotation for using namespace --- + { + Module mod("m1", "App", "cpp"); + + LangSpecific* usingAnno = new LangSpecific(); + usingAnno->language = "cpp"; + usingAnno->idiomType = "using_namespace"; + usingAnno->rawSyntax = "using namespace std;"; + mod.addChild("annotations", usingAnno); + + Function* fn = new Function("f1", "main"); + PrimitiveType* retType = new PrimitiveType("t1", "int"); + fn->setChild("returnType", retType); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert(contains(output, "using namespace") && "Should emit using namespace declaration"); + + std::cout << "Test 4 PASS: LangSpecific 'using_namespace' emits using declaration" << std::endl; + ++passed; + + delete retType; + delete fn; + delete usingAnno; + } + + // --- Test 5: void return type function --- + { + Function fn("f1", "doNothing"); + PrimitiveType* retType = new PrimitiveType("t1", "void"); + fn.setChild("returnType", retType); + + CppGenerator gen; + std::string output = gen.generate(&fn); + + assert(contains(output, "void") && "Should contain void return type"); + assert(contains(output, "doNothing") && "Should contain function name"); + + std::cout << "Test 5 PASS: void return type function" << std::endl; + ++passed; + + delete retType; + } + + // --- Test 6: IndexAccess generates bracket notation --- + { + IndexAccess access; + VariableReference* target = new VariableReference("v1", "arr"); + IntegerLiteral* index = new IntegerLiteral("i1", 0); + access.setChild("target", target); + access.setChild("index", index); + + CppGenerator gen; + std::string output = gen.generate(&access); + + assert(contains(output, "arr") && "Should contain target name"); + assert(contains(output, "[") && "Should contain opening bracket"); + assert(contains(output, "0") && "Should contain index"); + assert(contains(output, "]") && "Should contain closing bracket"); + + std::cout << "Test 6 PASS: IndexAccess generates arr[0]" << std::endl; + ++passed; + + delete index; + delete target; + } + + // --- Test 7: MemberAccess generates dot or arrow notation --- + { + MemberAccess access; + access.memberName = "size"; + VariableReference* target = new VariableReference("v1", "vec"); + access.setChild("target", target); + + CppGenerator gen; + std::string output = gen.generate(&access); + + assert(contains(output, "vec") && "Should contain target name"); + assert(contains(output, "size") && "Should contain member name"); + // Could be vec.size or vec->size depending on pointer context + assert((contains(output, ".") || contains(output, "->")) && + "Should use dot or arrow notation"); + + std::cout << "Test 7 PASS: MemberAccess generates member access" << std::endl; + ++passed; + + delete target; + } + + // --- Summary --- + std::cout << "\n=== Step 44 Results: " << passed << " passed, " << failed << " failed ===" << std::endl; + return failed > 0 ? 1 : 0; +}