Extract connect into core (app::connect_parts); thin the command + screen.
Move the wiring orchestration — transform lookup, identity-compatibility
check, identity NC fill, transform apply, Connection creation/add — out of
the `connect` command and the interactive connect screen into
core/app/connect.{hpp,cpp}: app::connect_parts(System*, m1,p1, m2,p2) returns
a ConnectResult (ok/refused/error, connection_name, transform_name, wires,
identity_info, nc_added) with no Print/dialog/FTXUI. Name/pattern resolution
and ambiguity reporting stay in the command — that is arg-parsing, not the op.
Both frontends now call the one core op, removing the duplicated logic. This
also unifies a divergence: the interactive screen previously called
CheckIdentityCompatible without the info pointer and so never filled identity
NC pins (unlike the command); routing it through app::connect_parts makes the
screen fill NCs and surface the same warning, matching the scriptable path.
Command output is unchanged. Prune the now-dead transform.hpp / domain
connect.hpp includes from the frontends (commands.cpp keeps transform_vpx.hpp
only for ValidatePartForKind).
Add tests/test_connect.cpp (core, no UI): identity-compatible pair wires,
unknown type pairing is refused with nothing created, subset side gets NC
pins filled and the warning reported.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
79
tests/test_connect.cpp
Normal file
79
tests/test_connect.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include "core/app/connect.hpp"
|
||||
#include "core/domain/connect.hpp"
|
||||
#include "core/domain/modules.hpp"
|
||||
#include "core/domain/parts.hpp"
|
||||
#include "core/domain/pins.hpp"
|
||||
#include "core/domain/system.hpp"
|
||||
|
||||
// app::connect_parts is pure core: given two already-resolved parts it looks up
|
||||
// the transform, fills identity NC pins, creates the Connection and returns a
|
||||
// ConnectResult. No Print/dialog/FTXUI. These tests drive it directly.
|
||||
|
||||
namespace {
|
||||
|
||||
// A part with the given pin names, attached to a fresh module.
|
||||
Part *make_part(System &sys, const std::string &mod, const std::string &part,
|
||||
std::initializer_list<const char *> pins,
|
||||
const std::string &type = "")
|
||||
{
|
||||
Module *m = sys.modules()->merge(mod);
|
||||
Part *p = new Part(part);
|
||||
p->connector_type = type;
|
||||
m->add(p);
|
||||
for (const char *pn : pins) p->add(new Pin(pn));
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("connect_parts wires an identity-compatible pair") {
|
||||
System sys;
|
||||
Module *a = sys.modules()->merge("A");
|
||||
Module *b = sys.modules()->merge("B");
|
||||
Part *p1 = make_part(sys, "A", "J1", {"1", "2"});
|
||||
Part *p2 = make_part(sys, "B", "P1", {"1", "2"});
|
||||
|
||||
app::ConnectResult r = app::connect_parts(&sys, a, p1, b, p2);
|
||||
|
||||
CHECK(r.ok);
|
||||
CHECK_FALSE(r.refused);
|
||||
CHECK(r.transform_name == "identity");
|
||||
CHECK(r.wires == 2);
|
||||
CHECK(r.identity_info.empty()); // identical sets → no NC fill, no warning
|
||||
CHECK(r.nc_added == 0);
|
||||
CHECK(r.connection_name == "A/J1 <-> B/P1");
|
||||
CHECK(sys.connections()->size() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("connect_parts refuses an unknown connector-type pairing") {
|
||||
System sys;
|
||||
Module *a = sys.modules()->merge("A");
|
||||
Module *b = sys.modules()->merge("B");
|
||||
Part *p1 = make_part(sys, "A", "J1", {"1"}, "foo");
|
||||
Part *p2 = make_part(sys, "B", "P1", {"1"}, "bar");
|
||||
|
||||
app::ConnectResult r = app::connect_parts(&sys, a, p1, b, p2);
|
||||
|
||||
CHECK_FALSE(r.ok);
|
||||
CHECK(r.refused);
|
||||
CHECK(r.error.find("no transform") != std::string::npos);
|
||||
CHECK(sys.connections()->size() == 0); // nothing created
|
||||
}
|
||||
|
||||
TEST_CASE("connect_parts fills NC pins on the subset side and reports it") {
|
||||
System sys;
|
||||
Module *a = sys.modules()->merge("A");
|
||||
Module *b = sys.modules()->merge("B");
|
||||
Part *p1 = make_part(sys, "A", "J1", {"1", "2", "3"}); // larger side
|
||||
Part *p2 = make_part(sys, "B", "P1", {"1", "2"}); // missing "3"
|
||||
|
||||
app::ConnectResult r = app::connect_parts(&sys, a, p1, b, p2);
|
||||
|
||||
CHECK(r.ok);
|
||||
CHECK_FALSE(r.identity_info.empty()); // subset path surfaces a warning
|
||||
CHECK(r.nc_added == 1); // pin "3" materialised on B
|
||||
CHECK(r.wires == 3); // all three now wired
|
||||
CHECK(p2->size() == 3); // the NC pin really got added
|
||||
}
|
||||
Reference in New Issue
Block a user