Domain - Signal carries a SignalType (Power/GndShield/Other), auto-inferred from the name in Signal::Signal via infer_signal_type. Override with the new `set-signal-type` command. - SignalType extracted to its own header so Pin can store an `expected_signal_type` without a pins↔signals include cycle. - pin_role(connector_type, pin_name) → SignalType lookup, called from set-type to populate each Pin's expected_signal_type. The VPX 3U table is currently a stub (returns Other). - New `verify` command walks typed parts and reports pins whose connected signal's type doesn't match the expectation. - ODS importer no longer drops pins with empty signal column — they stay in the part as NC, matching the rule "a pin is either NC or connected to a signal". - persist: new S tag for non-default signal type overrides. Tests - doctest v2.4.11 via FetchContent (with CMAKE_POLICY_VERSION_MINIMUM shim, doctest's CMakeLists has a too-old floor for current CMake). - Source files moved into a static library `essim_lib` so both `essim` and `essim_tests` reuse the same compilation. main.cpp is the only file kept out of the lib. - Layer 1 (pure helpers): ToLower, LongestCommonPrefix, Tokenize, NaturalLess (numeric/case/leading-zero edge cases + total-order invariants), signal_type round-trips and infer_signal_type families, VpxTransform registry + symmetry + reference-table mapping for connector P0 row 1, IdentityTransform same-name wiring. - Layer 2 (round-trip): build a synthetic 2-module system in code, save → restore → assert modules / parts / connector_types / NC pins / signal type overrides / connections + pin_map are all preserved. - Tui::Tokenize moved to a free function in tui_helpers so tests can call it without dragging ftxui into the unit-test layer. - 27 test cases, 123 assertions, ~150 ms. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
72 lines
2.1 KiB
C++
72 lines
2.1 KiB
C++
#include <doctest/doctest.h>
|
|
|
|
#include "tui/tui_helpers.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
TEST_CASE("ToLower") {
|
|
CHECK(ToLower("ABC") == "abc");
|
|
CHECK(ToLower("aBc 123") == "abc 123");
|
|
CHECK(ToLower("") == "");
|
|
}
|
|
|
|
TEST_CASE("LongestCommonPrefix") {
|
|
CHECK(LongestCommonPrefix({}) == "");
|
|
CHECK(LongestCommonPrefix({"foo"}) == "foo");
|
|
CHECK(LongestCommonPrefix({"foo", "foobar", "foobaz"}) == "foo");
|
|
CHECK(LongestCommonPrefix({"abc", "xyz"}) == "");
|
|
CHECK(LongestCommonPrefix({"abc", "abc"}) == "abc");
|
|
}
|
|
|
|
TEST_CASE("Tokenize splits on whitespace") {
|
|
CHECK(Tokenize("").empty());
|
|
CHECK(Tokenize(" ").empty());
|
|
auto t = Tokenize("a b c");
|
|
CHECK(t == std::vector<std::string>{"a", "b", "c"});
|
|
}
|
|
|
|
TEST_CASE("Tokenize preserves quoted spaces") {
|
|
auto t = Tokenize("load \"my mod\" /tmp/x mentor");
|
|
CHECK(t == std::vector<std::string>{"load", "my mod", "/tmp/x", "mentor"});
|
|
}
|
|
|
|
TEST_CASE("Tokenize handles tabs as separators") {
|
|
auto t = Tokenize("a\tb\tc");
|
|
CHECK(t == std::vector<std::string>{"a", "b", "c"});
|
|
}
|
|
|
|
TEST_CASE("NaturalLess: numeric runs sort numerically") {
|
|
CHECK(NaturalLess("J1", "J2"));
|
|
CHECK(NaturalLess("J2", "J10"));
|
|
CHECK(NaturalLess("J9", "J10"));
|
|
CHECK(!NaturalLess("J10", "J2"));
|
|
CHECK(!NaturalLess("J10", "J10"));
|
|
}
|
|
|
|
TEST_CASE("NaturalLess: case insensitive for letters") {
|
|
CHECK(NaturalLess("abc", "ABD"));
|
|
CHECK(!NaturalLess("ABD", "abc"));
|
|
CHECK(!NaturalLess("abc", "ABC"));
|
|
}
|
|
|
|
TEST_CASE("NaturalLess: leading zeros tie-break") {
|
|
CHECK(NaturalLess("J01", "J1"));
|
|
CHECK(!NaturalLess("J1", "J01"));
|
|
}
|
|
|
|
TEST_CASE("NaturalLess: produces a sorted order over a connector-style list") {
|
|
std::vector<std::string> v = {"J22", "J1", "J10", "J2", "P100", "P21", "P2"};
|
|
std::sort(v.begin(), v.end(), NaturalLess);
|
|
CHECK(v == std::vector<std::string>{"J1", "J2", "J10", "J22", "P2", "P21", "P100"});
|
|
}
|
|
|
|
TEST_CASE("NaturalLess: total order axioms") {
|
|
// !(a < a)
|
|
CHECK(!NaturalLess("foo", "foo"));
|
|
CHECK(!NaturalLess("J10", "J10"));
|
|
// a < b ⇒ !(b < a)
|
|
CHECK(NaturalLess("J1", "J2"));
|
|
CHECK(!NaturalLess("J2", "J1"));
|
|
}
|