ohmu
·
2026-10-15
1#include "common/format.h"
2#include "common/textModifier.h"
3#include "fastfetch.h"
4
5#include <stdlib.h>
6
7static void verify(const char* format, const char* arg, const char* expected, int lineNo) {
8 FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate();
9 FF_STRBUF_AUTO_DESTROY formatter = ffStrbufCreateStatic(format);
10 const FFformatarg arguments[] = { { .type = FF_ARG_TYPE_STRING, arg } };
11 ffParseFormatString(&result, &formatter, 1, arguments);
12 if (!ffStrbufEqualS(&result, expected)) {
13 fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %s: expected \"%s\", got \"%s\"\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, format, expected, result.chars);
14 exit(1);
15 }
16}
17
18#define VERIFY(format, argument, expected) verify((format), (argument), (expected), __LINE__)
19
20int main(void) {
21 instance.config.display.pipe = true;
22
23 {
24 VERIFY("output({})", "12345 67890", "output(12345 67890)");
25 VERIFY("output({1})", "12345 67890", "output(12345 67890)");
26 VERIFY("output({})", "", "output()");
27 VERIFY("output({1})", "", "output()");
28 }
29
30 {
31 VERIFY("output({1:20})", "12345 67890", "output(12345 67890)");
32 VERIFY("output({1:11})", "12345 67890", "output(12345 67890)");
33 VERIFY("output({1:-11})", "12345 67890", "output(12345 67890)");
34 VERIFY("output({1:6})", "12345 67890", "output(12345)");
35 VERIFY("output({:6})", "12345 67890", "output(12345)");
36 VERIFY("output({:-6})", "12345 67890", "output(12345…)");
37 VERIFY("output({:0})", "12345 67890", "output()");
38 VERIFY("output({:})", "12345 67890", "output()");
39 }
40
41 {
42 VERIFY("output({1<20})", "12345 67890", "output(12345 67890 )");
43 VERIFY("output({1<-20})", "12345 67890", "output(12345 67890 )");
44 VERIFY("output({1<11})", "12345 67890", "output(12345 67890)");
45 VERIFY("output({1<-11})", "12345 67890", "output(12345 67890)");
46 VERIFY("output({1<6})", "12345 67890", "output(12345 )");
47 VERIFY("output({<6})", "12345 67890", "output(12345 )");
48 VERIFY("output({<-6})", "12345 67890", "output(12345…)");
49 VERIFY("output({<0})", "12345 67890", "output()");
50 VERIFY("output({<})", "12345 67890", "output()");
51 }
52
53 {
54 VERIFY("output({1>20})", "12345 67890", "output( 12345 67890)");
55 VERIFY("output({1>-20})", "12345 67890", "output( 12345 67890)");
56 VERIFY("output({1>11})", "12345 67890", "output(12345 67890)");
57 VERIFY("output({1>-11})", "12345 67890", "output(12345 67890)");
58 VERIFY("output({1>6})", "12345 67890", "output(12345 )");
59 VERIFY("output({>6})", "12345 67890", "output(12345 )");
60 VERIFY("output({>-6})", "12345 67890", "output(12345…)");
61 VERIFY("output({>0})", "12345 67890", "output()");
62 VERIFY("output({>})", "12345 67890", "output()");
63 }
64
65 {
66 VERIFY("output({1|20})", "12345 67890", "output( 12345 67890 )");
67 VERIFY("output({1|-20})", "12345 67890", "output( 12345 67890 )");
68 VERIFY("output({1|11})", "12345 67890", "output(12345 67890)");
69 VERIFY("output({1|-11})", "12345 67890", "output(12345 67890)");
70 VERIFY("output({1|6})", "12345 67890", "output(12345 )");
71 VERIFY("output({|6})", "12345 67890", "output(12345 )");
72 VERIFY("output({|-6})", "12345 67890", "output(12345…)");
73 VERIFY("output({|0})", "12345 67890", "output()");
74 VERIFY("output({|})", "12345 67890", "output()");
75 }
76
77 {
78 VERIFY("output({1n>20})", "12345 67890", "output({1n>20})");
79 VERIFY("output({120})", "12345 67890", "output({120})");
80 VERIFY("output({1:11})", "", "output()");
81 VERIFY("output({2:2})", "", "output({2:2})");
82 }
83
84 {
85 VERIFY("output({1~0})", "12345 67890", "output(12345 67890)");
86 VERIFY("output({1~1})", "12345 67890", "output(2345 67890)");
87 VERIFY("output({1~10})", "12345 67890", "output(0)");
88 VERIFY("output({1~20})", "12345 67890", "output()");
89 VERIFY("output({1~-5})", "12345 67890", "output(67890)");
90 VERIFY("output({1~-50})", "12345 67890", "output()");
91 VERIFY("output({1~0,1})", "12345 67890", "output(1)");
92 VERIFY("output({1~0,6})", "12345 67890", "output(12345 )");
93 VERIFY("output({1~0,10})", "12345 67890", "output(12345 6789)");
94 VERIFY("output({1~5,10})", "12345 67890", "output( 6789)");
95 VERIFY("output({1~5,100})", "12345 67890", "output( 67890)");
96 VERIFY("output({1~10,10})", "12345 67890", "output()");
97 VERIFY("output({1~10,5})", "12345 67890", "output()");
98 VERIFY("output({1~3,-3})", "12345 67890", "output(45 67)");
99 VERIFY("output({1~-5,-3})", "12345 67890", "output(67)");
100 VERIFY("output({1~-0,10})", "12345 67890", "output(12345 6789)");
101 VERIFY("output({1~-3,-5})", "12345 67890", "output()");
102 VERIFY("output({1~})", "12345 67890", "output(12345 67890)"); // Same as {1~0}
103 VERIFY("output({1~-0})", "12345 67890", "output(12345 67890)"); // Same as {1~0}
104 VERIFY("output({1~,-1})", "12345 67890", "output(12345 6789)"); // Same as {1~0,-1}
105 VERIFY("output({1~,})", "12345 67890", "output()"); // Same as {1~0,0}
106 }
107
108 {
109 VERIFY("output({1n~0})", "12345 67890", "output({1n~0})");
110 VERIFY("output({1~<0})", "12345 67890", "output({1~<0})");
111 VERIFY("output({1~-})", "12345 67890", "output({1~-})");
112 VERIFY("output({1~-,1})", "12345 67890", "output({1~-,1})");
113 VERIFY("output({1~0,,1})", "12345 67890", "output({1~0,,1})");
114 VERIFY("output({1~0,1,})", "12345 67890", "output({1~0,1,})");
115 VERIFY("output({1~,0,1})", "12345 67890", "output({1~,0,1})");
116 VERIFY("output({2,0})", "12345 67890", "output({2,0})");
117 }
118
119 {
120 VERIFY("output({1:20}{1<20}{1>20})", "12345 67890", "output(12345 6789012345 67890 12345 67890)");
121 VERIFY("output({?1}OK{?}{/1}NOT OK{/})", "12345 67890", "output(OK)");
122 VERIFY("output({?1}OK{?}{/1}NOT OK{/})", "", "output(NOT OK)");
123 }
124
125 {
126 VERIFY("output({1:3})", "\e[1m12345", "output(\e[1m123)");
127 VERIFY("output({1:-3})", "\e[1m12345", "output(\e[1m123…)");
128 VERIFY("output({1:3})", "\e[1m12345\e[m", "output(\e[1m123\e[m)");
129 VERIFY("output({1:-3})", "\e[1m12345\e[m", "output(\e[1m123…\e[m)");
130 }
131
132 {
133 VERIFY("output({1<8})", "\e[1m12345", "output(\e[1m12345 )");
134 VERIFY("output({1>8})", "\e[1m12345", "output(\e[1m 12345)");
135 VERIFY("output({1<8})", "\e[1m12345\e[m", "output(\e[1m12345 \e[m)");
136 VERIFY("output({1>8})", "\e[1m12345\e[m", "output(\e[1m 12345\e[m)");
137 VERIFY("output({1<1})", "\e[30;47m12345\e[m", "output(\e[30;47m1\e[m)");
138 VERIFY("output({1|8})", "\e[1m12345\e[m", "output(\e[1m 12345 \e[m)");
139 VERIFY("output({1|1})", "\e[30;47m12345\e[m", "output(\e[30;47m1\e[m)");
140 }
141
142 {
143 VERIFY("output({1~0})", "\e[1m12345", "output(\e[1m12345)");
144 VERIFY("output({1~1})", "\e[1m12345", "output(\e[1m2345)");
145 VERIFY("output({1~0})", "\e[1m12345\e[m", "output(\e[1m12345\e[m)");
146 VERIFY("output({1~1})", "\e[1m12345\e[m", "output(\e[1m2345\e[m)");
147 VERIFY("output({1~2})", "\e[30;47m12345\e[m", "output(\e[30;47m345\e[m)");
148 }
149
150 {
151 // All leading escape codes must be skipped, not just the first one
152 VERIFY("output({1:3})", "\e[31m\e[1m12345", "output(\e[31m\e[1m123)");
153 VERIFY("output({1:-3})", "\e[31m\e[1m12345", "output(\e[31m\e[1m123…)");
154 VERIFY("output({1<8})", "\e[31m\e[1m12345", "output(\e[31m\e[1m12345 )");
155 VERIFY("output({1~2})", "\e[31m\e[1m12345", "output(\e[31m\e[1m345)");
156
157 // ... and so must all trailing ones
158 VERIFY("output({1:3})", "\e[31m\e[1m12345\e[m\e[39m", "output(\e[31m\e[1m123\e[m\e[39m)");
159 VERIFY("output({1~2})", "\e[31m\e[1m12345\e[m\e[39m", "output(\e[31m\e[1m345\e[m\e[39m)");
160 VERIFY("output({1<8})", "\e[31m\e[1m12345\e[m\e[39m", "output(\e[31m\e[1m12345 \e[m\e[39m)");
161
162 // `\e[?25l` is a complete CSI sequence, not just `\e[?`
163 VERIFY("output({1:3})", "\e[?25l12345", "output(\e[?25l123)");
164 VERIFY("output({1~4})", "\e[?25l12345", "output(\e[?25l5)");
165 }
166
167#ifndef _WIN32 // Windows doesn't have setenv
168 {
169 ffListInit(&instance.config.display.constants);
170 ffStrbufInitStatic(FF_LIST_ADD(FFstrbuf, instance.config.display.constants), "CONST1");
171 ffStrbufInitStatic(FF_LIST_ADD(FFstrbuf, instance.config.display.constants), "CONST2");
172 setenv("FF_TEST", "ENVVAR", 1);
173 VERIFY("output({$FF_TEST})", "", "output(ENVVAR)");
174 VERIFY("output({$1})", "", "output(CONST1)");
175 VERIFY("output({$FF_TEST}{$1})", "", "output(ENVVARCONST1)");
176 VERIFY("output({$1}{$FF_TEST})", "", "output(CONST1ENVVAR)");
177 VERIFY("output({$FF_TEST}{$FF_TEST})", "", "output(ENVVARENVVAR)");
178 VERIFY("output({$1}{$-1})", "", "output(CONST1CONST2)");
179
180 VERIFY("output({$FF_INVAL})", "", "output({$FF_INVAL})");
181 VERIFY("output({$9}{$0}${-9})", "", "output({$9}{$0}${-9})");
182 VERIFY("output({$1NO})", "", "output({$1NO})");
183 ffListDestroy(&instance.config.display.constants);
184 }
185#endif
186
187 // Success
188 puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
189}