#include #include "fgc/TestReport.h" using namespace fgc; namespace { TestReport makeReport() { TestReport r; r.ts_ms = 1719312345678LL; r.profile = "standard"; r.host = "towerpc"; r.fw = "fgc-1.2.3"; TestSection s; s.id = "homing"; s.title = "homing reproducibility"; s.ran = true; s.duration_ms = 1234; TestMetric m1; m1.name = "yaw_lim_neg_spread"; m1.value = 12; m1.unit = "counts"; m1.has_threshold = true; m1.threshold = 80; m1.pass = true; s.metrics.push_back(m1); TestMetric m2; m2.name = "home_ms_mean"; m2.value = 8200.5; m2.unit = "ms"; m2.pass = true; s.metrics.push_back(m2); s.pass = true; r.sections.push_back(s); r.all_pass = true; return r; } } // namespace TEST_CASE("formatTestReport round-trips through parseTestReport") { TestReport r = makeReport(); std::string text = formatTestReport(r); TestReport back = parseTestReport(text); CHECK(back.ts_ms == r.ts_ms); CHECK(back.profile == "standard"); CHECK(back.host == "towerpc"); CHECK(back.fw == "fgc-1.2.3"); CHECK(back.all_pass == true); REQUIRE(back.sections.size() == 1); CHECK(back.sections[0].id == "homing"); const TestMetric* m = back.find("homing", "yaw_lim_neg_spread"); REQUIRE(m != nullptr); CHECK(m->value == doctest::Approx(12)); CHECK(m->unit == "counts"); const TestMetric* m2 = back.find("homing", "home_ms_mean"); REQUIRE(m2 != nullptr); CHECK(m2->value == doctest::Approx(8200.5)); } TEST_CASE("applyComparison computes drift and flags regressions") { TestReport baseline = makeReport(); // yaw_lim_neg_spread = 12 TestReport prev = makeReport(); prev.sections[0].metrics[0].value = 13; TestReport cur = makeReport(); cur.sections[0].metrics[0].value = 18; // +50% vs baseline (12) applyComparison(cur, &baseline, &prev, /*warn_pct=*/15, /*gates=*/true); const TestMetric* m = cur.find("homing", "yaw_lim_neg_spread"); REQUIRE(m != nullptr); CHECK(m->has_baseline); CHECK(m->baseline == doctest::Approx(12)); CHECK(m->has_prev); CHECK(m->prev == doctest::Approx(13)); CHECK(m->drift_pct == doctest::Approx(50.0)); CHECK(m->drift_flag == true); CHECK(m->pass == false); // drift gate trips the metric CHECK(cur.sections[0].pass == false); CHECK(cur.all_pass == false); } TEST_CASE("applyComparison: improvement (lower is better) does not flag") { TestReport baseline = makeReport(); // 12 TestReport cur = makeReport(); cur.sections[0].metrics[0].value = 6; // -50%, an improvement applyComparison(cur, &baseline, nullptr, 15, true); const TestMetric* m = cur.find("homing", "yaw_lim_neg_spread"); REQUIRE(m != nullptr); CHECK(m->drift_flag == false); CHECK(m->pass == true); }