summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /tests
Add the files
Diffstat (limited to 'tests')
-rw-r--r--tests/color.c67
-rw-r--r--tests/duration.c117
-rw-r--r--tests/format.c172
-rw-r--r--tests/list.c117
-rw-r--r--tests/strbuf.c1144
-rw-r--r--tests/strutil.c108
-rw-r--r--tests/testlogo-hardcolors.fflogo4
-rw-r--r--tests/testlogo-softcolors.fflogo4
8 files changed, 1733 insertions, 0 deletions
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 <stdlib.h>
+
+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 <stdlib.h>
+
+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 <stdlib.h>
+
+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 <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdnoreturn.h>
+
+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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdnoreturn.h>
+
+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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+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