#include #include "system/connect.hpp" #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 namespace { std::string tmp_path(const std::string &name) { return (std::filesystem::temp_directory_path() / name).string(); } // Build a tiny system with two modules, parts, signals, and one connection // with a non-trivial pin_map. Used for the round-trip test. std::unique_ptr make_fixture() { auto sys = std::make_unique(); Module *bkp = sys->modules()->merge("BKP"); Module *pl = sys->modules()->merge("PL"); Part *p1 = new Part("U1"); p1->connector_type = "vpx-3u-bkp-p0"; bkp->add(p1); Part *p2 = new Part("J1"); p2->connector_type = "vpx-3u-payload-p0"; pl->add(p2); auto add_pin = [](Part *p, const std::string &name, Module *mod, const std::string &signal_name) -> Pin* { Pin *pin = new Pin(name); p->add(pin); if (!signal_name.empty()) { Signal *s = mod->signals->merge(signal_name); s->add(pin); pin->connect(s); } return pin; }; Pin *a1_bkp = add_pin(p1, "A1", bkp, "GND"); Pin *b1_bkp = add_pin(p1, "B1", bkp, "VCC"); /*Pin *nc_bkp =*/ add_pin(p1, "C1", bkp, ""); // NC Pin *a1_pl = add_pin(p2, "A1", pl, "GND"); Pin *c1_pl = add_pin(p2, "C1", pl, "VCC"); Connection *c = new Connection("BKP/U1 <-> PL/J1", bkp, p1, pl, p2); c->transform_name = "vpx-3u-p0"; c->pin_map.emplace_back(a1_bkp, a1_pl); c->pin_map.emplace_back(b1_bkp, c1_pl); sys->connections()->add(c); return sys; } } // namespace TEST_CASE("save+restore round-trip preserves modules, parts, types, signals, NC") { auto sys = make_fixture(); std::string path = tmp_path("essim_roundtrip.txt"); std::string err; REQUIRE(save_system(sys.get(), path, err)); System *restored_raw = restore_system(path, err); REQUIRE(restored_raw != nullptr); std::unique_ptr restored(restored_raw); std::filesystem::remove(path); CHECK(restored->modules()->size() == 2); Module *bkp = restored->modules()->get("BKP"); Module *pl = restored->modules()->get("PL"); REQUIRE(bkp); REQUIRE(pl); Part *p1 = bkp->get("U1"); Part *p2 = pl->get("J1"); REQUIRE(p1); REQUIRE(p2); CHECK(p1->connector_type == "vpx-3u-bkp-p0"); CHECK(p2->connector_type == "vpx-3u-payload-p0"); CHECK(p1->size() == 3); CHECK(p2->size() == 2); Pin *a1 = p1->get("A1"); Pin *c1_nc = p1->get("C1"); REQUIRE(a1); REQUIRE(c1_nc); REQUIRE(a1->signal()); CHECK(a1->signal()->name == "GND"); CHECK(c1_nc->signal() == nullptr); // NC preserved } TEST_CASE("save+restore preserves signal type overrides") { auto sys = make_fixture(); // Force a non-default override on a signal that auto-infers as Other. Signal *vcc = sys->modules()->get("BKP")->signals->get("VCC"); REQUIRE(vcc); CHECK(vcc->type == SignalType::Power); // auto-detected from "VCC" Signal *gnd = sys->modules()->get("BKP")->signals->get("GND"); REQUIRE(gnd); CHECK(gnd->type == SignalType::GndShield); std::string path = tmp_path("essim_signal_type.txt"); std::string err; REQUIRE(save_system(sys.get(), path, err)); std::unique_ptr restored(restore_system(path, err)); REQUIRE(restored); std::filesystem::remove(path); Signal *r_vcc = restored->modules()->get("BKP")->signals->get("VCC"); Signal *r_gnd = restored->modules()->get("BKP")->signals->get("GND"); CHECK(r_vcc->type == SignalType::Power); CHECK(r_gnd->type == SignalType::GndShield); } TEST_CASE("save+restore preserves connections and pin_map") { auto sys = make_fixture(); std::string path = tmp_path("essim_conn.txt"); std::string err; REQUIRE(save_system(sys.get(), path, err)); std::unique_ptr restored(restore_system(path, err)); REQUIRE(restored); std::filesystem::remove(path); CHECK(restored->connections()->size() == 1); Connection *c = restored->connections()->get("BKP/U1 <-> PL/J1"); REQUIRE(c); CHECK(c->transform_name == "vpx-3u-p0"); CHECK(c->pin_map.size() == 2); // Endpoints point into the restored system, not dangling. Module *bkp = restored->modules()->get("BKP"); Module *pl = restored->modules()->get("PL"); CHECK(c->m1 == bkp); CHECK(c->m2 == pl); CHECK(c->p1 == bkp->get("U1")); CHECK(c->p2 == pl->get("J1")); // Verify a specific wire pair. Pin *a1_bkp = bkp->get("U1")->get("A1"); bool found_a1 = false; for (auto &wp : c->pin_map) { if (wp.first == a1_bkp) { CHECK(wp.second == pl->get("J1")->get("A1")); found_a1 = true; } } CHECK(found_a1); } TEST_CASE("restore returns nullptr on bogus path") { std::string err; System *r = restore_system("/this/path/should/not/exist", err); CHECK(r == nullptr); CHECK(!err.empty()); }