#include #include "system/modules.hpp" #include "system/parts.hpp" #include "system/persist.hpp" #include "system/pins.hpp" #include "system/signals.hpp" #include "system/system.hpp" #include #include #include TEST_CASE("nc_origin_tag round-trips with from_tag for tagged variants") { NcOrigin o; REQUIRE(nc_origin_from_tag("U", o)); CHECK(o == NcOrigin::ImportedUnconnected); REQUIRE(nc_origin_from_tag("D", o)); CHECK(o == NcOrigin::DroppedSingleton); CHECK(std::string(nc_origin_tag(NcOrigin::ImportedUnconnected)) == "U"); CHECK(std::string(nc_origin_tag(NcOrigin::DroppedSingleton)) == "D"); CHECK(std::string(nc_origin_tag(NcOrigin::None)) == ""); } TEST_CASE("nc_origin_from_tag rejects unknown / empty tags") { NcOrigin o = NcOrigin::None; CHECK(!nc_origin_from_tag("", o)); CHECK(!nc_origin_from_tag("X", o)); CHECK(!nc_origin_from_tag("Unknown", o)); } TEST_CASE("drop_singleton_signals detaches size-1 signals and tags pins") { Module mod("M"); Part *prt = new Part("U1"); mod.add(prt); auto add_pin = [&](const std::string &pin_name, const std::string &sig) { Pin *p = new Pin(pin_name); prt->add(p); Signal *s = mod.signals->merge(sig); s->add(p); p->connect(s); return p; }; // Two-pin signal: should survive. Pin *pa = add_pin("A1", "BUS_X"); Pin *pb = add_pin("A2", "BUS_X"); // Singleton: should be dropped, pin tagged DroppedSingleton. Pin *po = add_pin("A3", "ORPHAN"); REQUIRE(mod.signals->size() == 2); int dropped = drop_singleton_signals(mod.signals); CHECK(dropped == 1); CHECK(mod.signals->size() == 1); // BUS_X kept CHECK(mod.signals->exists("BUS_X")); CHECK(!mod.signals->exists("ORPHAN")); CHECK(pa->signal() != nullptr); // unchanged CHECK(pb->signal() != nullptr); CHECK(po->signal() == nullptr); // detached CHECK(po->nc_origin == NcOrigin::DroppedSingleton); CHECK(pa->nc_origin == NcOrigin::None); } TEST_CASE("drop_singleton_signals is a no-op on a clean module") { Module mod("M"); Part *prt = new Part("U1"); mod.add(prt); auto *p1 = new Pin("A1"); prt->add(p1); auto *p2 = new Pin("A2"); prt->add(p2); Signal *s = mod.signals->merge("MULTIPIN"); s->add(p1); p1->connect(s); s->add(p2); p2->connect(s); CHECK(drop_singleton_signals(mod.signals) == 0); CHECK(mod.signals->size() == 1); } TEST_CASE("persist round-trip preserves nc_origin tags") { auto sys = std::make_unique(); Module *mod = sys->modules()->merge("M"); Part *prt = new Part("U1"); mod->add(prt); auto *connected = new Pin("A1"); prt->add(connected); Signal *s = mod->signals->merge("SIG"); s->add(connected); connected->connect(s); auto *imported_nc = new Pin("A2"); imported_nc->nc_origin = NcOrigin::ImportedUnconnected; prt->add(imported_nc); auto *dropped = new Pin("A3"); dropped->nc_origin = NcOrigin::DroppedSingleton; prt->add(dropped); // A pin with no signal and no origin (e.g. an old snapshot or a // FillIdentityNCs-style materialisation): tag stays None on restore. auto *bare_nc = new Pin("A4"); prt->add(bare_nc); std::string path = (std::filesystem::temp_directory_path() / "essim_nc_origin.txt").string(); std::string err; REQUIRE(save_system(sys.get(), path, err)); std::unique_ptr restored(restore_system(path, err)); REQUIRE(restored); std::filesystem::remove(path); Part *rp = restored->modules()->get("M")->get("U1"); CHECK(rp->get("A1")->nc_origin == NcOrigin::None); CHECK(rp->get("A2")->nc_origin == NcOrigin::ImportedUnconnected); CHECK(rp->get("A3")->nc_origin == NcOrigin::DroppedSingleton); CHECK(rp->get("A4")->nc_origin == NcOrigin::None); } TEST_CASE("next_signal_type cycles Power → Gnd → Other → Power") { CHECK(next_signal_type(SignalType::Power) == SignalType::GndShield); CHECK(next_signal_type(SignalType::GndShield) == SignalType::Other); CHECK(next_signal_type(SignalType::Other) == SignalType::Power); }