Files
essim/tests/tui/test_helpers.cpp
François 63ca17d048 build: split core/ from frontends/; prepare for multiple GUI/TUI targets
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>
2026-06-03 19:33:06 +02:00

72 lines
2.1 KiB
C++

#include <doctest/doctest.h>
#include "frontends/tui/tui_helpers.hpp"
#include <algorithm>
#include <vector>
TEST_CASE("ToLower") {
CHECK(ToLower("ABC") == "abc");
CHECK(ToLower("aBc 123") == "abc 123");
CHECK(ToLower("") == "");
}
TEST_CASE("LongestCommonPrefix") {
CHECK(LongestCommonPrefix({}) == "");
CHECK(LongestCommonPrefix({"foo"}) == "foo");
CHECK(LongestCommonPrefix({"foo", "foobar", "foobaz"}) == "foo");
CHECK(LongestCommonPrefix({"abc", "xyz"}) == "");
CHECK(LongestCommonPrefix({"abc", "abc"}) == "abc");
}
TEST_CASE("Tokenize splits on whitespace") {
CHECK(Tokenize("").empty());
CHECK(Tokenize(" ").empty());
auto t = Tokenize("a b c");
CHECK(t == std::vector<std::string>{"a", "b", "c"});
}
TEST_CASE("Tokenize preserves quoted spaces") {
auto t = Tokenize("load \"my mod\" /tmp/x mentor");
CHECK(t == std::vector<std::string>{"load", "my mod", "/tmp/x", "mentor"});
}
TEST_CASE("Tokenize handles tabs as separators") {
auto t = Tokenize("a\tb\tc");
CHECK(t == std::vector<std::string>{"a", "b", "c"});
}
TEST_CASE("NaturalLess: numeric runs sort numerically") {
CHECK(NaturalLess("J1", "J2"));
CHECK(NaturalLess("J2", "J10"));
CHECK(NaturalLess("J9", "J10"));
CHECK(!NaturalLess("J10", "J2"));
CHECK(!NaturalLess("J10", "J10"));
}
TEST_CASE("NaturalLess: case insensitive for letters") {
CHECK(NaturalLess("abc", "ABD"));
CHECK(!NaturalLess("ABD", "abc"));
CHECK(!NaturalLess("abc", "ABC"));
}
TEST_CASE("NaturalLess: leading zeros tie-break") {
CHECK(NaturalLess("J01", "J1"));
CHECK(!NaturalLess("J1", "J01"));
}
TEST_CASE("NaturalLess: produces a sorted order over a connector-style list") {
std::vector<std::string> v = {"J22", "J1", "J10", "J2", "P100", "P21", "P2"};
std::sort(v.begin(), v.end(), NaturalLess);
CHECK(v == std::vector<std::string>{"J1", "J2", "J10", "J22", "P2", "P21", "P100"});
}
TEST_CASE("NaturalLess: total order axioms") {
// !(a < a)
CHECK(!NaturalLess("foo", "foo"));
CHECK(!NaturalLess("J10", "J10"));
// a < b ⇒ !(b < a)
CHECK(NaturalLess("J1", "J2"));
CHECK(!NaturalLess("J2", "J1"));
}