Files
essim/tests/test_vpx_transform.cpp
François 516149cdae Rename set-type to set-connector-type; help-panel & types-glossary polish.
- Command renamed from `set-type` to `set-connector-type` for
  clarity (the previous name was ambiguous — "type" of what?). No
  legacy alias kept; old scripts that still used `set-type` must be
  migrated. `test/system.essim` and all user/design docs updated.
- Help panel (RenderHelpPanel) now wraps in borderRounded with a
  centred bold title, so it is visually distinct from the main
  content on every screen. Width bumped from 30 to 32 to include
  the border.
- Analyze screen's Types tab gains a sibling "type glossary" panel
  (also borderRounded, only visible when the Types tab is focused)
  that explains Power / Suspect Power / Hard floor / Gnd in plain
  language using `paragraph()` for clean word-wrap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 20:41:35 +02:00

125 lines
4.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <doctest/doctest.h>
#include "system/modules.hpp"
#include "system/parts.hpp"
#include "system/pins.hpp"
#include "system/signals.hpp"
#include "system/system.hpp"
#include "system/transform.hpp"
#include "system/transform_vpx.hpp"
#include <map>
#include <memory>
#include <set>
#include <string>
namespace {
// Build a Part with `pin_names` pins, attached to a fresh module so prnt
// chains exist (set-connector-type's validation depends on pins; transforms don't).
Part *make_part(Module *mod, const std::string &part_name,
const std::vector<std::string> &pin_names) {
Part *p = new Part(part_name);
mod->add(p); // sets p->prnt = mod
for (const auto &n : pin_names) {
Pin *pin = new Pin(n);
p->add(pin);
}
return p;
}
// VPX 3U bkp pinout for connector P0: 9 cols A-I × 1 row of "1".
std::vector<std::string> bkp_p0_pins_row1() {
std::vector<std::string> out;
for (char c = 'A'; c <= 'I'; ++c) out.push_back(std::string(1, c) + "1");
return out;
}
std::vector<std::string> payload_p0_pins_row1() {
std::vector<std::string> out;
for (char c = 'A'; c <= 'G'; ++c) out.push_back(std::string(1, c) + "1");
return out;
}
} // namespace
TEST_CASE("VPX transform registered and looked up by name") {
auto &reg = TransformRegistry::get();
Transform *t = reg.lookup("vpx-3u-bkp-p0", "vpx-3u-payload-p0");
REQUIRE(t != reg.identity());
CHECK(t->name == "vpx-3u-p0");
}
TEST_CASE("VPX transform lookup is symmetric (both pair orders work)") {
auto &reg = TransformRegistry::get();
Transform *forward = reg.lookup("vpx-3u-bkp-p1", "vpx-3u-payload-p1");
Transform *backward = reg.lookup("vpx-3u-payload-p1", "vpx-3u-bkp-p1");
REQUIRE(forward != reg.identity());
CHECK(forward == backward);
}
TEST_CASE("VPX transform refuses non-matching pairs (returns identity)") {
auto &reg = TransformRegistry::get();
CHECK(reg.lookup("vpx-3u-bkp-p0", "vpx-3u-payload-p1") == reg.identity());
CHECK(reg.lookup("vpx-3u-bkp-p0", "vpx-3u-bkp-p0") == reg.identity());
CHECK(reg.lookup("foo", "bar") == reg.identity());
}
TEST_CASE("VPX P0 row 1 mapping matches the reference table") {
// bkp_to_payload PCORR[0] row 1: A→A, B→C, C→C, D→C, E→D, F→E, G→E, H→F, I→G.
Module mod("M");
Part *bkp = make_part(&mod, "BKP", bkp_p0_pins_row1());
Part *pl = make_part(&mod, "PL", payload_p0_pins_row1());
bkp->connector_type = "vpx-3u-bkp-p0";
pl->connector_type = "vpx-3u-payload-p0";
auto &reg = TransformRegistry::get();
Transform *t = reg.lookup(bkp->connector_type, pl->connector_type);
REQUIRE(t != reg.identity());
auto pin_map = t->apply(bkp, pl);
// Build (bkp_pin_name → payload_pin_name) map for easy assertion.
std::map<std::string, std::string> got;
for (auto &wp : pin_map) got[wp.first->name] = wp.second->name;
std::map<std::string, std::string> expected = {
{"A1","A1"}, {"B1","C1"}, {"C1","C1"}, {"D1","C1"},
{"E1","D1"}, {"F1","E1"}, {"G1","E1"}, {"H1","F1"},
{"I1","G1"},
};
CHECK(got == expected);
}
TEST_CASE("VPX transform skips pins missing on the target side") {
// bkp has all 9 cols; payload has only A1, B1 → most bkp pins should drop.
Module mod("M");
Part *bkp = make_part(&mod, "BKP", bkp_p0_pins_row1());
Part *pl = make_part(&mod, "PL", {"A1", "B1"});
bkp->connector_type = "vpx-3u-bkp-p0";
pl->connector_type = "vpx-3u-payload-p0";
auto &reg = TransformRegistry::get();
Transform *t = reg.lookup(bkp->connector_type, pl->connector_type);
auto pin_map = t->apply(bkp, pl);
std::set<std::string> bkp_used;
for (auto &wp : pin_map) bkp_used.insert(wp.first->name);
// A1 maps to A1 (present), B1→C1 (absent), C1→C1 (absent), D1→C1 (absent),
// E1→D1 (absent), …, the only target-pin that exists for the row 1 mapping
// besides A1 is none — so only A1 keeps its wire (B1 in payload isn't
// a target of any bkp col on row 1).
CHECK(bkp_used == std::set<std::string>{"A1"});
}
TEST_CASE("Identity fallback wires same-named pins") {
Module mod("M");
Part *a = make_part(&mod, "A", {"X1", "X2", "Y1"});
Part *b = make_part(&mod, "B", {"X1", "X2", "Z1"});
auto &reg = TransformRegistry::get();
auto pin_map = reg.identity()->apply(a, b);
std::set<std::string> wired;
for (auto &wp : pin_map) wired.insert(wp.first->name);
CHECK(wired == std::set<std::string>{"X1", "X2"});
}