Files
essim/tests/test_verify.cpp
François 25939998ab De-dup verify passes: drive analyze screen + dashboard from app::verify.
The analyze Issues pane and the dashboard Health rows each recomputed the
same verify passes inline (pin-role mismatches, Power/Gnd net-mix, NC orphan
rollup, model-driven checks) — the third and second copies of what the verify
command also did. Route both screens through app::verify(System*) instead, so
the passes live in exactly one place.

Enrich VerifyReport with a per-pin OrphanPin detail list (module/part/pin +
dropped flag) so the dashboard can still nest its dropped-singleton breakdown
under the NC health line without re-walking modules/parts/pins. Output is
unchanged in both screens (same label formats, same numbers).

Prune the now-dead includes (nets/bsdl_check/connect/parts/pins as applicable,
<unordered_set>) from both screens. Extend tests/test_verify.cpp to cover the
new orphans detail.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:04:31 +02:00

96 lines
3.4 KiB
C++

#include <doctest/doctest.h>
#include "core/app/verify.hpp"
#include "core/domain/connect.hpp"
#include "core/domain/modules.hpp"
#include "core/domain/parts.hpp"
#include "core/domain/pins.hpp"
#include "core/domain/signals.hpp"
#include "core/domain/system.hpp"
// app::verify is pure core: it takes a System* and returns a VerifyReport of
// structured findings, with no Print/dialog/FTXUI. These tests build small
// systems by hand and assert the report — no UI involved.
TEST_CASE("verify on a null or empty system reports nothing") {
app::VerifyReport none = app::verify(nullptr);
CHECK(none.typed_pins == 0);
CHECK(none.total_nets == 0);
CHECK(none.role_mismatches.empty());
System sys;
app::VerifyReport r = app::verify(&sys);
CHECK(r.typed_pins == 0);
CHECK(r.total_nets == 0);
CHECK(r.bridged_nets == 0);
CHECK(r.net_inconsistencies.empty());
CHECK(r.orphan_total() == 0);
CHECK(r.model_total() == 0);
}
TEST_CASE("verify flags a bridged net that mixes Power and GndShield") {
// Two cards, one wired pin pair: A.NETA (Power) <-> B.NETB (GndShield).
System sys;
Module *a = sys.modules()->merge("A");
Module *b = sys.modules()->merge("B");
Part *ja = new Part("J1"); a->add(ja);
Part *jb = new Part("P1"); b->add(jb);
Pin *pa = new Pin("1"); ja->add(pa);
Pin *pb = new Pin("1"); jb->add(pb);
Signal *sa = a->signals->merge("NETA"); sa->type = SignalType::Power;
Signal *sb = b->signals->merge("NETB"); sb->type = SignalType::GndShield;
sa->add(pa); pa->connect(sa);
sb->add(pb); pb->connect(sb);
Connection *c = new Connection("A.J1<->B.P1", a, ja, b, jb);
c->transform_name = "identity";
c->pin_map.emplace_back(pa, pb);
sys.connections()->add(c);
app::VerifyReport r = app::verify(&sys);
CHECK(r.total_nets == 1);
CHECK(r.bridged_nets == 1);
REQUIRE(r.net_inconsistencies.size() == 1);
CHECK(r.net_inconsistencies[0].members.size() == 2);
// Both endpoints are present with their declared types.
bool seen_power = false, seen_gnd = false;
for (const auto &m : r.net_inconsistencies[0].members) {
if (m.type == SignalType::Power) seen_power = true;
if (m.type == SignalType::GndShield) seen_gnd = true;
}
CHECK(seen_power);
CHECK(seen_gnd);
}
TEST_CASE("verify counts orphan pins by their import origin") {
System sys;
Module *m = sys.modules()->merge("M");
Part *p = new Part("J1"); m->add(p);
Pin *imp = new Pin("1"); imp->nc_origin = NcOrigin::ImportedUnconnected; p->add(imp);
Pin *drp = new Pin("2"); drp->nc_origin = NcOrigin::DroppedSingleton; p->add(drp);
Pin *wired = new Pin("3"); p->add(wired);
Signal *s = m->signals->merge("NET"); s->add(wired); wired->connect(s);
app::VerifyReport r = app::verify(&sys);
CHECK(r.orphan_imported == 1);
CHECK(r.orphan_dropped == 1);
CHECK(r.orphan_total() == 2);
// Per-pin detail carries the path and origin (the dashboard lists the
// dropped ones under the NC health row).
REQUIRE(r.orphans.size() == 2);
int n_dropped = 0;
bool dropped_path_ok = false;
for (const auto &o : r.orphans) {
if (o.dropped) {
++n_dropped;
if (o.module == "M" && o.part == "J1" && o.pin == "2")
dropped_path_ok = true;
}
}
CHECK(n_dropped == 1);
CHECK(dropped_path_ok);
}