70 lines
5.6 KiB
C++
70 lines
5.6 KiB
C++
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||
|
|
|
||
|
|
// Normalising a pass: the synthesized finding, prefix resolution, discharge,
|
||
|
|
// contests, the vocabulary.
|
||
|
|
|
||
|
|
import std;
|
||
|
|
import Crafter.Review;
|
||
|
|
using namespace Crafter::Review;
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
std::int32_t Failures = 0;
|
||
|
|
|
||
|
|
void Check(std::string_view name, bool cond, std::string_view detail = {}) {
|
||
|
|
std::println("{}{}{}", cond ? " ok " : " FAIL ", name, !cond && !detail.empty() ? std::format(" ({})", detail) : std::string());
|
||
|
|
if (!cond) ++Failures;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool AnyKind(const Json& violations, std::string_view part) {
|
||
|
|
return std::ranges::any_of(violations, [&](const Json& v) { return v.at("kind").get<std::string>().contains(part); });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
std::println("normalize: synthesized finding, prefix resolution, discharge, contests, vocabulary");
|
||
|
|
const Json inv = Json::array({{{"id", "p1:x.py#1"}}, {{"id", "p1:src/components/a.tsx#1"}}, {{"id", "p1:src/components/a.tsx#2"}}});
|
||
|
|
std::vector<std::string> ids;
|
||
|
|
for (const Json& u : inv) ids.push_back(u.at("id").get<std::string>());
|
||
|
|
const std::string lens = "repo-bug-prover.md";
|
||
|
|
const Json first = Json::array({inv[0]});
|
||
|
|
auto run = [&](Json v, const std::vector<Json>& inForce, std::string_view lensFile = "repo-bug-prover.md") {
|
||
|
|
return Normalize::NormalizeOutput(v, inForce, lensFile, "h", first, ids);
|
||
|
|
};
|
||
|
|
const Json n = run({{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "p1:x.py#1"}, {"verdict", "defect"}, {"basis", "x"}}}}}, {});
|
||
|
|
Check("defect without finding -> synthesized undischarged finding, FIX FIRST", n.at("verdict") == "FIX FIRST" && !n.at("findings").empty()
|
||
|
|
&& Dyn::Truthy(Dyn::Get(n.at("findings").at(0), "synthesized")) && n.at("undischarged") == 1);
|
||
|
|
Check("declared SEND-READY over it -> contract violation", AnyKind(n.at("contractViolations"), "failed closed"));
|
||
|
|
Check("prefix: a unique prefix resolves, an ambiguous one stays", Normalize::ResolveId("p1:x", ids) == ids[0]
|
||
|
|
&& Normalize::ResolveId("p1:src/components/a.tsx#", ids) == "p1:src/components/a.tsx#");
|
||
|
|
const Json n2 = run({{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "p1:x"}, {"verdict", "clear"}, {"basis", "b"}}}}}, {});
|
||
|
|
Check("abbreviated coverage id resolved -> no MISSING", n2.at("coverageMissing").empty() && n2.at("coverage").at(0).at("item") == ids[0]);
|
||
|
|
const Json n3 = run({{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", Json::array()}}, {});
|
||
|
|
Check("no coverage entry -> coverageMissing (NOT RETURNED)", n3.at("coverageMissing") == Json::array({ids[0]}) && !n3.at("contractViolations").empty());
|
||
|
|
const std::vector<Json> d = {{{"id", "w1"}, {"kind", "waiver-owner"}, {"hash", "h"}}};
|
||
|
|
auto finding = [&](const Json& extra) {
|
||
|
|
Json f = {{"finding", "f"}, {"evidence", "e"}, {"proposedAction", "p"}, {"items", {ids[0]}}};
|
||
|
|
f.update(extra);
|
||
|
|
return f;
|
||
|
|
};
|
||
|
|
const Json n4 = run({{"verdict", "SEND-READY"}, {"findings", {finding({{"dischargedBy", "w1"}})}}, {"notes", Json::array()},
|
||
|
|
{"coverage", {{{"item", ids[0]}, {"verdict", "clear"}, {"basis", "discharged by w1"}}}}}, d);
|
||
|
|
Check("dischargedBy an in-force id -> discharged, SEND-READY", n4.at("verdict") == "SEND-READY" && n4.at("findings").at(0).at("discharged") == true);
|
||
|
|
const Json n5 = run({{"verdict", "SEND-READY"}, {"findings", {finding({{"dischargedBy", "nope"}})}}, {"notes", Json::array()},
|
||
|
|
{"coverage", {{{"item", ids[0]}, {"verdict", "clear"}, {"basis", "b"}}}}}, d);
|
||
|
|
Check("dischargedBy an unknown id -> undischarged, FIX FIRST", n5.at("verdict") == "FIX FIRST" && n5.at("findings").at(0).at("discharged") == false);
|
||
|
|
const Json n6 = run({{"verdict", "FIX FIRST"}, {"findings", {finding({{"contests", {{"id", "w1"}, {"why", "w"}}}})}}, {"notes", Json::array()},
|
||
|
|
{"coverage", {{{"item", ids[0]}, {"verdict", "defect"}, {"basis", "b"}}}}}, d);
|
||
|
|
Check("contest of an unsettled entry blocks", n6.at("verdict") == "FIX FIRST" && !n6.at("contests").empty() && n6.at("contests").at(0).at("outcome").get<std::string>().contains("CONTESTED"));
|
||
|
|
const std::vector<Json> d2 = {{{"id", "w1"}, {"kind", "waiver-owner"}, {"hash", "h"}, {"reaffirmed", {{{"hash", "h"}}}}}};
|
||
|
|
const Json n7 = run({{"verdict", "FIX FIRST"}, {"findings", {finding({{"contests", {{"id", "w1"}, {"why", "w"}}}})}}, {"notes", Json::array()},
|
||
|
|
{"coverage", {{{"item", ids[0]}, {"verdict", "clear"}, {"basis", "b"}}}}}, d2);
|
||
|
|
Check("contest of a reaffirmed entry is recorded, finding discharged (silent veto logged)", n7.at("verdict") == "SEND-READY" && n7.at("findings").at(0).at("discharged") == true
|
||
|
|
&& AnyKind(n7.at("contractViolations"), "silent veto"));
|
||
|
|
const Json n8 = run({{"verdict", "SEND-READY"}, {"findings", Json::array()},
|
||
|
|
{"notes", {{{"kind", "unverified"}, {"note", "x"}, {"evidence", "e"}, {"action", "a"}, {"items", {ids[0]}}}}},
|
||
|
|
{"coverage", {{{"item", ids[0]}, {"verdict", "n/a"}, {"basis", "unverified: login failed"}}}}}, {}, Plan::FunctionalLens);
|
||
|
|
Check("functional: n/a with an unverified note is a pass of the contract (not clear, not a hole in the pass)", n8.at("verdict") == "SEND-READY" && n8.at("coverageMissing").empty()
|
||
|
|
&& std::ranges::contains(Schema::NoteKinds, std::string_view("unverified")) && !std::ranges::contains(Schema::NoteKinds, std::string_view("disposition-review")));
|
||
|
|
return Failures ? 1 : 0;
|
||
|
|
}
|