Files
CoopAllTheThings/tests/text_util_test.cpp
BlackMark 30eccf749d Apply clang-format across the whole tree
Run clang-format (the repo's .clang-format: LLVM base, 120 cols, tabs,
Allman functions) over every source file so the tree is formatter-clean.
Whitespace only -- no behavior change; full x64 + x86 suites pass.

Also set SortIncludes: false in .clang-format. Windows include order is
load-bearing (windows.h must precede tlhelp32.h / mmreg.h / xinput.h /
dinput.h; winsock2.h must precede windows.h), and the default
alphabetical sort reorders tlhelp32.h ahead of windows.h -- a build
break. Leaving order alone keeps the manual, correct grouping.
2026-07-12 11:52:53 +02:00

65 lines
2.9 KiB
C++

// Unit test for the host's shared text helpers: the case-insensitive filter predicate the Log and
// Injection panels use (ui/text_match.hpp) and the UTF-8 <-> wide conversions (util/utf8.hpp) every
// panel bridges Win32 strings through. Pure logic; no window / device.
#include <cstdio>
#include <string>
#include "ui/text_match.hpp"
#include "util/utf8.hpp"
using namespace coop;
namespace {
int g_failures = 0;
void check(bool ok, const char* what)
{
std::printf("%s %s\n", ok ? " ok:" : "FAIL:", what);
if (!ok) {
++g_failures;
}
}
} // namespace
int main()
{
// --- contains_ci: the filter contract the panels rely on -------------------------------------
// An empty (or null) needle matches everything, so an empty filter box shows every row.
check(contains_ci("anything", ""), "empty needle matches");
check(contains_ci("anything", nullptr), "null needle matches");
check(contains_ci("", ""), "empty needle matches an empty haystack");
// Case-insensitive both ways (so typing 'error' finds 'ERROR', and 'ERR' finds 'stderr').
check(contains_ci("ERROR: disk full", "error"), "lowercase needle finds uppercase text");
check(contains_ci("stderr stream", "ERR"), "uppercase needle finds lowercase text");
check(contains_ci("MixedCase", "edca"), "case-folded substring across a case boundary");
// Substring position: start, middle, end, and whole-string.
check(contains_ci("game.exe", "game"), "match at the start");
check(contains_ci("coop_host.exe", "host"), "match in the middle");
check(contains_ci("coop_host.exe", ".exe"), "match at the end");
check(contains_ci("exact", "exact"), "whole-string match");
// Non-matches (so a filter actually hides non-matching rows).
check(!contains_ci("game.exe", "xyz"), "no false match");
check(!contains_ci("short", "longer than the haystack"), "needle longer than haystack");
check(!contains_ci("", "x"), "non-empty needle never matches an empty haystack");
// ascii_lower folds A-Z only and leaves other bytes untouched.
check(ascii_lower("AbC123!") == "abc123!", "ascii_lower folds letters, leaves digits/punct");
// --- narrow / widen: round-trip + boundary cases ---------------------------------------------
check(narrow(L"") == "", "narrow of an empty string is empty");
check(widen("") == L"", "widen of an empty string is empty");
check(narrow(L"game.exe") == "game.exe", "narrow of ASCII is byte-identical");
check(widen("game.exe") == L"game.exe", "widen of ASCII is byte-identical");
// Round-trip preserves the string (ASCII and a non-ASCII code point that must survive
// persist/reload of an override key -- the reason narrow/widen exist instead of a byte mask).
for (const wchar_t* s : {L"CoopAllTheThings", L"path\\to\\Game (2).exe", L"café.exe", L"游戏.exe"}) {
check(widen(narrow(std::wstring(s))) == std::wstring(s), "narrow->widen round-trips");
}
std::printf(g_failures == 0 ? "PASS text_util_test\n" : "FAILED text_util_test (%d)\n", g_failures);
return g_failures == 0 ? 0 : 1;
}