// 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 #include #include #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; }