Step 65 TDD test: Memory strategy inference
Tests MemoryStrategyInference: Python->@Reclaim(Tracing), C++ gets suggestions, inference does NOT auto-apply to AST, suggestions have confidence scores and reasons, Elisp->@Reclaim(Tracing). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -184,6 +184,9 @@ target_include_directories(step63_test PRIVATE src)
|
||||
add_executable(step64_test tests/step64_test.cpp)
|
||||
target_include_directories(step64_test PRIVATE src)
|
||||
|
||||
add_executable(step65_test tests/step65_test.cpp)
|
||||
target_include_directories(step65_test PRIVATE src)
|
||||
|
||||
add_executable(whetstone_editor src/main.cpp)
|
||||
target_include_directories(whetstone_editor PRIVATE src)
|
||||
# find_package(SDL2 REQUIRED) # Commented out for now to avoid build issues
|
||||
|
||||
149
editor/tests/step65_test.cpp
Normal file
149
editor/tests/step65_test.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// Step 65 TDD Test: Memory strategy inference
|
||||
//
|
||||
// Tests that the system can infer appropriate memory annotations:
|
||||
// 1. Python source → @Reclaim(Tracing)
|
||||
// 2. C++ unique_ptr patterns → @Lifetime(RAII) or @Owner(Single)
|
||||
// 3. C++ shared_ptr patterns → @Owner(Shared_ARC)
|
||||
// 4. C raw malloc/free → @Deallocate(Explicit)
|
||||
// 5. Immutable data → @Allocate(Static) candidate
|
||||
// 6. Suggestions are surfaced, not auto-applied
|
||||
//
|
||||
// Will fail until memory strategy inference 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/Annotation.h"
|
||||
|
||||
// Forward declaration — MemoryStrategyInference
|
||||
class MemoryStrategyInference {
|
||||
public:
|
||||
struct Suggestion {
|
||||
std::string nodeId;
|
||||
std::string annotationType; // e.g., "ReclaimAnnotation"
|
||||
std::string strategy; // e.g., "Tracing"
|
||||
std::string reason; // Human-readable explanation
|
||||
double confidence; // 0.0 to 1.0
|
||||
};
|
||||
|
||||
// Analyze an AST and suggest memory annotations
|
||||
std::vector<Suggestion> inferAnnotations(const ASTNode* root) const;
|
||||
};
|
||||
|
||||
static bool hasSuggestion(const std::vector<MemoryStrategyInference::Suggestion>& suggestions,
|
||||
const std::string& annotationType,
|
||||
const std::string& strategy) {
|
||||
for (const auto& s : suggestions) {
|
||||
if (s.annotationType == annotationType && s.strategy == strategy) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
MemoryStrategyInference inference;
|
||||
|
||||
// --- Test 1: Python module → @Reclaim(Tracing) suggested ---
|
||||
{
|
||||
Module mod("m1", "PyModule", "python");
|
||||
Function* fn = new Function("f1", "process");
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
auto suggestions = inference.inferAnnotations(&mod);
|
||||
assert(hasSuggestion(suggestions, "ReclaimAnnotation", "Tracing") &&
|
||||
"Python module should suggest @Reclaim(Tracing)");
|
||||
|
||||
std::cout << "Test 1 PASS: Python → @Reclaim(Tracing) suggested" << std::endl;
|
||||
++passed;
|
||||
|
||||
delete fn;
|
||||
}
|
||||
|
||||
// --- Test 2: C++ module with no specific patterns → generic suggestion ---
|
||||
{
|
||||
Module mod("m1", "CppModule", "cpp");
|
||||
Function* fn = new Function("f1", "compute");
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
auto suggestions = inference.inferAnnotations(&mod);
|
||||
// Should have at least one suggestion
|
||||
assert(!suggestions.empty() && "C++ module should have at least one suggestion");
|
||||
|
||||
std::cout << "Test 2 PASS: C++ module gets memory suggestions" << std::endl;
|
||||
++passed;
|
||||
|
||||
delete fn;
|
||||
}
|
||||
|
||||
// --- Test 3: Suggestions are not auto-applied ---
|
||||
{
|
||||
Module mod("m1", "PyModule", "python");
|
||||
Function* fn = new Function("f1", "process");
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
// Before inference
|
||||
auto annosBefore = fn->getChildren("annotations");
|
||||
size_t countBefore = annosBefore.size();
|
||||
|
||||
// Run inference
|
||||
inference.inferAnnotations(&mod);
|
||||
|
||||
// After inference — annotations should NOT be added to the AST
|
||||
auto annosAfter = fn->getChildren("annotations");
|
||||
assert(annosAfter.size() == countBefore &&
|
||||
"Inference should NOT auto-apply annotations to AST");
|
||||
|
||||
std::cout << "Test 3 PASS: Suggestions not auto-applied to AST" << std::endl;
|
||||
++passed;
|
||||
|
||||
delete fn;
|
||||
}
|
||||
|
||||
// --- Test 4: Suggestions include confidence scores ---
|
||||
{
|
||||
Module mod("m1", "PyModule", "python");
|
||||
Function* fn = new Function("f1", "process");
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
auto suggestions = inference.inferAnnotations(&mod);
|
||||
for (const auto& s : suggestions) {
|
||||
assert(s.confidence >= 0.0 && s.confidence <= 1.0 &&
|
||||
"Confidence should be between 0 and 1");
|
||||
assert(!s.reason.empty() && "Suggestion should have a reason");
|
||||
}
|
||||
|
||||
std::cout << "Test 4 PASS: Suggestions have confidence scores and reasons" << std::endl;
|
||||
++passed;
|
||||
|
||||
delete fn;
|
||||
}
|
||||
|
||||
// --- Test 5: Elisp module → @Reclaim(Tracing) suggested ---
|
||||
{
|
||||
Module mod("m1", "ElModule", "elisp");
|
||||
Function* fn = new Function("f1", "process");
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
auto suggestions = inference.inferAnnotations(&mod);
|
||||
assert(hasSuggestion(suggestions, "ReclaimAnnotation", "Tracing") &&
|
||||
"Elisp module should suggest @Reclaim(Tracing)");
|
||||
|
||||
std::cout << "Test 5 PASS: Elisp → @Reclaim(Tracing) suggested" << std::endl;
|
||||
++passed;
|
||||
|
||||
delete fn;
|
||||
}
|
||||
|
||||
// --- Summary ---
|
||||
std::cout << "\n=== Step 65 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user