Files
whetstone_DSL/editor/tests/step39_test.cpp
Bill fe32389271 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 <noreply@anthropic.com>
2026-02-07 08:17:35 -07:00

180 lines
6.5 KiB
C++

// Step 39 TDD Test: Basic C++ generator skeleton
//
// 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 <iostream>
#include <string>
#include <cassert>
#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() {
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;
}