// Step 66 TDD Test: Cross-language memory projection // // Tests the "Lossless Projection Logic" from Memory strategy.md Section 3: // 1. Python → C++: @Reclaim(Tracing) → inject ref-counting shim (shared_ptr) // 2. C++ → Python: @Deallocate(Explicit) → wrap in try-with-resources pattern // 3. Rust-like → Python: @Owner(Single) → preserve in metadata, don't enforce // 4. Round-trip: annotation survives language round-trip // 5. @Lifetime(RAII) → inject destructor calls at scope end // // Will fail until cross-language projection is implemented. #include #include #include #include "ast/ASTNode.h" #include "ast/Module.h" #include "ast/Function.h" #include "ast/Variable.h" #include "ast/Annotation.h" #include "ast/Generator.h" static bool contains(const std::string& haystack, const std::string& needle) { return haystack.find(needle) != std::string::npos; } #include "CrossLanguageProjector.h" int main() { int passed = 0; int failed = 0; CrossLanguageProjector projector; // --- Test 1: Python @Reclaim(Tracing) → C++ shared_ptr --- { Module pyMod("m1", "PyModule", "python"); Function* fn = new Function("f1", "process"); ReclaimAnnotation* anno = new ReclaimAnnotation(); anno->id = "a1"; anno->strategy = "Tracing"; fn->addChild("annotations", anno); Variable* var = new Variable("v1", "data"); fn->addChild("body", var); pyMod.addChild("functions", fn); auto cppMod = projector.project(&pyMod, "cpp"); assert(cppMod != nullptr && "Projection should produce a module"); assert(cppMod->targetLanguage == "cpp" && "Target should be cpp"); // Generate C++ from the projected module CppGenerator gen; std::string output = gen.generate(cppMod.get()); // @Reclaim(Tracing) in C++ → should use shared_ptr for GC-like semantics assert(contains(output, "shared_ptr") && "Python @Reclaim(Tracing) → C++ should use shared_ptr"); std::cout << "Test 1 PASS: Python @Reclaim(Tracing) → C++ shared_ptr" << std::endl; ++passed; delete var; delete anno; delete fn; } // --- Test 2: C++ @Deallocate(Explicit) → Python wrapper --- { Module cppMod("m1", "CppModule", "cpp"); Function* fn = new Function("f1", "allocate"); DeallocateAnnotation* anno = new DeallocateAnnotation(); anno->id = "a1"; anno->strategy = "Explicit"; fn->addChild("annotations", anno); Variable* var = new Variable("v1", "ptr"); fn->addChild("body", var); cppMod.addChild("functions", fn); auto pyMod = projector.project(&cppMod, "python"); assert(pyMod != nullptr && "Projection should produce a module"); assert(pyMod->targetLanguage == "python" && "Target should be python"); // The annotation should still be present in metadata auto projectedFns = pyMod->getChildren("functions"); assert(!projectedFns.empty() && "Should have functions"); std::cout << "Test 2 PASS: C++ @Deallocate(Explicit) → Python projection" << std::endl; ++passed; delete var; delete anno; delete fn; } // --- Test 3: @Owner(Single) → Python preserves in metadata --- { Module rustLike("m1", "RustLike", "cpp"); Function* fn = new Function("f1", "ownership"); OwnerAnnotation* anno = new OwnerAnnotation(); anno->id = "a1"; anno->strategy = "Single"; fn->addChild("annotations", anno); rustLike.addChild("functions", fn); auto pyMod = projector.project(&rustLike, "python"); // @Owner(Single) should be preserved in metadata even though Python doesn't enforce it auto projectedFns = pyMod->getChildren("functions"); auto* projectedFn = static_cast(projectedFns[0]); auto annos = projectedFn->getChildren("annotations"); bool hasOwner = false; for (auto* a : annos) { if (a->conceptType == "OwnerAnnotation") { hasOwner = true; } } assert(hasOwner && "@Owner(Single) should be preserved in Python projection metadata"); std::cout << "Test 3 PASS: @Owner(Single) preserved in Python metadata" << std::endl; ++passed; delete anno; delete fn; } // --- Test 4: Round-trip preserves annotations --- { Module pyMod("m1", "RoundTrip", "python"); Function* fn = new Function("f1", "process"); ReclaimAnnotation* anno = new ReclaimAnnotation(); anno->id = "a1"; anno->strategy = "Tracing"; fn->addChild("annotations", anno); pyMod.addChild("functions", fn); // Python → C++ auto cppMod = projector.project(&pyMod, "cpp"); // C++ → Python auto pyModBack = projector.project(cppMod.get(), "python"); // Annotation should survive round-trip assert(projector.annotationsPreserved(&pyMod, pyModBack.get()) && "Annotations should survive Python → C++ → Python round-trip"); std::cout << "Test 4 PASS: Round-trip preserves annotations" << std::endl; ++passed; delete anno; delete fn; } // --- Test 5: @Lifetime(RAII) in C++ generation --- { Module cppMod("m1", "RAIIModule", "cpp"); Function* fn = new Function("f1", "scoped"); LifetimeAnnotation* anno = new LifetimeAnnotation(); anno->id = "a1"; anno->strategy = "RAII"; fn->addChild("annotations", anno); Variable* var = new Variable("v1", "resource"); fn->addChild("body", var); PrimitiveType* retType = new PrimitiveType("t1", "void"); fn->setChild("returnType", retType); cppMod.addChild("functions", fn); CppGenerator gen; std::string output = gen.generate(&cppMod); // @Lifetime(RAII) → unique_ptr with RAII semantics assert(contains(output, "unique_ptr") && "@Lifetime(RAII) should produce unique_ptr in C++"); std::cout << "Test 5 PASS: @Lifetime(RAII) generates unique_ptr" << std::endl; ++passed; delete retType; delete var; delete anno; delete fn; } // --- Summary --- std::cout << "\n=== Step 66 Results: " << passed << " passed, " << failed << " failed ===" << std::endl; return failed > 0 ? 1 : 0; }