Files
whetstone_DSL/editor/tests/step385_test.cpp
2026-02-16 12:54:39 -07:00

193 lines
6.7 KiB
C++

// Step 385: Context bundle format (12 tests)
#include <cassert>
#include <iostream>
#include <string>
#include "ContextBundle.h"
static WorkItem makeItem(const std::string& id = "w1") {
WorkItem item;
item.id = id;
item.nodeId = id + "_node";
item.nodeName = "buildThing";
item.nodeType = "Function";
item.bufferId = "main.py";
item.contextWidth = "project";
item.workerType = "llm";
item.reviewRequired = true;
item.priority = "high";
item.status = WI_READY;
item.createdAt = workItemTimestamp();
return item;
}
static WorkerContext makeContext() {
WorkerContext ctx;
ctx.nodeAst = json{{"id", "w1_node"}, {"type", "Function"}, {"name", "buildThing"}};
ctx.bufferContent = "def helper():\n return 1\n";
ctx.projectSummary = json{{"files", 4}, {"keyModules", json::array({"core", "api"})}};
ctx.annotations = {
json{{"type", "Contract"}, {"name", "precondition"}, {"value", "input non-empty"}},
json{{"type", "Risk"}, {"name", "level"}, {"value", "medium"}}
};
ctx.skeletonIntent = "Build normalized result map";
return ctx;
}
static RoutingDecision makeDecision() {
RoutingDecision d;
d.workerType = "llm";
d.contextWidth = "project";
d.contextBudgetTokens = 8000;
d.reviewRequired = true;
d.confidence = 0.7f;
d.reasoning = "Project context";
d.agentRole = "generator";
return d;
}
int main() {
int passed = 0;
// Test 1: bundle contains core fields
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
assert(!b.taskDescription.empty());
assert(!b.skeletonCode.empty());
assert(!b.contextCode.empty());
assert(b.tokenBudget == 8000);
std::cout << "Test 1 PASSED: bundle contains required fields\n";
passed++;
}
// Test 2: bundleToPrompt produces structured readable output
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
std::string prompt = bundleToPrompt(b);
assert(prompt.find("Task:") != std::string::npos);
assert(prompt.find("Constraints:") != std::string::npos);
assert(prompt.find("Output Format:") != std::string::npos);
std::cout << "Test 2 PASSED: prompt rendering structured\n";
passed++;
}
// Test 3: rejection history included in previous attempts
{
WorkItem item = makeItem();
RejectionAttempt a;
a.workerType = "slm";
a.result.generatedCode = "return tmp";
a.feedback = "missed edge case";
item.rejectionHistory.push_back(a);
auto b = buildBundle(item, makeContext(), makeDecision());
assert(b.previousAttempts.size() == 1);
assert(b.previousAttempts[0].feedback == "missed edge case");
std::cout << "Test 3 PASSED: rejection history carried into bundle\n";
passed++;
}
// Test 4: token estimate is positive and size-correlated
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
int estimate = estimateBundleTokens(b);
assert(estimate > 0);
assert(std::abs(estimate - (int)(b.toJson().dump().size() / 4)) <= 1);
std::cout << "Test 4 PASSED: token estimate reasonable\n";
passed++;
}
// Test 5: budget value preserved from routing decision
{
RoutingDecision d = makeDecision();
d.contextBudgetTokens = 1234;
auto b = buildBundle(makeItem(), makeContext(), d);
assert(b.tokenBudget == 1234);
std::cout << "Test 5 PASSED: budget respected from routing decision\n";
passed++;
}
// Test 6: annotation constraints included
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
assert(!b.constraints.empty());
bool hasContract = false;
for (const auto& c : b.constraints) {
if (c.find("Contract") != std::string::npos) hasContract = true;
}
assert(hasContract);
std::cout << "Test 6 PASSED: constraints include annotations\n";
passed++;
}
// Test 7: intent comes from worker context
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
assert(b.intent == "Build normalized result map");
std::cout << "Test 7 PASSED: intent carried from context\n";
passed++;
}
// Test 8: empty context fields handled gracefully
{
WorkItem item = makeItem();
WorkerContext ctx;
RoutingDecision d = makeDecision();
auto b = buildBundle(item, ctx, d);
std::string prompt = bundleToPrompt(b);
assert(!prompt.empty());
assert(b.constraints.size() == 1); // default "none"
std::cout << "Test 8 PASSED: empty fields handled gracefully\n";
passed++;
}
// Test 9: bundle JSON roundtrip
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
auto round = ContextBundle::fromJson(bundleToJson(b));
assert(round.taskDescription == b.taskDescription);
assert(round.tokenBudget == b.tokenBudget);
assert(round.outputFormat == b.outputFormat);
std::cout << "Test 9 PASSED: JSON roundtrip works\n";
passed++;
}
// Test 10: prompt format remains model-agnostic
{
auto b = buildBundle(makeItem(), makeContext(), makeDecision());
std::string prompt = bundleToPrompt(b);
assert(prompt.find("Claude") == std::string::npos);
assert(prompt.find("OpenAI") == std::string::npos);
std::cout << "Test 10 PASSED: prompt format model-agnostic\n";
passed++;
}
// Test 11: deterministic/template defaults to code-only output format
{
RoutingDecision d = makeDecision();
d.workerType = "template";
auto b = buildBundle(makeItem(), makeContext(), d);
assert(b.outputFormat == "code-only");
std::cout << "Test 11 PASSED: code-only format for deterministic/template\n";
passed++;
}
// Test 12: previous attempts preserve insertion order
{
WorkItem item = makeItem();
RejectionAttempt a1; a1.workerType = "slm"; a1.feedback = "first";
RejectionAttempt a2; a2.workerType = "llm"; a2.feedback = "second";
item.rejectionHistory.push_back(a1);
item.rejectionHistory.push_back(a2);
auto b = buildBundle(item, makeContext(), makeDecision());
assert(b.previousAttempts.size() == 2);
assert(b.previousAttempts[0].feedback == "first");
assert(b.previousAttempts[1].feedback == "second");
std::cout << "Test 12 PASSED: previous-attempt order preserved\n";
passed++;
}
std::cout << "\nResults: " << passed << "/12\n";
assert(passed == 12);
return 0;
}