From fe32389271a7458d5fdf56f6cea65f6bc6cfb39f Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 7 Feb 2026 08:17:35 -0700 Subject: [PATCH] Step 39 TDD test: CppGenerator basic skeleton Tests CppGenerator inherits ProjectionGenerator, generates namespace from Module, produces C++ function signatures with types and braces, and does NOT emit Python syntax. Will fail to compile until CppGenerator is implemented. Co-Authored-By: Claude Opus 4.6 --- editor/tests/step39_test.cpp | 185 ++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 11 deletions(-) diff --git a/editor/tests/step39_test.cpp b/editor/tests/step39_test.cpp index 2f3a5b9..44df977 100644 --- a/editor/tests/step39_test.cpp +++ b/editor/tests/step39_test.cpp @@ -1,16 +1,179 @@ -// Step 39: Basic C++ generator skeleton. +// Step 39 TDD Test: Basic C++ generator skeleton // -// Create `CppGenerator` class inheriting from `ProjectionGenerator`. -// Implement basic concept mappings: Module → namespace/class, Function → function signature. -// Test: `generate(module)` → basic C++ skeleton with correct function signatures. +// Tests that CppGenerator (not yet implemented) can: +// 1. Inherit from ProjectionGenerator +// 2. Generate a namespace wrapper from a Module +// 3. Generate a C++ function signature from a Function with parameters +// 4. NOT produce Python syntax (def, colons) +// +// This test will fail to compile until CppGenerator is implemented in Generator.h. #include +#include +#include +#include "ast/Generator.h" + +// Helper to check if a string contains a substring +static bool contains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) != std::string::npos; +} + +// Helper to check a string does NOT contain a substring +static bool notContains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) == std::string::npos; +} int main() { - std::cout << "Step 39: PASS — Basic C++ generator skeleton implemented" << std::endl; - std::cout << "Created CppGenerator class inheriting from ProjectionGenerator" << std::endl; - std::cout << "Implemented basic concept mappings: Module → namespace/class, Function → function signature" << std::endl; - std::cout << "Test: generate(module) produces basic C++ skeleton with correct function signatures" << std::endl; - std::cout << "C++ generator foundation established for advanced memory management" << std::endl; - return 0; -} \ No newline at end of file + int passed = 0; + int failed = 0; + + // --- Test 1: CppGenerator is a ProjectionGenerator --- + { + CppGenerator gen; + ProjectionGenerator* base = &gen; + (void)base; // Compiles only if CppGenerator inherits from ProjectionGenerator + std::cout << "Test 1 PASS: CppGenerator inherits from ProjectionGenerator" << std::endl; + ++passed; + } + + // --- Test 2: Empty module produces namespace --- + { + Module mod("m1", "Calculator", "cpp"); + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert(contains(output, "namespace Calculator") && + "Module should produce a namespace declaration"); + assert(contains(output, "{") && "Namespace should have opening brace"); + assert(contains(output, "}") && "Namespace should have closing brace"); + + std::cout << "Test 2 PASS: Empty module produces namespace with braces" << std::endl; + ++passed; + } + + // --- Test 3: Module with a function produces C++ function signature --- + { + Module mod("m1", "Calculator", "cpp"); + + Function* addFn = new Function("f1", "add"); + + // Two int parameters + Parameter* paramX = new Parameter("p1", "x"); + PrimitiveType* intTypeX = new PrimitiveType("t1", "int"); + paramX->setChild("type", intTypeX); + + Parameter* paramY = new Parameter("p2", "y"); + PrimitiveType* intTypeY = new PrimitiveType("t2", "int"); + paramY->setChild("type", intTypeY); + + addFn->addChild("parameters", paramX); + addFn->addChild("parameters", paramY); + + // Add a return type to the function + PrimitiveType* returnType = new PrimitiveType("t3", "int"); + addFn->setChild("returnType", returnType); + + mod.addChild("functions", addFn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + // Should contain C++ function signature elements + assert(contains(output, "int") && "Output should contain 'int' type"); + assert(contains(output, "add") && "Output should contain function name 'add'"); + assert(contains(output, "(") && "Output should contain opening parenthesis"); + assert(contains(output, ")") && "Output should contain closing parenthesis"); + assert(contains(output, "x") && "Output should contain parameter 'x'"); + assert(contains(output, "y") && "Output should contain parameter 'y'"); + assert(contains(output, "{") && "Function body should have opening brace"); + assert(contains(output, "}") && "Function body should have closing brace"); + + std::cout << "Test 3 PASS: Function produces C++ signature with types and braces" << std::endl; + ++passed; + + delete returnType; + delete intTypeY; + delete paramY; + delete intTypeX; + delete paramX; + delete addFn; + } + + // --- Test 4: C++ output does NOT contain Python syntax --- + { + Module mod("m1", "Calculator", "cpp"); + + Function* fn = new Function("f1", "compute"); + Parameter* param = new Parameter("p1", "n"); + PrimitiveType* paramType = new PrimitiveType("t1", "int"); + param->setChild("type", paramType); + fn->addChild("parameters", param); + + PrimitiveType* retType = new PrimitiveType("t2", "int"); + fn->setChild("returnType", retType); + + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert(notContains(output, "def ") && "C++ output must not contain 'def '"); + assert(notContains(output, "pass") && "C++ output must not contain 'pass'"); + // Python uses colon after function signature; C++ uses brace + // (Note: colons can appear in C++ namespaces, so we check specifically for "def ...:") + assert(notContains(output, "def ") && "C++ output must not contain Python-style function definitions"); + + std::cout << "Test 4 PASS: C++ output contains no Python syntax" << std::endl; + ++passed; + + delete retType; + delete paramType; + delete param; + delete fn; + } + + // --- Test 5: generate(nullptr) returns empty string --- + { + CppGenerator gen; + std::string output = gen.generate(nullptr); + assert(output.empty() && "generate(nullptr) should return empty string"); + + std::cout << "Test 5 PASS: generate(nullptr) returns empty string" << std::endl; + ++passed; + } + + // --- Test 6: Module with multiple functions --- + { + Module mod("m1", "MathLib", "cpp"); + + Function* fn1 = new Function("f1", "add"); + PrimitiveType* ret1 = new PrimitiveType("t1", "int"); + fn1->setChild("returnType", ret1); + + Function* fn2 = new Function("f2", "subtract"); + PrimitiveType* ret2 = new PrimitiveType("t2", "int"); + fn2->setChild("returnType", ret2); + + mod.addChild("functions", fn1); + mod.addChild("functions", fn2); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert(contains(output, "add") && "Output should contain first function 'add'"); + assert(contains(output, "subtract") && "Output should contain second function 'subtract'"); + assert(contains(output, "namespace MathLib") && "Output should contain namespace 'MathLib'"); + + std::cout << "Test 6 PASS: Module with multiple functions generates all of them" << std::endl; + ++passed; + + delete ret2; + delete fn2; + delete ret1; + delete fn1; + } + + // --- Summary --- + std::cout << "\n=== Step 39 Results: " << passed << " passed, " << failed << " failed ===" << std::endl; + return failed > 0 ? 1 : 0; +}