Files
whetstone_DSL/editor/tests/step364_test.cpp

219 lines
7.9 KiB
C++

// Step 364: C Integration + Self-Hosting Prep (8 tests)
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include "Pipeline.h"
#include "AnnotationInference.h"
#include "MemoryStrategyInference.h"
#include "CrossLanguageProjector.h"
#include "MCPServer.h"
#include "ast/CParser.h"
#include "ast/CGenerator.h"
#include "ast/CppGenerator.h"
#include "ast/PythonGenerator.h"
#include "ast/RustGenerator.h"
static bool contains(const std::string& text, const std::string& token) {
return text.find(token) != std::string::npos;
}
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;
}
static bool hasInference(const std::vector<AnnotationInference::InferredAnnotation>& inferred,
const std::string& annotationType,
const std::string& value) {
for (const auto& a : inferred) {
if (a.annotationType == annotationType && a.value == value) return true;
}
return false;
}
int main() {
int passed = 0;
// Test 1: Parse C -> generate C -> reparse keeps core declarations
{
std::string src = "typedef struct Point { int x; int y; } Point;\\n"
"int add(int a, int b) { return a + b; }\\n";
auto mod = CParser::parseC(src);
CGenerator gen;
std::string out = gen.generate(mod.get());
auto roundtrip = CParser::parseC(out);
assert(!roundtrip->getChildren("classes").empty());
assert(contains(out, "typedef struct Point"));
std::cout << "Test 1 PASSED: C parse/generate roundtrip keeps declarations\\n";
passed++;
}
// Test 2: C struct projects as Python class shape
{
auto* cls = new ClassDeclaration("c1", "Point");
auto* x = new Variable("v1", "x");
x->setChild("type", new PrimitiveType("t1", "int"));
cls->addChild("fields", x);
PythonGenerator py;
std::string out = py.generate(cls);
assert(contains(out, "class Point"));
assert(contains(out, "x"));
std::cout << "Test 2 PASSED: C struct emits Python class form\\n";
passed++;
}
// Test 3: Python-style class emits C struct + constructor-style function
{
auto* cls = new ClassDeclaration("c1", "Widget");
auto* field = new Variable("v1", "value");
field->setChild("type", new PrimitiveType("t1", "int"));
cls->addChild("fields", field);
auto* init = new MethodDeclaration("m1", "init");
init->className = "Widget";
init->setChild("returnType", new PrimitiveType("rt", "void"));
cls->addChild("methods", init);
CGenerator cgen;
std::string outStruct = cgen.generate(cls);
std::string outCtor = cgen.generate(init);
assert(contains(outStruct, "typedef struct Widget"));
assert(contains(outCtor, "Widget_init("));
std::cout << "Test 3 PASSED: Python class shape + constructor-style method generation\\n";
passed++;
}
// Test 4: C manual ownership projects to Rust ownership semantics
{
Module cmod("m1", "cmod", "c");
auto* fn = new Function("f1", "make");
fn->addChild("annotations", new OwnerAnnotation("a1", "Manual"));
cmod.addChild("functions", fn);
CrossLanguageProjector projector;
auto rustMod = projector.project(&cmod, "rust");
auto* rustFn = static_cast<Function*>(rustMod->getChildren("functions")[0]);
bool hasBox = false;
for (auto* a : rustFn->getChildren("annotations")) {
if (a->conceptType == "OwnerAnnotation") {
auto* oa = static_cast<OwnerAnnotation*>(a);
hasBox = hasBox || (oa->strategy == "Box");
}
}
assert(hasBox);
RustGenerator rust;
std::string out = rust.generate(rustMod.get());
assert(contains(out, "@owner(Box)"));
std::cout << "Test 4 PASSED: C manual owner adapts to Rust Box\\n";
passed++;
}
// Test 5: Pipeline.run C->C++ succeeds and emits C++ translation unit shell
{
Pipeline p;
std::string src = "struct Point { int x; int y; };\\n";
auto result = p.run(src, "c", "cpp");
assert(result.success);
assert(!result.generatedCode.empty());
assert(contains(result.generatedCode, "namespace"));
std::cout << "Test 5 PASSED: pipeline C->C++ run succeeds with generated output\\n";
passed++;
}
// Test 6: C inference captures malloc + array access + pointer parameter
{
Module mod("m1", "infer", "c");
auto* fn = new Function("f1", "process");
auto* param = new Parameter("p1", "cb");
param->setChild("type", new PrimitiveType("pt", "void (*)(int)"));
fn->addChild("parameters", param);
auto* allocCall = new FunctionCall();
allocCall->id = "fc1";
allocCall->functionName = "malloc";
fn->addChild("body", allocCall);
auto* idx = new IndexAccess();
idx->id = "idx1";
idx->setChild("target", new VariableReference("vr1", "arr"));
idx->setChild("index", new VariableReference("vr2", "i"));
auto* stmt = new ExpressionStatement();
stmt->id = "s1";
stmt->setChild("expression", idx);
fn->addChild("body", stmt);
mod.addChild("functions", fn);
MemoryStrategyInference mem;
AnnotationInference anno;
auto suggestions = mem.inferAnnotations(&mod);
auto inferred = anno.inferAll(&mod);
assert(hasSuggestion(suggestions, "OwnerAnnotation", "Manual"));
assert(hasSuggestion(suggestions, "OwnerAnnotation", "Borrowed"));
assert(hasInference(inferred, "BoundsCheckAnnotation", "unchecked"));
std::cout << "Test 6 PASSED: C inference covers malloc/array/pointer patterns\\n";
passed++;
}
// Test 7: Parse simplified C header from dependency-style source
{
std::string header =
"#ifndef TINY_HDR_H\\n"
"#define TINY_HDR_H\\n"
"#include <stddef.h>\\n"
"typedef struct Tiny { int size; } Tiny;\\n"
"enum TinyMode { TinyFast = 1, TinySafe = 2 };\\n"
"#endif\\n";
auto mod = CParser::parseC(header);
assert(!mod->getChildren("classes").empty());
assert(!mod->getChildren("statements").empty());
std::cout << "Test 7 PASSED: simplified C header parses into expected AST\\n";
passed++;
}
// Test 8: MCP tools list stable and pipeline tool accepts language parameter
{
MCPServer server;
auto tools = server.getTools();
const size_t expectedCount = tools.size();
json req = {
{"jsonrpc", "2.0"},
{"id", 1},
{"method", "tools/list"},
{"params", json::object()}
};
auto resp = server.handleRequest(req);
assert(resp.contains("result"));
assert(resp["result"].contains("tools"));
auto listed = resp["result"]["tools"];
assert(listed.is_array());
assert(listed.size() == expectedCount);
bool hasRunPipeline = false;
for (const auto& t : listed) {
if (t.value("name", "") == "whetstone_run_pipeline") {
hasRunPipeline = true;
auto props = t["inputSchema"]["properties"];
assert(props.contains("sourceLanguage"));
assert(props["sourceLanguage"]["type"] == "string");
}
}
assert(hasRunPipeline);
std::cout << "Test 8 PASSED: MCP tools stable; run_pipeline accepts language string\\n";
passed++;
}
std::cout << "\\nResults: " << passed << "/8\\n";
assert(passed == 8);
return 0;
}