From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- tests/color.c | 67 +++ tests/duration.c | 117 ++++ tests/format.c | 172 ++++++ tests/list.c | 117 ++++ tests/strbuf.c | 1144 ++++++++++++++++++++++++++++++++++++++ tests/strutil.c | 108 ++++ tests/testlogo-hardcolors.fflogo | 4 + tests/testlogo-softcolors.fflogo | 4 + 8 files changed, 1733 insertions(+) create mode 100644 tests/color.c create mode 100644 tests/duration.c create mode 100644 tests/format.c create mode 100644 tests/list.c create mode 100644 tests/strbuf.c create mode 100644 tests/strutil.c create mode 100644 tests/testlogo-hardcolors.fflogo create mode 100644 tests/testlogo-softcolors.fflogo (limited to 'tests') diff --git a/tests/color.c b/tests/color.c new file mode 100644 index 0000000..90121d6 --- /dev/null +++ b/tests/color.c @@ -0,0 +1,67 @@ +#include "common/format.h" +#include "common/textModifier.h" +#include "fastfetch.h" + +#include + +static void verify(const char* color, const char* expected, int lineNo) { + FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate(); + ffOptionParseColorNoClear(color, &result); + if (!ffStrbufEqualS(&result, expected)) { + fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %s: expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, color, expected, result.chars); + exit(1); + } +} + +#define VERIFY(color, expected) verify((color), (expected), __LINE__) + +int main(void) { + instance.config.display.pipe = true; + // Initialize dummy config colors for property tests + ffStrbufInitS(&instance.config.display.colorKeys, "94"); // light_blue + ffStrbufInitS(&instance.config.display.colorTitle, "95"); // light_magenta + + { + VERIFY("", ""); + VERIFY("1", "1"); + + VERIFY("red", "31"); + VERIFY("light_green", "92"); + VERIFY("default", "39"); + VERIFY("blue", "34"); + VERIFY("light_cyan", "96"); + + VERIFY("bold_red", "1;31"); + VERIFY("dim_light_yellow", "2;93"); + VERIFY("italic_underline_green", "3;4;32"); + VERIFY("reset_blue", "0;34"); // Reset followed by color + + VERIFY("#ff0000", "38;2;255;0;0"); // RRGGBB + VERIFY("#0f0", "38;2;0;255;0"); // RGB + VERIFY("#123456", "38;2;18;52;86"); + VERIFY("#abc", "38;2;170;187;204"); + + // xterm 256 color codes + VERIFY("@0", "38;5;0"); + VERIFY("@1", "38;5;1"); + VERIFY("@255", "38;5;255"); + + VERIFY("bold_#ff00ff", "1;38;2;255;0;255"); + VERIFY("underline_#123", "4;38;2;17;34;51"); + + VERIFY("\e[32m", "32"); // Direct ANSI code + VERIFY("\e[1;94m", "1;94"); // Direct ANSI code with mode + + // Property colors (ensure dummy config colors are set) + VERIFY("keys", "94"); + VERIFY("title", "95"); + VERIFY("bold_keys", "1;94"); + } + + // Clean up dummy config colors + ffStrbufDestroy(&instance.config.display.colorKeys); + ffStrbufDestroy(&instance.config.display.colorTitle); + + // Success + puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); +} diff --git a/tests/duration.c b/tests/duration.c new file mode 100644 index 0000000..9d28ce1 --- /dev/null +++ b/tests/duration.c @@ -0,0 +1,117 @@ +#include "common/duration.h" +#include "common/textModifier.h" +#include "fastfetch.h" + +#include + +static void verify(uint64_t totalSeconds, const char* expected, int lineNo) { + FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate(); + ffDurationAppendNum(totalSeconds, &result); + if (!ffStrbufEqualS(&result, expected)) { + fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %llu: expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, (unsigned long long) totalSeconds, expected, result.chars); + exit(1); + } +} + +#define VERIFY(color, expected) verify((color), (expected), __LINE__) + +int main(void) { + // Test seconds less than 60 + VERIFY(0, "0 seconds"); + VERIFY(1, "1 second"); + VERIFY(2, "2 seconds"); + VERIFY(59, "59 seconds"); + + // Test minute rounding (when seconds >= 30) + VERIFY(60, "1 min"); + VERIFY(60 + 29, "1 min"); + VERIFY(60 + 30, "2 mins"); + + // Test only minutes + VERIFY(60 * 2 - 1, "2 mins"); + VERIFY(60 * 2, "2 mins"); + VERIFY(60 * 59 + 29, "59 mins"); + + // Test only hours (no minutes) + VERIFY(60 * 59 + 30, "1 hour"); + VERIFY(60 * 60, "1 hour"); + VERIFY(2 * 60 * 60, "2 hours"); + VERIFY(23 * 60 * 60, "23 hours"); + + // Test combination of hours and minutes + VERIFY(60 * 60 + 60, "1 hour, 1 min"); + VERIFY(60 * 60 + 60 * 2, "1 hour, 2 mins"); + VERIFY(60 * 60 * 2 + 60 + 29, "2 hours, 1 min"); + VERIFY(60 * 60 * 2 + 60 + 30, "2 hours, 2 mins"); + + // Test days + VERIFY(60 * 60 * 24, "1 day"); + VERIFY(60 * 60 * 24 - 1, "1 day"); + VERIFY(60 * 60 * 24 * 2, "2 days"); + + // Test combination of days and hours + VERIFY(60 * 60 * 24 + 60 * 60, "1 day, 1 hour"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60, "2 days, 1 hour"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60 * 2, "2 days, 2 hours"); + + // Test combination of days, hours, and minutes + VERIFY(60 * 60 * 24 + 60 * 60 + 60, "1 day, 1 hour, 1 min"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60 + 60 * 2, "2 days, 1 hour, 2 mins"); + VERIFY(60 * 60 * 24 * 2 + 60 * 2, "2 days, 2 mins"); + + // Test very large number of days + VERIFY(60 * 60 * 24 * 100, "100 days(!)"); + VERIFY(60 * 60 * 24 * 200, "200 days(!)"); + + instance.config.display.durationAbbreviation = true; + instance.config.display.durationSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_NEVER; + // Test seconds less than 60 + VERIFY(0, "0secs"); + VERIFY(1, "1sec"); + VERIFY(2, "2secs"); + VERIFY(59, "59secs"); + + // Test minute rounding (when seconds >= 30) + VERIFY(60, "1m"); + VERIFY(60 + 29, "1m"); + VERIFY(60 + 30, "2m"); + + // Test only minutes + VERIFY(60 * 2 - 1, "2m"); + VERIFY(60 * 2, "2m"); + VERIFY(60 * 59 + 29, "59m"); + + // Test only hours (no minutes) + VERIFY(60 * 59 + 30, "1h"); + VERIFY(60 * 60, "1h"); + VERIFY(2 * 60 * 60, "2h"); + VERIFY(23 * 60 * 60, "23h"); + + // Test combination of hours and minutes + VERIFY(60 * 60 + 60, "1h 1m"); + VERIFY(60 * 60 + 60 * 2, "1h 2m"); + VERIFY(60 * 60 * 2 + 60 + 29, "2h 1m"); + VERIFY(60 * 60 * 2 + 60 + 30, "2h 2m"); + + // Test days + VERIFY(60 * 60 * 24, "1d"); + VERIFY(60 * 60 * 24 - 1, "1d"); + VERIFY(60 * 60 * 24 * 2, "2d"); + + // Test combination of days and hours + VERIFY(60 * 60 * 24 + 60 * 60, "1d 1h"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60, "2d 1h"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60 * 2, "2d 2h"); + + // Test combination of days, hours, and minutes + VERIFY(60 * 60 * 24 + 60 * 60 + 60, "1d 1h 1m"); + VERIFY(60 * 60 * 24 * 2 + 60 * 60 + 60 * 2, "2d 1h 2m"); + VERIFY(60 * 60 * 24 * 2 + 60 * 2, "2d 2m"); + + // Test very large number of days + VERIFY(60 * 60 * 24 * 100, "100d"); + VERIFY(60 * 60 * 24 * 200, "200d"); + + // Success + puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); +} diff --git a/tests/format.c b/tests/format.c new file mode 100644 index 0000000..2366f55 --- /dev/null +++ b/tests/format.c @@ -0,0 +1,172 @@ +#include "common/format.h" +#include "common/textModifier.h" +#include "fastfetch.h" + +#include + +static void verify(const char* format, const char* arg, const char* expected, int lineNo) { + FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY formatter = ffStrbufCreateStatic(format); + const FFformatarg arguments[] = { { .type = FF_ARG_TYPE_STRING, arg } }; + ffParseFormatString(&result, &formatter, 1, arguments); + if (!ffStrbufEqualS(&result, expected)) { + fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %s: expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, format, expected, result.chars); + exit(1); + } +} + +#define VERIFY(format, argument, expected) verify((format), (argument), (expected), __LINE__) + +int main(void) { + instance.config.display.pipe = true; + + { + VERIFY("output({})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1})", "12345 67890", "output(12345 67890)"); + VERIFY("output({})", "", "output()"); + VERIFY("output({1})", "", "output()"); + } + + { + VERIFY("output({1:20})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1:11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1:-11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1:6})", "12345 67890", "output(12345)"); + VERIFY("output({:6})", "12345 67890", "output(12345)"); + VERIFY("output({:-6})", "12345 67890", "output(12345…)"); + VERIFY("output({:0})", "12345 67890", "output()"); + VERIFY("output({:})", "12345 67890", "output()"); + } + + { + VERIFY("output({1<20})", "12345 67890", "output(12345 67890 )"); + VERIFY("output({1<-20})", "12345 67890", "output(12345 67890 )"); + VERIFY("output({1<11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1<-11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1<6})", "12345 67890", "output(12345 )"); + VERIFY("output({<6})", "12345 67890", "output(12345 )"); + VERIFY("output({<-6})", "12345 67890", "output(12345…)"); + VERIFY("output({<0})", "12345 67890", "output()"); + VERIFY("output({<})", "12345 67890", "output()"); + } + + { + VERIFY("output({1>20})", "12345 67890", "output( 12345 67890)"); + VERIFY("output({1>-20})", "12345 67890", "output( 12345 67890)"); + VERIFY("output({1>11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1>-11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1>6})", "12345 67890", "output(12345 )"); + VERIFY("output({>6})", "12345 67890", "output(12345 )"); + VERIFY("output({>-6})", "12345 67890", "output(12345…)"); + VERIFY("output({>0})", "12345 67890", "output()"); + VERIFY("output({>})", "12345 67890", "output()"); + } + + { + VERIFY("output({1|20})", "12345 67890", "output( 12345 67890 )"); + VERIFY("output({1|-20})", "12345 67890", "output( 12345 67890 )"); + VERIFY("output({1|11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1|-11})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1|6})", "12345 67890", "output(12345 )"); + VERIFY("output({|6})", "12345 67890", "output(12345 )"); + VERIFY("output({|-6})", "12345 67890", "output(12345…)"); + VERIFY("output({|0})", "12345 67890", "output()"); + VERIFY("output({|})", "12345 67890", "output()"); + } + + { + VERIFY("output({1n>20})", "12345 67890", "output({1n>20})"); + VERIFY("output({120})", "12345 67890", "output({120})"); + VERIFY("output({1:11})", "", "output()"); + VERIFY("output({2:2})", "", "output({2:2})"); + } + + { + VERIFY("output({1~0})", "12345 67890", "output(12345 67890)"); + VERIFY("output({1~1})", "12345 67890", "output(2345 67890)"); + VERIFY("output({1~10})", "12345 67890", "output(0)"); + VERIFY("output({1~20})", "12345 67890", "output()"); + VERIFY("output({1~-5})", "12345 67890", "output(67890)"); + VERIFY("output({1~-50})", "12345 67890", "output()"); + VERIFY("output({1~0,1})", "12345 67890", "output(1)"); + VERIFY("output({1~0,6})", "12345 67890", "output(12345 )"); + VERIFY("output({1~0,10})", "12345 67890", "output(12345 6789)"); + VERIFY("output({1~5,10})", "12345 67890", "output( 6789)"); + VERIFY("output({1~5,100})", "12345 67890", "output( 67890)"); + VERIFY("output({1~10,10})", "12345 67890", "output()"); + VERIFY("output({1~10,5})", "12345 67890", "output()"); + VERIFY("output({1~3,-3})", "12345 67890", "output(45 67)"); + VERIFY("output({1~-5,-3})", "12345 67890", "output(67)"); + VERIFY("output({1~-0,10})", "12345 67890", "output(12345 6789)"); + VERIFY("output({1~-3,-5})", "12345 67890", "output()"); + VERIFY("output({1~})", "12345 67890", "output(12345 67890)"); // Same as {1~0} + VERIFY("output({1~-0})", "12345 67890", "output(12345 67890)"); // Same as {1~0} + VERIFY("output({1~,-1})", "12345 67890", "output(12345 6789)"); // Same as {1~0,-1} + VERIFY("output({1~,})", "12345 67890", "output()"); // Same as {1~0,0} + } + + { + VERIFY("output({1n~0})", "12345 67890", "output({1n~0})"); + VERIFY("output({1~<0})", "12345 67890", "output({1~<0})"); + VERIFY("output({1~-})", "12345 67890", "output({1~-})"); + VERIFY("output({1~-,1})", "12345 67890", "output({1~-,1})"); + VERIFY("output({1~0,,1})", "12345 67890", "output({1~0,,1})"); + VERIFY("output({1~0,1,})", "12345 67890", "output({1~0,1,})"); + VERIFY("output({1~,0,1})", "12345 67890", "output({1~,0,1})"); + VERIFY("output({2,0})", "12345 67890", "output({2,0})"); + } + + { + VERIFY("output({1:20}{1<20}{1>20})", "12345 67890", "output(12345 6789012345 67890 12345 67890)"); + VERIFY("output({?1}OK{?}{/1}NOT OK{/})", "12345 67890", "output(OK)"); + VERIFY("output({?1}OK{?}{/1}NOT OK{/})", "", "output(NOT OK)"); + } + + { + VERIFY("output({1:3})", "\e[1m12345", "output(\e[1m123)"); + VERIFY("output({1:-3})", "\e[1m12345", "output(\e[1m123…)"); + VERIFY("output({1:3})", "\e[1m12345\e[m", "output(\e[1m123\e[m)"); + VERIFY("output({1:-3})", "\e[1m12345\e[m", "output(\e[1m123…\e[m)"); + } + + { + VERIFY("output({1<8})", "\e[1m12345", "output(\e[1m12345 )"); + VERIFY("output({1>8})", "\e[1m12345", "output(\e[1m 12345)"); + VERIFY("output({1<8})", "\e[1m12345\e[m", "output(\e[1m12345 \e[m)"); + VERIFY("output({1>8})", "\e[1m12345\e[m", "output(\e[1m 12345\e[m)"); + VERIFY("output({1<1})", "\e[30;47m12345\e[m", "output(\e[30;47m1\e[m)"); + VERIFY("output({1|8})", "\e[1m12345\e[m", "output(\e[1m 12345 \e[m)"); + VERIFY("output({1|1})", "\e[30;47m12345\e[m", "output(\e[30;47m1\e[m)"); + } + + { + VERIFY("output({1~0})", "\e[1m12345", "output(\e[1m12345)"); + VERIFY("output({1~1})", "\e[1m12345", "output(\e[1m2345)"); + VERIFY("output({1~0})", "\e[1m12345\e[m", "output(\e[1m12345\e[m)"); + VERIFY("output({1~1})", "\e[1m12345\e[m", "output(\e[1m2345\e[m)"); + VERIFY("output({1~2})", "\e[30;47m12345\e[m", "output(\e[30;47m345\e[m)"); + } + +#ifndef _WIN32 // Windows doesn't have setenv + { + ffListInit(&instance.config.display.constants); + ffStrbufInitStatic(FF_LIST_ADD(FFstrbuf, instance.config.display.constants), "CONST1"); + ffStrbufInitStatic(FF_LIST_ADD(FFstrbuf, instance.config.display.constants), "CONST2"); + setenv("FF_TEST", "ENVVAR", 1); + VERIFY("output({$FF_TEST})", "", "output(ENVVAR)"); + VERIFY("output({$1})", "", "output(CONST1)"); + VERIFY("output({$FF_TEST}{$1})", "", "output(ENVVARCONST1)"); + VERIFY("output({$1}{$FF_TEST})", "", "output(CONST1ENVVAR)"); + VERIFY("output({$FF_TEST}{$FF_TEST})", "", "output(ENVVARENVVAR)"); + VERIFY("output({$1}{$-1})", "", "output(CONST1CONST2)"); + + VERIFY("output({$FF_INVAL})", "", "output({$FF_INVAL})"); + VERIFY("output({$9}{$0}${-9})", "", "output({$9}{$0}${-9})"); + VERIFY("output({$1NO})", "", "output({$1NO})"); + ffListDestroy(&instance.config.display.constants); + } +#endif + + // Success + puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); +} diff --git a/tests/list.c b/tests/list.c new file mode 100644 index 0000000..2184dd7 --- /dev/null +++ b/tests/list.c @@ -0,0 +1,117 @@ +#include "common/FFlist.h" +#include "common/textModifier.h" + +#include +#include +#include +#include +#include + +noreturn static void testFailed(const FFlist* list, const char* expression, int lineNo) { + fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stderr); + fprintf(stderr, "[%d] %s, list:", lineNo, expression); + for (uint32_t i = 0; i < list->length; ++i) { + fprintf(stderr, "%u ", *FF_LIST_GET(uint32_t, *list, i)); + } + fputc('\n', stderr); + fputs(FASTFETCH_TEXT_MODIFIER_RESET, stderr); + fputc('\n', stderr); + exit(1); +} + +static bool numEqualsAdapter(const uint32_t* first, const uint32_t* second) { + return *first == *second; +} + +#define VERIFY(expression) \ + if (!(expression)) testFailed(&list, #expression, __LINE__) + +int main(void) { + FFlist list; + uint32_t n = 0; + + // initA + + ffListInit(&list); + + VERIFY(list.capacity == 0); + VERIFY(list.length == 0); + + // forEach + FF_LIST_FOR_EACH (uint32_t, item, list) { + VERIFY(false); + } + + // shift + VERIFY(!FF_LIST_SHIFT(list, &n)); + VERIFY(list.length == 0); + + // pop + VERIFY(!FF_LIST_POP(list, &n)); + VERIFY(list.length == 0); + + // add + for (uint32_t i = 1; i <= FF_LIST_DEFAULT_ALLOC + 1; ++i) { + *FF_LIST_ADD(uint32_t, list) = i; + + VERIFY(list.length == i); + + if (i <= FF_LIST_DEFAULT_ALLOC) { + VERIFY(list.capacity == FF_LIST_DEFAULT_ALLOC); + } else { + VERIFY(list.capacity == FF_LIST_DEFAULT_ALLOC * 2); + } + + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 1); + VERIFY(*FF_LIST_GET(uint32_t, list, i - 1) == i); + } + VERIFY(list.length == FF_LIST_DEFAULT_ALLOC + 1); + + uint32_t sum = 0; + // forEach + FF_LIST_FOR_EACH (uint32_t, item, list) { + sum += *item; + } + VERIFY(sum == (1 + FF_LIST_DEFAULT_ALLOC + 1) * (FF_LIST_DEFAULT_ALLOC + 1) / 2); + + // ffListFirstIndexComp + n = 10; + VERIFY(ffListFirstIndexComp(&list, sizeof(n), &n, (void*) numEqualsAdapter) == 9); + n = 999; + VERIFY(ffListFirstIndexComp(&list, sizeof(n), &n, (void*) numEqualsAdapter) == list.length); + + // ffListContains + n = 10; + VERIFY(FF_LIST_CONTAINS(list, &n, numEqualsAdapter)); + n = 999; + VERIFY(!FF_LIST_CONTAINS(list, &n, numEqualsAdapter)); + + // shift + VERIFY(FF_LIST_SHIFT(list, &n)); + VERIFY(n == 1); + VERIFY(list.length == FF_LIST_DEFAULT_ALLOC); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, list.length - 1) == FF_LIST_DEFAULT_ALLOC + 1); + + // pop + VERIFY(FF_LIST_POP(list, &n)); + VERIFY(n == FF_LIST_DEFAULT_ALLOC + 1); + VERIFY(list.length == FF_LIST_DEFAULT_ALLOC - 1); + VERIFY(*FF_LIST_GET(uint32_t, list, 0) == 2); + VERIFY(*FF_LIST_GET(uint32_t, list, list.length - 1) == FF_LIST_DEFAULT_ALLOC); + + // Destroy + ffListDestroy(&list); + + VERIFY(list.capacity == 0); + VERIFY(list.length == 0); + + { + FF_LIST_AUTO_DESTROY test = ffListCreate(); + VERIFY(test.capacity == 0); + VERIFY(test.length == 0); + } + + // Success + puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); +} diff --git a/tests/strbuf.c b/tests/strbuf.c new file mode 100644 index 0000000..12ceac3 --- /dev/null +++ b/tests/strbuf.c @@ -0,0 +1,1144 @@ +#include "common/FFstrbuf.h" +#include "common/textModifier.h" + +#include +#include +#include +#include + +noreturn static void testFailed(const FFstrbuf* strbuf, const char* expression, int lineNo) { + fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stderr); + fprintf(stderr, "[%d] %s, strbuf:", lineNo, expression); + ffStrbufWriteTo(strbuf, stderr); + fputs(FASTFETCH_TEXT_MODIFIER_RESET, stderr); + fputc('\n', stderr); + exit(1); +} + +#define VERIFY(expression) \ + if (!(expression)) testFailed(&strbuf, #expression, __LINE__) + +int shouldNotBeCalled(int c) { + (void) c; + exit(1); +} + +int main(void) { + FFstrbuf strbuf; + + // destroy 0 + ffStrbufInit(&strbuf); + ffStrbufDestroy(&strbuf); + + // initA + + ffStrbufInit(&strbuf); + + VERIFY(strbuf.chars[0] == 0); + VERIFY(strbuf.allocated == 0); + VERIFY(strbuf.length == 0); + + VERIFY(!ffStrbufStartsWithC(&strbuf, '0')); + VERIFY(!ffStrbufEndsWithC(&strbuf, '0')); + VERIFY(!ffStrbufStartsWithS(&strbuf, "0")); + VERIFY(!ffStrbufEndsWithS(&strbuf, "0")); + VERIFY(ffStrbufCountC(&strbuf, '0') == 0); + + // Ensure following functions work with non-allocated string + ffStrbufAppendS(&strbuf, ""); + ffStrbufAppendF(&strbuf, "%s", ""); + ffStrbufAppendTransformS(&strbuf, "", shouldNotBeCalled); + ffStrbufPrependS(&strbuf, ""); + ffStrbufTrim(&strbuf, ' '); + + VERIFY(strbuf.chars[0] == 0); + VERIFY(strbuf.allocated == 0); + VERIFY(strbuf.length == 0); + + // append(N)C + + ffStrbufAppendC(&strbuf, '1'); + VERIFY(ffStrbufEqualS(&strbuf, "1")); + VERIFY(strbuf.allocated >= 1); + ffStrbufAppendNC(&strbuf, 5, '2'); + VERIFY(ffStrbufEqualS(&strbuf, "122222")); + VERIFY(strbuf.allocated >= 6); + ffStrbufClear(&strbuf); + + // appendS + + ffStrbufAppendS(&strbuf, "12345"); + ffStrbufAppendS(&strbuf, NULL); + + VERIFY(strbuf.length == 5); + VERIFY(strbuf.allocated >= 6); + VERIFY(ffStrbufEqualS(&strbuf, "12345")); + + // appendNS + + ffStrbufAppendNS(&strbuf, 4, "67890"); + ffStrbufAppendNS(&strbuf, 0, NULL); + + VERIFY(strbuf.length == 9); + VERIFY(strbuf.allocated >= 10); + VERIFY(ffStrbufEqualS(&strbuf, "123456789")); + + // appendS long + + ffStrbufAppendS(&strbuf, "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); + VERIFY(strbuf.length == 109); + VERIFY(strbuf.allocated >= 110); + VERIFY(strbuf.chars[strbuf.length] == 0); + + // substr + + VERIFY(ffStrbufSubstrBefore(&strbuf, 9)); + VERIFY(strbuf.length == 9); + VERIFY(strbuf.allocated >= 110); + VERIFY(strbuf.chars[strbuf.length] == 0); + VERIFY(ffStrbufEqualS(&strbuf, "123456789")); + + VERIFY(!ffStrbufSubstrBeforeFirstC(&strbuf, '0')); + VERIFY(!ffStrbufSubstrBeforeLastC(&strbuf, '0')); + VERIFY(!ffStrbufSubstrAfterFirstC(&strbuf, '0')); + VERIFY(!ffStrbufSubstrAfterLastC(&strbuf, '0')); + VERIFY(ffStrbufEqualS(&strbuf, "123456789")); + + VERIFY(ffStrbufSubstrBeforeFirstC(&strbuf, '9')); + VERIFY(ffStrbufSubstrBeforeLastC(&strbuf, '8')); + VERIFY(ffStrbufSubstrAfterFirstC(&strbuf, '1')); + VERIFY(ffStrbufSubstrAfterLastC(&strbuf, '2')); + VERIFY(ffStrbufEqualS(&strbuf, "34567")); + + ffStrbufSetS(&strbuf, "123456789"); + + // startsWithC + + VERIFY(ffStrbufStartsWithC(&strbuf, '1')); + VERIFY(!ffStrbufStartsWithC(&strbuf, '2')); + + // startsWithS + + VERIFY(ffStrbufStartsWithS(&strbuf, "123")); + VERIFY(ffStrbufStartsWithS(&strbuf, "123456789")); + VERIFY(!ffStrbufStartsWithS(&strbuf, "1234567890123")); + + // endsWithC + VERIFY(ffStrbufEndsWithC(&strbuf, '9')); + VERIFY(!ffStrbufEndsWithC(&strbuf, '1')); + + // endsWithS + + VERIFY(ffStrbufEndsWithS(&strbuf, "789")); + VERIFY(ffStrbufEndsWithS(&strbuf, "123456789")); + VERIFY(!ffStrbufEndsWithS(&strbuf, "1234567890123")); + + // toNumber + + VERIFY(ffStrbufToDouble(&strbuf, -DBL_MAX) == 123456789.0); + VERIFY(ffStrbufToUInt(&strbuf, 999) == 123456789); + + // countC + + VERIFY(ffStrbufCountC(&strbuf, '1') == 1); + VERIFY(ffStrbufCountC(&strbuf, '0') == 0); + + // removeS + + ffStrbufRemoveS(&strbuf, "78"); + + VERIFY(strbuf.length == 7); + VERIFY(strcmp(strbuf.chars, "1234569") == 0); + + // removeStrings + + ffStrbufRemoveStrings(&strbuf, 3, (const char*[]) { "23", "45", "9" }); + + VERIFY(strbuf.length == 2); + VERIFY(strcmp(strbuf.chars, "16") == 0); + + // PrependS + + ffStrbufPrependS(&strbuf, "123"); + ffStrbufPrependS(&strbuf, NULL); + + VERIFY(strbuf.length == 5); + VERIFY(strcmp(strbuf.chars, "12316") == 0); + + // indexC + VERIFY(ffStrbufFirstIndexC(&strbuf, '1') == 0); + VERIFY(ffStrbufNextIndexC(&strbuf, 1, '1') == 3); + VERIFY(ffStrbufNextIndexC(&strbuf, 4, '1') == 5); + VERIFY(ffStrbufLastIndexC(&strbuf, '1') == 3); + VERIFY(ffStrbufPreviousIndexC(&strbuf, 2, '1') == 0); + VERIFY(ffStrbufPreviousIndexC(&strbuf, 0, '1') == 0); + VERIFY(ffStrbufPreviousIndexC(&strbuf, 0, '2') == 5); + + // indexS + VERIFY(ffStrbufFirstIndexS(&strbuf, "12316") == 0); + VERIFY(ffStrbufNextIndexS(&strbuf, 1, "1") == 3); + VERIFY(ffStrbufNextIndexS(&strbuf, 4, "1") == 5); + + // ignCase + ffStrbufSetS(&strbuf, "AbCdEfG"); + + VERIFY(ffStrbufIgnCaseCompS(&strbuf, "aBcDeFg") == 0); + VERIFY(ffStrbufStartsWithIgnCaseS(&strbuf, "ABCD")); + VERIFY(ffStrbufEndsWithIgnCaseS(&strbuf, "defg")); + VERIFY(!ffStrbufStartsWithIgnCaseS(&strbuf, "aBcDeFgH")); + VERIFY(!ffStrbufEndsWithIgnCaseS(&strbuf, "0aBcDeFg")); + + // ensure + ffStrbufEnsureEndsWithC(&strbuf, '$'); + VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG$")); + ffStrbufEnsureEndsWithC(&strbuf, '$'); + VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG$")); + + // trimRight + ffStrbufTrimRight(&strbuf, '$'); + VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG")); + ffStrbufTrimRight(&strbuf, '$'); + VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG")); + + // clear + ffStrbufClear(&strbuf); + VERIFY(strbuf.allocated > 0); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.chars && strbuf.chars[0] == 0); + + // Destroy + + ffStrbufDestroy(&strbuf); + + VERIFY(strbuf.allocated == 0); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.chars && strbuf.chars[0] == 0); + + // initA + ffStrbufInitA(&strbuf, 32); + + VERIFY(strbuf.allocated == 32); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.chars && strbuf.chars[0] == 0); + + // appendF + ffStrbufAppendF(&strbuf, "%s", "1234567890123456789012345678901"); + VERIFY(strbuf.allocated == 32); + VERIFY(ffStrbufEqualS(&strbuf, "1234567890123456789012345678901")); + + ffStrbufDestroy(&strbuf); + + // initMoveS + { + char* heapStr = strdup("1234567890"); + ffStrbufInitMoveS(&strbuf, heapStr); + VERIFY(ffStrbufEqualS(&strbuf, "1234567890")); + VERIFY(strbuf.allocated >= 11); + ffStrbufDestroy(&strbuf); + } + + // initF + ffStrbufInitF(&strbuf, "%s", "1234567890123456789012345678901"); + VERIFY(strbuf.allocated >= 32); + VERIFY(ffStrbufEqualS(&strbuf, "1234567890123456789012345678901")); + + // containC + VERIFY(ffStrbufContainC(&strbuf, '1')); + VERIFY(!ffStrbufContainC(&strbuf, '-')); + + // replaceAllC + ffStrbufReplaceAllC(&strbuf, '1', '-'); + VERIFY(ffStrbufEqualS(&strbuf, "-234567890-234567890-234567890-")); + ffStrbufReplaceAllC(&strbuf, '1', '-'); + VERIFY(ffStrbufEqualS(&strbuf, "-234567890-234567890-234567890-")); + + // trim + ffStrbufTrim(&strbuf, '-'); + VERIFY(ffStrbufEqualS(&strbuf, "234567890-234567890-234567890")); + + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateS + { + FF_STRBUF_AUTO_DESTROY testCreate = ffStrbufCreateS("TEST"); + VERIFY(ffStrbufEqualS(&testCreate, "TEST")); + } + + // ffStrbufCreateStatic + ffStrbufInitStatic(&strbuf, "TEST"); + VERIFY(ffStrbufEqualS(&strbuf, "TEST")); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated == 0); + + ffStrbufDestroy(&strbuf); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 0); + + // ffStrbufCreateStatic / Allocate + ffStrbufInitStatic(&strbuf, "TEST"); + ffStrbufEnsureFree(&strbuf, 0); + VERIFY(ffStrbufEqualS(&strbuf, "TEST")); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated > 0); + + // ffStrbufCreateStatic / Append + ffStrbufInitStatic(&strbuf, "TEST"); + ffStrbufAppendS(&strbuf, "_TEST"); + VERIFY(ffStrbufEqualS(&strbuf, "TEST_TEST")); + VERIFY(strbuf.length == 9); + VERIFY(strbuf.allocated >= 10); + ffStrbufAppendC(&strbuf, '_'); + VERIFY(ffStrbufEqualS(&strbuf, "TEST_TEST_")); + ffStrbufDestroy(&strbuf); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 0); + + // ffStrbufCreateStatic / Prepend + ffStrbufInitStatic(&strbuf, "TEST"); + ffStrbufPrependS(&strbuf, "TEST_"); + VERIFY(ffStrbufEqualS(&strbuf, "TEST_TEST")); + VERIFY(strbuf.length == 9); + VERIFY(strbuf.allocated >= 10); + ffStrbufPrependC(&strbuf, '_'); + VERIFY(ffStrbufEqualS(&strbuf, "_TEST_TEST")); + ffStrbufDestroy(&strbuf); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 0); + + // ffStrbufCreateStatic / Clear + ffStrbufInitStatic(&strbuf, "TEST"); + ffStrbufClear(&strbuf); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / Set + ffStrbufInitStatic(&strbuf, "TEST"); // static + ffStrbufSetStatic(&strbuf, "test"); + VERIFY(ffStrbufEqualS(&strbuf, "test")); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / Set + ffStrbufInitS(&strbuf, "TEST"); // allocated + ffStrbufSetStatic(&strbuf, "test"); + VERIFY(ffStrbufEqualS(&strbuf, "test")); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / TrimL + ffStrbufInitStatic(&strbuf, "_TEST_"); + ffStrbufTrimLeft(&strbuf, '_'); + VERIFY(ffStrbufEqualS(&strbuf, "TEST_")); + VERIFY(strbuf.length == 5); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / TrimR + ffStrbufInitStatic(&strbuf, "_TEST_"); + ffStrbufTrimRight(&strbuf, ' '); + VERIFY(strbuf.allocated == 0); + VERIFY(ffStrbufEqualS(&strbuf, "_TEST_")); + ffStrbufTrimRight(&strbuf, '_'); + VERIFY(ffStrbufEqualS(&strbuf, "_TEST")); + VERIFY(strbuf.length == 5); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / Substr + ffStrbufInitStatic(&strbuf, "__TEST__"); + VERIFY(ffStrbufRemoveSubstr(&strbuf, 0, 6)); + VERIFY(ffStrbufEqualS(&strbuf, "__")); + VERIFY(strbuf.length == 2); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / Substr + ffStrbufInitStatic(&strbuf, "__TEST__"); + VERIFY(ffStrbufRemoveSubstr(&strbuf, 2, 8)); + VERIFY(ffStrbufEqualS(&strbuf, "__")); + VERIFY(strbuf.length == 2); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / Substr + ffStrbufInitStatic(&strbuf, "__TEST__"); + VERIFY(ffStrbufRemoveSubstr(&strbuf, 2, 6)); + VERIFY(ffStrbufEqualS(&strbuf, "____")); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / ReplaceAllC + ffStrbufInitStatic(&strbuf, "__TEST__"); + ffStrbufReplaceAllC(&strbuf, '_', '-'); + VERIFY(ffStrbufEqualS(&strbuf, "--TEST--")); + VERIFY(strbuf.length == 8); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreateStatic / TrimSpace + ffStrbufInitStatic(&strbuf, "\n TEST\n "); + ffStrbufTrimSpace(&strbuf); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated > 0); + VERIFY(ffStrbufEqualS(&strbuf, "TEST")); + ffStrbufDestroy(&strbuf); + + // ffStrbufCreate / TrimSpace + ffStrbufInitS(&strbuf, "\n TEST\n "); + ffStrbufTrimSpace(&strbuf); + VERIFY(strbuf.length == 4); + VERIFY(strbuf.allocated > 0); + VERIFY(ffStrbufEqualS(&strbuf, "TEST")); + ffStrbufDestroy(&strbuf); + + // ffStrbufEnsureFixedLengthFree / empty buffer + ffStrbufInit(&strbuf); + ffStrbufEnsureFixedLengthFree(&strbuf, 10); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 11); + ffStrbufDestroy(&strbuf); + ffStrbufInitA(&strbuf, 10); + ffStrbufEnsureFixedLengthFree(&strbuf, 10); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 11); + ffStrbufEnsureFixedLengthFree(&strbuf, 12); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 13); + ffStrbufDestroy(&strbuf); + + // ffStrbufEnsureFixedLengthFree / empty buffer with zero free length + ffStrbufInit(&strbuf); + ffStrbufEnsureFixedLengthFree(&strbuf, 0); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // ffStrbufEnsureFixedLengthFree / empty buffer but oldFree >= newFree + ffStrbufInitA(&strbuf, 11); + ffStrbufEnsureFixedLengthFree(&strbuf, 10); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 11); + ffStrbufDestroy(&strbuf); + ffStrbufInitA(&strbuf, 12); + ffStrbufEnsureFixedLengthFree(&strbuf, 10); + VERIFY(strbuf.length == 0); + VERIFY(strbuf.allocated == 12); + ffStrbufDestroy(&strbuf); + + // ffStrbufEnsureFixedLengthFree / non empty buffer + ffStrbufAppendF(&strbuf, "%s", "1234567890"); + VERIFY(strbuf.length == 10); + VERIFY(strbuf.allocated == 32); + ffStrbufEnsureFixedLengthFree(&strbuf, 0); + VERIFY(strbuf.length == 10); + VERIFY(strbuf.allocated == 32); + ffStrbufEnsureFixedLengthFree(&strbuf, 20); // less than oldFree (=21) + VERIFY(strbuf.length == 10); + VERIFY(strbuf.allocated == 32); + ffStrbufEnsureFixedLengthFree(&strbuf, 21); // equal to oldFree (=21) + VERIFY(strbuf.length == 10); + VERIFY(strbuf.allocated == 32); + ffStrbufEnsureFixedLengthFree(&strbuf, 22); // greater than oldFree (=21) + VERIFY(strbuf.length == 10); + VERIFY(strbuf.allocated == 33); + ffStrbufDestroy(&strbuf); + + // ffStrbufEnsureFixedLengthFree / static buffer + ffStrbufInitStatic(&strbuf, "__TEST__"); + VERIFY(strbuf.length > 0); + VERIFY(strbuf.allocated == 0); + ffStrbufEnsureFixedLengthFree(&strbuf, 10); + VERIFY(strbuf.length == strlen("__TEST__")); + VERIFY(strbuf.allocated == strlen("__TEST__") + 1 + 10); + VERIFY(ffStrbufEqualS(&strbuf, "__TEST__")); + ffStrbufDestroy(&strbuf); + + // ffStrbufInsertNC + ffStrbufInitStatic(&strbuf, "123456"); + ffStrbufInsertNC(&strbuf, 0, 2, 'A'); + VERIFY(ffStrbufEqualS(&strbuf, "AA123456")); + ffStrbufInsertNC(&strbuf, 4, 2, 'B'); + VERIFY(ffStrbufEqualS(&strbuf, "AA12BB3456")); + ffStrbufInsertNC(&strbuf, strbuf.length, 2, 'C'); + VERIFY(ffStrbufEqualS(&strbuf, "AA12BB3456CC")); + ffStrbufInsertNC(&strbuf, 999, 2, 'D'); + VERIFY(ffStrbufEqualS(&strbuf, "AA12BB3456CCDD")); + ffStrbufDestroy(&strbuf); + + // smallest allocation test + { + FF_STRBUF_AUTO_DESTROY strbuf1 = ffStrbufCreateA(10); + VERIFY(strbuf1.allocated == 10); + ffStrbufEnsureFree(&strbuf1, 16); + VERIFY(strbuf1.allocated == 32); + + FF_STRBUF_AUTO_DESTROY strbuf2 = ffStrbufCreate(); + VERIFY(strbuf2.allocated == 0); + ffStrbufEnsureFree(&strbuf2, 16); + VERIFY(strbuf2.allocated == 32); + } + + { + int i = 0; + char* lineptr = NULL; + size_t n = 0; + const char* text = "Processor\t: ARMv7\nprocessor\t: 0\nBogoMIPS\t: 38.00\n\nprocessor\t: 1\nBogoMIPS\t: 38.00"; + ffStrbufSetS(&strbuf, text); + + while (ffStrbufGetline(&lineptr, &n, &strbuf)) { + ++i; + switch (i) { + case 1: + VERIFY(strcmp(lineptr, "Processor\t: ARMv7") == 0); + VERIFY(n == strlen("Processor\t: ARMv7")); + break; + case 2: + VERIFY(strcmp(lineptr, "processor\t: 0") == 0); + VERIFY(n == strlen("processor\t: 0")); + break; + case 3: + VERIFY(strcmp(lineptr, "BogoMIPS\t: 38.00") == 0); + VERIFY(n == strlen("BogoMIPS\t: 38.00")); + break; + case 4: + VERIFY(strcmp(lineptr, "") == 0); + VERIFY(n == 0); + break; + case 5: + VERIFY(strcmp(lineptr, "processor\t: 1") == 0); + VERIFY(n == strlen("processor\t: 1")); + break; + case 6: + VERIFY(strcmp(lineptr, "BogoMIPS\t: 38.00") == 0); + VERIFY(n == strlen("BogoMIPS\t: 38.00")); + break; + default: + VERIFY(false); + break; + } + } + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 6); + + lineptr = NULL; + n = 0; + i = 0; + text = "\n"; + ffStrbufSetS(&strbuf, text); + while (ffStrbufGetline(&lineptr, &n, &strbuf)) { + ++i; + switch (i) { + case 1: + VERIFY(strcmp(lineptr, "") == 0); + VERIFY(n == 0); + break; + default: + VERIFY(false); + break; + } + } + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 1); + + lineptr = NULL; + n = 0; + i = 0; + text = "abcd"; + ffStrbufSetS(&strbuf, text); + while (ffStrbufGetline(&lineptr, &n, &strbuf)) { + ++i; + switch (i) { + case 1: + VERIFY(strcmp(lineptr, "abcd") == 0); + VERIFY(n == strlen("abcd")); + break; + default: + VERIFY(false); + break; + } + } + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 1); + + lineptr = NULL; + n = 0; + i = 0; + text = ""; + ffStrbufSetS(&strbuf, text); + while (ffStrbufGetline(&lineptr, &n, &strbuf)) { + ++i; + VERIFY(false); + } + + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 0); + } + + ffStrbufSetS(&strbuf, "Hello World"); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == false); + VERIFY(strcmp(strbuf.chars, "Hello World") == 0); + + ffStrbufSetS(&strbuf, "Hello World"); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, "Hello World") == 0); + + ffStrbufSetS(&strbuf, " Hello World "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, " Hello World ") == 0); + + ffStrbufSetS(&strbuf, " Hello World "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, " Hello World ") == 0); + + ffStrbufSetS(&strbuf, " "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, " ") == 0); + + ffStrbufClear(&strbuf); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == false); + VERIFY(strcmp(strbuf.chars, "") == 0); + + ffStrbufSetStatic(&strbuf, " "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == false); + VERIFY(strcmp(strbuf.chars, " ") == 0); + + { + ffStrbufSetStatic(&strbuf, "abcdef"); + FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateCopy(&strbuf); + VERIFY(newStr.allocated == 0); + VERIFY(newStr.chars == strbuf.chars); + } + + { + ffStrbufSetStatic(&strbuf, "abcdef"); + FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456"); + ffStrbufSet(&newStr, &strbuf); + VERIFY(newStr.allocated == 0); + VERIFY(newStr.chars == strbuf.chars); + VERIFY(ffStrbufEqualS(&newStr, "abcdef")); + } + + { + ffStrbufClear(&strbuf); + FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456"); + uint32_t oldAlloc = newStr.allocated; + VERIFY(oldAlloc > newStr.length); + ffStrbufSet(&newStr, &strbuf); + VERIFY(newStr.allocated == oldAlloc); + VERIFY(newStr.chars != strbuf.chars); + VERIFY(ffStrbufEqualS(&newStr, "")); + } + + { + ffStrbufSetStatic(&strbuf, "abcdefghijkl"); + FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456"); + ffStrbufSet(&newStr, &strbuf); + VERIFY(newStr.allocated == 0); + VERIFY(newStr.chars == strbuf.chars); + VERIFY(ffStrbufEqualS(&newStr, "abcdefghijkl")); + } + + { + ffStrbufClear(&strbuf); + FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateCopy(&strbuf); + VERIFY(newStr.allocated == 0); + VERIFY(newStr.chars == strbuf.chars); + VERIFY(newStr.chars[0] == '\0'); + } + + { + ffStrbufClear(&strbuf); + FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456"); + ffStrbufSet(&newStr, &strbuf); + VERIFY(newStr.allocated > 0); + VERIFY(newStr.chars != strbuf.chars); + VERIFY(ffStrbufEqualS(&newStr, "")); + } + + { + ffStrbufSetStatic(&strbuf, "abc"); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "abc:def:ghi", ' ') == false); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "abc:def:ghi", ':') == true); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "def:ghi", ' ') == false); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "def:ghi", ':') == false); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "def", ':') == false); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "abc", ':') == true); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "", ' ') == false); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abc:", ':') == true); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, "abc:", ':') == true); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abc", ':') == true); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":ABC", ':') == false); + VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abcdef", ':') == false); + } + + { + ffStrbufSetStatic(&strbuf, "ABC"); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:def:ghi", ' ') == false); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:def:ghi", ':') == true); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def:ghi", ' ') == false); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def:ghi", ':') == false); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def", ':') == false); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc", ':') == true); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "", ' ') == false); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abc:", ':') == true); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:", ':') == true); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abc", ':') == true); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":ABC", ':') == true); + VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abcdef", ':') == false); + } + + { + ffStrbufSetStatic(&strbuf, "abc:def:ghi"); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "abc", ' ') == false); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "abc", ':') == true); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "def", ' ') == false); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "def", ':') == true); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "DEF", ':') == false); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "a", ':') == false); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "e", ':') == false); + VERIFY(ffStrbufSeparatedContainS(&strbuf, "i", ':') == false); + } + + { + ffStrbufSetStatic(&strbuf, "ABC:DEF:GHI"); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "abc", ' ') == false); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "abc", ':') == true); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "def", ' ') == false); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "def", ':') == true); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "DEF", ':') == true); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "a", ':') == false); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "e", ':') == false); + VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "i", ':') == false); + } + + { + ffStrbufSetStatic(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 0, 1); // start, end + VERIFY(ffStrbufEqualS(&strbuf, "a")); + + ffStrbufSetStatic(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 1, 1); + VERIFY(ffStrbufEqualS(&strbuf, "")); + + ffStrbufSetStatic(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 2, 1); + VERIFY(ffStrbufEqualS(&strbuf, "")); + + ffStrbufSetStatic(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 2, 3); + VERIFY(ffStrbufEqualS(&strbuf, "c")); + + ffStrbufSetStatic(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 0, 3); + VERIFY(ffStrbufEqualS(&strbuf, "abc")); + } + + { + ffStrbufSetS(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 0, 1); // start, end + VERIFY(ffStrbufEqualS(&strbuf, "a")); + + ffStrbufSetS(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 1, 1); + VERIFY(ffStrbufEqualS(&strbuf, "")); + + ffStrbufSetS(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 2, 1); + VERIFY(ffStrbufEqualS(&strbuf, "")); + + ffStrbufSetS(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 2, 3); + VERIFY(ffStrbufEqualS(&strbuf, "c")); + + ffStrbufSetS(&strbuf, "abc"); + ffStrbufSubstr(&strbuf, 0, 3); + VERIFY(ffStrbufEqualS(&strbuf, "abc")); + + ffStrbufDestroy(&strbuf); + } + + { + ffStrbufAppendUtf32CodePoint(&strbuf, 0x6587); + ffStrbufAppendUtf32CodePoint(&strbuf, 0x6cc9); + ffStrbufAppendUtf32CodePoint(&strbuf, 0x9a7f); + VERIFY(ffStrbufEqualS(&strbuf, u8"文泉驿")); + + ffStrbufDestroy(&strbuf); + } + + { + ffStrbufAppendSInt(&strbuf, 1234567890); + VERIFY(ffStrbufEqualS(&strbuf, "1234567890")); + + ffStrbufClear(&strbuf); + ffStrbufAppendSInt(&strbuf, -1234567890); + VERIFY(ffStrbufEqualS(&strbuf, "-1234567890")); + + ffStrbufClear(&strbuf); + ffStrbufAppendSInt(&strbuf, 0); + VERIFY(ffStrbufEqualS(&strbuf, "0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendUInt(&strbuf, 1234567890); + VERIFY(ffStrbufEqualS(&strbuf, "1234567890")); + + ffStrbufClear(&strbuf); + ffStrbufAppendUInt(&strbuf, 0); + VERIFY(ffStrbufEqualS(&strbuf, "0")); + + ffStrbufDestroy(&strbuf); + } + + { + ffStrbufAppendDouble(&strbuf, 120.0, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 1, true); + VERIFY(ffStrbufEqualS(&strbuf, "120.0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 5, true); + VERIFY(ffStrbufEqualS(&strbuf, "120.00000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 5, true); + VERIFY(ffStrbufEqualS(&strbuf, "120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.888888, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.999999, 2, true); + VERIFY(ffStrbufEqualS(&strbuf, "121.00")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1, true); + VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123, 5, true); + VERIFY(ffStrbufEqualS(&strbuf, "120.12300")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 1, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120.0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 5, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120.00000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 5, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123, 5, true); + VERIFY(ffStrbufEqualS(&strbuf, "-120.12300")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.888888, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.999999, 2, true); + VERIFY(ffStrbufEqualS(&strbuf, "-121.00")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, true); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, true); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, true); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, true); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, true); + VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000.0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, true); + VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000.0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, +0.0, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -0.0, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-0")); + + ffStrbufDestroy(&strbuf); + } + + { + ffStrbufAppendDouble(&strbuf, 120.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.888888, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.999999, 2, false); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.123")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.888888, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.999999, 2, false); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, +0.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -0.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-0")); + + ffStrbufDestroy(&strbuf); + } + + // decode hex escape sequences + { + ffStrbufSetS(&strbuf, "Basic\\x20data\\x20partition"); + VERIFY(ffStrbufDecodeHexEscapeSequences(&strbuf) == true); + VERIFY(ffStrbufEqualS(&strbuf, "Basic data partition")); + + ffStrbufSetS(&strbuf, "\\x41\\x42\\x43"); + VERIFY(ffStrbufDecodeHexEscapeSequences(&strbuf) == true); + VERIFY(ffStrbufEqualS(&strbuf, "ABC")); + + ffStrbufSetS(&strbuf, "abc\\x4"); + VERIFY(ffStrbufDecodeHexEscapeSequences(&strbuf) == false); + VERIFY(ffStrbufEqualS(&strbuf, "abc\\x4")); + + ffStrbufSetS(&strbuf, "abc\\xZZ"); + VERIFY(ffStrbufDecodeHexEscapeSequences(&strbuf) == false); + VERIFY(ffStrbufEqualS(&strbuf, "abc\\xZZ")); + + ffStrbufSetS(&strbuf, "abc\\x2G"); + VERIFY(ffStrbufDecodeHexEscapeSequences(&strbuf) == false); + VERIFY(ffStrbufEqualS(&strbuf, "abc\\x2G")); + } + + // setS + ffStrbufInitStatic(&strbuf, "STATIC"); + ffStrbufSetS(&strbuf, "DYNAMIC"); + VERIFY(ffStrbufEqualS(&strbuf, "DYNAMIC")); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInit(&strbuf); + ffStrbufSetS(&strbuf, ""); + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitStatic(&strbuf, "STATIC"); + ffStrbufSetS(&strbuf, ""); + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitStatic(&strbuf, "STATIC"); + ffStrbufSetStatic(&strbuf, ""); + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitS(&strbuf, "DYNAMIC"); + ffStrbufSetStatic(&strbuf, ""); + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitS(&strbuf, "DYNAMIC"); + ffStrbufSetS(&strbuf, "ANOTHER DYNAMIC"); + VERIFY(ffStrbufEqualS(&strbuf, "ANOTHER DYNAMIC")); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInit(&strbuf); + ffStrbufSetStatic(&strbuf, ""); + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // set + ffStrbufInitStatic(&strbuf, "STATIC"); + { + FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS("DYNAMIC"); + ffStrbufSet(&strbuf, &other); + } + VERIFY(ffStrbufEqualS(&strbuf, "DYNAMIC")); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInit(&strbuf); + { + FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS(""); + ffStrbufSet(&strbuf, &other); + } + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitStatic(&strbuf, "STATIC"); + { + FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS(""); + ffStrbufSet(&strbuf, &other); + } + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitS(&strbuf, "DYNAMIC"); + { + FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS(""); + ffStrbufSet(&strbuf, &other); + } + VERIFY(ffStrbufEqualS(&strbuf, "")); + VERIFY(strbuf.allocated > 0); + ffStrbufDestroy(&strbuf); + + ffStrbufInitS(&strbuf, "DYNAMIC"); + { + FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateStatic("STATIC"); + ffStrbufSet(&strbuf, &other); + } + VERIFY(ffStrbufEqualS(&strbuf, "STATIC")); + VERIFY(strbuf.allocated == 0); + ffStrbufDestroy(&strbuf); + + // Success + puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); +} diff --git a/tests/strutil.c b/tests/strutil.c new file mode 100644 index 0000000..3d065ee --- /dev/null +++ b/tests/strutil.c @@ -0,0 +1,108 @@ +#include "common/strutil.h" +#include "common/textModifier.h" + +#include +#include +#include + +static void verify(bool expression, const char* expressionStr, int lineNo) { + if (expression) { + return; + } + + fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %s\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, expressionStr); + exit(1); +} + +#define VERIFY(expression) verify((expression), #expression, __LINE__) + +int main(void) { + #if FF_ENABLE_WCWIDTH + { + uint8_t width = 255; + uint8_t bytes = ffUtf8CharLenWidth("", 0, &width); + VERIFY(bytes == 0); + VERIFY(width == 0); + } + + { + uint8_t width = 0; + uint8_t bytes = ffUtf8CharLenWidth("A", 1, &width); + VERIFY(bytes == 1); + VERIFY(width == 1); + } + + { + const char* ch = "\xE6\x96\x87"; // 文 U+6587 + uint8_t width = 0; + uint8_t bytes = ffUtf8CharLenWidth(ch, 3, &width); + VERIFY(bytes == 3); + VERIFY(width == 2); + } + + { + const char* combining = "\xCC\x81"; // ◌́ U+0301 + uint8_t width = 0; + uint8_t bytes = ffUtf8CharLenWidth(combining, 2, &width); + VERIFY(bytes == 2); + VERIFY(width == 0); // Should be 1 since there's no base character + } + + { + uint8_t width = 0; + uint8_t bytes = ffUtf8CharLenWidth("\xE6\x96\x87", 1, &width); // truncated + VERIFY(bytes == 1); + VERIFY(width == 1); + } + + { + uint8_t width = 0; + uint8_t bytes = ffUtf8CharLenWidth("\xE6" + "A", + 2, + &width); // invalid continuation + VERIFY(bytes == 1); + VERIFY(width == 1); + } + + { + VERIFY(ffUtf8StrWidth("abc", 3) == 3); + } + + { + const char* mixed = "A" + "\xE6\x96\x87" // 文 U+6587 + "B"; + VERIFY(ffUtf8StrWidth(mixed, 5) == 4); + } + + { + const char* combining = "A\xCC\x81"; // Á + VERIFY(ffUtf8StrWidth(combining, 3) == 1); + } + + { + VERIFY(ffUtf8StrWidth("\xE6" + "A", + 2) == 2); + } + + { + VERIFY(ffUtf8StrWidth("", 0) == 0); + VERIFY(ffUtf8StrWidth("A\0B", 3) == 1); + } + + { + const char* emoji = "\xF0\x9F\x98\x80"; // U+1F600 😀 + uint8_t width = 0; + uint8_t bytes = ffUtf8CharLenWidth(emoji, 4, &width); + VERIFY(bytes == 4); + VERIFY(width == 2); + } + + puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); + #else + puts("\033[33mTests skipped because wcwidth support is disabled." FASTFETCH_TEXT_MODIFIER_RESET); + #endif + return 0; +} diff --git a/tests/testlogo-hardcolors.fflogo b/tests/testlogo-hardcolors.fflogo new file mode 100644 index 0000000..ab93080 --- /dev/null +++ b/tests/testlogo-hardcolors.fflogo @@ -0,0 +1,4 @@ + . + ... + .-|-. +.-| |-. \ No newline at end of file diff --git a/tests/testlogo-softcolors.fflogo b/tests/testlogo-softcolors.fflogo new file mode 100644 index 0000000..4e42ced --- /dev/null +++ b/tests/testlogo-softcolors.fflogo @@ -0,0 +1,4 @@ +$1 . +$1 ... +$1 .-|-. +$1.-| |-. \ No newline at end of file -- cgit v1.2.3