Files
whetstone_DSL/editor/tests/step296_test.cpp

337 lines
16 KiB
C++

// Step 296: Phase 11a Integration Tests (8 tests)
#include "ast/PythonGenerator.h"
#include "ast/CppGenerator.h"
#include "ast/RustGenerator.h"
#include "ast/GoGenerator.h"
#include "ast/JavaGenerator.h"
#include "ast/JavaScriptGenerator.h"
#include "ast/ElispGenerator.h"
#include "SemannoFormat.h"
#include "SemannoSidecar.h"
#include "ast/Module.h"
#include "ast/Function.h"
#include "ast/Annotation.h"
#include "EnvironmentSpec.h"
#include <iostream>
#include <filesystem>
#include <vector>
#include <string>
#include <memory>
static int passed = 0, failed = 0;
#define TEST(name) { std::cout << " " << #name << "... "; }
#define PASS() { std::cout << "PASS\n"; ++passed; }
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
static std::string tmpDir() {
auto p = std::filesystem::temp_directory_path() / "whetstone_test_296";
std::filesystem::create_directories(p);
return p.string();
}
static void cleanup() {
std::filesystem::remove_all(std::filesystem::temp_directory_path() / "whetstone_test_296");
}
// 1. Module with Subject 2-8 annotations generates Semanno in all generators
void test_multi_subject_generation() {
TEST(multi_subject_generation);
auto mod = std::make_unique<Module>();
mod->name = "annotated";
auto fn = std::make_unique<Function>();
fn->name = "process";
// One from each subject
auto bw = new BitWidthAnnotation(); bw->width = 32; // S2
auto atomic = new AtomicAnnotation(); atomic->consistency = "seq_cst"; // S3
auto cap = new CaptureAnnotation(); cap->strategy = "move"; // S4
auto shim = new ShimAnnotation(); shim->strategy = "vtable"; // S5
auto loop = new LoopAnnotation(); loop->hint = "unroll"; // S6
auto meta = new MetaAnnotation(); meta->state = "quoted"; meta->phase = "compile"; // S7
auto policy = new PolicyAnnotation(); policy->strictness = "high"; // S8
fn->addChild("annotations", bw);
fn->addChild("annotations", atomic);
fn->addChild("annotations", cap);
fn->addChild("annotations", shim);
fn->addChild("annotations", loop);
fn->addChild("annotations", meta);
fn->addChild("annotations", policy);
mod->addChild("functions", fn.release());
PythonGenerator gen;
std::string result = gen.generate(mod.get());
CHECK(result.find("@semanno:bitwidth") != std::string::npos, "missing S2");
CHECK(result.find("@semanno:atomic") != std::string::npos, "missing S3");
CHECK(result.find("@semanno:capture") != std::string::npos, "missing S4");
CHECK(result.find("@semanno:shim") != std::string::npos, "missing S5");
CHECK(result.find("@semanno:loop") != std::string::npos, "missing S6");
CHECK(result.find("@semanno:meta") != std::string::npos, "missing S7");
CHECK(result.find("@semanno:policy") != std::string::npos, "missing S8");
PASS();
}
// 2. Cross-language: annotations preserved through projection (generate same module with diff generators)
void test_cross_language_preservation() {
TEST(cross_language_preservation);
auto mod = std::make_unique<Module>();
mod->name = "cross";
auto fn = std::make_unique<Function>();
fn->name = "sort";
fn->addChild("annotations", new LoopAnnotation());
fn->addChild("annotations", new PureAnnotation());
mod->addChild("functions", fn.release());
PythonGenerator pyGen;
CppGenerator cppGen;
RustGenerator rsGen;
std::string py = pyGen.generate(mod.get());
std::string cpp = cppGen.generate(mod.get());
std::string rs = rsGen.generate(mod.get());
CHECK(py.find("@semanno:loop") != std::string::npos, "py missing loop");
CHECK(cpp.find("@semanno:loop") != std::string::npos, "cpp missing loop");
CHECK(rs.find("@semanno:loop") != std::string::npos, "rs missing loop");
PASS();
}
// 3. All 7 generators produce non-empty Semanno for every annotation type (exhaustive)
void test_exhaustive_no_unknown() {
TEST(exhaustive_no_unknown);
// Create one of each annotation type
std::vector<std::unique_ptr<ASTNode>> annotations;
// Subject 2
{ auto a = std::make_unique<BitWidthAnnotation>(); a->width = 8; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<EndianAnnotation>(); a->order = "little"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<LayoutAnnotation>(); a->mode = "aligned"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<NullabilityAnnotation>(); a->nullable = true; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<VarianceAnnotation>(); a->variance = "invariant"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<IdentityAnnotation>(); a->mode = "structural"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<MutAnnotation>(); a->depth = "shallow"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<TypeStateAnnotation>(); a->state = "erased"; annotations.push_back(std::move(a)); }
// Subject 3
{ auto a = std::make_unique<AtomicAnnotation>(); a->consistency = "relaxed"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<SyncAnnotation>(); a->primitive = "spin"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ThreadModelAnnotation>(); a->model = "os"; annotations.push_back(std::move(a)); }
{ annotations.push_back(std::make_unique<MemoryBarrierAnnotation>()); }
{ auto a = std::make_unique<ExecAnnotation>(); a->mode = "event"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<BlockingAnnotation>(); a->kind = "compute"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ParallelAnnotation>(); a->kind = "task"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<TrapAnnotation>(); a->signal = "SIGSEGV"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ExceptionAnnotation>(); a->style = "unchecked"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<PanicAnnotation>(); a->behavior = "unwind"; annotations.push_back(std::move(a)); }
// Subject 4
{ auto a = std::make_unique<BindingAnnotation>(); a->time = "dynamic"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<LookupAnnotation>(); a->mode = "hoisted"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<CaptureAnnotation>(); a->strategy = "ref"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<VisibilityAnnotation>(); a->level = "internal"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<NamespaceAnnotation>(); a->style = "flat"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ScopeAnnotation>(); a->kind = "global_leaked"; annotations.push_back(std::move(a)); }
// Subject 5
{ auto a = std::make_unique<IntrinsicAnnotation>(); a->instruction = "nop"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<RawAnnotation>(); a->language = "c"; a->code = "x"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<CallingConvAnnotation>(); a->convention = "fastcall"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<LinkAnnotation>(); a->symbolName = "s"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ShimAnnotation>(); a->strategy = "cast"; annotations.push_back(std::move(a)); }
{ annotations.push_back(std::make_unique<PointerArithmeticAnnotation>()); }
{ auto a = std::make_unique<OpaqueAnnotation>(); a->reason = "r"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<TargetAnnotation>(); a->platform = "linux"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<FeatureAnnotation>(); a->flag = "sse2"; a->enabled = true; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<OriginalAnnotation>(); a->sourceCode = "x"; a->sourceLanguage = "py"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<MappingAnnotation>(); a->history = {"a"}; annotations.push_back(std::move(a)); }
// Subject 6
{ annotations.push_back(std::make_unique<TailCallAnnotation>()); }
{ auto a = std::make_unique<LoopAnnotation>(); a->hint = "vectorize"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<DataAnnotation>(); a->hint = "restrict"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<AlignAnnotation>(); a->bytes = 16; annotations.push_back(std::move(a)); }
{ annotations.push_back(std::make_unique<PackAnnotation>()); }
{ auto a = std::make_unique<BoundsCheckAnnotation>(); a->enabled = true; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<OverflowAnnotation>(); a->behavior = "saturation"; annotations.push_back(std::move(a)); }
// Subject 7
{ auto a = std::make_unique<MetaAnnotation>(); a->state = "quoted"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<SymbolAnnotation>(); a->mode = "gensym"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<EvaluateAnnotation>(); a->phase = "compile_time"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<TemplateAnnotation>(); a->specialization = "erasure"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<SyntheticAnnotation>(); a->generator = "macro"; annotations.push_back(std::move(a)); }
// Subject 8
{ auto a = std::make_unique<PolicyAnnotation>(); a->strictness = "low"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<AmbiguityAnnotation>(); a->intent = "x"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<CandidateAnnotation>(); a->inferredTypes = {"int"}; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<TradeoffAnnotation>(); a->reason = "r"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ChoiceAnnotation>(); a->choiceId = "c"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<DecisionAnnotation>(); a->choiceId = "c"; a->selection = "a"; annotations.push_back(std::move(a)); }
// Semantic Core
{ auto a = std::make_unique<IntentAnnotation>(); a->summary = "s"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ComplexityAnnotation>(); a->timeComplexity = "O(1)"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<RiskAnnotation>(); a->level = "low"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<ContractAnnotation>(); a->preconditions = "x"; annotations.push_back(std::move(a)); }
{ auto a = std::make_unique<SemanticTagAnnotation>(); a->tags = {"io"}; annotations.push_back(std::move(a)); }
// Environment
{ auto a = std::make_unique<CapabilityRequirement>(); a->capability = "gc"; a->required = true; annotations.push_back(std::move(a)); }
PythonGenerator py;
CppGenerator cpp;
int unknownCount = 0;
for (const auto& a : annotations) {
std::string pyRes = py.generate(a.get());
std::string cppRes = cpp.generate(a.get());
if (pyRes.find("Unknown") != std::string::npos) {
std::cout << "Python Unknown: " << a->conceptType << "\n";
++unknownCount;
}
if (cppRes.find("Unknown") != std::string::npos) {
std::cout << "C++ Unknown: " << a->conceptType << "\n";
++unknownCount;
}
}
CHECK(unknownCount == 0, std::to_string(unknownCount) + " Unknown results");
CHECK(annotations.size() >= 56, "expected 56+ types, got " + std::to_string(annotations.size()));
PASS();
}
// 4. Semanno roundtrip: generate → parse back → match
void test_semanno_roundtrip() {
TEST(semanno_roundtrip);
CppGenerator gen;
auto anno = std::make_unique<PolicyAnnotation>();
anno->strictness = "high";
anno->perf = "critical";
anno->style = "idiomatic";
anno->binaryStable = false;
std::string generated = gen.generate(anno.get());
auto entry = SemannoParser::parse(generated);
CHECK(entry.type == "policy", "wrong type");
CHECK(entry.properties["strictness"] == "high", "strictness lost");
CHECK(entry.properties["perf"] == "critical", "perf lost");
CHECK(entry.properties["style"] == "idiomatic", "style lost");
PASS();
}
// 5. Mixed legacy + new annotations in single module
void test_mixed_legacy_new() {
TEST(mixed_legacy_new);
auto mod = std::make_unique<Module>();
mod->name = "mixed";
auto fn = std::make_unique<Function>();
fn->name = "calc";
// Legacy (Subject 1 memory)
auto reclaim = new ReclaimAnnotation();
reclaim->strategy = "Tracing";
fn->addChild("annotations", reclaim);
// New (Subject 6)
auto loop = new LoopAnnotation();
loop->hint = "vectorize";
fn->addChild("annotations", loop);
// Semantic core
auto intent = new IntentAnnotation();
intent->summary = "calculates sum";
fn->addChild("annotations", intent);
mod->addChild("functions", fn.release());
CppGenerator gen;
std::string result = gen.generate(mod.get());
// Legacy memory annotations may use their own format (not semanno)
// New annotations should use semanno
CHECK(result.find("@semanno:loop") != std::string::npos, "missing loop");
CHECK(result.find("@semanno:intent") != std::string::npos, "missing intent");
PASS();
}
// 6. Semanno sidecar roundtrip with all subjects
void test_sidecar_all_subjects() {
TEST(sidecar_all_subjects);
cleanup();
auto mod = std::make_unique<Module>();
mod->name = "sidecar_test";
auto fn = std::make_unique<Function>();
fn->name = "f";
fn->spanStartLine = 1;
fn->addChild("annotations", new IntentAnnotation());
auto bw = new BitWidthAnnotation(); bw->width = 32;
fn->addChild("annotations", bw);
auto atomic = new AtomicAnnotation(); atomic->consistency = "seq_cst";
fn->addChild("annotations", atomic);
mod->addChild("functions", fn.release());
auto saved = saveSemannoSidecar(tmpDir(), "all.py", mod.get());
CHECK(saved.success, "save failed");
CHECK(saved.annotationCount == 3, "wrong save count: " + std::to_string(saved.annotationCount));
auto loaded = loadSemannoSidecar(tmpDir(), "all.py");
CHECK(loaded.success, "load failed");
CHECK(loaded.count == 3, "wrong load count: " + std::to_string(loaded.count));
PASS();
}
// 7. Generator comment prefix matches language convention
void test_all_prefixes() {
TEST(all_prefixes);
PythonGenerator py;
CppGenerator cpp;
RustGenerator rs;
GoGenerator go;
JavaGenerator java;
JavaScriptGenerator js;
ElispGenerator elisp;
CHECK(py.commentPrefix() == "# ", "py");
CHECK(cpp.commentPrefix() == "// ", "cpp");
CHECK(rs.commentPrefix() == "// ", "rs");
CHECK(go.commentPrefix() == "// ", "go");
CHECK(java.commentPrefix() == "// ", "java");
CHECK(js.commentPrefix() == "// ", "js");
CHECK(elisp.commentPrefix() == ";; ", "elisp");
PASS();
}
// 8. Marker annotations produce correct Semanno (no parentheses)
void test_marker_semanno() {
TEST(marker_semanno);
CppGenerator gen;
auto pure = std::make_unique<PureAnnotation>();
auto tailcall = std::make_unique<TailCallAnnotation>();
auto pack = std::make_unique<PackAnnotation>();
auto barrier = std::make_unique<MemoryBarrierAnnotation>();
auto ptrArith = std::make_unique<PointerArithmeticAnnotation>();
std::string pureResult = gen.generate(pure.get());
std::string tailResult = gen.generate(tailcall.get());
std::string packResult = gen.generate(pack.get());
// Marker annotations should NOT have parentheses
CHECK(pureResult.find("(") == std::string::npos, "pure has parens: " + pureResult);
CHECK(tailResult.find("(") == std::string::npos, "tailcall has parens: " + tailResult);
CHECK(packResult.find("(") == std::string::npos, "pack has parens: " + packResult);
PASS();
}
int main() {
std::cout << "=== Step 296: Phase 11a Integration Tests ===\n";
test_multi_subject_generation();
test_cross_language_preservation();
test_exhaustive_no_unknown();
test_semanno_roundtrip();
test_mixed_legacy_new();
test_sidecar_all_subjects();
test_all_prefixes();
test_marker_semanno();
cleanup();
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
return failed > 0 ? 1 : 0;
}