Files
whetstone_DSL/editor/tests/step70_test.cpp

246 lines
7.6 KiB
C++
Raw Normal View History

// Step 70 TDD Test: Cross-strategy validation
//
// Tests post-optimization invariant verification:
// 1. @Deallocate(Explicit): no use-after-free detected
// 2. @Deallocate(Explicit): leaked allocation detected
// 3. @Owner(Single): no double-move detected
// 4. @Owner(Single): aliasing detected
// 5. @Lifetime(RAII): destructor unreachable on some path detected
// 6. Clean code passes validation
//
// Will fail until cross-strategy validation is implemented.
#include <iostream>
#include <string>
#include <cassert>
#include <vector>
#include "ast/ASTNode.h"
#include "ast/Module.h"
#include "ast/Function.h"
#include "ast/Variable.h"
#include "ast/Statement.h"
#include "ast/Expression.h"
#include "ast/Annotation.h"
#include "StrategyValidator.h"
static bool hasViolation(const std::vector<StrategyValidator::Violation>& violations,
const std::string& category) {
for (const auto& v : violations) {
if (v.category == category) return true;
}
return false;
}
int main() {
int passed = 0;
int failed = 0;
StrategyValidator validator;
// --- Test 1: @Deallocate(Explicit) use-after-free detected ---
{
Module mod("m1", "Test", "cpp");
Function* fn = new Function("f1", "useAfterFree");
DeallocateAnnotation* anno = new DeallocateAnnotation();
anno->id = "a1";
anno->strategy = "Explicit";
fn->addChild("annotations", anno);
// ptr = new Widget; delete ptr; use(ptr) -- use after free
Variable* ptr = new Variable("v1", "ptr");
fn->addChild("body", ptr);
// delete ptr
ExpressionStatement* freeStmt = new ExpressionStatement();
freeStmt->id = "del1";
FunctionCall* freeCall = new FunctionCall();
freeCall->id = "fc1";
freeCall->functionName = "delete";
VariableReference* freeArg = new VariableReference("vr1", "ptr");
freeCall->addChild("arguments", freeArg);
freeStmt->setChild("expression", freeCall);
fn->addChild("body", freeStmt);
// use(ptr) — after delete
ExpressionStatement* useStmt = new ExpressionStatement();
useStmt->id = "use1";
FunctionCall* useCall = new FunctionCall();
useCall->id = "fc2";
useCall->functionName = "use";
VariableReference* useArg = new VariableReference("vr2", "ptr");
useCall->addChild("arguments", useArg);
useStmt->setChild("expression", useCall);
fn->addChild("body", useStmt);
mod.addChild("functions", fn);
auto violations = validator.validateInvariants(&mod);
assert(hasViolation(violations, "use-after-free") &&
"Should detect use-after-free");
std::cout << "Test 1 PASS: use-after-free detected" << std::endl;
++passed;
delete useArg;
delete useCall;
delete useStmt;
delete freeArg;
delete freeCall;
delete freeStmt;
delete ptr;
delete anno;
delete fn;
}
// --- Test 2: @Deallocate(Explicit) leaked allocation detected ---
{
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);
// ptr = new Widget; return; -- no delete → leak
Variable* ptr = new Variable("v1", "ptr");
fn->addChild("body", ptr);
Return* ret = new Return();
ret->id = "r1";
fn->addChild("body", ret);
mod.addChild("functions", fn);
auto violations = validator.validateInvariants(&mod);
assert(hasViolation(violations, "leak") &&
"Should detect leaked allocation");
std::cout << "Test 2 PASS: Leaked allocation detected" << std::endl;
++passed;
delete ret;
delete ptr;
delete anno;
delete fn;
}
// --- Test 3: @Owner(Single) aliasing detected ---
{
Module mod("m1", "Test", "cpp");
Function* fn = new Function("f1", "alias");
OwnerAnnotation* anno = new OwnerAnnotation();
anno->id = "a1";
anno->strategy = "Single";
fn->addChild("annotations", anno);
// a = resource; b = resource; -- aliasing under single ownership
Variable* resource = new Variable("v1", "resource");
fn->addChild("body", resource);
Assignment* assign1 = new Assignment();
assign1->id = "as1";
VariableReference* t1 = new VariableReference("vr1", "a");
VariableReference* v1 = new VariableReference("vr2", "resource");
assign1->setChild("target", t1);
assign1->setChild("value", v1);
fn->addChild("body", assign1);
Assignment* assign2 = new Assignment();
assign2->id = "as2";
VariableReference* t2 = new VariableReference("vr3", "b");
VariableReference* v2 = new VariableReference("vr4", "resource");
assign2->setChild("target", t2);
assign2->setChild("value", v2);
fn->addChild("body", assign2);
mod.addChild("functions", fn);
auto violations = validator.validateInvariants(&mod);
assert(hasViolation(violations, "aliasing") &&
"Should detect aliasing under @Owner(Single)");
std::cout << "Test 3 PASS: @Owner(Single) aliasing detected" << std::endl;
++passed;
delete v2;
delete t2;
delete assign2;
delete v1;
delete t1;
delete assign1;
delete resource;
delete anno;
delete fn;
}
// --- Test 4: Clean code passes validation ---
{
Module mod("m1", "Test", "python");
Function* fn = new Function("f1", "clean");
ReclaimAnnotation* anno = new ReclaimAnnotation();
anno->id = "a1";
anno->strategy = "Tracing";
fn->addChild("annotations", anno);
Return* ret = new Return();
ret->id = "r1";
IntegerLiteral* val = new IntegerLiteral("i1", 42);
ret->setChild("value", val);
fn->addChild("body", ret);
mod.addChild("functions", fn);
auto violations = validator.validateInvariants(&mod);
bool hasErrors = false;
for (const auto& v : violations) {
if (v.severity == "error") hasErrors = true;
}
assert(!hasErrors && "Clean code should pass validation");
std::cout << "Test 4 PASS: Clean code passes validation" << std::endl;
++passed;
delete val;
delete ret;
delete anno;
delete fn;
}
// --- Test 5: Violations include node IDs for diagnostics ---
{
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* ptr = new Variable("v1", "ptr");
fn->addChild("body", ptr);
mod.addChild("functions", fn);
auto violations = validator.validateInvariants(&mod);
for (const auto& v : violations) {
assert(!v.nodeId.empty() && "Violation should reference a node ID");
assert(!v.message.empty() && "Violation should have a message");
}
std::cout << "Test 5 PASS: Violations include node IDs and messages" << std::endl;
++passed;
delete ptr;
delete anno;
delete fn;
}
// --- Summary ---
std::cout << "\n=== Step 70 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
return failed > 0 ? 1 : 0;
}