Reorganise the tree into business vs frontend as separate directories:
src/core/{domain,imports,app} (was system/, imports/, app/)
src/frontends/tui/ (was tui/ + main.cpp)
tests/tui/ (the FTXUI-coupled helper test)
All cross-dir #include paths rewritten; same-dir includes untouched.
CMake: essim_core is the frontend-agnostic business library — links libzip,
pugixml and bsdl, NO GUI toolkit. Each frontend is a self-contained
src/frontends/<name>/ (own CMakeLists, toolkit, main.cpp) that links
essim_core, selected with -DESSIM_FRONTEND=<name> (default tui; 'none' = core +
tests only, no toolkit fetched). FTXUI moved into the tui frontend. Tests are
split: essim_tests links essim_core (no FTXUI), essim_tui_tests links essim_tui.
Verified: default tui build green (ctest 2/2); ESSIM_FRONTEND=none builds the
core + tests with FTXUI never fetched and no `essim` binary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
77 lines
2.4 KiB
C++
77 lines
2.4 KiB
C++
#include <doctest/doctest.h>
|
|
|
|
#include "core/app/export.hpp"
|
|
#include "core/domain/connect.hpp"
|
|
#include "core/domain/modules.hpp"
|
|
#include "core/domain/parts.hpp"
|
|
#include "core/domain/pins.hpp"
|
|
#include "core/domain/signals.hpp"
|
|
#include "core/domain/system.hpp"
|
|
|
|
#include <cstdio>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
std::string slurp(const std::string &path)
|
|
{
|
|
std::ifstream f(path);
|
|
std::stringstream ss;
|
|
ss << f.rdbuf();
|
|
return ss.str();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("export_format_from_path maps extensions") {
|
|
app::ExportFormat f;
|
|
CHECK(app::export_format_from_path("a.csv", f));
|
|
CHECK(f == app::ExportFormat::Csv);
|
|
CHECK(app::export_format_from_path("a.ODS", f));
|
|
CHECK(f == app::ExportFormat::Ods);
|
|
CHECK_FALSE(app::export_format_from_path("a.txt", f));
|
|
CHECK_FALSE(app::export_format_from_path("noext", f));
|
|
}
|
|
|
|
TEST_CASE("export_connections writes a flat CSV (no UI needed)") {
|
|
// Two cards, one wired pin pair via a connection.
|
|
System sys;
|
|
Module *a = sys.modules()->merge("A");
|
|
Module *b = sys.modules()->merge("B");
|
|
Part *ja = new Part("J1"); a->add(ja);
|
|
Part *jb = new Part("P1"); b->add(jb);
|
|
Pin *pa = new Pin("1"); ja->add(pa);
|
|
Pin *pb = new Pin("1"); jb->add(pb);
|
|
Signal *sa = a->signals->merge("NETA"); sa->add(pa); pa->connect(sa);
|
|
Signal *sb = b->signals->merge("NETB"); sb->add(pb); pb->connect(sb);
|
|
|
|
Connection *c = new Connection("A.J1<->B.P1", a, ja, b, jb);
|
|
c->transform_name = "identity";
|
|
c->pin_map.emplace_back(pa, pb);
|
|
sys.connections()->add(c);
|
|
|
|
const char *path = "test_export_out.csv";
|
|
app::ExportResult r = app::export_connections(&sys, path, app::ExportFormat::Csv);
|
|
CHECK(r.ok);
|
|
CHECK(r.rows == 1);
|
|
|
|
std::string out = slurp(path);
|
|
CHECK(out.find("connection,transform,") == 0); // header present
|
|
CHECK(out.find("A.J1<->B.P1") != std::string::npos); // connection name
|
|
CHECK(out.find("identity") != std::string::npos); // transform
|
|
CHECK(out.find("NETA") != std::string::npos); // left signal
|
|
CHECK(out.find("NETB") != std::string::npos); // right signal
|
|
|
|
std::remove(path);
|
|
}
|
|
|
|
TEST_CASE("export_connections reports a bad path instead of crashing") {
|
|
System sys;
|
|
app::ExportResult r = app::export_connections(
|
|
&sys, "/nonexistent-dir-xyz/out.csv", app::ExportFormat::Csv);
|
|
CHECK_FALSE(r.ok);
|
|
CHECK_FALSE(r.error.empty());
|
|
}
|