Files
whetstone_DSL/editor/tests/step1976_test.cpp
Bill 03dc4dc208 Sprint 289: Integration into generate_taskitems (steps 1973-1977)
EnrichedExecutionContract, TaskitemLibraryAnnotator, AnnotatedTaskitemValidator,
DispatchJustificationReport, Sprint289IntegrationSummary. 25/25 tests passing.
Full pipeline: spec -> classifier -> selector -> advisor -> enriched contracts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 10:21:06 -07:00

118 lines
4.1 KiB
C++

// Step 1976: DispatchJustificationReport
//
// t1: add entries, finalize computes averageScore correctly
// t2: serialize returns valid JSON string (parseable by nlohmann)
// t3: JSON contains all required top-level fields
// t4: unenriched entry (empty selectedLibrary) not counted in enrichedCount
// t5: projectId present in JSON and entries array present
#include "DispatchJustificationReport.h"
#include <iostream>
namespace ws = whetstone;
static int p = 0, f = 0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c, m) if (!(c)) { F(m); return; }
static ws::JustificationEntry makeEntry(const std::string& task,
const std::string& lib,
const std::string& domain,
float score) {
ws::JustificationEntry e;
e.taskDescription = task;
e.selectedLibrary = lib;
e.operationDomain = domain;
e.capabilityScore = score;
e.justification = lib + " scores " + std::to_string(score);
return e;
}
void t1() {
T(finalize_computes_average_score);
ws::DispatchJustificationReport r;
r.projectId = "test-project";
r.add(makeEntry("task A", "nlohmann_json", "serialization.json", 0.92f));
r.add(makeEntry("task B", "cublas", "compute.matrix", 0.99f));
r.finalize();
C(r.totalTasks == 2, "2 total tasks");
C(r.enrichedCount == 2, "2 enriched");
// averageScore = (0.92 + 0.99) / 2 = 0.955
C(r.averageScore > 0.9f && r.averageScore < 1.0f, "averageScore in (0.9, 1.0)");
P();
}
void t2() {
T(serialize_returns_valid_json);
ws::DispatchJustificationReport r;
r.projectId = "parse-test";
r.add(makeEntry("task X", "thrust", "compute.parallel", 0.97f));
r.finalize();
std::string json = r.serialize();
C(!json.empty(), "JSON non-empty");
// Must be parseable
bool ok = false;
try {
auto parsed = nlohmann::json::parse(json);
ok = true;
} catch (...) {}
C(ok, "JSON parseable");
P();
}
void t3() {
T(json_has_all_required_fields);
ws::DispatchJustificationReport r;
r.projectId = "fields-test";
r.add(makeEntry("task Y", "protobuf", "serialization.binary", 0.95f));
r.finalize();
auto j = nlohmann::json::parse(r.serialize());
C(j.contains("projectId"), "projectId");
C(j.contains("totalTasks"), "totalTasks");
C(j.contains("enrichedCount"), "enrichedCount");
C(j.contains("averageScore"), "averageScore");
C(j.contains("entries"), "entries");
C(j["entries"].is_array(), "entries is array");
P();
}
void t4() {
T(unenriched_entry_not_counted_in_enriched_count);
ws::DispatchJustificationReport r;
r.projectId = "mixed";
r.add(makeEntry("enriched task", "thrust", "compute.parallel", 0.97f));
// Unenriched entry: empty selectedLibrary
ws::JustificationEntry ue;
ue.taskDescription = "unenriched task";
r.add(ue);
r.finalize();
C(r.totalTasks == 2, "2 total");
C(r.enrichedCount == 1, "1 enriched");
// averageScore should be based on enriched entry only
C(r.averageScore > 0.9f, "averageScore based on enriched only");
P();
}
void t5() {
T(project_id_in_json_and_entries_array);
ws::DispatchJustificationReport r;
r.projectId = "my-special-project";
r.add(makeEntry("a", "cublas", "compute.matrix", 0.99f));
r.add(makeEntry("b", "nlohmann_json", "serialization.json", 0.92f));
r.finalize();
auto j = nlohmann::json::parse(r.serialize());
C(j["projectId"] == "my-special-project", "projectId value");
C(j["entries"].size() == 2, "2 entries");
C(j["entries"][0].contains("taskDescription"), "entry has taskDescription");
C(j["entries"][0].contains("avoidedLibraries"), "entry has avoidedLibraries");
P();
}
int main() {
std::cout << "Step 1976: DispatchJustificationReport\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p + f) << " passed\n";
return f > 0 ? 1 : 0;
}