#include #include "fgc/DiagParser.h" using namespace fgc; namespace { // A DIAG stream as captured on the wire: DG lines interleaved with an ST line. const char* kDiag = "DG BEGIN Y\n" "ST Y:A,5,5,80084000,0,8,8,S P:A,5,5,80084000,0,8,8,S\n" "DG Y S12500 FWD ERR_PEAK 234 ERR_RMS 45 ERR_STILL 89 CS_MIN 10 CS_MAX 20 " "SG_MIN 456 PWM_AVG 128 FLAGS 0x00000000 PASS\n" "DG Y S25000 REV ERR_PEAK 300 ERR_RMS 50 ERR_STILL 100 CS_MIN 11 CS_MAX 21 " "SG_MIN 400 PWM_AVG 130 FLAGS 0x00000000 PASS\n" "DG Y RESULT PASS\n" "DG BEGIN P\n" "DG P S12500 FWD ERR_PEAK -1 ERR_RMS -1 ERR_STILL -1 CS_MIN 12 CS_MAX 22 " "SG_MIN 0 PWM_AVG 64 FLAGS 0x00000020 FAIL\n" "DG P RESULT FAIL\n" "DG DONE\n"; } // namespace TEST_CASE("parseDiag decodes axes, tests and results") { DiagResult d = parseDiag(kDiag); REQUIRE(d.valid); CHECK(d.done); REQUIRE(d.axes.size() == 2); const DiagAxis& y = d.axes[0]; CHECK(y.axis == 'Y'); CHECK(y.has_result); CHECK(y.pass); REQUIRE(y.tests.size() == 2); CHECK(y.tests[0].speed == 12500); CHECK(y.tests[0].fwd); CHECK(y.tests[0].err_peak == 234); CHECK(y.tests[0].err_still == 89); CHECK(y.tests[0].cs_min == 10); CHECK(y.tests[0].cs_max == 20); CHECK(y.tests[0].sg_min == 456); CHECK(y.tests[0].pass); CHECK_FALSE(y.tests[1].fwd); // REV const DiagAxis& p = d.axes[1]; CHECK(p.axis == 'P'); CHECK_FALSE(p.pass); // RESULT FAIL REQUIRE(p.tests.size() == 1); CHECK(p.tests[0].err_peak == -1); // no encoder CHECK(p.tests[0].flags == 0x20u); CHECK_FALSE(p.tests[0].pass); } TEST_CASE("DiagResult::allPass requires every axis result to pass") { CHECK_FALSE(parseDiag(kDiag).allPass()); // P failed DiagResult ok = parseDiag( "DG BEGIN Y\nDG Y RESULT PASS\nDG BEGIN P\nDG P RESULT PASS\nDG DONE\n"); CHECK(ok.allPass()); } TEST_CASE("parseDiag handles empty/garbage and incomplete streams") { CHECK_FALSE(parseDiag("").valid); CHECK_FALSE(parseDiag("ST Y:A,1,1,0,0,0,0,S\nnothing\n").valid); DiagResult inc = parseDiag("DG BEGIN Y\nDG Y RESULT PASS\n"); // no DG DONE CHECK(inc.valid); CHECK_FALSE(inc.done); } TEST_CASE("formatDiag renders a summary") { auto bad = formatDiag(DiagResult{}); REQUIRE(bad.size() == 1); CHECK(bad[0].find("no diagnostic") != std::string::npos); auto good = formatDiag(parseDiag(kDiag)); std::string joined; for (const auto& l : good) joined += l + "\n"; CHECK(joined.find("[Y]") != std::string::npos); CHECK(joined.find("[P]") != std::string::npos); CHECK(joined.find("overall: FAIL") != std::string::npos); }