test(viz): cubrir helpers de dod_evidence_panel (issue 0117)

7 test cases via Catch2: count_status (3 escenarios incl. unknown
status y missing_required), find_evidence (2 lookup positivo/negativo)
y status_icon_id/status_color_token (mapeo de 4+2 keys). Linkamos solo
helpers — sin ImGui ni vendor extra.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 18:30:30 +02:00
parent c1e88af5c7
commit a4077913ef
2 changed files with 126 additions and 0 deletions
+7
View File
@@ -297,3 +297,10 @@ target_compile_definitions(test_visual PRIVATE
"FN_TEST_REPO_ROOT=\"${CMAKE_SOURCE_DIR}/..\"")
# Asegura que primitives_gallery existe antes de correr el test.
add_dependencies(test_visual primitives_gallery)
# --- Issue 0117 — dod_evidence_panel helpers: logica pura para panel DoD ----
# Solo helpers (count_status, find_evidence, status_icon_id, status_color_token).
# El render con ImGui (dod_evidence_panel.cpp) NO se compila aqui: requiere
# imgui + tokens + icons_tabler — cubierto en builds de apps consumidoras.
add_fn_test(test_dod_evidence_panel test_dod_evidence_panel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../functions/viz/dod_evidence_panel_helpers.cpp)
+119
View File
@@ -0,0 +1,119 @@
// 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);
}