// Tests para la logica pura de dod_evidence_panel (issue 0117). // // El render real con ImGui no se testea aqui (requiere context). Cubrimos: // - count_status: tally por status + missing_required. // - find_evidence: lookup por item_id. // - status_icon_id: mapeo a icon key. // - status_color_token: mapeo a token semantico. #define CATCH_CONFIG_MAIN #include "catch_amalgamated.hpp" #include "viz/dod_evidence_panel_helpers.h" using namespace fn_viz; using namespace fn_viz::dod_panel; namespace { DodItem mk_item(std::string id, std::string kind, std::string status, bool required = true) { DodItem it; it.id = std::move(id); it.kind = std::move(kind); it.status = std::move(status); it.required = required; it.expected = "expected_" + it.id; return it; } DodEvidence mk_evidence(std::string item_id, std::string kind = "screenshot") { DodEvidence ev; ev.item_id = std::move(item_id); ev.kind = std::move(kind); ev.payload_path = "/tmp/" + ev.item_id + ".png"; return ev; } } // namespace TEST_CASE("count_status: total = items.size", "[dod_panel]") { DodPanelState s; s.items.push_back(mk_item("a", "screenshot", "pending")); s.items.push_back(mk_item("b", "log", "done")); s.items.push_back(mk_item("c", "url", "validated")); s.items.push_back(mk_item("d", "cmd", "failed")); auto c = count_status(s); REQUIRE(c.total == 4); REQUIRE(c.pending == 1); REQUIRE(c.done == 1); REQUIRE(c.validated == 1); REQUIRE(c.failed == 1); } TEST_CASE("count_status: unknown status counts as pending", "[dod_panel]") { DodPanelState s; s.items.push_back(mk_item("a", "log", "weird")); s.items.push_back(mk_item("b", "log", "pending")); auto c = count_status(s); REQUIRE(c.total == 2); REQUIRE(c.pending == 2); } TEST_CASE("count_status: missing_required only when required+no evidence+unresolved", "[dod_panel]") { DodPanelState s; // required + no evidence + pending -> missing s.items.push_back(mk_item("missing_one", "screenshot", "pending", /*required*/ true)); // required + no evidence + done -> resolved, no missing s.items.push_back(mk_item("done_no_ev", "log", "done", true)); // required + evidence + pending -> no missing s.items.push_back(mk_item("has_ev", "url", "pending", true)); s.evidences.push_back(mk_evidence("has_ev", "url")); // optional + no evidence + pending -> no missing s.items.push_back(mk_item("optional", "log", "pending", /*required*/ false)); auto c = count_status(s); REQUIRE(c.missing_required == 1); } TEST_CASE("find_evidence: returns matching evidence", "[dod_panel]") { DodPanelState s; s.items.push_back(mk_item("a", "log", "done")); s.evidences.push_back(mk_evidence("a", "log")); s.evidences.push_back(mk_evidence("b", "screenshot")); const DodEvidence* a = find_evidence(s, "a"); REQUIRE(a != nullptr); REQUIRE(a->item_id == "a"); REQUIRE(a->kind == "log"); const DodEvidence* b = find_evidence(s, "b"); REQUIRE(b != nullptr); REQUIRE(b->kind == "screenshot"); REQUIRE(find_evidence(s, "missing") == nullptr); } TEST_CASE("find_evidence: empty state returns nullptr", "[dod_panel]") { DodPanelState s; REQUIRE(find_evidence(s, "anything") == nullptr); } TEST_CASE("status_icon_id: mapping per status", "[dod_panel]") { REQUIRE(status_icon_id("pending") == "circle-dashed"); REQUIRE(status_icon_id("done") == "circle-dot"); REQUIRE(status_icon_id("validated") == "circle-check"); REQUIRE(status_icon_id("failed") == "circle-x"); REQUIRE(status_icon_id("") == "circle-dashed"); REQUIRE(status_icon_id("garbage") == "circle-dashed"); } TEST_CASE("status_color_token: mapping per status", "[dod_panel]") { REQUIRE(status_color_token("pending") == 0); REQUIRE(status_color_token("done") == 1); REQUIRE(status_color_token("validated") == 2); REQUIRE(status_color_token("failed") == 3); REQUIRE(status_color_token("") == 0); REQUIRE(status_color_token("garbage") == 0); }