#include #include "core/app/edit.hpp" #include "core/domain/modules.hpp" #include "core/domain/parts.hpp" #include "core/domain/pins.hpp" #include "core/domain/signal_type.hpp" #include "core/domain/signals.hpp" #include "core/domain/system.hpp" // app::set_connector_type is pure core: validate the kind, tag the part and // apply the connector model. No Print/dialog/FTXUI. TEST_CASE("set_connector_type tags a part with a free-form kind") { Part p("J1"); p.add(new Pin("1")); p.add(new Pin("2")); app::SetConnectorTypeResult r = app::set_connector_type(&p, "myconn"); CHECK(r.ok); CHECK(r.error.empty()); CHECK(p.connector_type == "myconn"); } TEST_CASE("set_connector_type refuses a kind the part doesn't fit — no mutation") { Part p("J1"); p.add(new Pin("1")); p.add(new Pin("2")); p.add(new Pin("3")); // numeric pins don't fit the VPX single-letter columns app::SetConnectorTypeResult r = app::set_connector_type(&p, "vpx-3u-bkp-p0"); CHECK_FALSE(r.ok); CHECK_FALSE(r.error.empty()); CHECK(p.connector_type.empty()); // refused before any change } TEST_CASE("set_connector_type on a null part fails cleanly") { app::SetConnectorTypeResult r = app::set_connector_type(nullptr, "x"); CHECK_FALSE(r.ok); CHECK_FALSE(r.error.empty()); } TEST_CASE("attach_bsdl reports a parse failure without mutating the part") { Part p("J1"); p.add(new Pin("1")); app::AttachBsdlResult r = app::attach_bsdl(&p, "/nonexistent-xyz/none.bsd"); CHECK_FALSE(r.ok); CHECK(r.error.find("cannot parse") != std::string::npos); CHECK(p.bsdl_path.empty()); // failure leaves the part untouched } TEST_CASE("attach_bsdl on a null part fails cleanly") { app::AttachBsdlResult r = app::attach_bsdl(nullptr, "x.bsd"); CHECK_FALSE(r.ok); CHECK_FALSE(r.error.empty()); } TEST_CASE("set_signal_type parses the name and sets the type") { Signal s("NET"); app::SetSignalTypeResult r = app::set_signal_type(&s, "power"); CHECK(r.ok); CHECK(r.type == SignalType::Power); CHECK(s.type == SignalType::Power); } TEST_CASE("set_signal_type rejects an unknown name without mutating") { Signal s("NET"); s.type = SignalType::Other; app::SetSignalTypeResult r = app::set_signal_type(&s, "bogus"); CHECK_FALSE(r.ok); CHECK(r.error.find("power, gnd, other") != std::string::npos); CHECK(s.type == SignalType::Other); // unchanged } TEST_CASE("duplicate_module deep-clones parts, pins and signals") { System sys; Module *a = sys.modules()->merge("A"); Part *p = new Part("J1"); a->add(p); Pin *pin = new Pin("1"); p->add(pin); Signal *s = a->signals->merge("NET"); s->type = SignalType::Power; s->add(pin); pin->connect(s); app::DuplicateResult r = app::duplicate_module(&sys, "A", "B"); CHECK(r.ok); CHECK(r.parts == 1); CHECK(r.signals == 1); REQUIRE(sys.modules()->exists("B")); Module *b = sys.modules()->get("B"); CHECK(b->signals->get("NET")->type == SignalType::Power); // type preserved Pin *bpin = b->get("J1")->get("1"); REQUIRE(bpin->signal() != nullptr); CHECK(bpin->signal() == b->signals->get("NET")); // wired to the clone's own signal CHECK(bpin->signal() != s); // not aliasing the source } TEST_CASE("duplicate_module refuses an unknown source or an existing destination") { System sys; sys.modules()->merge("A"); app::DuplicateResult dst = app::duplicate_module(&sys, "A", "A"); CHECK_FALSE(dst.ok); CHECK(dst.error.find("already exists") != std::string::npos); app::DuplicateResult unk = app::duplicate_module(&sys, "NOPE", "X"); CHECK_FALSE(unk.ok); CHECK(unk.error.find("unknown module") != std::string::npos); }