Files
whetstone_DSL/editor/tests/step72_test.cpp

178 lines
6.3 KiB
C++
Raw Normal View History

// Step 72 TDD Test: End-to-end pipeline
//
// Tests the full Whetstone pipeline:
// 1. Python source → parse → infer → validate → optimize → generate Python
// 2. Python source → parse → project to C++ → generate C++
// 3. C++ source → parse → infer → generate C++
// 4. Parse with constant expressions → verify folding occurs
// 5. Pipeline with diagnostics (parser errors flow through)
// 6. Round-trip: Python source → AST → Python output preserves semantics
#include <iostream>
#include <string>
#include <cassert>
#include "Pipeline.h"
int main() {
int passed = 0;
int failed = 0;
Pipeline pipeline;
// --- Test 1: Python source → full pipeline → Python output ---
{
std::string source = R"(
def greet(name):
return name
)";
auto result = pipeline.run(source, "python", "python");
assert(result.success && "Pipeline should succeed");
assert(result.ast != nullptr && "AST should be produced");
assert(!result.generatedCode.empty() && "Generated code should not be empty");
assert(result.generatedCode.find("def ") != std::string::npos &&
"Python output should contain 'def'");
// Should have inferred @Reclaim(Tracing) for Python
bool foundTracing = false;
for (const auto& s : result.suggestions) {
if (s.strategy == "Tracing") foundTracing = true;
}
assert(foundTracing && "Should infer @Reclaim(Tracing) for Python");
std::cout << "Test 1 PASS: Python → full pipeline → Python output" << std::endl;
++passed;
}
// --- Test 2: Python → project to C++ → generate C++ ---
{
std::string source = R"(
def add(a, b):
return a
)";
auto result = pipeline.run(source, "python", "cpp");
assert(result.success && "Pipeline should succeed");
assert(!result.generatedCode.empty() && "C++ code should be generated");
std::cout << "Test 2 PASS: Python → project to C++ → C++ output" << std::endl;
++passed;
}
// --- Test 3: C++ source → parse → infer → generate C++ ---
{
std::string source = R"(
int compute() {
return 42;
}
)";
auto result = pipeline.run(source, "cpp", "cpp");
assert(result.success && "Pipeline should succeed for C++ source");
assert(result.ast != nullptr && "AST should be produced from C++");
// Should infer RAII for C++
bool foundRAII = false;
for (const auto& s : result.suggestions) {
if (s.strategy == "RAII") foundRAII = true;
}
assert(foundRAII && "Should infer @Lifetime(RAII) for C++");
std::cout << "Test 3 PASS: C++ → parse → infer → generate C++" << std::endl;
++passed;
}
// --- Test 4: Constant folding in pipeline ---
{
// Build an AST manually with a foldable expression
Module mod("m1", "Test", "python");
Function* fn = new Function("f1", "calc");
Return* ret = new Return();
ret->id = "r1";
BinaryOperation* binOp = new BinaryOperation("b1", "+");
IntegerLiteral* left = new IntegerLiteral("i1", 10);
IntegerLiteral* right = new IntegerLiteral("i2", 20);
binOp->setChild("left", left);
binOp->setChild("right", right);
ret->setChild("value", binOp);
fn->addChild("body", ret);
mod.addChild("functions", fn);
// Run transform engine
TransformEngine engine;
engine.setRoot(&mod);
auto foldResult = engine.constantFolding();
assert(foldResult.applied && "Constant folding should apply");
// Generate and verify the folded value appears
PythonGenerator gen;
std::string output = gen.generate(&mod);
assert(output.find("30") != std::string::npos &&
"Folded constant 10+20=30 should appear in output");
std::cout << "Test 4 PASS: Constant folding produces correct generated output" << std::endl;
++passed;
delete right;
delete left;
delete binOp;
delete ret;
delete fn;
}
// --- Test 5: Pipeline results include parse diagnostics ---
{
// Even valid Python should produce a result with empty diagnostics
std::string source = "def f():\n return 1\n";
auto result = pipeline.run(source, "python", "python");
assert(result.success && "Pipeline should succeed");
// Parse diagnostics available (may be empty for valid source)
// Just verify the pipeline carried them through
assert(result.ast != nullptr && "Valid source should produce AST");
std::cout << "Test 5 PASS: Parse diagnostics flow through pipeline" << std::endl;
++passed;
}
// --- Test 6: Pipeline with annotation validation ---
{
// Create AST with @Deallocate(Explicit) but no deallocation
Module mod("m1", "Test", "cpp");
Function* fn = new Function("f1", "leak");
DeallocateAnnotation* anno = new DeallocateAnnotation();
anno->id = "a1";
anno->strategy = "Explicit";
fn->addChild("annotations", anno);
Variable* var = new Variable("v1", "ptr");
fn->addChild("body", var);
mod.addChild("functions", fn);
// Validate
AnnotationValidator validator;
auto diags = validator.validate(&mod);
bool foundMissing = false;
for (const auto& d : diags) {
if (d.message.find("Missing Intent") != std::string::npos)
foundMissing = true;
}
assert(foundMissing && "Should detect missing deallocation intent");
// Post-optimization invariant check
StrategyValidator stratValidator;
auto violations = stratValidator.validateInvariants(&mod);
bool foundLeak = false;
for (const auto& v : violations) {
if (v.category == "leak") foundLeak = true;
}
assert(foundLeak && "Should detect leak in invariant check");
std::cout << "Test 6 PASS: Annotation + invariant validation in pipeline" << std::endl;
++passed;
delete var;
delete anno;
delete fn;
}
// --- Summary ---
std::cout << "\n=== Step 72 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
return failed > 0 ? 1 : 0;
}