dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 99.9% 3039 / 1 / 3041
Functions: 100.0% 115 / 0 / 115
Branches: 99.1% 107 / 42 / 150

test/util.c
Line Branch Exec Source
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <limits.h>
4 #include <locale.h>
5 #include <signal.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include "test.h"
11 #include "util/arith.h"
12 #include "util/array.h"
13 #include "util/ascii.h"
14 #include "util/base64.h"
15 #include "util/bit.h"
16 #include "util/fd.h"
17 #include "util/fork-exec.h"
18 #include "util/hashmap.h"
19 #include "util/hashset.h"
20 #include "util/intern.h"
21 #include "util/intmap.h"
22 #include "util/list.h"
23 #include "util/log.h"
24 #include "util/numtostr.h"
25 #include "util/path.h"
26 #include "util/progname.h"
27 #include "util/ptr-array.h"
28 #include "util/readfile.h"
29 #include "util/str-array.h"
30 #include "util/str-util.h"
31 #include "util/string-view.h"
32 #include "util/string.h"
33 #include "util/strtonum.h"
34 #include "util/time-util.h"
35 #include "util/unicode.h"
36 #include "util/utf8.h"
37 #include "util/xmalloc.h"
38 #include "util/xmemmem.h"
39 #include "util/xmemrchr.h"
40 #include "util/xreadwrite.h"
41 #include "util/xsnprintf.h"
42 #include "util/xstdio.h"
43
44 1 static void test_util_macros(TestContext *ctx)
45 {
46 1 EXPECT_EQ(STRLEN(""), 0);
47 1 EXPECT_EQ(STRLEN("a"), 1);
48 1 EXPECT_EQ(STRLEN("123456789"), 9);
49
50 1 EXPECT_EQ(BITSIZE(char), 8);
51 1 EXPECT_EQ(BITSIZE(uint16_t), 16);
52 1 EXPECT_EQ(BITSIZE(uint32_t), 32);
53 1 EXPECT_EQ(BITSIZE(uint64_t), 64);
54 1 EXPECT_EQ(BITSIZE("123456789"), sizeof("123456789") * 8);
55
56 1 EXPECT_EQ(HEX_STR_MAX(char), sizeof("FF") + 1);
57 1 EXPECT_EQ(HEX_STR_MAX(uint16_t), sizeof("FFFF") + 1);
58 1 EXPECT_EQ(HEX_STR_MAX(uint32_t), sizeof("FFFFFFFF") + 1);
59 1 EXPECT_EQ(HEX_STR_MAX(uint64_t), sizeof("FFFFFFFFFFFFFFFF") + 1);
60
61 1 EXPECT_TRUE(DECIMAL_STR_MAX(char) >= sizeof("255"));
62 1 EXPECT_TRUE(DECIMAL_STR_MAX(uint16_t) >= sizeof("65535"));
63 1 EXPECT_TRUE(DECIMAL_STR_MAX(uint32_t) >= sizeof("4294967295"));
64 1 EXPECT_TRUE(DECIMAL_STR_MAX(uint64_t) >= sizeof("18446744073709551615"));
65
66 1 EXPECT_EQ(ARRAYLEN(""), 1);
67 1 EXPECT_EQ(ARRAYLEN("a"), 2);
68 1 EXPECT_EQ(ARRAYLEN("123456789"), 10);
69
70 1 UNUSED const char a2[] = {1, 2};
71 1 UNUSED const int a3[] = {1, 2, 3};
72 1 UNUSED const long long a4[] = {1, 2, 3, 4};
73 1 EXPECT_EQ(ARRAYLEN(a2), 2);
74 1 EXPECT_EQ(ARRAYLEN(a3), 3);
75 1 EXPECT_EQ(ARRAYLEN(a4), 4);
76
77 1 EXPECT_EQ(MIN(0, 1), 0);
78 1 EXPECT_EQ(MIN(99, 100), 99);
79 1 EXPECT_EQ(MIN(-10, 10), -10);
80
81 1 EXPECT_EQ(MIN3(2, 1, 0), 0);
82 1 EXPECT_EQ(MIN3(10, 20, 30), 10);
83 1 EXPECT_EQ(MIN3(10, 20, -10), -10);
84
85 1 EXPECT_EQ(MAX(0, 1), 1);
86 1 EXPECT_EQ(MAX(99, 100), 100);
87 1 EXPECT_EQ(MAX(-10, 10), 10);
88
89 1 EXPECT_EQ(MAX4(1, 2, 3, 4), 4);
90 1 EXPECT_EQ(MAX4(4, 3, 2, 1), 4);
91 1 EXPECT_EQ(MAX4(-10, 10, 0, -20), 10);
92 1 EXPECT_EQ(MAX4(40, 41, 42, 41), 42);
93 1 EXPECT_EQ(MAX4(-10, -20, -50, -80), -10);
94
95 1 EXPECT_EQ(CLAMP(1, 50, 100), 50);
96 1 EXPECT_EQ(CLAMP(200, 50, 100), 100);
97 1 EXPECT_EQ(CLAMP(200, 100, 50), 50); // Invalid edge case (lo > hi)
98 1 EXPECT_EQ(CLAMP(-55, 50, 100), 50);
99 1 EXPECT_EQ(CLAMP(10, -10, -20), -20); // lo > hi
100 1 EXPECT_EQ(CLAMP(10, -20, -10), -10);
101 1 EXPECT_EQ(CLAMP(-15, -10, -20), -20); // lo > hi
102 1 EXPECT_EQ(CLAMP(-15, -20, -10), -15);
103
104 1 EXPECT_TRUE(VERSION_GE(0, 0, 0, 0));
105 1 EXPECT_TRUE(VERSION_GE(1, 0, 0, 0));
106 1 EXPECT_TRUE(VERSION_GE(4, 1, 4, 1));
107 1 EXPECT_TRUE(VERSION_GE(4, 2, 4, 1));
108 1 EXPECT_FALSE(VERSION_GE(0, 1, 1, 0));
109 1 EXPECT_FALSE(VERSION_GE(0, 9, 1, 0));
110 1 EXPECT_FALSE(VERSION_GE(4, 0, 4, 1));
111
112 1 EXPECT_UINT_EQ(UNSIGNED_MAX_VALUE(123U), UINT_MAX);
113 1 EXPECT_UINT_EQ(UNSIGNED_MAX_VALUE(456UL), ULONG_MAX);
114 1 EXPECT_UINT_EQ(UNSIGNED_MAX_VALUE(789ULL), ULLONG_MAX);
115 1 EXPECT_UINT_EQ(UNSIGNED_MAX_VALUE((size_t)123), SIZE_MAX);
116 1 EXPECT_UINT_EQ(UNSIGNED_MAX_VALUE((uintmax_t)456), UINTMAX_MAX);
117
118 1 int n = snprintf(NULL, 0, "%d", INT_MIN);
119 1 EXPECT_TRUE(n >= STRLEN("-2147483647"));
120 1 EXPECT_TRUE(DECIMAL_STR_MAX(int) > n);
121 1 n = snprintf(NULL, 0, "%llu", ULLONG_MAX);
122 1 EXPECT_TRUE(n >= STRLEN("18446744073709551615"));
123 1 EXPECT_TRUE(DECIMAL_STR_MAX(unsigned long long) > n);
124 1 }
125
126 1 static void test_is_power_of_2(TestContext *ctx)
127 {
128 1 EXPECT_TRUE(IS_POWER_OF_2(1));
129 1 EXPECT_TRUE(IS_POWER_OF_2(2));
130 1 EXPECT_TRUE(IS_POWER_OF_2(4));
131 1 EXPECT_TRUE(IS_POWER_OF_2(8));
132 1 EXPECT_TRUE(IS_POWER_OF_2(4096));
133 1 EXPECT_TRUE(IS_POWER_OF_2(8192));
134 1 EXPECT_TRUE(IS_POWER_OF_2(1ULL << 63));
135
136 1 EXPECT_FALSE(IS_POWER_OF_2(0));
137 1 EXPECT_FALSE(IS_POWER_OF_2(3));
138 1 EXPECT_FALSE(IS_POWER_OF_2(5));
139 1 EXPECT_FALSE(IS_POWER_OF_2(6));
140 1 EXPECT_FALSE(IS_POWER_OF_2(7));
141 1 EXPECT_FALSE(IS_POWER_OF_2(12));
142 1 EXPECT_FALSE(IS_POWER_OF_2(15));
143 1 EXPECT_FALSE(IS_POWER_OF_2(-2));
144 1 EXPECT_FALSE(IS_POWER_OF_2(-10));
145
146 1 const uintmax_t max_pow2 = ~(UINTMAX_MAX >> 1);
147 1 EXPECT_TRUE(max_pow2 >= 1ULL << 63);
148 1 EXPECT_TRUE(IS_POWER_OF_2(max_pow2));
149 1 EXPECT_UINT_EQ(max_pow2 << 1, 0);
150
151
2/2
✓ Branch 37 → 22 taken 61 times.
✓ Branch 37 → 38 taken 1 time.
63 for (uintmax_t i = max_pow2; i > 4; i >>= 1) {
152 61 EXPECT_TRUE(IS_POWER_OF_2(i));
153
2/2
✓ Branch 35 → 26 taken 183 times.
✓ Branch 35 → 36 taken 61 times.
305 for (uintmax_t j = 1; j < 4; j++) {
154 366 EXPECT_FALSE(IS_POWER_OF_2(i + j));
155 366 EXPECT_FALSE(IS_POWER_OF_2(i - j));
156 }
157 }
158 1 }
159
160 // Note: some of these tests are more for the sake of AddressSanitizer
161 // coverage than making actual assertions about the code
162 1 static void test_xmalloc(TestContext *ctx)
163 {
164 1 char *str = xmalloc(8);
165 1 ASSERT_NONNULL(str);
166 1 memcpy(str, "1234567", 8);
167 1 EXPECT_STREQ(str, "1234567");
168 1 free(str);
169
170 1 str = xstrdup("foobar");
171 1 EXPECT_STREQ(str, "foobar");
172 1 free(str);
173
174 1 str = xasprintf("%s %d", "xyz", 12340);
175 1 EXPECT_STREQ(str, "xyz 12340");
176 1 free(str);
177
178 1 str = xcalloc(4, 1);
179 1 ASSERT_NONNULL(str);
180 1 EXPECT_MEMEQ(str, 4, "\0\0\0\0", 4);
181 1 free(str);
182
183 1 str = xcalloc1(4);
184 1 ASSERT_NONNULL(str);
185 1 EXPECT_MEMEQ(str, 4, "\0\0\0\0", 4);
186 1 free(str);
187
188 1 str = xstrslice("one two three", 4, 7);
189 1 EXPECT_STREQ(str, "two");
190 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice("one two three", 4, 7), str);
191 1 free(str);
192
193 1 str = xstrjoin("foo", "-bar");
194 1 EXPECT_STREQ(str, "foo-bar");
195 1 free(str);
196
197 1 str = xmemjoin3(STRN("123"), STRN("::"), STRN("456") + 1);
198 1 EXPECT_STREQ(str, "123::456");
199 1 free(str);
200
201 1 str = xmemjoin4(STRN("AA"), STRN("BB"), STRN("CC"), STRN("DD") + 1);
202 1 EXPECT_STREQ(str, "AABBCCDD");
203 1 free(str);
204
205 // All xmemjoin*() functions allow NULL pointers when the corresponding
206 // length argument is 0, but the sum of all lengths must be at least 1,
207 // otherwise the BUG_ON() assertion in xmalloc() will fail
208 1 str = xmemjoin4(NULL, 0, NULL, 0, NULL, 0, "", 1);
209 1 EXPECT_STREQ(str, "");
210 1 free(str);
211
212 1 str = xcalloc(4, sizeof(str[0]));
213 1 ASSERT_NONNULL(str);
214 1 EXPECT_EQ(str[3], 0);
215 1 str = xrenew(str, 64);
216 1 ASSERT_NONNULL(str);
217 1 str[63] = 'p';
218 1 EXPECT_EQ(str[63], 'p');
219 1 free(str);
220 1 }
221
222 1 static void test_xstreq(TestContext *ctx)
223 {
224 1 EXPECT_TRUE(xstreq("foo", "foo"));
225 1 EXPECT_TRUE(xstreq("foo\0\n", "foo\0\0"));
226 1 EXPECT_TRUE(xstreq("\0foo", "\0bar"));
227 1 EXPECT_TRUE(xstreq(NULL, NULL));
228 1 EXPECT_FALSE(xstreq("foo", "bar"));
229 1 EXPECT_FALSE(xstreq("abc", "abcd"));
230 1 EXPECT_FALSE(xstreq("abcd", "abc"));
231 1 EXPECT_FALSE(xstreq(NULL, ""));
232 1 EXPECT_FALSE(xstreq("", NULL));
233 1 }
234
235 1 static void test_xstrrchr(TestContext *ctx)
236 {
237 1 static const char str[] = "12345432";
238 1 EXPECT_PTREQ(xstrrchr(str, '1'), str);
239 1 EXPECT_PTREQ(xstrrchr(str, '2'), str + 7);
240 1 EXPECT_PTREQ(xstrrchr(str, '5'), str + 4);
241 1 EXPECT_PTREQ(xstrrchr(str, '\0'), str + sizeof(str) - 1);
242 1 }
243
244 1 static void test_xmempcpy(TestContext *ctx)
245 {
246 1 char buf[16] = "12345678";
247 1 EXPECT_PTREQ(xmempcpy4(buf, NULL, 0, NULL, 0, NULL, 0, NULL, 0), buf);
248 1 EXPECT_STREQ(buf, "12345678");
249
250 1 EXPECT_PTREQ(xmempcpy4(buf, "a", 1, "b", 1, "c", 1, "d", 2), buf + 5);
251 1 EXPECT_STREQ(buf, "abcd");
252 1 }
253
254 1 static void test_str_has_sv_prefix(TestContext *ctx)
255 {
256 1 EXPECT_TRUE(str_has_sv_prefix("xyz", strview("xyz")));
257 1 EXPECT_FALSE(str_has_sv_prefix("xyz", strview("x.z")));
258 1 EXPECT_TRUE(str_has_sv_prefix("12345678", string_view("1234..", 4)));
259 1 EXPECT_FALSE(str_has_sv_prefix("12345678", string_view("1234..", 5)));
260 1 EXPECT_TRUE(str_has_sv_prefix("x", strview("")));
261 1 EXPECT_TRUE(str_has_sv_prefix("", strview("")));
262 1 EXPECT_TRUE(str_has_sv_prefix("foo", string_view("bar", 0)));
263 1 EXPECT_FALSE(str_has_sv_prefix("foo", string_view("bar", 3)));
264 1 EXPECT_FALSE(str_has_sv_prefix("aaa", string_view("aaa", 4)));
265 1 }
266
267 1 static void test_str_has_prefix(TestContext *ctx)
268 {
269 1 EXPECT_TRUE(str_has_prefix("foo", "foo"));
270 1 EXPECT_TRUE(str_has_prefix("foobar", "foo"));
271 1 EXPECT_TRUE(str_has_prefix("xyz", "xy"));
272 1 EXPECT_TRUE(str_has_prefix("a", "a"));
273 1 EXPECT_FALSE(str_has_prefix("foobar", "bar"));
274 1 EXPECT_FALSE(str_has_prefix("foo", "foobar"));
275 1 EXPECT_FALSE(str_has_prefix("xyz", "xyz."));
276 1 EXPECT_FALSE(str_has_prefix("ab", "b"));
277 1 EXPECT_FALSE(str_has_prefix("123", "xyz"));
278 1 }
279
280 1 static void test_hex_decode(TestContext *ctx)
281 {
282 1 EXPECT_EQ(hex_decode('0'), 0);
283 1 EXPECT_EQ(hex_decode('1'), 1);
284 1 EXPECT_EQ(hex_decode('9'), 9);
285 1 EXPECT_EQ(hex_decode('a'), 10);
286 1 EXPECT_EQ(hex_decode('A'), 10);
287 1 EXPECT_EQ(hex_decode('f'), 15);
288 1 EXPECT_EQ(hex_decode('F'), 15);
289 1 EXPECT_EQ(hex_decode('g'), HEX_INVALID);
290 1 EXPECT_EQ(hex_decode('G'), HEX_INVALID);
291 1 EXPECT_EQ(hex_decode('o'), HEX_INVALID);
292 1 EXPECT_EQ(hex_decode('p'), HEX_INVALID);
293 1 EXPECT_EQ(hex_decode('q'), HEX_INVALID);
294 1 EXPECT_EQ(hex_decode('`'), HEX_INVALID);
295 1 EXPECT_EQ(hex_decode('@'), HEX_INVALID);
296 1 EXPECT_EQ(hex_decode('/'), HEX_INVALID);
297 1 EXPECT_EQ(hex_decode(':'), HEX_INVALID);
298 1 EXPECT_EQ(hex_decode(' '), HEX_INVALID);
299 1 EXPECT_EQ(hex_decode('~'), HEX_INVALID);
300 1 EXPECT_EQ(hex_decode('\0'), HEX_INVALID);
301 1 EXPECT_EQ(hex_decode(0xFF), HEX_INVALID);
302
303
2/2
✓ Branch 25 → 23 taken 10 times.
✓ Branch 25 → 29 taken 1 time.
12 for (unsigned int i = '0'; i <= '9'; i++) {
304 10 IEXPECT_EQ(hex_decode(i), i - '0');
305 }
306
307
2/2
✓ Branch 29 → 26 taken 6 times.
✓ Branch 29 → 35 taken 1 time.
7 for (unsigned int i = 'A'; i <= 'F'; i++) {
308 6 unsigned int expected = 10 + (i - 'A');
309 6 IEXPECT_EQ(hex_decode(i), expected);
310 6 IEXPECT_EQ(hex_decode(ascii_tolower(i)), expected);
311 }
312
313
2/2
✓ Branch 35 → 30 taken 256 times.
✓ Branch 35 → 36 taken 1 time.
257 for (unsigned int i = 0; i < 256; i++) {
314 256 unsigned int decoded = hex_decode(i);
315
4/4
✓ Branch 30 → 31 taken 62 times.
✓ Branch 30 → 33 taken 194 times.
✓ Branch 31 → 32 taken 22 times.
✓ Branch 31 → 33 taken 40 times.
256 bool is_hex = ascii_isalnum(i) && ascii_toupper(i) <= 'F';
316 256 IEXPECT_EQ(decoded, is_hex ? (decoded & 0xF) : HEX_INVALID);
317 }
318 1 }
319
320 1 static void test_hex_encode_byte(TestContext *ctx)
321 {
322 1 char buf[4] = "";
323 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0x00), "00", 2);
324 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0x05), "05", 2);
325 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0x10), "10", 2);
326 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0x1b), "1b", 2);
327 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0xee), "ee", 2);
328 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0xfe), "fe", 2);
329 1 EXPECT_MEMEQ(buf, hex_encode_byte(buf, 0xff), "ff", 2);
330 1 }
331
332 1 static void test_ascii(TestContext *ctx)
333 {
334 1 EXPECT_EQ(ascii_tolower('A'), 'a');
335 1 EXPECT_EQ(ascii_tolower('F'), 'f');
336 1 EXPECT_EQ(ascii_tolower('Z'), 'z');
337 1 EXPECT_EQ(ascii_tolower('a'), 'a');
338 1 EXPECT_EQ(ascii_tolower('f'), 'f');
339 1 EXPECT_EQ(ascii_tolower('z'), 'z');
340 1 EXPECT_EQ(ascii_tolower('9'), '9');
341 1 EXPECT_EQ(ascii_tolower('~'), '~');
342 1 EXPECT_EQ(ascii_tolower('\0'), '\0');
343
344 1 EXPECT_EQ(ascii_toupper('a'), 'A');
345 1 EXPECT_EQ(ascii_toupper('f'), 'F');
346 1 EXPECT_EQ(ascii_toupper('z'), 'Z');
347 1 EXPECT_EQ(ascii_toupper('A'), 'A');
348 1 EXPECT_EQ(ascii_toupper('F'), 'F');
349 1 EXPECT_EQ(ascii_toupper('Z'), 'Z');
350 1 EXPECT_EQ(ascii_toupper('9'), '9');
351 1 EXPECT_EQ(ascii_toupper('~'), '~');
352 1 EXPECT_EQ(ascii_toupper('\0'), '\0');
353
354 1 EXPECT_TRUE(ascii_isspace(' '));
355 1 EXPECT_TRUE(ascii_isspace('\t'));
356 1 EXPECT_TRUE(ascii_isspace('\r'));
357 1 EXPECT_TRUE(ascii_isspace('\n'));
358 1 EXPECT_FALSE(ascii_isspace('\v')); // (differs from POSIX)
359 1 EXPECT_FALSE(ascii_isspace('\f')); // (differs from POSIX)
360 1 EXPECT_FALSE(ascii_isspace('\0'));
361 1 EXPECT_FALSE(ascii_isspace('a'));
362 1 EXPECT_FALSE(ascii_isspace(0x7F));
363 1 EXPECT_FALSE(ascii_isspace(0x80));
364
365 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=cntrl,-%3Calert
366 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=may%20add%20additional%20characters
367 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap06.html
368 1 EXPECT_TRUE(ascii_iscntrl('\0')); // <NUL>
369 1 EXPECT_TRUE(ascii_iscntrl('\a')); // <alert>, <BEL>
370 1 EXPECT_TRUE(ascii_iscntrl('\b')); // <backspace>, <BS>
371 1 EXPECT_TRUE(ascii_iscntrl('\t')); // <tab>, <HT>
372 1 EXPECT_TRUE(ascii_iscntrl('\n')); // <newline>, <LF>
373 1 EXPECT_TRUE(ascii_iscntrl('\v')); // <vertical-tab>, <VT>
374 1 EXPECT_TRUE(ascii_iscntrl('\f')); // <form-feed>, <FF>
375 1 EXPECT_TRUE(ascii_iscntrl('\r')); // <carriage-return>, <CR>
376 1 EXPECT_TRUE(ascii_iscntrl(0x0E)); // <SO>
377 1 EXPECT_TRUE(ascii_iscntrl(0x1F)); // <IS1>, <US>
378 1 EXPECT_TRUE(ascii_iscntrl(0x7F)); // <DEL>
379 1 EXPECT_FALSE(ascii_iscntrl(' ')); // <space>
380 1 EXPECT_FALSE(ascii_iscntrl('a')); // <a>
381 1 EXPECT_FALSE(ascii_iscntrl('~')); // <tilde>
382 1 EXPECT_FALSE(ascii_iscntrl(0x80));
383 1 EXPECT_FALSE(ascii_iscntrl(0xFF));
384
385 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=cntrl,-%3Calert
386 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=space,-%3Ctab
387 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=may%20add%20additional%20characters
388 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap06.html
389 1 EXPECT_TRUE(ascii_is_nonspace_cntrl('\0')); // <NUL>
390 1 EXPECT_TRUE(ascii_is_nonspace_cntrl('\a')); // <alert>, <BEL>
391 1 EXPECT_TRUE(ascii_is_nonspace_cntrl('\b')); // <backspace>, <BS>
392 1 EXPECT_TRUE(ascii_is_nonspace_cntrl(0x0E)); // <SO>
393 1 EXPECT_TRUE(ascii_is_nonspace_cntrl(0x1F)); // <IS1>, <US>
394 1 EXPECT_TRUE(ascii_is_nonspace_cntrl(0x7F)); // <DEL>
395 1 EXPECT_TRUE(ascii_is_nonspace_cntrl('\v')); // <vertical-tab>, <VT> (differs from POSIX)
396 1 EXPECT_TRUE(ascii_is_nonspace_cntrl('\f')); // <form-feed>, <FF> (differs from POSIX)
397 1 EXPECT_FALSE(ascii_is_nonspace_cntrl('\t')); // <tab>, <HT>
398 1 EXPECT_FALSE(ascii_is_nonspace_cntrl('\n')); // <newline>, <LF>
399 1 EXPECT_FALSE(ascii_is_nonspace_cntrl('\r')); // <carriage-return>, <CR>
400 1 EXPECT_FALSE(ascii_is_nonspace_cntrl(' ')); // <space>
401 1 EXPECT_FALSE(ascii_is_nonspace_cntrl('a'));
402 1 EXPECT_FALSE(ascii_is_nonspace_cntrl(0x7E));
403 1 EXPECT_FALSE(ascii_is_nonspace_cntrl(0x80));
404 1 EXPECT_FALSE(ascii_is_nonspace_cntrl(0xFF));
405
406 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=punct,-%3Cexclamation
407 // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01:~:text=may%20add%20additional%20characters
408 1 EXPECT_TRUE(ascii_ispunct('!'));
409 1 EXPECT_TRUE(ascii_ispunct('"'));
410 1 EXPECT_TRUE(ascii_ispunct('#'));
411 1 EXPECT_TRUE(ascii_ispunct('$'));
412 1 EXPECT_TRUE(ascii_ispunct('%'));
413 1 EXPECT_TRUE(ascii_ispunct('&'));
414 1 EXPECT_TRUE(ascii_ispunct('\''));
415 1 EXPECT_TRUE(ascii_ispunct('('));
416 1 EXPECT_TRUE(ascii_ispunct(')'));
417 1 EXPECT_TRUE(ascii_ispunct('*'));
418 1 EXPECT_TRUE(ascii_ispunct('+'));
419 1 EXPECT_TRUE(ascii_ispunct(','));
420 1 EXPECT_TRUE(ascii_ispunct('-'));
421 1 EXPECT_TRUE(ascii_ispunct('.'));
422 1 EXPECT_TRUE(ascii_ispunct('/'));
423 1 EXPECT_TRUE(ascii_ispunct(':'));
424 1 EXPECT_TRUE(ascii_ispunct(';'));
425 1 EXPECT_TRUE(ascii_ispunct('<'));
426 1 EXPECT_TRUE(ascii_ispunct('='));
427 1 EXPECT_TRUE(ascii_ispunct('>'));
428 1 EXPECT_TRUE(ascii_ispunct('?'));
429 1 EXPECT_TRUE(ascii_ispunct('@'));
430 1 EXPECT_TRUE(ascii_ispunct('['));
431 1 EXPECT_TRUE(ascii_ispunct('\\'));
432 1 EXPECT_TRUE(ascii_ispunct(']'));
433 1 EXPECT_TRUE(ascii_ispunct('^'));
434 1 EXPECT_TRUE(ascii_ispunct('_'));
435 1 EXPECT_TRUE(ascii_ispunct('`'));
436 1 EXPECT_TRUE(ascii_ispunct('{'));
437 1 EXPECT_TRUE(ascii_ispunct('|'));
438 1 EXPECT_TRUE(ascii_ispunct('}'));
439 1 EXPECT_TRUE(ascii_ispunct('~'));
440 1 EXPECT_FALSE(ascii_ispunct(' '));
441 1 EXPECT_FALSE(ascii_ispunct('0'));
442 1 EXPECT_FALSE(ascii_ispunct('9'));
443 1 EXPECT_FALSE(ascii_ispunct('A'));
444 1 EXPECT_FALSE(ascii_ispunct('Z'));
445 1 EXPECT_FALSE(ascii_ispunct('a'));
446 1 EXPECT_FALSE(ascii_ispunct('z'));
447 1 EXPECT_FALSE(ascii_ispunct(0x00));
448 1 EXPECT_FALSE(ascii_ispunct(0x7F));
449 1 EXPECT_FALSE(ascii_ispunct(0xFF));
450
451 1 EXPECT_TRUE(ascii_isdigit('0'));
452 1 EXPECT_TRUE(ascii_isdigit('1'));
453 1 EXPECT_TRUE(ascii_isdigit('9'));
454 1 EXPECT_FALSE(ascii_isdigit('a'));
455 1 EXPECT_FALSE(ascii_isdigit('f'));
456 1 EXPECT_FALSE(ascii_isdigit('/'));
457 1 EXPECT_FALSE(ascii_isdigit(':'));
458 1 EXPECT_FALSE(ascii_isdigit('\0'));
459 1 EXPECT_FALSE(ascii_isdigit(0xFF));
460
461 1 EXPECT_TRUE(ascii_isprint(' '));
462 1 EXPECT_TRUE(ascii_isprint('!'));
463 1 EXPECT_TRUE(ascii_isprint('/'));
464 1 EXPECT_TRUE(ascii_isprint('a'));
465 1 EXPECT_TRUE(ascii_isprint('z'));
466 1 EXPECT_TRUE(ascii_isprint('0'));
467 1 EXPECT_TRUE(ascii_isprint('_'));
468 1 EXPECT_TRUE(ascii_isprint('~'));
469 1 EXPECT_FALSE(ascii_isprint('\0'));
470 1 EXPECT_FALSE(ascii_isprint('\t'));
471 1 EXPECT_FALSE(ascii_isprint('\n'));
472 1 EXPECT_FALSE(ascii_isprint('\r'));
473 1 EXPECT_FALSE(ascii_isprint(0x1F));
474 1 EXPECT_FALSE(ascii_isprint(0x7F));
475 1 EXPECT_FALSE(ascii_isprint(0x80));
476 1 EXPECT_FALSE(ascii_isprint(0xFF));
477
478 1 EXPECT_TRUE(is_word_byte('a'));
479 1 EXPECT_TRUE(is_word_byte('z'));
480 1 EXPECT_TRUE(is_word_byte('A'));
481 1 EXPECT_TRUE(is_word_byte('Z'));
482 1 EXPECT_TRUE(is_word_byte('0'));
483 1 EXPECT_TRUE(is_word_byte('9'));
484 1 EXPECT_TRUE(is_word_byte('_'));
485 1 EXPECT_TRUE(is_word_byte(0x80));
486 1 EXPECT_TRUE(is_word_byte(0xFF));
487 1 EXPECT_FALSE(is_word_byte('-'));
488 1 EXPECT_FALSE(is_word_byte('.'));
489 1 EXPECT_FALSE(is_word_byte(0x7F));
490 1 EXPECT_FALSE(is_word_byte(0x00));
491
492 1 EXPECT_TRUE(is_regex_special_char('$'));
493 1 EXPECT_TRUE(is_regex_special_char('('));
494 1 EXPECT_TRUE(is_regex_special_char(')'));
495 1 EXPECT_TRUE(is_regex_special_char('*'));
496 1 EXPECT_TRUE(is_regex_special_char('+'));
497 1 EXPECT_TRUE(is_regex_special_char('.'));
498 1 EXPECT_TRUE(is_regex_special_char('?'));
499 1 EXPECT_TRUE(is_regex_special_char('['));
500 1 EXPECT_TRUE(is_regex_special_char('^'));
501 1 EXPECT_TRUE(is_regex_special_char('{'));
502 1 EXPECT_TRUE(is_regex_special_char('|'));
503 1 EXPECT_TRUE(is_regex_special_char('\\'));
504 1 EXPECT_FALSE(is_regex_special_char('"'));
505 1 EXPECT_FALSE(is_regex_special_char('&'));
506 1 EXPECT_FALSE(is_regex_special_char(','));
507 1 EXPECT_FALSE(is_regex_special_char('0'));
508 1 EXPECT_FALSE(is_regex_special_char('@'));
509 1 EXPECT_FALSE(is_regex_special_char('A'));
510 1 EXPECT_FALSE(is_regex_special_char('\''));
511 1 EXPECT_FALSE(is_regex_special_char(']'));
512 1 EXPECT_FALSE(is_regex_special_char('_'));
513 1 EXPECT_FALSE(is_regex_special_char('z'));
514 1 EXPECT_FALSE(is_regex_special_char('}'));
515 1 EXPECT_FALSE(is_regex_special_char('~'));
516 1 EXPECT_FALSE(is_regex_special_char(0x00));
517 1 EXPECT_FALSE(is_regex_special_char(0x80));
518 1 EXPECT_FALSE(is_regex_special_char(0xFF));
519
520 1 EXPECT_TRUE(ascii_streq_icase("", ""));
521 1 EXPECT_TRUE(ascii_streq_icase("a", "a"));
522 1 EXPECT_TRUE(ascii_streq_icase("a", "A"));
523 1 EXPECT_TRUE(ascii_streq_icase("z", "Z"));
524 1 EXPECT_TRUE(ascii_streq_icase("cx", "CX"));
525 1 EXPECT_TRUE(ascii_streq_icase("ABC..XYZ", "abc..xyz"));
526 1 EXPECT_TRUE(ascii_streq_icase("Ctrl", "CTRL"));
527 1 EXPECT_FALSE(ascii_streq_icase("a", ""));
528 1 EXPECT_FALSE(ascii_streq_icase("", "a"));
529 1 EXPECT_FALSE(ascii_streq_icase("Ctrl+", "CTRL"));
530 1 EXPECT_FALSE(ascii_streq_icase("Ctrl", "CTRL+"));
531 1 EXPECT_FALSE(ascii_streq_icase("Ctrl", "Ctr"));
532 1 EXPECT_FALSE(ascii_streq_icase("Ctrl", "CtrM"));
533
534 1 EXPECT_EQ(ascii_strcmp_icase("", ""), 0);
535 1 EXPECT_EQ(ascii_strcmp_icase("A", "A"), 0);
536 1 EXPECT_EQ(ascii_strcmp_icase("xyz", ""), 'x');
537 1 EXPECT_EQ(ascii_strcmp_icase("", "xyz"), -'x');
538 1 EXPECT_EQ(ascii_strcmp_icase("xyz", "xy"), 'z');
539 1 EXPECT_EQ(ascii_strcmp_icase("xy", "xyz"), -'z');
540 1 EXPECT_EQ(ascii_strcmp_icase("\xFF", "\xFE"), 1);
541 1 EXPECT_EQ(ascii_strcmp_icase("\xFE", "\xFF"), -1);
542 1 EXPECT_EQ(ascii_strcmp_icase("\x80\xFF\xC1", "\x80\xFF\x01"), 0xC0);
543 1 EXPECT_EQ(ascii_strcmp_icase("\x80\xFF\x01", "\x80\xFF\xC1"), -0xC0);
544 1 EXPECT_EQ(ascii_strcmp_icase("\x80\xFF\x01", "\x80"), 0xFF);
545 1 EXPECT_EQ(ascii_strcmp_icase("\x80", "\x80\xFF\x01"), -0xFF);
546
547 // Query the current locale
548 1 const char *locale = setlocale(LC_CTYPE, NULL);
549 1 ASSERT_NONNULL(locale);
550
551 // Copy the locale string (which may be in static storage)
552 1 char *saved_locale = xstrdup(locale);
553
554 // Check that the ascii_is*() functions behave like their corresponding
555 // <ctype.h> macros, when in the standard C/POSIX locale.
556 // See also: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html#tag_07_03_01_01
557 1 ASSERT_NONNULL(setlocale(LC_CTYPE, "C"));
558
2/2
✓ Branch 260 → 225 taken 257 times.
✓ Branch 260 → 261 taken 1 time.
259 for (int i = -1; i < 256; i++) {
559 257 EXPECT_EQ(ascii_isalpha(i), !!isalpha(i));
560 257 EXPECT_EQ(ascii_isalnum(i), !!isalnum(i));
561 257 EXPECT_EQ(ascii_islower(i), !!islower(i));
562 257 EXPECT_EQ(ascii_isupper(i), !!isupper(i));
563 257 EXPECT_EQ(ascii_isdigit(i), !!isdigit(i));
564 257 EXPECT_EQ(ascii_isblank(i), !!isblank(i));
565 257 EXPECT_EQ(ascii_isprint(i), !!isprint(i));
566 257 EXPECT_EQ(ascii_isxdigit(i), !!isxdigit(i));
567 257 EXPECT_EQ(u_is_ascii_upper(i), !!isupper(i));
568 461 EXPECT_EQ(is_alpha_or_underscore(i), !!isalpha(i) || i == '_');
569 451 EXPECT_EQ(is_alnum_or_underscore(i), !!isalnum(i) || i == '_');
570
2/2
✓ Branch 242 → 243 taken 255 times.
✓ Branch 242 → 245 taken 2 times.
257 if (i != '\v' && i != '\f') {
571 255 EXPECT_EQ(ascii_isspace(i), !!isspace(i));
572 }
573
2/2
✓ Branch 244 → 245 taken 254 times.
✓ Branch 244 → 259 taken 1 time.
255 if (i != -1) {
574 321 EXPECT_EQ(is_word_byte(i), !!isalnum(i) || i == '_' || i >= 0x80);
575 256 EXPECT_EQ(ascii_tolower(i), tolower(i));
576 256 EXPECT_EQ(ascii_toupper(i), toupper(i));
577 }
578 }
579
580 // Restore the original locale
581 1 ASSERT_NONNULL(setlocale(LC_CTYPE, saved_locale));
582 1 free(saved_locale);
583 1 }
584
585 1 static void test_mem_equal(TestContext *ctx)
586 {
587 1 static const char s1[] = "abcxyz";
588 1 static const char s2[] = "abcXYZ";
589 1 EXPECT_TRUE(mem_equal(NULL, NULL, 0));
590 1 EXPECT_TRUE(mem_equal(s1, s2, 0));
591 1 EXPECT_TRUE(mem_equal(s1, s2, 1));
592 1 EXPECT_TRUE(mem_equal(s1, s2, 2));
593 1 EXPECT_TRUE(mem_equal(s1, s2, 3));
594 1 EXPECT_TRUE(mem_equal(s1 + 1, s2 + 1, 2));
595 1 EXPECT_TRUE(mem_equal(s1 + 6, s2 + 6, 1));
596 1 EXPECT_FALSE(mem_equal(s1, s2, 4));
597 1 EXPECT_FALSE(mem_equal(s1, s2, 5));
598 1 EXPECT_FALSE(mem_equal(s1, s2, 6));
599 1 EXPECT_FALSE(mem_equal(s1, s2, 7));
600 1 }
601
602 1 static void test_mem_equal_icase(TestContext *ctx)
603 {
604 1 static const char s1[8] = "Ctrl+Up";
605 1 static const char s2[8] = "CTRL+U_";
606 1 EXPECT_TRUE(mem_equal_icase(NULL, NULL, 0));
607 1 EXPECT_TRUE(mem_equal_icase(NULL, s1, 0));
608 1 EXPECT_TRUE(mem_equal_icase(s1, NULL, 0));
609 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 0));
610 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 1));
611 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 2));
612 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 3));
613 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 4));
614 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 5));
615 1 EXPECT_TRUE(mem_equal_icase(s1, s2, 6));
616 1 EXPECT_FALSE(mem_equal_icase(s1, s2, 7));
617 1 EXPECT_FALSE(mem_equal_icase(s1, s2, 8));
618 1 }
619
620 1 static void test_base64_decode(TestContext *ctx)
621 {
622 1 EXPECT_EQ(base64_decode('A'), 0);
623 1 EXPECT_EQ(base64_decode('Z'), 25);
624 1 EXPECT_EQ(base64_decode('a'), 26);
625 1 EXPECT_EQ(base64_decode('z'), 51);
626 1 EXPECT_EQ(base64_decode('0'), 52);
627 1 EXPECT_EQ(base64_decode('9'), 61);
628 1 EXPECT_EQ(base64_decode('+'), 62);
629 1 EXPECT_EQ(base64_decode('/'), 63);
630
631 1 EXPECT_EQ(base64_encode_table[0], 'A');
632 1 EXPECT_EQ(base64_encode_table[25], 'Z');
633 1 EXPECT_EQ(base64_encode_table[26], 'a');
634 1 EXPECT_EQ(base64_encode_table[51], 'z');
635 1 EXPECT_EQ(base64_encode_table[52], '0');
636 1 EXPECT_EQ(base64_encode_table[61], '9');
637 1 EXPECT_EQ(base64_encode_table[62], '+');
638 1 EXPECT_EQ(base64_encode_table[63], '/');
639
640 1 EXPECT_EQ(base64_decode('='), BASE64_PADDING);
641 1 EXPECT_EQ(base64_decode(' '), BASE64_INVALID);
642 1 EXPECT_EQ(base64_decode('*'), BASE64_INVALID);
643 1 EXPECT_EQ(base64_decode(','), BASE64_INVALID);
644 1 EXPECT_EQ(base64_decode(':'), BASE64_INVALID);
645 1 EXPECT_EQ(base64_decode('?'), BASE64_INVALID);
646 1 EXPECT_EQ(base64_decode('@'), BASE64_INVALID);
647 1 EXPECT_EQ(base64_decode('['), BASE64_INVALID);
648 1 EXPECT_EQ(base64_decode('`'), BASE64_INVALID);
649 1 EXPECT_EQ(base64_decode('{'), BASE64_INVALID);
650 1 EXPECT_EQ(base64_decode('~'), BASE64_INVALID);
651 1 EXPECT_EQ(base64_decode('}'), BASE64_INVALID);
652 1 EXPECT_EQ(base64_decode(0), BASE64_INVALID);
653 1 EXPECT_EQ(base64_decode(127), BASE64_INVALID);
654 1 EXPECT_EQ(base64_decode(128), BASE64_INVALID);
655 1 EXPECT_EQ(base64_decode(255), BASE64_INVALID);
656
657
2/2
✓ Branch 37 → 35 taken 26 times.
✓ Branch 37 → 40 taken 1 time.
28 for (unsigned int i = 'A'; i <= 'Z'; i++) {
658 26 IEXPECT_EQ(base64_decode(i), i - 'A');
659 }
660
661
2/2
✓ Branch 40 → 38 taken 26 times.
✓ Branch 40 → 43 taken 1 time.
27 for (unsigned int i = 'a'; i <= 'z'; i++) {
662 26 IEXPECT_EQ(base64_decode(i), (i - 'a') + 26);
663 }
664
665
2/2
✓ Branch 43 → 41 taken 10 times.
✓ Branch 43 → 51 taken 1 time.
11 for (unsigned int i = '0'; i <= '9'; i++) {
666 10 IEXPECT_EQ(base64_decode(i), (i - '0') + 52);
667 }
668
669
2/2
✓ Branch 51 → 44 taken 256 times.
✓ Branch 51 → 52 taken 1 time.
257 for (unsigned int i = 0; i < 256; i++) {
670 256 unsigned int val = base64_decode(i);
671
4/4
✓ Branch 44 → 45 taken 194 times.
✓ Branch 44 → 46 taken 62 times.
✓ Branch 45 → 46 taken 2 times.
✓ Branch 45 → 48 taken 192 times.
256 if (ascii_isalnum(i) || i == '+' || i == '/') {
672 64 IEXPECT_EQ(val, val & 63);
673 64 IEXPECT_EQ(i, base64_encode_table[val & 63]);
674 } else {
675 192 IEXPECT_EQ(val, val & 192);
676 }
677 256 IEXPECT_EQ(val, base64_decode_branchy(i));
678 }
679 1 }
680
681 1 static void test_base64_encode_block(TestContext *ctx)
682 {
683 1 char buf[16];
684 1 size_t n = base64_encode_block(STRN("xyz"), buf, sizeof(buf));
685 1 EXPECT_MEMEQ(buf, n, "eHl6", 4);
686
687 1 n = base64_encode_block(STRN("123456"), buf, sizeof(buf));
688 1 EXPECT_MEMEQ(buf, n, "MTIzNDU2", 8);
689
690 1 n = base64_encode_block(STRN("a == *x++"), buf, sizeof(buf));
691 1 EXPECT_MEMEQ(buf, n, "YSA9PSAqeCsr", 12);
692 1 }
693
694 1 static void test_base64_encode_final(TestContext *ctx)
695 {
696 1 char buf[4];
697 1 base64_encode_final(STRN("+"), buf);
698 1 EXPECT_MEMEQ(buf, 4, "Kw==", 4);
699
700 1 base64_encode_final(STRN(".."), buf);
701 1 EXPECT_MEMEQ(buf, 4, "Li4=", 4);
702
703 1 base64_encode_final(STRN("~."), buf);
704 1 EXPECT_MEMEQ(buf, 4, "fi4=", 4);
705
706 1 base64_encode_final(STRN("\xC2\xA9"), buf);
707 1 EXPECT_MEMEQ(buf, 4, "wqk=", 4);
708 1 }
709
710 1 static void test_string(TestContext *ctx)
711 {
712 1 String s = STRING_INIT;
713 1 EXPECT_EQ(s.len, 0);
714 1 EXPECT_EQ(s.alloc, 0);
715 1 EXPECT_NULL(s.buffer);
716
717 1 char *cstr = string_clone_cstring(&s);
718 1 EXPECT_STREQ(cstr, "");
719 1 free(cstr);
720 1 EXPECT_EQ(s.len, 0);
721 1 EXPECT_EQ(s.alloc, 0);
722 1 EXPECT_NULL(s.buffer);
723
724 1 EXPECT_EQ(string_insert_codepoint(&s, 0, 0x1F4AF), 4);
725 1 EXPECT_STRING_EQ_CSTRING(&s, "\xF0\x9F\x92\xAF");
726 1 EXPECT_STREQ(string_borrow_cstring(&s), "\xF0\x9F\x92\xAF");
727
728 1 string_append_cstring(&s, "test");
729 1 EXPECT_STRING_EQ_CSTRING(&s, "\xF0\x9F\x92\xAFtest");
730
731 1 string_remove(&s, 0, 5);
732 1 EXPECT_EQ(s.len, 3);
733 1 EXPECT_STRING_EQ_CSTRING(&s, "est");
734
735 1 EXPECT_EQ(string_insert_codepoint(&s, 0, 't'), 1);
736 1 EXPECT_STRING_EQ_CSTRING(&s, "test");
737
738 1 EXPECT_EQ(string_clear(&s), 4);
739 1 EXPECT_EQ(s.len, 0);
740 1 EXPECT_EQ(string_insert_codepoint(&s, 0, 0x0E01), 3);
741 1 EXPECT_STRING_EQ_CSTRING(&s, "\xE0\xB8\x81");
742
743 1 EXPECT_EQ(string_clear(&s), 3);
744 1 string_sprintf(&s, "%d %s\n", 88, "test");
745 1 EXPECT_STRING_EQ_CSTRING(&s, "88 test\n");
746
747 1 string_free(&s);
748 1 EXPECT_EQ(s.len, 0);
749 1 EXPECT_EQ(s.alloc, 0);
750 1 EXPECT_NULL(s.buffer);
751
752
2/2
✓ Branch 40 → 38 taken 40 times.
✓ Branch 40 → 41 taken 1 time.
42 for (size_t i = 0; i < 40; i++) {
753 40 string_append_byte(&s, 'a');
754 }
755
756 1 EXPECT_EQ(s.len, 40);
757 1 cstr = string_steal_cstring(&s);
758 1 EXPECT_EQ(s.len, 0);
759 1 EXPECT_EQ(s.alloc, 0);
760 1 EXPECT_NULL(s.buffer);
761 1 EXPECT_STREQ(cstr, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
762 1 free(cstr);
763
764 1 s = string_new(12);
765 1 EXPECT_EQ(s.len, 0);
766 1 EXPECT_EQ3(s.alloc, 16, STRING_ALLOC_MULTIPLE);
767 1 ASSERT_NONNULL(s.buffer);
768
769 1 string_append_cstring(&s, "123");
770 1 EXPECT_STRING_EQ_CSTRING(&s, "123");
771
772 1 string_append_string(&s, &s);
773 1 EXPECT_STRING_EQ_CSTRING(&s, "123123");
774
775 1 string_insert_buf(&s, 2, STRN("foo"));
776 1 EXPECT_STRING_EQ_CSTRING(&s, "12foo3123");
777
778 1 cstr = string_clone_cstring(&s);
779 1 EXPECT_STREQ(cstr, "12foo3123");
780
781 1 EXPECT_EQ(string_insert_codepoint(&s, 0, '>'), 1);
782 1 EXPECT_STRING_EQ_CSTRING(&s, ">12foo3123");
783
784 1 string_replace_byte(&s, '1', '_');
785 1 EXPECT_STRING_EQ_CSTRING(&s, ">_2foo3_23");
786 1 string_replace_byte(&s, '_', '.');
787 1 string_replace_byte(&s, '2', '+');
788 1 string_replace_byte(&s, '3', '$');
789 1 EXPECT_STRING_EQ_CSTRING(&s, ">.+foo$.+$");
790
791 1 string_free(&s);
792 1 EXPECT_NULL(s.buffer);
793 1 EXPECT_EQ(s.len, 0);
794 1 EXPECT_EQ(s.alloc, 0);
795 1 EXPECT_STREQ(cstr, "12foo3123");
796 1 free(cstr);
797
798 1 EXPECT_STREQ(string_borrow_cstring(&s), "");
799 1 EXPECT_EQ(s.len, 0);
800 1 EXPECT_EQ3(s.alloc, 16, STRING_ALLOC_MULTIPLE);
801 1 EXPECT_NONNULL(s.buffer);
802 1 string_free(&s);
803
804 // This is mostly for UBSan coverage
805 // See also: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf
806 1 s = string_new(0);
807 1 EXPECT_NULL(s.buffer);
808 1 EXPECT_EQ(s.len, 0);
809 1 EXPECT_EQ(s.alloc, 0);
810 1 string_append_buf(&s, NULL, 0);
811 1 string_insert_buf(&s, 0, NULL, 0);
812 1 string_append_memset(&s, 'q', 0);
813 1 string_replace_byte(&s, 'q', 'z');
814 1 string_remove(&s, 0, 0);
815 1 EXPECT_NULL(s.buffer);
816 1 EXPECT_EQ(s.len, 0);
817 1 EXPECT_EQ(s.alloc, 0);
818 1 string_free(&s);
819
820 // string_sprintf() always reserves and writes at least 1 byte,
821 // for null-termination. This isn't strictly necessary and is only
822 // tested here for completeness.
823 1 string_sprintf(&s, "%s", "");
824 1 EXPECT_EQ3(s.alloc, 16, STRING_ALLOC_MULTIPLE);
825 1 string_free(&s);
826
827 1 s = string_new_from_buf(STRN("1234567"));
828 1 EXPECT_STRING_EQ_CSTRING(&s, "1234567");
829 1 EXPECT_EQ3(s.alloc, 16, STRING_ALLOC_MULTIPLE);
830 1 string_free(&s);
831 1 EXPECT_NULL(s.buffer);
832 1 EXPECT_EQ(s.len, 0);
833 1 EXPECT_EQ(s.alloc, 0);
834 1 }
835
836 1 static void test_string_next_alloc_size(TestContext *ctx)
837 {
838 1 static const size_t expected_alloc_sizes[] = {
839 0, 16, 32, 64,
840 112, 176, 272, 416,
841 640, 976, 1472, 2224,
842 3344, 5024, 7552, 11344,
843 17024, 25552, 38336, 57520,
844 };
845
846 1 EXPECT_TRUE(IS_POWER_OF_2(STRING_ALLOC_MULTIPLE));
847 1 size_t remainder_mask = STRING_ALLOC_MULTIPLE - 1;
848
849
2/2
✓ Branch 8 → 4 taken 19 times.
✓ Branch 8 → 9 taken 1 time.
21 for (size_t i = 1, size = 0; i < ARRAYLEN(expected_alloc_sizes); i++) {
850 19 size_t expected = expected_alloc_sizes[i];
851 19 EXPECT_EQ(expected & remainder_mask, 0);
852 19 size = string_next_alloc_size(size, size + 1);
853 19 EXPECT_EQ(size, expected);
854 }
855 1 }
856
857 1 static void test_string_view(TestContext *ctx)
858 {
859 1 StringView sv = strview("testing");
860 1 EXPECT_TRUE(strview_equal_cstring(sv, "testing"));
861 1 EXPECT_FALSE(strview_equal_cstring(sv, "testin"));
862 1 EXPECT_FALSE(strview_equal_cstring(sv, "TESTING"));
863 1 EXPECT_TRUE(strview_has_prefix(sv, "test"));
864 1 EXPECT_TRUE(strview_has_prefix_icase(sv, "TEst"));
865 1 EXPECT_FALSE(strview_has_prefix(sv, "TEst"));
866 1 EXPECT_FALSE(strview_has_prefix_icase(sv, "TEst_"));
867
868 1 sv = string_view(sv.data, sv.length);
869 1 EXPECT_TRUE(strview_equal(sv, sv));
870
871 1 sv = strview("foobar");
872 1 EXPECT_TRUE(strview_equal_cstring(sv, "foobar"));
873 1 EXPECT_TRUE(strview_has_prefix(sv, "foo"));
874 1 EXPECT_FALSE(strview_equal_cstring(sv, "foo"));
875
876 1 sv = strview("\t \t\t ");
877 1 EXPECT_TRUE(strview_isblank(sv));
878 1 sv.length = 0;
879 1 EXPECT_TRUE(strview_isblank(sv));
880 1 sv = strview(" \t . ");
881 1 EXPECT_FALSE(strview_isblank(sv));
882 1 sv = strview("\n");
883 1 EXPECT_FALSE(strview_isblank(sv));
884 1 sv = strview(" \r ");
885 1 EXPECT_FALSE(strview_isblank(sv));
886
887 1 sv = strview(" \t\t \ttrim test \t\t");
888 1 EXPECT_EQ(strview_trim(&sv), 9);
889 1 EXPECT_TRUE(strview_equal_cstring(sv, "trim test"));
890
891 1 sv = strview(NULL);
892 1 EXPECT_NULL(strview_memrchr(sv, '.'));
893 1 EXPECT_NULL(strview_memchr(sv, '.'));
894 1 EXPECT_TRUE(strview_equal(sv, sv));
895 1 EXPECT_TRUE(strview_equal_icase(sv, sv));
896 1 EXPECT_FALSE(strview_contains_char_type(sv, ASCII_DIGIT));
897 1 EXPECT_TRUE(strview_isblank(sv));
898 1 EXPECT_EQ(strview_trim_left(&sv), 0);
899 1 EXPECT_EQ(strview_trim_right(&sv), 0);
900 1 EXPECT_EQ(strview_trim(&sv), 0);
901 1 EXPECT_TRUE(strview_equal_cstring(sv, ""));
902 1 EXPECT_TRUE(strview_equal_icase(sv, strview("")));
903 1 EXPECT_TRUE(strview_has_prefix(sv, ""));
904 1 EXPECT_TRUE(strview_has_suffix(sv, ""));
905 1 EXPECT_TRUE(strview_has_prefix_icase(sv, ""));
906 1 EXPECT_EQ(strview_remove_prefix(&sv, 0), 0);
907 1 EXPECT_EQ(strview_remove_suffix(&sv, 0), 0);
908 1 EXPECT_NULL(sv.data);
909 1 EXPECT_EQ(sv.length, 0);
910
911 1 sv = strview("prefix - suffix");
912 1 EXPECT_PTREQ(strview_memchr(sv, '-'), strview_memrchr(sv, '-'));
913 1 EXPECT_PTREQ(strview_memchr(sv, 'x'), sv.data + 5);
914 1 EXPECT_PTREQ(strview_memrchr(sv, 'x'), sv.data + 14);
915 1 EXPECT_PTREQ(strview_memrchr(sv, '@'), NULL);
916 1 EXPECT_EQ(strview_memrchr_idx(sv, 'p'), 0);
917 1 EXPECT_EQ(strview_memrchr_idx(sv, 'x'), 14);
918 1 EXPECT_EQ(strview_memrchr_idx(sv, '@'), -1);
919 1 }
920
921 1 static void test_strview_has_suffix(TestContext *ctx)
922 {
923 1 EXPECT_TRUE(strview_has_suffix(strview("foo"), "foo"));
924 1 EXPECT_TRUE(strview_has_suffix(strview("foobar"), "bar"));
925 1 EXPECT_TRUE(strview_has_suffix(strview("1234"), "234"));
926 1 EXPECT_TRUE(strview_has_suffix(strview("x"), "x"));
927 1 EXPECT_TRUE(strview_has_suffix(strview("aa"), "a"));
928 1 EXPECT_FALSE(strview_has_suffix(strview("foobar."), "bar"));
929 1 EXPECT_FALSE(strview_has_suffix(strview("foo"), "foobar"));
930 1 EXPECT_FALSE(strview_has_suffix(strview("bar"), "foobar"));
931 1 EXPECT_FALSE(strview_has_suffix(strview("foo"), "bar"));
932 1 EXPECT_FALSE(strview_has_suffix(strview("bar"), "foo"));
933 1 EXPECT_FALSE(strview_has_suffix(strview("123"), "1234"));
934 1 EXPECT_FALSE(strview_has_suffix(strview("a"), "aa"));
935
936 1 StringView sv = strview("foobar");
937 1 EXPECT_TRUE(strview_has_suffix(sv, "foobar"));
938 1 EXPECT_TRUE(strview_has_suffix(sv, "bar"));
939 1 EXPECT_TRUE(strview_has_suffix(sv, "r"));
940 1 EXPECT_TRUE(strview_has_suffix(sv, ""));
941 1 EXPECT_FALSE(strview_has_suffix(sv, "foo"));
942 1 EXPECT_FALSE(strview_has_suffix(sv, "foobars"));
943
944 1 const StringView suffix = strview(NULL);
945 1 EXPECT_TRUE(strview_has_sv_suffix(sv, suffix));
946 1 EXPECT_TRUE(strview_has_sv_suffix(suffix, suffix));
947
948 1 sv.length--;
949 1 EXPECT_FALSE(strview_has_suffix(sv, "bar"));
950 1 EXPECT_TRUE(strview_has_suffix(sv, "ba"));
951 1 EXPECT_TRUE(strview_has_sv_suffix(sv, suffix));
952
953 1 sv.length = 0;
954 1 EXPECT_TRUE(strview_has_suffix(sv, ""));
955 1 EXPECT_FALSE(strview_has_suffix(sv, "f"));
956 1 EXPECT_TRUE(strview_has_sv_suffix(sv, suffix));
957
958 1 sv.data = NULL;
959 1 EXPECT_TRUE(strview_has_suffix(sv, ""));
960 1 EXPECT_FALSE(strview_has_suffix(sv, "f"));
961 1 EXPECT_TRUE(strview_has_sv_suffix(sv, suffix));
962 1 }
963
964 1 static void test_strview_remove_matching(TestContext *ctx)
965 {
966 1 StringView sv = strview("ABCDEFGHIJKLMN");
967 1 EXPECT_TRUE(strview_remove_matching_prefix(&sv, "ABC"));
968 1 EXPECT_STRVIEW_EQ_CSTRING(sv, "DEFGHIJKLMN");
969
970 1 EXPECT_TRUE(strview_remove_matching_suffix(&sv, "KLMN"));
971 1 EXPECT_STRVIEW_EQ_CSTRING(sv, "DEFGHIJ");
972
973 1 EXPECT_FALSE(strview_remove_matching_prefix(&sv, "A"));
974 1 EXPECT_FALSE(strview_remove_matching_suffix(&sv, "K"));
975 1 EXPECT_STRVIEW_EQ_CSTRING(sv, "DEFGHIJ");
976
977 1 EXPECT_TRUE(strview_remove_matching_prefix(&sv, ""));
978 1 EXPECT_STRVIEW_EQ_CSTRING(sv, "DEFGHIJ");
979
980 1 EXPECT_TRUE(strview_remove_matching_suffix(&sv, ""));
981 1 EXPECT_STRVIEW_EQ_CSTRING(sv, "DEFGHIJ");
982
983 1 sv.length = 0;
984 1 sv.data = NULL;
985 1 EXPECT_TRUE(strview_remove_matching_prefix(&sv, ""));
986 1 EXPECT_TRUE(strview_remove_matching_suffix(&sv, ""));
987 1 EXPECT_FALSE(strview_remove_matching_prefix(&sv, "pre"));
988 1 EXPECT_FALSE(strview_remove_matching_suffix(&sv, "suf"));
989 1 EXPECT_EQ(sv.length, 0);
990 1 EXPECT_NULL(sv.data);
991 1 EXPECT_STRVIEW_EQ_CSTRING(sv, "");
992 1 }
993
994 1 static void test_strview_from_slice(TestContext *ctx)
995 {
996 1 static const char src[] = "01234567890";
997 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice(NULL, 0, 0), "");
998 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice(src, 0, 0), "");
999 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice(src, 1, 1), "");
1000 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice(src, 2, 3), "2");
1001 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice(src, 3, 7), "3456");
1002 1 EXPECT_STRVIEW_EQ_CSTRING(strview_from_slice(src, 0, sizeof(src) - 1), src);
1003 1 }
1004
1005 1 static void test_get_delim(TestContext *ctx)
1006 {
1007 1 static const char input[] = "-x-y-foo--bar--";
1008 1 static const char parts[][4] = {"", "x", "y", "foo", "", "bar", "", ""};
1009 1 const size_t nparts = ARRAYLEN(parts);
1010 1 const size_t part_size = ARRAYLEN(parts[0]);
1011
1012 1 size_t idx = 0;
1013
2/2
✓ Branch 8 → 3 taken 7 times.
✓ Branch 8 → 9 taken 1 time.
8 for (size_t pos = 0, len = sizeof(input) - 1; pos < len; idx++) {
1014 7 const StringView sv = get_delim(input, &pos, len, '-');
1015 7 ASSERT_TRUE(idx < nparts);
1016 7 ASSERT_EQ(parts[idx][part_size - 1], '\0');
1017 7 EXPECT_STRVIEW_EQ_CSTRING(sv, parts[idx]);
1018 }
1019
1020 1 EXPECT_EQ(idx, nparts - 1);
1021 1 }
1022
1023 1 static void test_get_delim_str(TestContext *ctx)
1024 {
1025 1 char str[] = "word1-word2-end-";
1026 1 size_t len = sizeof(str) - 1;
1027 1 ASSERT_EQ(str[len - 1], '-'); // Last character in bounds is a delimiter
1028
1029 1 size_t pos = 0;
1030 1 const char *substr = get_delim_str(str, &pos, len, '-');
1031 1 EXPECT_STREQ(substr, "word1");
1032 1 EXPECT_EQ(pos, 6);
1033
1034 1 substr = get_delim_str(str, &pos, len, '-');
1035 1 EXPECT_STREQ(substr, "word2");
1036 1 EXPECT_EQ(pos, 12);
1037
1038 1 substr = get_delim_str(str, &pos, len, '-');
1039 1 EXPECT_STREQ(substr, "end");
1040 1 EXPECT_EQ(pos, 16);
1041
1042 // Note: str2 is not null-terminated and there are no delimiters present,
1043 // but there's one extra, writable byte in the buffer that falls outside
1044 // the length bound
1045 1 char str2[16] = "no delimiter...!";
1046 1 len = sizeof(str2) - 1;
1047 1 ASSERT_EQ(str2[len], '!');
1048 1 pos = 0;
1049 1 substr = get_delim_str(str2, &pos, len, '-');
1050 1 EXPECT_STREQ(substr, "no delimiter...");
1051 1 EXPECT_EQ(pos, len);
1052
1053 1 static const char after[] = "\0\0\0\0aa\0b\0c\0dd\0\0";
1054 1 char before[] = ",,,,aa,b,c,dd,,";
1055 1 unsigned int iters = 0;
1056 1 unsigned int width = 0;
1057
2/2
✓ Branch 19 → 17 taken 9 times.
✓ Branch 19 → 20 taken 1 time.
10 for (pos = 0, len = sizeof(before) - 1; pos < len; iters++) {
1058 9 width += strlen(get_delim_str(before, &pos, len, ','));
1059 }
1060 1 EXPECT_MEMEQ(before, sizeof(before), after, sizeof(after));
1061 1 EXPECT_EQ(width, 6);
1062 1 EXPECT_EQ(iters, 9);
1063 1 }
1064
1065 1 static void test_strn_replace_byte(TestContext *ctx)
1066 {
1067 1 static const char expected[] = "||a|b|c||\n\0\0|d|e|f|||\0g|h||\0\0";
1068 1 char str[] = /* ........... */ "..a.b.c..\n\0\0.d.e.f...\0g.h..\0\0";
1069 1 strn_replace_byte(str, sizeof(str), '.', '|');
1070 1 EXPECT_MEMEQ(str, sizeof(str), expected, sizeof(expected));
1071 1 }
1072
1073 1 static void test_string_array_concat(TestContext *ctx)
1074 {
1075 1 static const char *const strs[] = {"A", "B", "CC", "D", "EE"};
1076 1 char buf[64] = "\0";
1077 1 size_t nstrs = ARRAYLEN(strs);
1078
1079 1 StringView delim = strview(",");
1080 1 StringView expected = strview("A,B,CC,D,EE");
1081 1 ASSERT_TRUE(expected.length + 1 < sizeof(buf));
1082 1 memset(buf, '@', sizeof(buf) - 1);
1083 1 EXPECT_FALSE(string_array_concat_(buf, expected.length, strs, nstrs, delim));
1084 1 memset(buf, '@', sizeof(buf) - 1);
1085 1 EXPECT_TRUE(string_array_concat_(buf, expected.length + 1, strs, nstrs, delim));
1086 1 EXPECT_STRVIEW_EQ_CSTRING(expected, buf);
1087
1088 1 delim = strview(" ... ");
1089 1 expected = strview("A ... B ... CC ... D ... EE");
1090 1 ASSERT_TRUE(expected.length + 1 < sizeof(buf));
1091 1 memset(buf, '@', sizeof(buf) - 1);
1092 1 EXPECT_FALSE(string_array_concat_(buf, expected.length, strs, nstrs, delim));
1093 1 memset(buf, '@', sizeof(buf) - 1);
1094 1 EXPECT_TRUE(string_array_concat_(buf, expected.length + 1, strs, nstrs, delim));
1095 1 EXPECT_STRVIEW_EQ_CSTRING(expected, buf);
1096
1097
2/2
✓ Branch 18 → 15 taken 27 times.
✓ Branch 18 → 19 taken 1 time.
29 for (size_t i = 0; i < expected.length; i++) {
1098 27 EXPECT_FALSE(string_array_concat_(buf, expected.length - i, strs, nstrs, delim));
1099 }
1100
1101 1 memset(buf, '@', sizeof(buf) - 1);
1102 1 EXPECT_TRUE(string_array_concat_(buf, sizeof(buf), strs, 0, delim));
1103 1 EXPECT_STREQ(buf, "");
1104 1 }
1105
1106 1 static void test_size_str_width(TestContext *ctx)
1107 {
1108 1 EXPECT_EQ(size_str_width(0), 1);
1109 1 EXPECT_EQ(size_str_width(1), 1);
1110 1 EXPECT_EQ(size_str_width(9), 1);
1111 1 EXPECT_EQ(size_str_width(19), 2);
1112 1 EXPECT_EQ(size_str_width(425), 3);
1113 1 EXPECT_EQ(size_str_width(12345), 5);
1114 1 EXPECT_EQ(size_str_width(2147483647), 10);
1115 1 }
1116
1117 1 static void test_buf_parse_uintmax(TestContext *ctx)
1118 {
1119 1 uintmax_t val;
1120 1 char max[DECIMAL_STR_MAX(val) + 2];
1121 1 size_t max_len = xsnprintf(max, sizeof max, "%ju", UINTMAX_MAX);
1122
1123 1 val = 11;
1124 1 EXPECT_EQ(buf_parse_uintmax(string_view(max, max_len), &val), max_len);
1125 1 EXPECT_UINT_EQ(val, UINTMAX_MAX);
1126
1127 1 val = 22;
1128 1 max[max_len++] = '9';
1129 1 EXPECT_EQ(buf_parse_uintmax(string_view(max, max_len), &val), 0);
1130 1 EXPECT_EQ(val, 22);
1131
1132 1 val = 33;
1133 1 max[max_len++] = '7';
1134 1 EXPECT_EQ(buf_parse_uintmax(string_view(max, max_len), &val), 0);
1135 1 EXPECT_EQ(val, 33);
1136
1137 1 EXPECT_EQ(buf_parse_uintmax(strview("0"), &val), 1);
1138 1 EXPECT_EQ(val, 0);
1139
1140 1 EXPECT_EQ(buf_parse_uintmax(string_view("0019817", 8), &val), 7);
1141 1 EXPECT_EQ(val, 19817);
1142
1143 1 EXPECT_EQ(buf_parse_uintmax(string_view("0098765", 5), &val), 5);
1144 1 EXPECT_EQ(val, 987);
1145
1146 1 char buf[4] = " 90/";
1147 1 buf[0] = CHAR_MAX;
1148 1 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 4), &val), 0);
1149
1150
2/2
✓ Branch 46 → 24 taken 255 times.
✓ Branch 46 → 47 taken 1 time.
257 for (char c = CHAR_MIN; c < CHAR_MAX; c++) {
1151 255 buf[0] = c;
1152
2/2
✓ Branch 24 → 25 taken 245 times.
✓ Branch 24 → 28 taken 10 times.
255 if (!ascii_isdigit(c)) {
1153 245 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 4), &val), 0);
1154 245 continue;
1155 }
1156 10 val = 337;
1157 10 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 0), &val), 0);
1158 10 EXPECT_EQ(val, 337);
1159 10 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 1), &val), 1);
1160 10 EXPECT_TRUE(val <= 9);
1161 10 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 2), &val), 2);
1162 10 EXPECT_TRUE(val >= 9);
1163 10 EXPECT_TRUE(val <= 99);
1164 10 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 3), &val), 3);
1165 10 EXPECT_TRUE(val >= 90);
1166 10 EXPECT_TRUE(val <= 990);
1167 10 const uintmax_t prev = val;
1168 10 EXPECT_EQ(buf_parse_uintmax(string_view(buf, 4), &val), 3);
1169 10 EXPECT_EQ(val, prev);
1170 }
1171 1 }
1172
1173 1 static void test_buf_parse_ulong(TestContext *ctx)
1174 {
1175 1 unsigned long val;
1176 1 char max[DECIMAL_STR_MAX(val) + 1];
1177 1 size_t max_len = xsnprintf(max, sizeof max, "%lu", ULONG_MAX);
1178
1179 1 val = 88;
1180 1 EXPECT_EQ(buf_parse_ulong(strview(max), &val), max_len);
1181 1 EXPECT_UINT_EQ(val, ULONG_MAX);
1182
1183 1 val = 99;
1184 1 max[max_len++] = '1';
1185 1 EXPECT_EQ(buf_parse_ulong(string_view(max, max_len), &val), 0);
1186 1 EXPECT_EQ(val, 99);
1187
1188 1 EXPECT_EQ(buf_parse_ulong(strview("0"), &val), 1);
1189 1 EXPECT_EQ(val, 0);
1190
1191 1 EXPECT_EQ(buf_parse_ulong(strview("9876"), &val), 4);
1192 1 EXPECT_EQ(val, 9876);
1193 1 }
1194
1195 1 static void test_buf_parse_size(TestContext *ctx)
1196 {
1197 1 size_t val;
1198 1 char max[DECIMAL_STR_MAX(val) + 1];
1199 1 size_t max_len = xsnprintf(max, sizeof max, "%zu", SIZE_MAX);
1200
1201 1 val = 14;
1202 1 EXPECT_EQ(buf_parse_size(strview(max), &val), max_len);
1203 1 EXPECT_UINT_EQ(val, SIZE_MAX);
1204
1205 1 val = 88;
1206 1 max[max_len++] = '0';
1207 1 EXPECT_EQ(buf_parse_size(strview(max), &val), 0);
1208 1 EXPECT_EQ(val, 88);
1209 1 }
1210
1211 1 static void test_buf_parse_hex_uint(TestContext *ctx)
1212 {
1213 1 unsigned int val;
1214 1 char buf[HEX_STR_MAX(val) + 1];
1215 1 size_t buf_len = xsnprintf(buf, sizeof buf, "%x", UINT_MAX);
1216 1 val = 0x90;
1217 1 EXPECT_EQ(buf_parse_hex_uint(strview(buf), &val), buf_len);
1218 1 EXPECT_UINT_EQ(val, UINT_MAX);
1219
1220 1 buf_len = xsnprintf(buf, sizeof buf, "1%x", UINT_MAX);
1221 1 val = 0x100;
1222 1 EXPECT_EQ(buf_parse_hex_uint(strview(buf), &val), 0);
1223 1 EXPECT_UINT_EQ(val, 0x100);
1224
1225 1 buf_len = xsnprintf(buf, sizeof buf, "%xg", UINT_MAX);
1226 1 val = 0x110;
1227 1 EXPECT_EQ(buf_parse_hex_uint(strview(buf), &val), buf_len - 1);
1228 1 EXPECT_UINT_EQ(val, UINT_MAX);
1229
1230 1 buf_len = xsnprintf(buf, sizeof buf, "%xf", UINT_MAX);
1231 1 val = 0x120;
1232 1 EXPECT_EQ(buf_parse_hex_uint(strview(buf), &val), 0);
1233 1 EXPECT_UINT_EQ(val, 0x120);
1234
1235 1 buf_len = sizeof(buf);
1236 1 memset(buf, '0', buf_len);
1237 1 val = 0x130;
1238 1 EXPECT_EQ(buf_parse_hex_uint(string_view(buf, buf_len), &val), buf_len);
1239 1 EXPECT_UINT_EQ(val, 0);
1240
1241 1 val = 0x140;
1242 1 EXPECT_EQ(buf_parse_hex_uint(string_view(buf, buf_len - 2), &val), buf_len - 2);
1243 1 EXPECT_UINT_EQ(val, 0);
1244
1245 1 val = 0x150;
1246 1 EXPECT_EQ(buf_parse_hex_uint(strview("12345678"), &val), 8);
1247 1 EXPECT_UINT_EQ(val, 0x12345678);
1248
1249 1 val = 0x160;
1250 1 EXPECT_EQ(buf_parse_hex_uint(strview("00abcdeF01"), &val), 10);
1251 1 EXPECT_UINT_EQ(val, 0xABCDEF01);
1252
1253 1 val = 0x170;
1254 1 EXPECT_EQ(buf_parse_hex_uint(string_view("0123456789", 4), &val), 4);
1255 1 EXPECT_UINT_EQ(val, 0x123);
1256 1 }
1257
1258 1 static void test_str_to_int(TestContext *ctx)
1259 {
1260 1 int val = 0;
1261 1 EXPECT_TRUE(str_to_int("-1", &val));
1262 1 EXPECT_EQ(val, -1);
1263 1 EXPECT_TRUE(str_to_int("+1", &val));
1264 1 EXPECT_EQ(val, 1);
1265 1 EXPECT_TRUE(str_to_int("0", &val));
1266 1 EXPECT_EQ(val, 0);
1267 1 EXPECT_TRUE(str_to_int("1", &val));
1268 1 EXPECT_EQ(val, 1);
1269 1 EXPECT_TRUE(str_to_int("+00299", &val));
1270 1 EXPECT_EQ(val, 299);
1271
1272 1 EXPECT_FALSE(str_to_int("", &val));
1273 1 EXPECT_FALSE(str_to_int("100x", &val));
1274 1 EXPECT_FALSE(str_to_int("+-100", &val));
1275 1 EXPECT_FALSE(str_to_int("99999999999999999999999999999999", &val));
1276 1 }
1277
1278 1 static void test_str_to_size(TestContext *ctx)
1279 {
1280 1 size_t val = 0;
1281 1 EXPECT_TRUE(str_to_size("100", &val));
1282 1 EXPECT_EQ(val, 100);
1283 1 EXPECT_TRUE(str_to_size("0", &val));
1284 1 EXPECT_EQ(val, 0);
1285 1 EXPECT_TRUE(str_to_size("000000001003", &val));
1286 1 EXPECT_EQ(val, 1003);
1287 1 EXPECT_TRUE(str_to_size("29132", &val));
1288 1 EXPECT_EQ(val, 29132);
1289
1290 1 EXPECT_FALSE(str_to_size("", &val));
1291 1 EXPECT_FALSE(str_to_size("100x", &val));
1292 1 EXPECT_FALSE(str_to_size("-100", &val));
1293 1 EXPECT_FALSE(str_to_size("99999999999999999999999999999999", &val));
1294 1 }
1295
1296 1 static void test_str_to_filepos(TestContext *ctx)
1297 {
1298 1 size_t line = 0;
1299 1 size_t col = 0;
1300 1 EXPECT_TRUE(str_to_filepos("10,60", &line, &col));
1301 1 EXPECT_EQ(line, 10);
1302 1 EXPECT_EQ(col, 60);
1303
1304 1 EXPECT_TRUE(str_to_filepos("1:9", &line, &col));
1305 1 EXPECT_EQ(line, 1);
1306 1 EXPECT_EQ(col, 9);
1307
1308 1 EXPECT_TRUE(str_to_filepos("2", &line, &col));
1309 1 EXPECT_EQ(line, 2);
1310 1 EXPECT_EQ(col, 1);
1311
1312 1 EXPECT_TRUE(str_to_filepos("3,1", &line, &col));
1313 1 EXPECT_EQ(line, 3);
1314 1 EXPECT_EQ(col, 1);
1315
1316 1 EXPECT_TRUE(str_to_xfilepos(strview("4"), &line, &col));
1317 1 EXPECT_EQ(line, 4);
1318 1 EXPECT_EQ(col, 0);
1319
1320 1 EXPECT_TRUE(str_to_xfilepos(strview("5,1"), &line, &col));
1321 1 EXPECT_EQ(line, 5);
1322 1 EXPECT_EQ(col, 1);
1323
1324 1 line = 1111;
1325 1 col = 2222;
1326 1 EXPECT_FALSE(str_to_filepos("0", &line, &col));
1327 1 EXPECT_FALSE(str_to_filepos("1,0", &line, &col));
1328 1 EXPECT_FALSE(str_to_filepos("0,1", &line, &col));
1329 1 EXPECT_FALSE(str_to_filepos("1,2,3", &line, &col));
1330 1 EXPECT_FALSE(str_to_filepos("1,2.3", &line, &col));
1331 1 EXPECT_FALSE(str_to_filepos("5,", &line, &col));
1332 1 EXPECT_FALSE(str_to_filepos("5:", &line, &col));
1333 1 EXPECT_FALSE(str_to_filepos(",5", &line, &col));
1334 1 EXPECT_FALSE(str_to_filepos("6.7", &line, &col));
1335 1 EXPECT_FALSE(str_to_filepos("2 3", &line, &col));
1336 1 EXPECT_FALSE(str_to_filepos("9 ", &line, &col));
1337 1 EXPECT_FALSE(str_to_filepos("", &line, &col));
1338 1 EXPECT_FALSE(str_to_filepos("\t", &line, &col));
1339 1 EXPECT_FALSE(str_to_filepos("44,9x", &line, &col));
1340 1 EXPECT_EQ(line, 1111);
1341 1 EXPECT_EQ(col, 2222);
1342 1 }
1343
1344 1 static void test_parse_file_line_col(TestContext *ctx)
1345 {
1346 1 size_t line = 44;
1347 1 size_t col = 77;
1348 1 StringView path = parse_file_line_col("dir/file.ext:12:45", &line, &col);
1349 1 EXPECT_STRVIEW_EQ_CSTRING(path, "dir/file.ext");
1350 1 EXPECT_EQ(line, 12);
1351 1 EXPECT_EQ(col, 45);
1352
1353 1 path = parse_file_line_col("/x/y/z/file:901", &line, &col);
1354 1 EXPECT_STRVIEW_EQ_CSTRING(path, "/x/y/z/file");
1355 1 EXPECT_EQ(line, 901);
1356 1 EXPECT_EQ(col, 1);
1357
1358 // Colons are searched from the end of the string, so the filename may
1359 // contain colons
1360 1 path = parse_file_line_col("/x/:y:/z/file:99:32", &line, &col);
1361 1 EXPECT_STRVIEW_EQ_CSTRING(path, "/x/:y:/z/file");
1362 1 EXPECT_EQ(line, 99);
1363 1 EXPECT_EQ(col, 32);
1364
1365 1 path = parse_file_line_col("a:5", &line, &col);
1366 1 EXPECT_STRVIEW_EQ_CSTRING(path, "a");
1367 1 EXPECT_EQ(line, 5);
1368 1 EXPECT_EQ(col, 1);
1369
1370 1 static const char invalid[][8] = {
1371 "a", // Invalid because line number is mandatory
1372 "",
1373 ":",
1374 "::",
1375 "a:",
1376 "a::",
1377 ":1:1",
1378 "a:2:",
1379 "a::2",
1380 "a:1:0",
1381 "a:0:1",
1382 "a:0:0",
1383 "a:1:1:",
1384 "a:_:1",
1385 "a:1:_",
1386 "a:1:1_",
1387 };
1388
1389
2/2
✓ Branch 24 → 19 taken 16 times.
✓ Branch 24 → 25 taken 1 time.
18 FOR_EACH_I(i, invalid) {
1390 16 line = 7;
1391 16 col = 8;
1392 16 path = parse_file_line_col(invalid[i], &line, &col);
1393 16 EXPECT_STRVIEW_EQ_CSTRING(path, "");
1394 16 IEXPECT_EQ(line, 7);
1395 16 IEXPECT_EQ(col, 8);
1396 }
1397 1 }
1398
1399 1 static void test_buf_umax_to_hex_str(TestContext *ctx)
1400 {
1401 1 char buf[HEX_STR_MAX(uintmax_t)];
1402 1 memset(buf, '@', sizeof(buf));
1403
1404 1 size_t ndigits = buf_umax_to_hex_str(0x98EA412F0ull, buf, 0);
1405 1 EXPECT_EQ(ndigits, 9);
1406 1 EXPECT_STREQ(buf, "98EA412F0");
1407
1408 1 ndigits = buf_umax_to_hex_str(0xE, buf, 0);
1409 1 EXPECT_EQ(ndigits, 1);
1410 1 EXPECT_STREQ(buf, "E");
1411
1412 1 ndigits = buf_umax_to_hex_str(0xF, buf, 4);
1413 1 EXPECT_EQ(ndigits, 4);
1414 1 EXPECT_STREQ(buf, "000F");
1415
1416 1 ndigits = buf_umax_to_hex_str(0, buf, 10);
1417 1 EXPECT_EQ(ndigits, 10);
1418 1 EXPECT_STREQ(buf, "0000000000");
1419
1420 1 ndigits = buf_umax_to_hex_str(0xEF1300, buf, 8);
1421 1 EXPECT_EQ(ndigits, 8);
1422 1 EXPECT_STREQ(buf, "00EF1300");
1423
1424 1 ndigits = buf_umax_to_hex_str(0x1000, buf, 3);
1425 1 EXPECT_EQ(ndigits, 4);
1426 1 EXPECT_STREQ(buf, "1000");
1427
1428 1 ndigits = buf_umax_to_hex_str(0, buf, 0);
1429 1 EXPECT_EQ(ndigits, 1);
1430 1 EXPECT_STREQ(buf, "0");
1431
1432 1 ndigits = buf_umax_to_hex_str(1, buf, 0);
1433 1 EXPECT_EQ(ndigits, 1);
1434 1 EXPECT_STREQ(buf, "1");
1435
1436 1 ndigits = buf_umax_to_hex_str(0x10000000ULL, buf, 0);
1437 1 EXPECT_EQ(ndigits, 8);
1438 1 EXPECT_STREQ(buf, "10000000");
1439
1440 1 ndigits = buf_umax_to_hex_str(0x11111111ULL, buf, 0);
1441 1 EXPECT_EQ(ndigits, 8);
1442 1 EXPECT_STREQ(buf, "11111111");
1443
1444 1 ndigits = buf_umax_to_hex_str(0x123456789ABCDEF0ULL, buf, 0);
1445 1 EXPECT_EQ(ndigits, 16);
1446 1 EXPECT_STREQ(buf, "123456789ABCDEF0");
1447
1448 1 ndigits = buf_umax_to_hex_str(0xFFFFFFFFFFFFFFFFULL, buf, 0);
1449 1 EXPECT_EQ(ndigits, 16);
1450 1 EXPECT_STREQ(buf, "FFFFFFFFFFFFFFFF");
1451 1 }
1452
1453 1 static void test_parse_filesize(TestContext *ctx)
1454 {
1455 1 EXPECT_EQ(parse_filesize("0"), 0);
1456 1 EXPECT_EQ(parse_filesize("1"), 1);
1457 1 EXPECT_EQ(parse_filesize("1KiB"), 1024);
1458 1 EXPECT_EQ(parse_filesize("4GiB"), 4LL << 30);
1459 1 EXPECT_EQ(parse_filesize("4096MiB"), 4LL << 30);
1460 1 EXPECT_EQ(parse_filesize("1234567890"), 1234567890LL);
1461 1 EXPECT_EQ(parse_filesize("9GiB"), 9LL << 30);
1462 1 EXPECT_EQ(parse_filesize("1GiB"), 1LL << 30);
1463 1 EXPECT_EQ(parse_filesize("0GiB"), 0);
1464 1 EXPECT_EQ(parse_filesize("0KiB"), 0);
1465 1 EXPECT_EQ(parse_filesize("1MiB"), 1LL << 20);
1466 1 EXPECT_EQ(parse_filesize("1TiB"), 1LL << 40);
1467 1 EXPECT_EQ(parse_filesize("1PiB"), 1LL << 50);
1468 1 EXPECT_EQ(parse_filesize("1EiB"), 1LL << 60);
1469 1 EXPECT_EQ(parse_filesize("9223372036854775807"), (1ULL << 63) - 1);
1470
1471 1 EXPECT_EQ(parse_filesize("4i"), -EINVAL);
1472 1 EXPECT_EQ(parse_filesize("4B"), -EINVAL);
1473 1 EXPECT_EQ(parse_filesize("4GB"), -EINVAL);
1474 1 EXPECT_EQ(parse_filesize("G4"), -EINVAL);
1475 1 EXPECT_EQ(parse_filesize("4G_"), -EINVAL);
1476 1 EXPECT_EQ(parse_filesize(" 4G"), -EINVAL);
1477 1 EXPECT_EQ(parse_filesize("4G "), -EINVAL);
1478 1 EXPECT_EQ(parse_filesize("1K"), -EINVAL);
1479 1 EXPECT_EQ(parse_filesize("4G"), -EINVAL);
1480 1 EXPECT_EQ(parse_filesize("4096M"), -EINVAL);
1481 1 EXPECT_EQ(parse_filesize("9Gi"), -EINVAL);
1482 1 EXPECT_EQ(parse_filesize("0K"), -EINVAL);
1483
1484 1 intmax_t a = parse_filesize("8EiB");
1485 1 intmax_t b = parse_filesize("9223372036854775808");
1486 1 EXPECT_TRUE(a > 0 || a == -EOVERFLOW);
1487 1 EXPECT_EQ(a, b);
1488
1489 1 char buf[DECIMAL_STR_MAX(uintmax_t) + 4];
1490 1 xsnprintf(buf, sizeof buf, "%jd", INTMAX_MAX);
1491 1 EXPECT_EQ(parse_filesize(buf), INTMAX_MAX);
1492 1 xsnprintf(buf, sizeof buf, "%ju", (uintmax_t)(INTMAX_MAX) + 1);
1493 1 EXPECT_EQ(parse_filesize(buf), -EOVERFLOW);
1494 1 xsnprintf(buf, sizeof buf, "%jdKiB", INTMAX_MAX);
1495 1 EXPECT_EQ(parse_filesize(buf), -EOVERFLOW);
1496 1 xsnprintf(buf, sizeof buf, "%jdEiB", INTMAX_MAX);
1497 1 EXPECT_EQ(parse_filesize(buf), -EOVERFLOW);
1498 1 xsnprintf(buf, sizeof buf, "%ju", UINTMAX_MAX);
1499 1 EXPECT_EQ(parse_filesize(buf), -EOVERFLOW);
1500 1 }
1501
1502 1 static void test_umax_to_str(TestContext *ctx)
1503 {
1504 1 EXPECT_STREQ(umax_to_str(0), "0");
1505 1 EXPECT_STREQ(umax_to_str(1), "1");
1506 1 EXPECT_STREQ(umax_to_str(7), "7");
1507 1 EXPECT_STREQ(umax_to_str(99), "99");
1508 1 EXPECT_STREQ(umax_to_str(111), "111");
1509 1 EXPECT_STREQ(umax_to_str(1000), "1000");
1510 1 EXPECT_STREQ(umax_to_str(20998), "20998");
1511
1512 1 uintmax_t x = UINTMAX_MAX;
1513 1 char ref[DECIMAL_STR_MAX(x)];
1514 1 xsnprintf(ref, sizeof ref, "%ju", x);
1515 1 EXPECT_STREQ(umax_to_str(x), ref);
1516 1 x--;
1517 1 xsnprintf(ref, sizeof ref, "%ju", x);
1518 1 EXPECT_STREQ(umax_to_str(x), ref);
1519 1 }
1520
1521 1 static void test_uint_to_str(TestContext *ctx)
1522 {
1523 1 EXPECT_STREQ(uint_to_str(0), "0");
1524 1 EXPECT_STREQ(uint_to_str(1), "1");
1525 1 EXPECT_STREQ(uint_to_str(9), "9");
1526 1 EXPECT_STREQ(uint_to_str(10), "10");
1527 1 EXPECT_STREQ(uint_to_str(11), "11");
1528 1 EXPECT_STREQ(uint_to_str(99), "99");
1529 1 EXPECT_STREQ(uint_to_str(100), "100");
1530 1 EXPECT_STREQ(uint_to_str(101), "101");
1531 1 EXPECT_STREQ(uint_to_str(21904), "21904");
1532
1533 // See also: test_posix_sanity()
1534 1 EXPECT_STREQ(uint_to_str(4294967295u), "4294967295");
1535 1 }
1536
1537 1 static void test_ulong_to_str(TestContext *ctx)
1538 {
1539 1 unsigned long x = ULONG_MAX;
1540 1 char ref[DECIMAL_STR_MAX(x)];
1541 1 xsnprintf(ref, sizeof ref, "%lu", x);
1542 1 EXPECT_STREQ(ulong_to_str(x), ref);
1543 1 EXPECT_STREQ(ulong_to_str(x + 1), "0");
1544 1 }
1545
1546 1 static void test_buf_umax_to_str(TestContext *ctx)
1547 {
1548 1 char buf[DECIMAL_STR_MAX(uintmax_t)];
1549 1 EXPECT_EQ(buf_umax_to_str(0, buf), 1);
1550 1 EXPECT_STREQ(buf, "0");
1551 1 EXPECT_EQ(buf_umax_to_str(1, buf), 1);
1552 1 EXPECT_STREQ(buf, "1");
1553 1 EXPECT_EQ(buf_umax_to_str(9, buf), 1);
1554 1 EXPECT_STREQ(buf, "9");
1555 1 EXPECT_EQ(buf_umax_to_str(10, buf), 2);
1556 1 EXPECT_STREQ(buf, "10");
1557 1 EXPECT_EQ(buf_umax_to_str(1234567890ull, buf), 10);
1558 1 EXPECT_STREQ(buf, "1234567890");
1559 1 EXPECT_EQ(buf_umax_to_str(9087654321ull, buf), 10);
1560 1 EXPECT_STREQ(buf, "9087654321");
1561 1 static_assert(sizeof(buf) > 20);
1562 1 EXPECT_EQ(buf_umax_to_str(18446744073709551615ull, buf), 20);
1563 1 EXPECT_STREQ(buf, "18446744073709551615");
1564 1 }
1565
1566 1 static void test_buf_uint_to_str(TestContext *ctx)
1567 {
1568 1 char buf[DECIMAL_STR_MAX(unsigned int)];
1569 1 EXPECT_EQ(buf_uint_to_str(0, buf), 1);
1570 1 EXPECT_STREQ(buf, "0");
1571 1 EXPECT_EQ(buf_uint_to_str(1, buf), 1);
1572 1 EXPECT_STREQ(buf, "1");
1573 1 EXPECT_EQ(buf_uint_to_str(9, buf), 1);
1574 1 EXPECT_STREQ(buf, "9");
1575 1 EXPECT_EQ(buf_uint_to_str(129, buf), 3);
1576 1 EXPECT_STREQ(buf, "129");
1577 1 EXPECT_EQ(buf_uint_to_str(21904, buf), 5);
1578 1 EXPECT_STREQ(buf, "21904");
1579 1 static_assert(sizeof(buf) > 10);
1580 1 EXPECT_EQ(buf_uint_to_str(4294967295u, buf), 10);
1581 1 EXPECT_STREQ(buf, "4294967295");
1582 1 }
1583
1584 1 static void test_buf_u8_to_str(TestContext *ctx)
1585 {
1586 // Note that buf_u8_to_str() doesn't null-terminate the buffer
1587 1 char buf[4] = "";
1588 1 EXPECT_MEMEQ(buf, buf_u8_to_str(0, buf), "0", 1);
1589 1 EXPECT_MEMEQ(buf, buf_u8_to_str(1, buf), "1", 1);
1590 1 EXPECT_MEMEQ(buf, buf_u8_to_str(9, buf), "9", 1);
1591 1 EXPECT_MEMEQ(buf, buf_u8_to_str(10, buf), "10", 2);
1592 1 EXPECT_MEMEQ(buf, buf_u8_to_str(72, buf), "72", 2);
1593 1 EXPECT_MEMEQ(buf, buf_u8_to_str(99, buf), "99", 2);
1594 1 EXPECT_MEMEQ(buf, buf_u8_to_str(100, buf), "100", 3);
1595 1 EXPECT_MEMEQ(buf, buf_u8_to_str(101, buf), "101", 3);
1596 1 EXPECT_MEMEQ(buf, buf_u8_to_str(123, buf), "123", 3);
1597 1 EXPECT_MEMEQ(buf, buf_u8_to_str(205, buf), "205", 3);
1598 1 EXPECT_MEMEQ(buf, buf_u8_to_str(215, buf), "215", 3);
1599 1 EXPECT_MEMEQ(buf, buf_u8_to_str(225, buf), "225", 3);
1600 1 EXPECT_MEMEQ(buf, buf_u8_to_str(250, buf), "250", 3);
1601 1 EXPECT_MEMEQ(buf, buf_u8_to_str(251, buf), "251", 3);
1602 1 EXPECT_MEMEQ(buf, buf_u8_to_str(255, buf), "255", 3);
1603 1 }
1604
1605 1 static void test_file_permissions_to_str(TestContext *ctx)
1606 {
1607 1 char buf[FILE_PERMISSIONS_BUFSIZE];
1608 1 EXPECT_STREQ("---------", file_permissions_to_str(0, buf));
1609 1 EXPECT_STREQ("--------x", file_permissions_to_str(01, buf));
1610 1 EXPECT_STREQ("--x--x--x", file_permissions_to_str(0111, buf));
1611 1 EXPECT_STREQ("rwx------", file_permissions_to_str(0700, buf));
1612 1 EXPECT_STREQ("r--r--r--", file_permissions_to_str(0444, buf));
1613 1 EXPECT_STREQ("rw-rw-rw-", file_permissions_to_str(0666, buf));
1614 1 EXPECT_STREQ("rwxrwxrwx", file_permissions_to_str(0777, buf));
1615
1616 1 EXPECT_STREQ("-----S---", file_permissions_to_str(02000, buf));
1617 1 EXPECT_STREQ("-----s---", file_permissions_to_str(02010, buf));
1618 1 EXPECT_STREQ("--S------", file_permissions_to_str(04000, buf));
1619 1 EXPECT_STREQ("--s------", file_permissions_to_str(04100, buf));
1620 1 EXPECT_STREQ("--S--S---", file_permissions_to_str(06000, buf));
1621 1 EXPECT_STREQ("--s--s---", file_permissions_to_str(06110, buf));
1622 1 EXPECT_STREQ("--s--S---", file_permissions_to_str(06100, buf));
1623 1 EXPECT_STREQ("--S--s---", file_permissions_to_str(06010, buf));
1624
1625 #ifdef S_ISVTX
1626 1 EXPECT_STREQ("--S--S--T", file_permissions_to_str(07000, buf));
1627 1 EXPECT_STREQ("--s--s--t", file_permissions_to_str(07111, buf));
1628 1 EXPECT_STREQ("rwsrwsrwt", file_permissions_to_str(07777, buf));
1629 1 EXPECT_STREQ("rwSrwSrwT", file_permissions_to_str(07666, buf));
1630 1 EXPECT_STREQ("------rwt", file_permissions_to_str(01007, buf));
1631 #else
1632 EXPECT_STREQ("--S--S---", file_permissions_to_str(07000, buf));
1633 EXPECT_STREQ("--s--s--x", file_permissions_to_str(07111, buf));
1634 EXPECT_STREQ("rwsrwsrwx", file_permissions_to_str(07777, buf));
1635 EXPECT_STREQ("rwSrwSrw-", file_permissions_to_str(07666, buf));
1636 EXPECT_STREQ("------rwx", file_permissions_to_str(01007, buf));
1637 #endif
1638 1 }
1639
1640 1 static void test_human_readable_size(TestContext *ctx)
1641 {
1642 1 char buf[HRSIZE_MAX];
1643 1 EXPECT_STREQ(human_readable_size(0, buf), "0");
1644 1 EXPECT_STREQ(human_readable_size(1, buf), "1");
1645 1 EXPECT_STREQ(human_readable_size(10, buf), "10");
1646 1 EXPECT_STREQ(human_readable_size(1u << 10, buf), "1 KiB");
1647 1 EXPECT_STREQ(human_readable_size(4u << 10, buf), "4 KiB");
1648 1 EXPECT_STREQ(human_readable_size(9u << 20, buf), "9 MiB");
1649 1 EXPECT_STREQ(human_readable_size(1024u << 10, buf), "1 MiB");
1650 1 EXPECT_STREQ(human_readable_size(1024u << 20, buf), "1 GiB");
1651 1 EXPECT_STREQ(human_readable_size(1023u << 10, buf), "1023 KiB");
1652 1 EXPECT_STREQ(human_readable_size(1023u << 20, buf), "1023 MiB");
1653 1 EXPECT_STREQ(human_readable_size(900ull << 30, buf), "900 GiB");
1654 1 EXPECT_STREQ(human_readable_size(1ull << 62, buf), "4 EiB");
1655 1 EXPECT_STREQ(human_readable_size((1ull << 62) + 232ull, buf), "4 EiB");
1656 1 EXPECT_STREQ(human_readable_size(3ull << 61, buf), "6 EiB");
1657 1 EXPECT_STREQ(human_readable_size(11ull << 59, buf), "5.50 EiB");
1658
1659 // Compare to e.g.: numfmt --to=iec --format=%0.7f 7427273
1660 1 EXPECT_STREQ(human_readable_size(990, buf), "990");
1661 1 EXPECT_STREQ(human_readable_size(1023, buf), "1023");
1662 1 EXPECT_STREQ(human_readable_size(1025, buf), "1 KiB");
1663 1 EXPECT_STREQ(human_readable_size(1123, buf), "1.09 KiB");
1664 1 EXPECT_STREQ(human_readable_size(1124, buf), "1.10 KiB");
1665 1 EXPECT_STREQ(human_readable_size(1127, buf), "1.10 KiB");
1666 1 EXPECT_STREQ(human_readable_size(4106, buf), "4.01 KiB");
1667 1 EXPECT_STREQ(human_readable_size(4192, buf), "4.09 KiB");
1668 1 EXPECT_STREQ(human_readable_size(4195, buf), "4.09 KiB");
1669 1 EXPECT_STREQ(human_readable_size(4196, buf), "4.10 KiB");
1670 1 EXPECT_STREQ(human_readable_size(4197, buf), "4.10 KiB");
1671 1 EXPECT_STREQ(human_readable_size(6947713, buf), "6.62 MiB");
1672 1 EXPECT_STREQ(human_readable_size(7427273, buf), "7.08 MiB");
1673 1 EXPECT_STREQ(human_readable_size(1116691500ull, buf), "1.04 GiB");
1674 1 EXPECT_STREQ(human_readable_size(8951980327583ull, buf), "8.14 TiB");
1675 1 EXPECT_STREQ(human_readable_size(8951998035275183ull, buf), "7.95 PiB");
1676
1677 // Some of these results are arguably off by 0.01, but that's fine
1678 // given the approximate nature of the function and its use cases.
1679 // These tests are here mostly to exercise edge cases and provide
1680 // useful feedback when tweaking the algorithm.
1681 1 EXPECT_STREQ(human_readable_size(5242803, buf), "4.99 MiB");
1682 1 EXPECT_STREQ(human_readable_size(5242804, buf), "5 MiB");
1683 1 EXPECT_STREQ(human_readable_size(5242879, buf), "5 MiB");
1684 1 EXPECT_STREQ(human_readable_size(5242880, buf), "5 MiB");
1685 1 EXPECT_STREQ(human_readable_size(5242881, buf), "5 MiB");
1686
1687 // Compare with e.g. `units '0xFF00000000000000 bytes' EiB`
1688 1 EXPECT_STREQ(human_readable_size(0xFFFFFFFFFFFFFFFFull, buf), "16 EiB");
1689 1 EXPECT_STREQ(human_readable_size(0x7FFFFFFFFFFFFFFFull, buf), "8 EiB");
1690 1 EXPECT_STREQ(human_readable_size(0x3FFFFFFFFFFFFFFFull, buf), "4 EiB");
1691 1 EXPECT_STREQ(human_readable_size(0xFF00000000000000ull, buf), "15.93 EiB");
1692
1693 1 const uintmax_t u64pow2max = 0x8000000000000000ull;
1694 1 EXPECT_STREQ(human_readable_size(u64pow2max, buf), "8 EiB");
1695 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 1), buf), "12 EiB");
1696 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 2), buf), "10 EiB");
1697 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 3), buf), "9 EiB");
1698 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 4), buf), "8.50 EiB");
1699 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 5), buf), "8.25 EiB");
1700 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 6), buf), "8.12 EiB");
1701 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 7), buf), "8.06 EiB");
1702 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 8), buf), "8.03 EiB");
1703 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 9), buf), "8.01 EiB");
1704 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 10), buf), "8 EiB");
1705 1 EXPECT_STREQ(human_readable_size(u64pow2max | (u64pow2max >> 11), buf), "8 EiB");
1706 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 1, buf), "4 EiB");
1707 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 2, buf), "2 EiB");
1708 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 3, buf), "1 EiB");
1709 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 4, buf), "512 PiB");
1710 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 1 | (u64pow2max >> 2), buf), "6 EiB");
1711 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 1 | (u64pow2max >> 3), buf), "5 EiB");
1712 1 EXPECT_STREQ(human_readable_size(u64pow2max >> 1 | (u64pow2max >> 4), buf), "4.50 EiB");
1713 1 }
1714
1715 1 static void test_filesize_to_str(TestContext *ctx)
1716 {
1717 1 char buf[FILESIZE_STR_MAX];
1718 1 EXPECT_STREQ(filesize_to_str(0, buf), "0");
1719 1 EXPECT_STREQ(filesize_to_str(1023, buf), "1023");
1720 1 EXPECT_STREQ(filesize_to_str(1024, buf), "1 KiB (1024)");
1721
1722 1 static_assert(18446744073709551615ull == 0xFFFFFFFFFFFFFFFFull);
1723 1 EXPECT_STREQ(filesize_to_str(18446744073709551615ull, buf), "16 EiB (18446744073709551615)");
1724 1 EXPECT_STREQ(filesize_to_str(17446744073709551615ull, buf), "15.13 EiB (17446744073709551615)");
1725 1 }
1726
1727 1 static void test_filesize_to_str_precise(TestContext *ctx)
1728 {
1729 1 char buf[PRECISE_FILESIZE_STR_MAX];
1730 1 EXPECT_STREQ(filesize_to_str_precise(0, buf), "0");
1731 1 EXPECT_STREQ(filesize_to_str_precise(1, buf), "1");
1732 1 EXPECT_STREQ(filesize_to_str_precise(99, buf), "99");
1733 1 EXPECT_STREQ(filesize_to_str_precise(1023, buf), "1023");
1734 1 EXPECT_STREQ(filesize_to_str_precise(1024, buf), "1KiB");
1735 1 EXPECT_STREQ(filesize_to_str_precise(1025, buf), "1025");
1736 1 EXPECT_STREQ(filesize_to_str_precise(2047, buf), "2047");
1737 1 EXPECT_STREQ(filesize_to_str_precise(2048, buf), "2KiB");
1738 1 EXPECT_STREQ(filesize_to_str_precise(3 << 9, buf), "1536"); // Exactly 1.5 KiB
1739 1 EXPECT_STREQ(filesize_to_str_precise(3 << 19, buf), "1536KiB"); // Exactly 1.5 MiB
1740 1 EXPECT_STREQ(filesize_to_str_precise(3 << 29, buf), "1536MiB"); // Exactly 1.5 GiB
1741 1 EXPECT_STREQ(filesize_to_str_precise((3 << 29) + 1, buf), "1610612737");
1742 1 EXPECT_STREQ(filesize_to_str_precise(0x8000000000000000ull, buf), "8EiB");
1743 1 EXPECT_STREQ(filesize_to_str_precise(0xF000000000000000ull, buf), "15EiB");
1744 1 EXPECT_STREQ(filesize_to_str_precise(0xFF00000000000000ull, buf), "16320PiB");
1745 1 EXPECT_STREQ(filesize_to_str_precise(0xFFFFFFFFFFFFFFFFull, buf), "18446744073709551615");
1746 1 }
1747
1748 1 static void test_u_char_size(TestContext *ctx)
1749 {
1750 1 EXPECT_EQ(u_char_size('\0'), 1);
1751 1 EXPECT_EQ(u_char_size(' '), 1);
1752 1 EXPECT_EQ(u_char_size('z'), 1);
1753 1 EXPECT_EQ(u_char_size(0x7E), 1);
1754 1 EXPECT_EQ(u_char_size(0x7F), 1);
1755 1 EXPECT_EQ(u_char_size(0x80), 2);
1756 1 EXPECT_EQ(u_char_size(0x81), 2);
1757 1 EXPECT_EQ(u_char_size(0xFF), 2);
1758 1 EXPECT_EQ(u_char_size(0x7FE), 2);
1759 1 EXPECT_EQ(u_char_size(0x7FF), 2);
1760 1 EXPECT_EQ(u_char_size(0x800), 3);
1761 1 EXPECT_EQ(u_char_size(0x801), 3);
1762 1 EXPECT_EQ(u_char_size(0x1234), 3);
1763 1 EXPECT_EQ(u_char_size(0xFFFE), 3);
1764 1 EXPECT_EQ(u_char_size(0xFFFF), 3);
1765 1 EXPECT_EQ(u_char_size(0x10000), 4);
1766 1 EXPECT_EQ(u_char_size(0x10001), 4);
1767 1 EXPECT_EQ(u_char_size(0x10FFFE), 4);
1768 1 EXPECT_EQ(u_char_size(0x10FFFF), 4);
1769 1 EXPECT_EQ(u_char_size(0x110000), 1);
1770 1 EXPECT_EQ(u_char_size(0x110001), 1);
1771 1 EXPECT_EQ(u_char_size(UINT32_MAX), 1);
1772 1 }
1773
1774 1 static void test_u_char_width(TestContext *ctx)
1775 {
1776 // ASCII (1 column)
1777 1 EXPECT_EQ(u_char_width('a'), 1);
1778 1 EXPECT_EQ(u_char_width('z'), 1);
1779 1 EXPECT_EQ(u_char_width('A'), 1);
1780 1 EXPECT_EQ(u_char_width('Z'), 1);
1781 1 EXPECT_EQ(u_char_width(' '), 1);
1782 1 EXPECT_EQ(u_char_width('!'), 1);
1783 1 EXPECT_EQ(u_char_width('/'), 1);
1784 1 EXPECT_EQ(u_char_width('^'), 1);
1785 1 EXPECT_EQ(u_char_width('`'), 1);
1786 1 EXPECT_EQ(u_char_width('~'), 1);
1787
1788 // Rendered in caret notation (2 columns)
1789 1 EXPECT_EQ(u_char_width('\0'), 2);
1790 1 EXPECT_EQ(u_char_width('\t'), 2);
1791 1 EXPECT_EQ(u_char_width('\n'), 2);
1792 1 EXPECT_EQ(u_char_width('\r'), 2);
1793 1 EXPECT_EQ(u_char_width(0x1F), 2);
1794 1 EXPECT_EQ(u_char_width(0x7F), 2);
1795
1796 // Unprintable (rendered as <xx> -- 4 columns)
1797 1 EXPECT_EQ(u_char_width(0x0080), 4);
1798 1 EXPECT_EQ(u_char_width(0xDFFF), 4);
1799
1800 // Zero width (0 columns)
1801 1 EXPECT_EQ(u_char_width(0xAA31), 0);
1802 1 EXPECT_EQ(u_char_width(0xAA32), 0);
1803
1804 // Double width (2 columns)
1805 1 EXPECT_EQ(u_char_width(0x2757), 2);
1806 1 EXPECT_EQ(u_char_width(0x312F), 2);
1807 1 EXPECT_EQ(u_char_width(0x30000), 2);
1808
1809 // Double width but unassigned (rendered as <xx> -- 4 columns)
1810 1 EXPECT_EQ(u_char_width(0x3A009), 4);
1811 1 EXPECT_EQ(u_char_width(0x3FFFD), 4);
1812
1813 // 1 column character >= 0x1100
1814 1 EXPECT_EQ(u_char_width(0x104B3), 1);
1815 1 }
1816
1817 1 static void test_u_to_lower(TestContext *ctx)
1818 {
1819 1 EXPECT_EQ(u_to_lower('A'), 'a');
1820 1 EXPECT_EQ(u_to_lower('Z'), 'z');
1821 1 EXPECT_EQ(u_to_lower('a'), 'a');
1822 1 EXPECT_EQ(u_to_lower('0'), '0');
1823 1 EXPECT_EQ(u_to_lower('~'), '~');
1824 1 EXPECT_EQ(u_to_lower('@'), '@');
1825 1 EXPECT_EQ(u_to_lower('\0'), '\0');
1826 1 }
1827
1828 1 static void test_u_to_upper(TestContext *ctx)
1829 {
1830 1 EXPECT_EQ(u_to_upper('a'), 'A');
1831 1 EXPECT_EQ(u_to_upper('z'), 'Z');
1832 1 EXPECT_EQ(u_to_upper('A'), 'A');
1833 1 EXPECT_EQ(u_to_upper('0'), '0');
1834 1 EXPECT_EQ(u_to_upper('~'), '~');
1835 1 EXPECT_EQ(u_to_upper('@'), '@');
1836 1 EXPECT_EQ(u_to_upper('\0'), '\0');
1837 1 }
1838
1839 1 static void test_u_is_lower(TestContext *ctx)
1840 {
1841 1 EXPECT_TRUE(u_is_lower('a'));
1842 1 EXPECT_TRUE(u_is_lower('z'));
1843 1 EXPECT_FALSE(u_is_lower('A'));
1844 1 EXPECT_FALSE(u_is_lower('Z'));
1845 1 EXPECT_FALSE(u_is_lower('0'));
1846 1 EXPECT_FALSE(u_is_lower('9'));
1847 1 EXPECT_FALSE(u_is_lower('@'));
1848 1 EXPECT_FALSE(u_is_lower('['));
1849 1 EXPECT_FALSE(u_is_lower('{'));
1850 1 EXPECT_FALSE(u_is_lower('\0'));
1851 1 EXPECT_FALSE(u_is_lower('\t'));
1852 1 EXPECT_FALSE(u_is_lower(' '));
1853 1 EXPECT_FALSE(u_is_lower(0x1F315));
1854 1 EXPECT_FALSE(u_is_lower(0x10ffff));
1855
1856 /*
1857 Even if SANE_WCTYPE is defined, we still can't make many assumptions
1858 about the iswlower(3) implementation, since it depends on all kinds
1859 of factors out of our control. Otherwise it'd be reasonable to test
1860 something like:
1861
1862 EXPECT_TRUE(u_is_lower(0x00E0));
1863 EXPECT_TRUE(u_is_lower(0x00E7));
1864 */
1865 1 }
1866
1867 1 static void test_u_is_upper(TestContext *ctx)
1868 {
1869 1 EXPECT_TRUE(u_is_upper('A'));
1870 1 EXPECT_TRUE(u_is_upper('Z'));
1871 1 EXPECT_FALSE(u_is_upper('a'));
1872 1 EXPECT_FALSE(u_is_upper('z'));
1873 1 EXPECT_FALSE(u_is_upper('0'));
1874 1 EXPECT_FALSE(u_is_upper('9'));
1875 1 EXPECT_FALSE(u_is_upper('@'));
1876 1 EXPECT_FALSE(u_is_upper('['));
1877 1 EXPECT_FALSE(u_is_upper('{'));
1878 1 EXPECT_FALSE(u_is_upper('\0'));
1879 1 EXPECT_FALSE(u_is_upper('\t'));
1880 1 EXPECT_FALSE(u_is_upper(' '));
1881 1 EXPECT_FALSE(u_is_upper(0x1F315));
1882 1 EXPECT_FALSE(u_is_upper(0x10ffff));
1883 1 EXPECT_FALSE(u_is_upper(0x00E0));
1884 1 EXPECT_FALSE(u_is_upper(0x00E7));
1885 1 }
1886
1887 1 static void test_u_is_ascii_upper(TestContext *ctx)
1888 {
1889 1 EXPECT_TRUE(u_is_ascii_upper('A'));
1890 1 EXPECT_TRUE(u_is_ascii_upper('Z'));
1891 1 EXPECT_FALSE(u_is_ascii_upper('a'));
1892 1 EXPECT_FALSE(u_is_ascii_upper('z'));
1893 1 EXPECT_FALSE(u_is_ascii_upper('0'));
1894 1 EXPECT_FALSE(u_is_ascii_upper('9'));
1895 1 EXPECT_FALSE(u_is_ascii_upper('@'));
1896 1 EXPECT_FALSE(u_is_ascii_upper('['));
1897 1 EXPECT_FALSE(u_is_ascii_upper('{'));
1898 1 EXPECT_FALSE(u_is_ascii_upper('\0'));
1899 1 EXPECT_FALSE(u_is_ascii_upper('\t'));
1900 1 EXPECT_FALSE(u_is_ascii_upper(' '));
1901 1 EXPECT_FALSE(u_is_ascii_upper(0x7F));
1902 1 EXPECT_FALSE(u_is_ascii_upper(0x1D440));
1903 1 EXPECT_FALSE(u_is_ascii_upper(UNICODE_MAX_VALID_CODEPOINT));
1904 1 }
1905
1906 1 static void test_u_is_cntrl(TestContext *ctx)
1907 {
1908 1 EXPECT_TRUE(u_is_cntrl(0x00));
1909 1 EXPECT_TRUE(u_is_cntrl(0x09));
1910 1 EXPECT_TRUE(u_is_cntrl(0x0D));
1911 1 EXPECT_TRUE(u_is_cntrl(0x1F));
1912 1 EXPECT_TRUE(u_is_cntrl(0x7F));
1913 1 EXPECT_TRUE(u_is_cntrl(0x80));
1914 1 EXPECT_TRUE(u_is_cntrl(0x81));
1915 1 EXPECT_TRUE(u_is_cntrl(0x9E));
1916 1 EXPECT_TRUE(u_is_cntrl(0x9F));
1917 1 EXPECT_FALSE(u_is_cntrl(0x20));
1918 1 EXPECT_FALSE(u_is_cntrl(0x21));
1919 1 EXPECT_FALSE(u_is_cntrl(0x7E));
1920 1 EXPECT_FALSE(u_is_cntrl(0xA0));
1921 1 EXPECT_FALSE(u_is_cntrl(0x41));
1922 1 EXPECT_FALSE(u_is_cntrl(0x61));
1923 1 EXPECT_FALSE(u_is_cntrl(0xFF));
1924 1 }
1925
1926 1 static void test_u_is_unicode(TestContext *ctx)
1927 {
1928 1 EXPECT_TRUE(u_is_unicode(0));
1929 1 EXPECT_TRUE(u_is_unicode(1));
1930 1 EXPECT_TRUE(u_is_unicode(UNICODE_MAX_VALID_CODEPOINT));
1931 1 EXPECT_FALSE(u_is_unicode(UNICODE_MAX_VALID_CODEPOINT + 1));
1932 1 }
1933
1934 1 static void test_u_is_zero_width(TestContext *ctx)
1935 {
1936 // Default ignorable codepoints:
1937 1 EXPECT_TRUE(u_is_zero_width(0x034F));
1938 1 EXPECT_TRUE(u_is_zero_width(0x061C));
1939 1 EXPECT_TRUE(u_is_zero_width(0x115F));
1940 1 EXPECT_TRUE(u_is_zero_width(0x1160));
1941 1 EXPECT_TRUE(u_is_zero_width(0x180B));
1942 1 EXPECT_TRUE(u_is_zero_width(0x200B));
1943 1 EXPECT_TRUE(u_is_zero_width(0x202E));
1944 1 EXPECT_TRUE(u_is_zero_width(0xFEFF));
1945 1 EXPECT_TRUE(u_is_zero_width(0xE0000));
1946 1 EXPECT_TRUE(u_is_zero_width(0xE0FFF));
1947 // Non-spacing marks:
1948 1 EXPECT_TRUE(u_is_zero_width(0x0300));
1949 1 EXPECT_TRUE(u_is_zero_width(0x0730));
1950 1 EXPECT_TRUE(u_is_zero_width(0x11839));
1951 1 EXPECT_TRUE(u_is_zero_width(0x1183A));
1952 1 EXPECT_TRUE(u_is_zero_width(0xE01EF));
1953 // Not zero-width:
1954 1 EXPECT_FALSE(u_is_zero_width(0x0000));
1955 1 EXPECT_FALSE(u_is_zero_width('Z'));
1956 1 }
1957
1958 1 static void test_u_is_special_whitespace(TestContext *ctx)
1959 {
1960 1 EXPECT_FALSE(u_is_special_whitespace(' '));
1961 1 EXPECT_FALSE(u_is_special_whitespace('\t'));
1962 1 EXPECT_FALSE(u_is_special_whitespace('\n'));
1963 1 EXPECT_FALSE(u_is_special_whitespace('a'));
1964 1 EXPECT_FALSE(u_is_special_whitespace(0x1680));
1965 1 EXPECT_FALSE(u_is_special_whitespace(0x3000));
1966 1 EXPECT_TRUE(u_is_special_whitespace(0x00A0));
1967 1 EXPECT_TRUE(u_is_special_whitespace(0x00AD));
1968 1 EXPECT_TRUE(u_is_special_whitespace(0x2000));
1969 1 EXPECT_TRUE(u_is_special_whitespace(0x200a));
1970 1 EXPECT_TRUE(u_is_special_whitespace(0x2028));
1971 1 EXPECT_TRUE(u_is_special_whitespace(0x2029));
1972 1 EXPECT_TRUE(u_is_special_whitespace(0x202f));
1973 1 EXPECT_TRUE(u_is_special_whitespace(0x205f));
1974 1 }
1975
1976 1 static void test_u_is_unprintable(TestContext *ctx)
1977 {
1978 // Private-use characters ------------------------------------------------
1979 // • https://www.unicode.org/faq/private_use.html#pua2
1980 // • https://www.unicode.org/versions/latest/core-spec/chapter-2/#G286941:~:text=Private%2Duse,-Usage
1981
1982 // There are three ranges of private-use characters in the standard.
1983 // The main range in the BMP is U+E000..U+F8FF, containing 6,400
1984 // private-use characters.
1985 1 EXPECT_FALSE(u_is_unprintable(0xE000));
1986 1 EXPECT_FALSE(u_is_unprintable(0xF8FF));
1987
1988 // ... there are also two large ranges of supplementary private-use
1989 // characters, consisting of most of the code points on planes 15
1990 // and 16: U+F0000..U+FFFFD and U+100000..U+10FFFD. Together those
1991 // ranges allocate another 131,068 private-use characters.
1992 1 EXPECT_FALSE(u_is_unprintable(0xF0000));
1993 1 EXPECT_FALSE(u_is_unprintable(0xFFFFD));
1994 1 EXPECT_FALSE(u_is_unprintable(0x100000));
1995 1 EXPECT_FALSE(u_is_unprintable(0x10FFFD));
1996
1997 // Surrogates ------------------------------------------------------------
1998 // • https://www.unicode.org/versions/latest/core-spec/chapter-3/#G2630
1999 // • https://www.unicode.org/versions/latest/core-spec/chapter-2/#G286941:~:text=Surrogate,-Permanently
2000 1 EXPECT_TRUE(u_is_unprintable(0xD800));
2001 1 EXPECT_TRUE(u_is_unprintable(0xDBFF));
2002 1 EXPECT_TRUE(u_is_unprintable(0xDC00));
2003 1 EXPECT_TRUE(u_is_unprintable(0xDFFF));
2004
2005 // Non-characters --------------------------------------------------------
2006 // • https://www.unicode.org/faq/private_use.html#noncharacters
2007 // • https://www.unicode.org/versions/latest/core-spec/chapter-2/#G286941:~:text=Noncharacter,-Permanently
2008 1 unsigned int noncharacter_count = 0;
2009
2010 // "A contiguous range of 32 noncharacters: U+FDD0..U+FDEF in the BMP"
2011
2/2
✓ Branch 26 → 23 taken 32 times.
✓ Branch 26 → 27 taken 1 time.
34 for (CodePoint u = 0xFDD0; u <= 0xFDEF; u++) {
2012 32 EXPECT_TRUE(u_is_unprintable(u));
2013 32 noncharacter_count++;
2014 }
2015
2016 // "The last two code points of the BMP, U+FFFE and U+FFFF"
2017 1 EXPECT_TRUE(u_is_unprintable(0xFFFE));
2018 1 EXPECT_TRUE(u_is_unprintable(0xFFFF));
2019 1 noncharacter_count += 2;
2020
2021 // "The last two code points of each of the 16 supplementary planes:
2022 // U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF, ... U+10FFFE, U+10FFFF"
2023
2/2
✓ Branch 37 → 32 taken 16 times.
✓ Branch 37 → 38 taken 1 time.
17 for (CodePoint step = 1; step <= 16; step++) {
2024 16 const CodePoint u = (0x10000 * step) + 0xFFFE;
2025 16 EXPECT_TRUE(u_is_unprintable(u));
2026 16 EXPECT_TRUE(u_is_unprintable(u + 1));
2027 16 noncharacter_count += 2;
2028 }
2029
2030 // "Q: How many noncharacters does Unicode have?"
2031 // "A: Exactly 66"
2032 1 EXPECT_EQ(noncharacter_count, 66);
2033 1 }
2034
2035 1 static void test_u_str_width(TestContext *ctx)
2036 {
2037 1 static const char ustr[] =
2038 "\xE0\xB8\x81\xE0\xB8\xB3\xE0\xB9\x81\xE0\xB8\x9E\xE0\xB8"
2039 "\x87\xE0\xB8\xA1\xE0\xB8\xB5\xE0\xB8\xAB\xE0\xB8\xB9"
2040 ;
2041
2042 1 EXPECT_EQ(u_str_width("foo"), 3);
2043 1 EXPECT_EQ(u_str_width(ustr), 7);
2044 1 }
2045
2046 1 static void test_u_set_char_raw(TestContext *ctx)
2047 {
2048 1 char buf[UTF8_MAX_SEQ_LEN] = "";
2049 1 EXPECT_EQ(sizeof(buf), 4);
2050 1 EXPECT_EQ(u_set_char_raw(buf, 'a'), 1);
2051 1 EXPECT_EQ(buf[0], 'a');
2052
2053 1 EXPECT_EQ(u_set_char_raw(buf, '\0'), 1);
2054 1 EXPECT_EQ(buf[0], '\0');
2055
2056 1 EXPECT_EQ(u_set_char_raw(buf, 0x1F), 1);
2057 1 EXPECT_EQ(buf[0], '\x1F');
2058
2059 1 EXPECT_EQ(u_set_char_raw(buf, 0x7F), 1);
2060 1 EXPECT_EQ(buf[0], '\x7F');
2061
2062 1 EXPECT_EQ(u_set_char_raw(buf, 0x7FF), 2);
2063 1 EXPECT_EQ(buf[0], '\xDF');
2064 1 EXPECT_EQ(buf[1], '\xBF');
2065
2066 1 EXPECT_EQ(u_set_char_raw(buf, 0xFF45), 3);
2067 1 EXPECT_EQ(buf[0], '\xEF');
2068 1 EXPECT_EQ(buf[1], '\xBD');
2069 1 EXPECT_EQ(buf[2], '\x85');
2070
2071 1 EXPECT_EQ(u_set_char_raw(buf, 0x1F311), 4);
2072 1 EXPECT_EQ(buf[0], '\xF0');
2073 1 EXPECT_EQ(buf[1], '\x9F');
2074 1 EXPECT_EQ(buf[2], '\x8C');
2075 1 EXPECT_EQ(buf[3], '\x91');
2076
2077 1 buf[1] = 0x88;
2078 1 EXPECT_EQ(u_set_char_raw(buf, 0x110000), 1);
2079 1 EXPECT_EQ(buf[0], '\0');
2080 1 EXPECT_EQ(buf[1], '\x88');
2081
2082 1 EXPECT_EQ(u_set_char_raw(buf, 0x110042), 1);
2083 1 EXPECT_EQ(buf[0], '\x42');
2084 1 EXPECT_EQ(buf[1], '\x88');
2085 1 }
2086
2087 1 static void test_u_set_char(TestContext *ctx)
2088 {
2089 1 char buf[U_SET_CHAR_MAXLEN] = "";
2090 1 EXPECT_EQ(sizeof(buf), 4);
2091 1 EXPECT_EQ(u_set_char(buf, 'a'), 1);
2092 1 EXPECT_EQ(buf[0], 'a');
2093
2094 1 EXPECT_EQ(u_set_char(buf, 0x00DF), 2);
2095 1 EXPECT_EQ(buf[0], '\xC3');
2096 1 EXPECT_EQ(buf[1], '\x9F');
2097
2098 1 EXPECT_EQ(u_set_char(buf, 0x0E01), 3);
2099 1 EXPECT_EQ(buf[0], '\xE0');
2100 1 EXPECT_EQ(buf[1], '\xB8');
2101 1 EXPECT_EQ(buf[2], '\x81');
2102
2103 1 EXPECT_EQ(UTF8_MAX_SEQ_LEN, 4);
2104 1 EXPECT_EQ(u_set_char(buf, 0x1F914), 4);
2105 1 EXPECT_EQ(buf[0], '\xF0');
2106 1 EXPECT_EQ(buf[1], '\x9F');
2107 1 EXPECT_EQ(buf[2], '\xA4');
2108 1 EXPECT_EQ(buf[3], '\x94');
2109
2110 1 EXPECT_EQ(U_SET_HEX_LEN, 4);
2111 1 EXPECT_EQ(u_set_char(buf, 0x10FFFF), 4);
2112 1 EXPECT_EQ(buf[0], '<');
2113 1 EXPECT_EQ(buf[1], '?');
2114 1 EXPECT_EQ(buf[2], '?');
2115 1 EXPECT_EQ(buf[3], '>');
2116
2117 1 EXPECT_EQ(u_set_char(buf, '\0'), 2);
2118 1 EXPECT_EQ(buf[0], '^');
2119 1 EXPECT_EQ(buf[1], '@');
2120
2121 1 EXPECT_EQ(u_set_char(buf, '\t'), 2);
2122 1 EXPECT_EQ(buf[0], '^');
2123 1 EXPECT_EQ(buf[1], 'I');
2124
2125 1 EXPECT_EQ(u_set_char(buf, 0x1F), 2);
2126 1 EXPECT_EQ(buf[0], '^');
2127 1 EXPECT_EQ(buf[1], '_');
2128
2129 1 EXPECT_EQ(u_set_char(buf, 0x7F), 2);
2130 1 EXPECT_EQ(buf[0], '^');
2131 1 EXPECT_EQ(buf[1], '?');
2132
2133 1 EXPECT_EQ(u_set_char(buf, 0x80), 4);
2134 1 EXPECT_EQ(buf[0], '<');
2135 1 EXPECT_EQ(buf[1], '?');
2136 1 EXPECT_EQ(buf[2], '?');
2137 1 EXPECT_EQ(buf[3], '>');
2138
2139 1 EXPECT_EQ(u_set_char(buf, 0x7E), 1);
2140 1 EXPECT_EQ(buf[0], '~');
2141
2142 1 EXPECT_EQ(u_set_char(buf, 0x20), 1);
2143 1 EXPECT_EQ(buf[0], ' ');
2144
2145 1 CodePoint u = -0x5Bu; // See comment in u_set_hex()
2146 1 EXPECT_UINT_EQ(u, 0xFFFFFFA5u);
2147 1 EXPECT_EQ(u_set_char(buf, u), 4);
2148 1 EXPECT_EQ(buf[0], '<');
2149 1 EXPECT_EQ(buf[1], '5');
2150 1 EXPECT_EQ(buf[2], 'b');
2151 1 EXPECT_EQ(buf[3], '>');
2152 1 }
2153
2154 1 static void test_u_make_printable(TestContext *ctx)
2155 {
2156 1 char buf[5];
2157 1 MakePrintableFlags flags = 0;
2158 1 EXPECT_EQ(sizeof(buf), U_SET_CHAR_MAXLEN + 1);
2159 1 memset(buf, '_', sizeof(buf));
2160 1 EXPECT_EQ(u_make_printable(strview("\xffxyz"), buf, sizeof(buf), flags), 4);
2161 1 EXPECT_STREQ(buf, "<ff>");
2162
2163 // Enough space for `U_SET_CHAR_MAXLEN + 1` is needed, regardless of
2164 // the CodePoint encountered, so 5 is the minimum remaining space
2165 // required in order to write more than just a null-terminator
2166 1 memset(buf, '_', sizeof(buf));
2167 1 EXPECT_TRUE(sizeof(buf) >= 5);
2168 1 EXPECT_EQ(u_make_printable(strview("12345"), buf, 1, flags), 0);
2169 1 EXPECT_EQ(u_make_printable(strview("12345"), buf, 2, flags), 0);
2170 1 EXPECT_EQ(u_make_printable(strview("12345"), buf, 3, flags), 0);
2171 1 EXPECT_EQ(u_make_printable(strview("12345"), buf, 4, flags), 0);
2172 1 EXPECT_EQ(buf[0], '\0');
2173 1 EXPECT_EQ(buf[1], '_');
2174 1 EXPECT_EQ(buf[2], '_');
2175 1 EXPECT_EQ(buf[3], '_');
2176 1 EXPECT_EQ(buf[4], '_');
2177 1 memset(buf, '_', sizeof(buf));
2178 1 EXPECT_EQ(u_make_printable(strview("12345"), buf, 5, flags), 1);
2179 1 EXPECT_EQ(buf[0], '1');
2180 1 EXPECT_EQ(buf[1], '\0');
2181 1 EXPECT_EQ(buf[2], '_');
2182 1 EXPECT_EQ(buf[3], '_');
2183 1 EXPECT_EQ(buf[4], '_');
2184
2185 1 memset(buf, '_', sizeof(buf));
2186 1 EXPECT_EQ(u_make_printable(strview("\x7F\n123"), buf, 5, flags), 2);
2187 1 EXPECT_STREQ(buf, "^?");
2188 1 EXPECT_EQ(buf[3], '_');
2189
2190 1 flags |= MPF_C0_SYMBOLS;
2191 1 memset(buf, '_', sizeof(buf));
2192 1 EXPECT_EQ(u_make_printable(strview("\x7F\n123"), buf, 5, flags), 3);
2193 1 EXPECT_STREQ(buf, "\xE2\x90\xA1"); // UTF-8 encoding of U+2421
2194 1 EXPECT_EQ(buf[4], '_');
2195
2196 1 memset(buf, '_', sizeof(buf));
2197 1 EXPECT_EQ(u_make_printable(string_view(STRN("\0xyz")), buf, 5, flags), 3);
2198 1 EXPECT_STREQ(buf, "\xE2\x90\x80"); // UTF-8 encoding of U+2400
2199 1 EXPECT_EQ(buf[4], '_');
2200 1 }
2201
2202 1 static void test_u_get_char(TestContext *ctx)
2203 {
2204 1 static const char a[] = "//";
2205 1 size_t idx = 0;
2206 1 EXPECT_UINT_EQ(u_get_char(a, sizeof a, &idx), '/');
2207 1 ASSERT_EQ(idx, 1);
2208 1 EXPECT_UINT_EQ(u_get_char(a, sizeof a, &idx), '/');
2209 1 ASSERT_EQ(idx, 2);
2210 1 EXPECT_UINT_EQ(u_get_char(a, sizeof a, &idx), 0);
2211 1 ASSERT_EQ(idx, 3);
2212
2213 // Non-character U+FDD0.
2214 // • https://www.unicode.org/faq/private_use.html#nonchar4:~:text=EF%20B7%2090
2215 1 static const char nc1[] = "\xEF\xB7\x90";
2216 1 idx = 0;
2217 1 EXPECT_UINT_EQ(u_get_char(nc1, sizeof nc1, &idx), 0xFDD0);
2218 1 ASSERT_EQ(idx, 3);
2219 1 EXPECT_TRUE(u_is_unprintable(0xFDD0));
2220
2221 // Non-character U+FFFE
2222 // • https://www.unicode.org/faq/private_use.html#nonchar4:~:text=EF%20BF%20B%23
2223 1 static const char nc2[] = "\xEF\xBF\xBE";
2224 1 idx = 0;
2225 1 EXPECT_UINT_EQ(u_get_char(nc2, sizeof nc2, &idx), 0xFFFE);
2226 1 ASSERT_EQ(idx, 3);
2227 1 EXPECT_TRUE(u_is_unprintable(0xFFFE));
2228
2229 // -----------------------------------------------------------------------
2230
2231 // "In UTF-8, the code point sequence <004D, 0430, 4E8C, 10302> is
2232 // represented as <4D D0 B0 E4 BA 8C F0 90 8C 82>, where <4D>
2233 // corresponds to U+004D, <D0 B0> corresponds to U+0430, <E4 BA 8C>
2234 // corresponds to U+4E8C, and <F0 90 8C 82> corresponds to U+10302."
2235 // - https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G31703
2236 1 static const char b[] = "\x4D\xD0\xB0\xE4\xBA\x8C\xF0\x90\x8C\x82";
2237 1 idx = 0;
2238 1 EXPECT_UINT_EQ(u_get_char(b, sizeof b, &idx), 0x004D);
2239 1 ASSERT_EQ(idx, 1);
2240 1 EXPECT_UINT_EQ(u_get_char(b, sizeof b, &idx), 0x0430);
2241 1 ASSERT_EQ(idx, 3);
2242 1 EXPECT_UINT_EQ(u_get_char(b, sizeof b, &idx), 0x4E8C);
2243 1 ASSERT_EQ(idx, 6);
2244 1 EXPECT_UINT_EQ(u_get_char(b, sizeof b, &idx), 0x10302);
2245 1 ASSERT_EQ(idx, 10);
2246
2247 // "The byte sequence <F4 80 83 92> is well-formed, because every
2248 // byte in that sequence matches a byte range in a row of the table
2249 // (the last row)."
2250 // - https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G27288
2251 1 idx = 0;
2252 1 EXPECT_UINT_EQ(u_get_char(STRN("\xF4\x80\x83\x92"), &idx), 0x1000D2);
2253 1 EXPECT_EQ(idx, 4);
2254
2255 // Overlong encodings are consumed as individual bytes and
2256 // each byte returned negated (to indicate that it's invalid).
2257 // See also: u_get_nonascii(), u_seq_len_ok(), u_char_size()
2258
2259 // Overlong (2 byte) encoding of U+002F ('/').
2260 // "The byte sequence <C0 AF> is ill-formed, because C0 is not
2261 // well-formed in the “First Byte” column."
2262 1 static const char ol1[] = "\xC0\xAF";
2263 1 idx = 0;
2264 1 EXPECT_UINT_EQ(u_get_char(ol1, sizeof ol1, &idx), -0xC0u);
2265 1 ASSERT_EQ(idx, 1);
2266 1 EXPECT_UINT_EQ(u_get_char(ol1, sizeof ol1, &idx), -0xAFu);
2267 1 ASSERT_EQ(idx, 2);
2268
2269 // Overlong (3 byte) encoding of U+002F ('/')
2270 1 static const char ol2[] = "\xE0\x80\xAF";
2271 1 idx = 0;
2272 1 EXPECT_UINT_EQ(u_get_char(ol2, sizeof ol2, &idx), -0xE0u);
2273 1 ASSERT_EQ(idx, 1);
2274 1 EXPECT_UINT_EQ(u_get_char(ol2, sizeof ol2, &idx), -0x80u);
2275 1 ASSERT_EQ(idx, 2);
2276 1 EXPECT_UINT_EQ(u_get_char(ol2, sizeof ol2, &idx), -0xAFu);
2277 1 ASSERT_EQ(idx, 3);
2278
2279 // Overlong (2 byte) encoding of U+0041 ('A')
2280 1 static const char ol3[] = "\xC1\x81";
2281 1 idx = 0;
2282 1 EXPECT_UINT_EQ(u_get_char(ol3, sizeof ol3, &idx), -0xC1u);
2283 1 ASSERT_EQ(idx, 1);
2284 1 EXPECT_UINT_EQ(u_get_char(ol3, sizeof ol3, &idx), -0x81u);
2285 1 ASSERT_EQ(idx, 2);
2286
2287 // "The byte sequence <E0 9F 80> is ill-formed, because in the row
2288 // where E0 is well-formed as a first byte, 9F is not well-formed
2289 // as a second byte."
2290 1 static const char ol4[] = "\xE0\x9F\x80";
2291 1 idx = 0;
2292 1 EXPECT_UINT_EQ(u_get_char(ol4, sizeof ol4, &idx), -0xE0u);
2293 1 ASSERT_EQ(idx, 1);
2294 1 EXPECT_UINT_EQ(u_get_char(ol4, sizeof ol4, &idx), -0x9Fu);
2295 1 ASSERT_EQ(idx, 2);
2296 1 EXPECT_UINT_EQ(u_get_char(ol4, sizeof ol4, &idx), -0x80u);
2297 1 ASSERT_EQ(idx, 3);
2298
2299 // "For example, in processing the UTF-8 code unit sequence
2300 // <F0 80 80 41>, the only formal requirement mandated by Unicode
2301 // conformance for a converter is that the <41> be processed and
2302 // correctly interpreted as <U+0041>. The converter could return
2303 // <U+FFFD, U+0041>, handling <F0 80 80> as a single error, or
2304 // <U+FFFD, U+FFFD, U+FFFD, U+0041>, handling each byte of
2305 // <F0 80 80> as a separate error, or could take other approaches
2306 // to signalling <F0 80 80> as an ill-formed code unit subsequence."
2307 // - https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G48534
2308 1 static const char e1[] = "\xF0\x80\x80\x41";
2309 1 idx = 0;
2310 1 EXPECT_UINT_EQ(u_get_char(e1, sizeof e1, &idx), -0xF0u);
2311 1 ASSERT_EQ(idx, 1);
2312 1 EXPECT_UINT_EQ(u_get_char(e1, sizeof e1, &idx), -0x80u);
2313 1 ASSERT_EQ(idx, 2);
2314 1 EXPECT_UINT_EQ(u_get_char(e1, sizeof e1, &idx), -0x80u);
2315 1 ASSERT_EQ(idx, 3);
2316 1 EXPECT_UINT_EQ(u_get_char(e1, sizeof e1, &idx), 0x41u);
2317 1 ASSERT_EQ(idx, 4);
2318
2319 // The following test cases are taken from Unicode's examples in
2320 // Tables 3-{8,9,10,11}. We return the negation of each individual
2321 // byte in an ill-formed sequence, instead of the "maximal subpart"
2322 // approach mentioned there. This is explicitly permitted by the
2323 // spec and is more flexible for our purposes:
2324 //
2325 // "Although the Unicode Standard does not require this practice for
2326 // conformance, the following text describes this practice and gives
2327 // detailed examples."
2328 //
2329 // - https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G66453
2330
2331 // Table 3-8. … Non-Shortest Form Sequences
2332 // https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G67519
2333 1 static const char s8[] = "\xC0\xAF\xE0\x80\xBF\xF0\x81\x82\x41";
2334 1 idx = 0;
2335 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0xC0u);
2336 1 ASSERT_EQ(idx, 1);
2337 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0xAFu);
2338 1 ASSERT_EQ(idx, 2);
2339 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0xE0u);
2340 1 ASSERT_EQ(idx, 3);
2341 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0x80u);
2342 1 ASSERT_EQ(idx, 4);
2343 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0xBFu);
2344 1 ASSERT_EQ(idx, 5);
2345 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0xF0u);
2346 1 ASSERT_EQ(idx, 6);
2347 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0x81u);
2348 1 ASSERT_EQ(idx, 7);
2349 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), -0x82u);
2350 1 ASSERT_EQ(idx, 8);
2351 1 EXPECT_UINT_EQ(u_get_char(s8, sizeof s8, &idx), 0x41u);
2352 1 ASSERT_EQ(idx, 9);
2353
2354 // Table 3-9. … Ill-Formed Sequences for Surrogates
2355 // https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G67520
2356 1 static const char s9[] = "\xED\xA0\x80\xED\xBF\xBF\xED\xAF\x41";
2357 1 EXPECT_TRUE(u_is_surrogate(0xD800)); // "\xED\xA0\x80"
2358 1 EXPECT_TRUE(u_is_unprintable(0xD800));
2359 1 idx = 0;
2360 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xEDu);
2361 1 ASSERT_EQ(idx, 1);
2362 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xA0u);
2363 1 ASSERT_EQ(idx, 2);
2364 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0x80u);
2365 1 ASSERT_EQ(idx, 3);
2366 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xEDu);
2367 1 ASSERT_EQ(idx, 4);
2368 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xBFu);
2369 1 ASSERT_EQ(idx, 5);
2370 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xBFu);
2371 1 ASSERT_EQ(idx, 6);
2372 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xEDu);
2373 1 ASSERT_EQ(idx, 7);
2374 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), -0xAFu);
2375 1 ASSERT_EQ(idx, 8);
2376 1 EXPECT_UINT_EQ(u_get_char(s9, sizeof s9, &idx), 0x41u);
2377 1 ASSERT_EQ(idx, 9);
2378
2379 // Table 3-10. … Other Ill-Formed Sequences
2380 // https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G68064
2381 1 static const char s10[] = "\xF4\x91\x92\x93\xFF\x41\x80\xBF\x42";
2382 1 idx = 0;
2383 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0xF4u);
2384 1 ASSERT_EQ(idx, 1);
2385 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0x91u);
2386 1 ASSERT_EQ(idx, 2);
2387 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0x92u);
2388 1 ASSERT_EQ(idx, 3);
2389 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0x93u);
2390 1 ASSERT_EQ(idx, 4);
2391 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0xFFu);
2392 1 ASSERT_EQ(idx, 5);
2393 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), 0x41u);
2394 1 ASSERT_EQ(idx, 6);
2395 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0x80u);
2396 1 ASSERT_EQ(idx, 7);
2397 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), -0xBFu);
2398 1 ASSERT_EQ(idx, 8);
2399 1 EXPECT_UINT_EQ(u_get_char(s10, sizeof s10, &idx), 0x42u);
2400 1 ASSERT_EQ(idx, 9);
2401
2402 // Table 3-11. … Truncated Sequences
2403 // https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G68202
2404 1 static const char s11[] = "\xE1\x80\xE2\xF0\x91\x92\xF1\xBF\x41";
2405 1 idx = 0;
2406 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0xE1u);
2407 1 ASSERT_EQ(idx, 1);
2408 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0x80u);
2409 1 ASSERT_EQ(idx, 2);
2410 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0xE2u);
2411 1 ASSERT_EQ(idx, 3);
2412 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0xF0u);
2413 1 ASSERT_EQ(idx, 4);
2414 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0x91u);
2415 1 ASSERT_EQ(idx, 5);
2416 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0x92u);
2417 1 ASSERT_EQ(idx, 6);
2418 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0xF1u);
2419 1 ASSERT_EQ(idx, 7);
2420 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), -0xBFu);
2421 1 ASSERT_EQ(idx, 8);
2422 1 EXPECT_UINT_EQ(u_get_char(s11, sizeof s11, &idx), 0x41u);
2423 1 ASSERT_EQ(idx, 9);
2424
2425 // TODO: Provide explicit coverage for each row of Table 3-7:
2426 // https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G27506
2427 1 }
2428
2429 1 static void test_u_prev_char(TestContext *ctx)
2430 {
2431 1 const char *buf = "\xE6\xB7\xB1\xE5\x9C\xB3\xE5\xB8\x82"; // 深圳市
2432 1 size_t idx = 9;
2433 1 CodePoint c = u_prev_char(buf, &idx);
2434 1 EXPECT_UINT_EQ(c, 0x5E02);
2435 1 EXPECT_EQ(idx, 6);
2436 1 c = u_prev_char(buf, &idx);
2437 1 EXPECT_UINT_EQ(c, 0x5733);
2438 1 EXPECT_EQ(idx, 3);
2439 1 c = u_prev_char(buf, &idx);
2440 1 EXPECT_UINT_EQ(c, 0x6DF1);
2441 1 EXPECT_EQ(idx, 0);
2442
2443 1 idx = 1;
2444 1 c = u_prev_char(buf, &idx);
2445 1 EXPECT_UINT_EQ(c, -0xE6u);
2446 1 EXPECT_EQ(idx, 0);
2447
2448 1 buf = "Shenzhen";
2449 1 idx = 8;
2450 1 c = u_prev_char(buf, &idx);
2451 1 EXPECT_UINT_EQ(c, 'n');
2452 1 EXPECT_EQ(idx, 7);
2453 1 c = u_prev_char(buf, &idx);
2454 1 EXPECT_UINT_EQ(c, 'e');
2455 1 EXPECT_EQ(idx, 6);
2456
2457 1 buf = "\xF0\x9F\xA5\xA3\xF0\x9F\xA5\xA4"; // 🥣🥤
2458 1 idx = 8;
2459 1 c = u_prev_char(buf, &idx);
2460 1 EXPECT_UINT_EQ(c, 0x1F964);
2461 1 EXPECT_EQ(idx, 4);
2462 1 c = u_prev_char(buf, &idx);
2463 1 EXPECT_UINT_EQ(c, 0x1F963);
2464 1 EXPECT_EQ(idx, 0);
2465
2466 1 buf = "\xF0\xF5";
2467 1 idx = 2;
2468 1 c = u_prev_char(buf, &idx);
2469 1 EXPECT_UINT_EQ(-c, 0xF5);
2470 1 EXPECT_EQ(idx, 1);
2471 1 c = u_prev_char(buf, &idx);
2472 1 EXPECT_UINT_EQ(-c, 0xF0);
2473 1 EXPECT_EQ(idx, 0);
2474
2475 1 buf = "\xF5\xF0";
2476 1 idx = 2;
2477 1 c = u_prev_char(buf, &idx);
2478 1 EXPECT_UINT_EQ(-c, 0xF0);
2479 1 EXPECT_EQ(idx, 1);
2480 1 c = u_prev_char(buf, &idx);
2481 1 EXPECT_UINT_EQ(-c, 0xF5);
2482 1 EXPECT_EQ(idx, 0);
2483 1 }
2484
2485 1 static void test_u_skip_chars(TestContext *ctx)
2486 {
2487 1 EXPECT_EQ(u_skip_chars("12345", 5), 5);
2488 1 EXPECT_EQ(u_skip_chars("12345", 3), 3);
2489 1 EXPECT_EQ(u_skip_chars("12345", 0), 0);
2490
2491 // Display: <c1> x ^G y 😁 z ^G .
2492 1 static const char str[] = "\xc1x\ay\xF0\x9F\x98\x81z\a.";
2493 1 const size_t w = u_str_width(str);
2494 1 const size_t n = sizeof(str) - 1;
2495 1 EXPECT_EQ(w, 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1);
2496 1 EXPECT_EQ(w, 14);
2497 1 EXPECT_EQ(n, 11);
2498
2499 1 EXPECT_EQ(u_skip_chars(str, 1), 1); // <c1>
2500 1 EXPECT_EQ(u_skip_chars(str, 2), 1);
2501 1 EXPECT_EQ(u_skip_chars(str, 3), 1);
2502 1 EXPECT_EQ(u_skip_chars(str, 4), 1);
2503 1 EXPECT_EQ(u_skip_chars(str, 5), 2); // x
2504 1 EXPECT_EQ(u_skip_chars(str, 6), 3); // ^G
2505 1 EXPECT_EQ(u_skip_chars(str, 7), 3);
2506 1 EXPECT_EQ(u_skip_chars(str, 8), 4); // y
2507 1 EXPECT_EQ(u_skip_chars(str, 9), 8); // 😁
2508 1 EXPECT_EQ(u_skip_chars(str, 10), 8);
2509 1 EXPECT_EQ(u_skip_chars(str, 11), 9); // z
2510 1 EXPECT_EQ(u_skip_chars(str, 12), 10); // ^G
2511 1 EXPECT_EQ(u_skip_chars(str, 13), 10);
2512 1 EXPECT_EQ(14, w);
2513 1 EXPECT_EQ(u_skip_chars(str, 14), n); // .
2514 1 EXPECT_TRUE(15 > w);
2515 1 EXPECT_EQ(u_skip_chars(str, 15), n);
2516 1 EXPECT_EQ(u_skip_chars(str, 16), n);
2517 1 }
2518
2519 1 static void test_ptr_array(TestContext *ctx)
2520 {
2521 1 PointerArray a = PTR_ARRAY_INIT;
2522 1 ptr_array_append(&a, NULL);
2523 1 ptr_array_append(&a, NULL);
2524 1 ptr_array_append(&a, xstrdup("foo"));
2525 1 ptr_array_append(&a, NULL);
2526 1 ptr_array_append(&a, xstrdup("bar"));
2527 1 ptr_array_append(&a, NULL);
2528 1 ptr_array_append(&a, NULL);
2529 1 EXPECT_EQ(a.count, 7);
2530
2531 1 ptr_array_trim_nulls(&a);
2532 1 EXPECT_EQ(a.count, 4);
2533 1 EXPECT_STREQ(a.ptrs[0], "foo");
2534 1 EXPECT_NULL(a.ptrs[1]);
2535 1 EXPECT_STREQ(a.ptrs[2], "bar");
2536 1 EXPECT_NULL(a.ptrs[3]);
2537 1 ptr_array_trim_nulls(&a);
2538 1 EXPECT_EQ(a.count, 4);
2539
2540 1 ptr_array_free(&a);
2541 1 EXPECT_EQ(a.count, 0);
2542 1 ptr_array_trim_nulls(&a);
2543 1 EXPECT_EQ(a.count, 0);
2544
2545 1 ptr_array_init(&a, 0);
2546 1 EXPECT_EQ(a.alloc, 0);
2547 1 EXPECT_NULL(a.ptrs);
2548 1 ptr_array_free(&a);
2549 1 ptr_array_init(&a, 1);
2550 1 EXPECT_EQ(a.alloc, 8);
2551 1 EXPECT_NONNULL(a.ptrs);
2552 1 ptr_array_free(&a);
2553
2554 // ptr_array_trim_nulls() should remove everything (i.e. not leave 1
2555 // trailing NULL) when all elements are NULL
2556 1 ptr_array_init(&a, 0);
2557 1 ptr_array_append(&a, NULL);
2558 1 ptr_array_append(&a, NULL);
2559 1 ptr_array_append(&a, NULL);
2560 1 EXPECT_EQ(a.count, 3);
2561 1 ptr_array_trim_nulls(&a);
2562 1 EXPECT_EQ(a.count, 0);
2563 1 ptr_array_free(&a);
2564 1 }
2565
2566 1 static void test_ptr_array_move(TestContext *ctx)
2567 {
2568 1 PointerArray a = PTR_ARRAY_INIT;
2569 1 ptr_array_append(&a, xstrdup("A"));
2570 1 ptr_array_append(&a, xstrdup("B"));
2571 1 ptr_array_append(&a, xstrdup("C"));
2572 1 ptr_array_append(&a, xstrdup("D"));
2573 1 ptr_array_append(&a, xstrdup("E"));
2574 1 ptr_array_append(&a, xstrdup("F"));
2575 1 EXPECT_EQ(a.count, 6);
2576
2577 1 ptr_array_move(&a, 0, 1);
2578 1 EXPECT_STREQ(a.ptrs[0], "B");
2579 1 EXPECT_STREQ(a.ptrs[1], "A");
2580
2581 1 ptr_array_move(&a, 1, 0);
2582 1 EXPECT_STREQ(a.ptrs[0], "A");
2583 1 EXPECT_STREQ(a.ptrs[1], "B");
2584
2585 1 ptr_array_move(&a, 1, 5);
2586 1 EXPECT_STREQ(a.ptrs[0], "A");
2587 1 EXPECT_STREQ(a.ptrs[1], "C");
2588 1 EXPECT_STREQ(a.ptrs[2], "D");
2589 1 EXPECT_STREQ(a.ptrs[3], "E");
2590 1 EXPECT_STREQ(a.ptrs[4], "F");
2591 1 EXPECT_STREQ(a.ptrs[5], "B");
2592
2593 1 ptr_array_move(&a, 5, 1);
2594 1 EXPECT_STREQ(a.ptrs[0], "A");
2595 1 EXPECT_STREQ(a.ptrs[1], "B");
2596 1 EXPECT_STREQ(a.ptrs[2], "C");
2597 1 EXPECT_STREQ(a.ptrs[3], "D");
2598 1 EXPECT_STREQ(a.ptrs[4], "E");
2599 1 EXPECT_STREQ(a.ptrs[5], "F");
2600
2601 1 ptr_array_move(&a, 0, 5);
2602 1 EXPECT_STREQ(a.ptrs[0], "B");
2603 1 EXPECT_STREQ(a.ptrs[1], "C");
2604 1 EXPECT_STREQ(a.ptrs[2], "D");
2605 1 EXPECT_STREQ(a.ptrs[3], "E");
2606 1 EXPECT_STREQ(a.ptrs[4], "F");
2607 1 EXPECT_STREQ(a.ptrs[5], "A");
2608
2609 1 ptr_array_move(&a, 5, 0);
2610 1 EXPECT_STREQ(a.ptrs[0], "A");
2611 1 EXPECT_STREQ(a.ptrs[1], "B");
2612 1 EXPECT_STREQ(a.ptrs[2], "C");
2613 1 EXPECT_STREQ(a.ptrs[3], "D");
2614 1 EXPECT_STREQ(a.ptrs[4], "E");
2615 1 EXPECT_STREQ(a.ptrs[5], "F");
2616
2617 1 ptr_array_move(&a, 5, 0);
2618 1 EXPECT_STREQ(a.ptrs[0], "F");
2619 1 EXPECT_STREQ(a.ptrs[1], "A");
2620 1 EXPECT_STREQ(a.ptrs[2], "B");
2621 1 EXPECT_STREQ(a.ptrs[3], "C");
2622 1 EXPECT_STREQ(a.ptrs[4], "D");
2623 1 EXPECT_STREQ(a.ptrs[5], "E");
2624
2625 1 ptr_array_move(&a, 4, 5);
2626 1 EXPECT_STREQ(a.ptrs[4], "E");
2627 1 EXPECT_STREQ(a.ptrs[5], "D");
2628
2629 1 ptr_array_move(&a, 1, 3);
2630 1 EXPECT_STREQ(a.ptrs[1], "B");
2631 1 EXPECT_STREQ(a.ptrs[2], "C");
2632 1 EXPECT_STREQ(a.ptrs[3], "A");
2633
2634 1 ptr_array_move(&a, 3, 3);
2635 1 EXPECT_STREQ(a.ptrs[3], "A");
2636 1 ptr_array_move(&a, 1, 1);
2637 1 EXPECT_STREQ(a.ptrs[1], "B");
2638 1 ptr_array_move(&a, 0, 0);
2639 1 EXPECT_STREQ(a.ptrs[0], "F");
2640
2641 1 ptr_array_free(&a);
2642 1 }
2643
2644 1 static void test_ptr_array_insert(TestContext *ctx)
2645 {
2646 1 PointerArray a = PTR_ARRAY_INIT;
2647 1 ptr_array_insert(&a, xstrdup("D"), 0);
2648 1 ptr_array_insert(&a, xstrdup("C"), 0);
2649 1 ptr_array_insert(&a, xstrdup("B"), 0);
2650 1 ptr_array_insert(&a, xstrdup("A"), 0);
2651 1 EXPECT_EQ(a.count, 4);
2652
2653 1 ptr_array_insert(&a, xstrdup("X"), 1);
2654 1 ptr_array_insert(&a, xstrdup("Y"), 3);
2655 1 EXPECT_EQ(a.count, 6);
2656
2657 1 ptr_array_insert(&a, xstrdup("Z"), a.count);
2658 1 EXPECT_EQ(a.count, 7);
2659
2660 1 EXPECT_STREQ(a.ptrs[0], "A");
2661 1 EXPECT_STREQ(a.ptrs[1], "X");
2662 1 EXPECT_STREQ(a.ptrs[2], "B");
2663 1 EXPECT_STREQ(a.ptrs[3], "Y");
2664 1 EXPECT_STREQ(a.ptrs[4], "C");
2665 1 EXPECT_STREQ(a.ptrs[5], "D");
2666 1 EXPECT_STREQ(a.ptrs[6], "Z");
2667
2668 1 ptr_array_free(&a);
2669 1 }
2670
2671 1 static void test_list(TestContext *ctx)
2672 {
2673 1 ListHead a, b, c;
2674 1 list_init(&b);
2675 1 EXPECT_TRUE(list_empty(&b));
2676
2677 1 list_insert_before(&a, &b);
2678 1 EXPECT_FALSE(list_empty(&a));
2679 1 EXPECT_FALSE(list_empty(&b));
2680 1 EXPECT_PTREQ(a.next, &b);
2681 1 EXPECT_PTREQ(a.prev, &b);
2682 1 EXPECT_PTREQ(b.next, &a);
2683 1 EXPECT_PTREQ(b.prev, &a);
2684
2685 1 list_insert_after(&c, &b);
2686 1 EXPECT_FALSE(list_empty(&a));
2687 1 EXPECT_FALSE(list_empty(&b));
2688 1 EXPECT_FALSE(list_empty(&c));
2689 1 EXPECT_PTREQ(a.next, &b);
2690 1 EXPECT_PTREQ(a.prev, &c);
2691 1 EXPECT_PTREQ(b.next, &c);
2692 1 EXPECT_PTREQ(b.prev, &a);
2693 1 EXPECT_PTREQ(c.next, &a);
2694 1 EXPECT_PTREQ(c.prev, &b);
2695
2696 1 list_remove(&b);
2697 1 EXPECT_FALSE(list_empty(&a));
2698 1 EXPECT_FALSE(list_empty(&c));
2699 1 EXPECT_PTREQ(a.next, &c);
2700 1 EXPECT_PTREQ(a.prev, &c);
2701 1 EXPECT_PTREQ(c.next, &a);
2702 1 EXPECT_PTREQ(c.prev, &a);
2703 1 EXPECT_NULL(b.next);
2704 1 EXPECT_NULL(b.prev);
2705 1 }
2706
2707 1 static void test_hashmap(TestContext *ctx)
2708 {
2709 1 static const char strings[][8] = {
2710 "foo", "bar", "quux", "etc", "",
2711 "A", "B", "C", "D", "E", "F", "G",
2712 "a", "b", "c", "d", "e", "f", "g",
2713 "test", "1234567", "..", "...",
2714 "\x01\x02\x03 \t\xfe\xff",
2715 };
2716
2717 1 HashMap map;
2718 1 hashmap_init(&map, ARRAYLEN(strings), HMAP_NO_FLAGS);
2719 1 ASSERT_NONNULL(map.entries);
2720 1 EXPECT_EQ(map.mask, 31);
2721 1 EXPECT_EQ(map.count, 0);
2722 1 EXPECT_NULL(hashmap_find(&map, "foo"));
2723
2724 1 static const char value[] = "VALUE";
2725
2/2
✓ Branch 18 → 9 taken 24 times.
✓ Branch 18 → 19 taken 1 time.
26 FOR_EACH_I(i, strings) {
2726 24 const char *key = strings[i];
2727 24 ASSERT_EQ(key[sizeof(strings[0]) - 1], '\0');
2728 24 EXPECT_PTREQ(hashmap_insert(&map, xstrdup(key), (void*)value), value);
2729 24 HashMapEntry *e = hashmap_find(&map, key);
2730 24 ASSERT_NONNULL(e);
2731 24 EXPECT_STREQ(e->key, key);
2732 24 EXPECT_PTREQ(e->value, value);
2733 }
2734
2735 1 EXPECT_EQ(map.count, 24);
2736 1 EXPECT_EQ(map.mask, 31);
2737
2738 1 HashMapIter it = hashmap_iter(&map);
2739 1 EXPECT_PTREQ(it.map, &map);
2740 1 EXPECT_NULL(it.entry);
2741 1 EXPECT_EQ(it.idx, 0);
2742
2743
2/2
✓ Branch 29 → 25 taken 24 times.
✓ Branch 29 → 41 taken 1 time.
25 while (hashmap_next(&it)) {
2744 24 ASSERT_NONNULL(it.entry);
2745 24 ASSERT_NONNULL(it.entry->key);
2746 24 EXPECT_PTREQ(it.entry->value, value);
2747 }
2748
2749
2/2
✓ Branch 41 → 30 taken 24 times.
✓ Branch 41 → 42 taken 1 time.
25 FOR_EACH_I(i, strings) {
2750 24 const char *key = strings[i];
2751 24 HashMapEntry *e = hashmap_find(&map, key);
2752 24 ASSERT_NONNULL(e);
2753 24 EXPECT_STREQ(e->key, key);
2754 24 EXPECT_PTREQ(e->value, value);
2755 24 EXPECT_PTREQ(hashmap_remove(&map, key), value);
2756 24 EXPECT_STREQ(e->key, NULL);
2757 24 EXPECT_UINT_EQ(e->hash, 0xdead);
2758 24 EXPECT_NULL(hashmap_find(&map, key));
2759 }
2760
2761 1 EXPECT_EQ(map.count, 0);
2762 1 it = hashmap_iter(&map);
2763 1 EXPECT_FALSE(hashmap_next(&it));
2764
2765 1 EXPECT_PTREQ(hashmap_insert(&map, xstrdup("new"), (void*)value), value);
2766 1 ASSERT_NONNULL(hashmap_find(&map, "new"));
2767 1 EXPECT_STREQ(hashmap_find(&map, "new")->key, "new");
2768 1 EXPECT_EQ(map.count, 1);
2769
2770
2/2
✓ Branch 62 → 54 taken 24 times.
✓ Branch 62 → 63 taken 1 time.
26 FOR_EACH_I(i, strings) {
2771 24 const char *key = strings[i];
2772 24 EXPECT_PTREQ(hashmap_insert(&map, xstrdup(key), (void*)value), value);
2773 24 HashMapEntry *e = hashmap_find(&map, key);
2774 24 ASSERT_NONNULL(e);
2775 24 EXPECT_STREQ(e->key, key);
2776 24 EXPECT_PTREQ(e->value, value);
2777 }
2778
2779 1 EXPECT_EQ(map.count, 25);
2780
2781
2/2
✓ Branch 75 → 65 taken 24 times.
✓ Branch 75 → 76 taken 1 time.
26 FOR_EACH_I(i, strings) {
2782 24 const char *key = strings[i];
2783 24 HashMapEntry *e = hashmap_find(&map, key);
2784 24 ASSERT_NONNULL(e);
2785 24 EXPECT_STREQ(e->key, key);
2786 24 EXPECT_PTREQ(hashmap_remove(&map, key), value);
2787 24 EXPECT_STREQ(e->key, NULL);
2788 24 EXPECT_UINT_EQ(e->hash, 0xdead);
2789 24 EXPECT_NULL(hashmap_find(&map, key));
2790 }
2791
2792 1 EXPECT_EQ(map.count, 1);
2793 1 EXPECT_NULL(hashmap_remove(&map, "non-existent-key"));
2794 1 EXPECT_EQ(map.count, 1);
2795 1 EXPECT_PTREQ(hashmap_remove(&map, "new"), value);
2796 1 EXPECT_EQ(map.count, 0);
2797
2798 1 it = hashmap_iter(&map);
2799 1 EXPECT_FALSE(hashmap_next(&it));
2800
2801 1 hashmap_free(&map, NULL);
2802 1 EXPECT_NULL(map.entries);
2803 1 EXPECT_EQ(map.count, 0);
2804 1 EXPECT_EQ(map.mask, 0);
2805
2806 1 hashmap_init(&map, 0, HMAP_NO_FLAGS);
2807 1 ASSERT_NONNULL(map.entries);
2808 1 EXPECT_EQ(map.mask, 7);
2809 1 EXPECT_EQ(map.count, 0);
2810 1 hashmap_free(&map, NULL);
2811 1 EXPECT_NULL(map.entries);
2812
2813 1 hashmap_init(&map, 13, HMAP_NO_FLAGS);
2814 1 ASSERT_NONNULL(map.entries);
2815 1 EXPECT_EQ(map.mask, 31);
2816 1 EXPECT_EQ(map.count, 0);
2817
2818
2/2
✓ Branch 110 → 100 taken 380 times.
✓ Branch 110 → 111 taken 1 time.
382 for (unsigned int i = 1; i <= 380; i++) {
2819 380 char key[4];
2820 380 ASSERT_TRUE(buf_uint_to_str(i, key) < sizeof(key));
2821 380 EXPECT_PTREQ(hashmap_insert(&map, xstrdup(key), (void*)value), value);
2822 380 HashMapEntry *e = hashmap_find(&map, key);
2823 380 ASSERT_NONNULL(e);
2824 380 EXPECT_STREQ(e->key, key);
2825 380 EXPECT_PTREQ(e->value, value);
2826 }
2827
2828 1 EXPECT_EQ(map.count, 380);
2829 1 EXPECT_EQ(map.mask, 511);
2830 1 hashmap_free(&map, NULL);
2831
2832 1 static const char val[] = "VAL";
2833 1 char *key = xstrdup("KEY");
2834 1 EXPECT_NULL(hashmap_insert_or_replace(&map, key, (char*)val));
2835 1 EXPECT_EQ(map.count, 1);
2836 1 EXPECT_STREQ(hashmap_get(&map, "KEY"), val);
2837
2838 1 static const char new_val[] = "NEW";
2839 1 char *duplicate_key = xstrdup(key);
2840 1 EXPECT_PTREQ(val, hashmap_insert_or_replace(&map, duplicate_key, (char*)new_val));
2841 1 EXPECT_EQ(map.count, 1);
2842 1 EXPECT_STREQ(hashmap_get(&map, "KEY"), new_val);
2843 1 hashmap_free(&map, NULL);
2844 1 }
2845
2846 1 static void test_hashset(TestContext *ctx)
2847 {
2848 1 static const char *const strings[] = {
2849 "foo", "Foo", "bar", "quux", "etc",
2850 "\t\xff\x80\b", "\t\t\t", "\x01\x02\x03\xfe\xff",
2851 #if __STDC_VERSION__ >= 201112L
2852 (const char*)u8"ภาษาไทย",
2853 (const char*)u8"中文",
2854 (const char*)u8"日本語",
2855 #endif
2856 };
2857
2858 1 HashSet set;
2859 1 hashset_init(&set, ARRAYLEN(strings), false);
2860 1 EXPECT_EQ(set.nr_entries, 0);
2861 1 EXPECT_EQ(set.table_size, 16);
2862 1 EXPECT_EQ(set.grow_at, 12);
2863 1 EXPECT_NONNULL(set.table);
2864 1 EXPECT_NONNULL(set.hash);
2865 1 EXPECT_NONNULL(set.equal);
2866 1 EXPECT_NULL(hashset_get(&set, "foo", 3));
2867
2868 1 HashSetIter iter = hashset_iter(&set);
2869 1 EXPECT_PTREQ(iter.set, &set);
2870 1 EXPECT_NULL(iter.entry);
2871 1 EXPECT_EQ(iter.idx, 0);
2872 1 EXPECT_FALSE(hashset_next(&iter));
2873 1 EXPECT_PTREQ(iter.set, &set);
2874 1 EXPECT_NULL(iter.entry);
2875 1 EXPECT_EQ(iter.idx, 0);
2876
2877
2/2
✓ Branch 22 → 20 taken 11 times.
✓ Branch 22 → 26 taken 1 time.
13 FOR_EACH_I(i, strings) {
2878 11 hashset_insert(&set, strings[i], strlen(strings[i]));
2879 }
2880
2881
2/2
✓ Branch 26 → 23 taken 11 times.
✓ Branch 26 → 27 taken 1 time.
12 FOR_EACH_I(i, strings) {
2882 11 EXPECT_TRUE(hashset_next(&iter));
2883 }
2884 1 EXPECT_FALSE(hashset_next(&iter));
2885 1 EXPECT_FALSE(hashset_next(&iter));
2886
2887 1 EXPECT_EQ(set.nr_entries, ARRAYLEN(strings));
2888 1 EXPECT_NONNULL(hashset_get(&set, "\t\xff\x80\b", 4));
2889 1 EXPECT_NONNULL(hashset_get(&set, "foo", 3));
2890 1 EXPECT_NONNULL(hashset_get(&set, "Foo", 3));
2891
2892 1 EXPECT_NULL(hashset_get(&set, "FOO", 3));
2893 1 EXPECT_NULL(hashset_get(&set, "", 0));
2894 1 EXPECT_NULL(hashset_get(&set, NULL, 0));
2895 1 EXPECT_NULL(hashset_get(&set, "\0", 1));
2896
2897 1 const char *last_string = strings[ARRAYLEN(strings) - 1];
2898 1 EXPECT_NONNULL(hashset_get(&set, last_string, strlen(last_string)));
2899
2900
2/2
✓ Branch 56 → 49 taken 11 times.
✓ Branch 56 → 57 taken 1 time.
13 FOR_EACH_I(i, strings) {
2901 11 const char *str = strings[i];
2902 11 const size_t len = strlen(str);
2903 11 EXPECT_NONNULL(hashset_get(&set, str, len));
2904 11 EXPECT_NULL(hashset_get(&set, str, len - 1));
2905 11 EXPECT_NULL(hashset_get(&set, str + 1, len - 1));
2906 }
2907
2908 1 hashset_free(&set);
2909 1 hashset_init(&set, 0, true);
2910 1 EXPECT_EQ(set.nr_entries, 0);
2911 1 hashset_insert(&set, STRN("foo"));
2912 1 hashset_insert(&set, STRN("Foo"));
2913 1 EXPECT_EQ(set.nr_entries, 1);
2914 1 EXPECT_NONNULL(hashset_get(&set, STRN("foo")));
2915 1 EXPECT_NONNULL(hashset_get(&set, STRN("FOO")));
2916 1 EXPECT_NONNULL(hashset_get(&set, STRN("fOO")));
2917 1 hashset_free(&set);
2918
2919 // Check that hashset_insert() returns existing entries instead of
2920 // inserting duplicates
2921 1 hashset_init(&set, 0, false);
2922 1 EXPECT_EQ(set.nr_entries, 0);
2923 1 HashSetEntry *e1 = hashset_insert(&set, STRN("foo"));
2924 1 EXPECT_EQ(e1->str_len, 3);
2925 1 EXPECT_STREQ(e1->str, "foo");
2926 1 EXPECT_EQ(set.nr_entries, 1);
2927 1 HashSetEntry *e2 = hashset_insert(&set, STRN("foo"));
2928 1 EXPECT_PTREQ(e1, e2);
2929 1 EXPECT_EQ(set.nr_entries, 1);
2930 1 hashset_free(&set);
2931
2932 1 hashset_init(&set, 0, false);
2933 // Initial table size should be 16 (minimum + load factor + rounding)
2934 1 EXPECT_EQ(set.table_size, 16);
2935
2/2
✓ Branch 87 → 83 taken 80 times.
✓ Branch 87 → 88 taken 1 time.
82 for (unsigned int i = 1; i <= 80; i++) {
2936 80 char buf[4];
2937 80 size_t len = buf_uint_to_str(i, buf);
2938 80 ASSERT_TRUE(len < sizeof(buf));
2939 80 hashset_insert(&set, buf, len);
2940 }
2941 1 EXPECT_EQ(set.nr_entries, 80);
2942 1 EXPECT_NONNULL(hashset_get(&set, STRN("1")));
2943 1 EXPECT_NONNULL(hashset_get(&set, STRN("80")));
2944 1 EXPECT_NULL(hashset_get(&set, STRN("0")));
2945 1 EXPECT_NULL(hashset_get(&set, STRN("81")));
2946 // Table size should be the first power of 2 larger than the number
2947 // of entries (including load factor adjustment)
2948 1 EXPECT_EQ(set.table_size, 128);
2949 1 hashset_free(&set);
2950 1 }
2951
2952 1 static void test_intmap(TestContext *ctx)
2953 {
2954 1 IntMap map = INTMAP_INIT;
2955 1 EXPECT_NULL(intmap_find(&map, 0));
2956 1 EXPECT_NULL(intmap_get(&map, 0));
2957 1 intmap_free(&map, free);
2958
2959 1 static const char value[] = "value";
2960 1 EXPECT_NULL(intmap_insert_or_replace(&map, 0, xstrdup(value)));
2961 1 EXPECT_NULL(intmap_insert_or_replace(&map, 1, xstrdup(value)));
2962 1 EXPECT_NULL(intmap_insert_or_replace(&map, 2, xstrdup(value)));
2963 1 EXPECT_NULL(intmap_insert_or_replace(&map, 4, xstrdup(value)));
2964 1 EXPECT_EQ(map.count, 4);
2965 1 EXPECT_EQ(map.mask, 7);
2966
2967 1 char *replaced = intmap_insert_or_replace(&map, 0, xstrdup(value));
2968 1 EXPECT_STREQ(replaced, value);
2969 1 free(replaced);
2970 1 EXPECT_EQ(map.tombstones, 0);
2971 1 EXPECT_STREQ(intmap_get(&map, 0), value);
2972
2973 1 char *removed = intmap_remove(&map, 0);
2974 1 EXPECT_STREQ(removed, value);
2975 1 free(removed);
2976 1 EXPECT_EQ(map.tombstones, 1);
2977 1 EXPECT_NULL(intmap_get(&map, 0));
2978
2979 1 EXPECT_NULL(intmap_insert_or_replace(&map, 100, xstrdup(value)));
2980 1 EXPECT_NULL(intmap_insert_or_replace(&map, 488, xstrdup(value)));
2981 1 EXPECT_NULL(intmap_insert_or_replace(&map, 899, xstrdup(value)));
2982 1 EXPECT_NULL(intmap_insert_or_replace(&map, 256, xstrdup(value)));
2983 1 EXPECT_EQ(map.count, 7);
2984 1 EXPECT_EQ(map.mask, 15);
2985
2986 1 intmap_free(&map, free);
2987 1 }
2988
2989 1 static void test_next_multiple(TestContext *ctx)
2990 {
2991 1 EXPECT_EQ(next_multiple(0, 1), 0);
2992 1 EXPECT_EQ(next_multiple(1, 1), 1);
2993 1 EXPECT_EQ(next_multiple(2, 1), 2);
2994 1 EXPECT_EQ(next_multiple(3, 1), 3);
2995 1 EXPECT_EQ(next_multiple(0, 2), 0);
2996 1 EXPECT_EQ(next_multiple(1, 2), 2);
2997 1 EXPECT_EQ(next_multiple(5, 2), 6);
2998 1 EXPECT_EQ(next_multiple(1, 8), 8);
2999 1 EXPECT_EQ(next_multiple(3, 8), 8);
3000 1 EXPECT_EQ(next_multiple(8, 8), 8);
3001 1 EXPECT_EQ(next_multiple(9, 8), 16);
3002 1 EXPECT_EQ(next_multiple(0, 8), 0);
3003 1 EXPECT_EQ(next_multiple(0, 16), 0);
3004 1 EXPECT_EQ(next_multiple(1, 16), 16);
3005 1 EXPECT_EQ(next_multiple(123, 16), 128);
3006 1 EXPECT_EQ(next_multiple(4, 64), 64);
3007 1 EXPECT_EQ(next_multiple(80, 64), 128);
3008 1 EXPECT_EQ(next_multiple(256, 256), 256);
3009 1 EXPECT_EQ(next_multiple(257, 256), 512);
3010 1 EXPECT_EQ(next_multiple(8000, 256), 8192);
3011
3012
2/2
✓ Branch 27 → 25 taken 70 times.
✓ Branch 27 → 28 taken 1 time.
72 for (size_t i = 0; i < 70; i++) {
3013
2/2
✓ Branch 25 → 23 taken 490 times.
✓ Branch 25 → 26 taken 70 times.
560 for (size_t p2 = 64; p2; p2 >>= 1) {
3014 490 size_t remainder_complement = (-i & (p2 - 1));
3015 490 IEXPECT_EQ(next_multiple(i, p2), i + remainder_complement);
3016 }
3017 }
3018
3019 1 const size_t size_max = (size_t)-1;
3020 1 const size_t pow2_max = size_max & ~(size_max >> 1);
3021 1 EXPECT_TRUE(IS_POWER_OF_2(pow2_max));
3022 1 EXPECT_UINT_EQ(next_multiple(size_max, 1), size_max);
3023 1 EXPECT_UINT_EQ(next_multiple(pow2_max, 1), pow2_max);
3024 1 EXPECT_UINT_EQ(next_multiple(pow2_max, pow2_max), pow2_max);
3025
3026 // Note: returns 0 on overflow
3027 1 EXPECT_UINT_EQ(next_multiple(pow2_max + 1, pow2_max), 0);
3028 1 EXPECT_UINT_EQ(next_multiple(size_max + 0, pow2_max), 0);
3029 1 EXPECT_UINT_EQ(next_multiple(size_max - 1, pow2_max), 0);
3030
3031 1 const size_t a = pow2_max >> 1;
3032 1 EXPECT_UINT_EQ(next_multiple(a, a), a);
3033 1 EXPECT_UINT_EQ(next_multiple(a + 1, a), pow2_max);
3034 1 }
3035
3036 1 static void test_next_pow2(TestContext *ctx)
3037 {
3038 1 EXPECT_UINT_EQ(next_pow2(0), 1);
3039 1 EXPECT_UINT_EQ(next_pow2(1), 1);
3040 1 EXPECT_UINT_EQ(next_pow2(2), 2);
3041 1 EXPECT_UINT_EQ(next_pow2(3), 4);
3042 1 EXPECT_UINT_EQ(next_pow2(4), 4);
3043 1 EXPECT_UINT_EQ(next_pow2(5), 8);
3044 1 EXPECT_UINT_EQ(next_pow2(8), 8);
3045 1 EXPECT_UINT_EQ(next_pow2(9), 16);
3046 1 EXPECT_UINT_EQ(next_pow2(17), 32);
3047 1 EXPECT_UINT_EQ(next_pow2(61), 64);
3048 1 EXPECT_UINT_EQ(next_pow2(64), 64);
3049 1 EXPECT_UINT_EQ(next_pow2(65), 128);
3050 1 EXPECT_UINT_EQ(next_pow2(200), 256);
3051 1 EXPECT_UINT_EQ(next_pow2(1000), 1024);
3052 1 EXPECT_UINT_EQ(next_pow2(5500), 8192);
3053
3054 1 const size_t size_max = (size_t)-1;
3055 1 const size_t pow2_max = ~(size_max >> 1);
3056 1 EXPECT_TRUE(IS_POWER_OF_2(pow2_max));
3057 1 EXPECT_UINT_EQ(next_pow2(size_max >> 1), pow2_max);
3058 1 EXPECT_UINT_EQ(next_pow2(pow2_max), pow2_max);
3059 1 EXPECT_UINT_EQ(next_pow2(pow2_max - 1), pow2_max);
3060
3061 // Note: returns 0 on overflow
3062 1 EXPECT_UINT_EQ(next_pow2(pow2_max + 1), 0);
3063 1 EXPECT_UINT_EQ(next_pow2(size_max), 0);
3064 1 EXPECT_UINT_EQ(next_pow2(size_max - 1), 0);
3065 1 }
3066
3067 1 static void test_popcount(TestContext *ctx)
3068 {
3069 1 EXPECT_EQ(u32_popcount(0), 0);
3070 1 EXPECT_EQ(u32_popcount(1), 1);
3071 1 EXPECT_EQ(u32_popcount(11), 3);
3072 1 EXPECT_EQ(u32_popcount(128), 1);
3073 1 EXPECT_EQ(u32_popcount(255), 8);
3074 1 EXPECT_EQ(u32_popcount(UINT32_MAX), 32);
3075 1 EXPECT_EQ(u32_popcount(UINT32_MAX - 1), 31);
3076 1 EXPECT_EQ(u32_popcount(0xE10F02C9u), 13);
3077
3078 1 EXPECT_EQ(u64_popcount(0), 0);
3079 1 EXPECT_EQ(u64_popcount(1), 1);
3080 1 EXPECT_EQ(u64_popcount(255), 8);
3081 1 EXPECT_EQ(u64_popcount(UINT64_MAX), 64);
3082 1 EXPECT_EQ(u64_popcount(UINT64_MAX - 1), 63);
3083 1 EXPECT_EQ(u64_popcount(0xFFFFFFFFFFull), 40);
3084 1 EXPECT_EQ(u64_popcount(0x10000000000ull), 1);
3085 1 EXPECT_EQ(u64_popcount(0x9010F0EEC2003B70ull), 24);
3086
3087
2/2
✓ Branch 23 → 19 taken 32 times.
✓ Branch 23 → 28 taken 1 time.
34 for (unsigned int i = 0; i < 32; i++) {
3088 32 IEXPECT_EQ(u32_popcount(UINT32_MAX << i), 32 - i);
3089 32 IEXPECT_EQ(u32_popcount(UINT32_MAX >> i), 32 - i);
3090 32 IEXPECT_EQ(u32_popcount(1u << i), 1);
3091 }
3092
3093
2/2
✓ Branch 28 → 24 taken 64 times.
✓ Branch 28 → 29 taken 1 time.
65 for (unsigned int i = 0; i < 64; i++) {
3094 64 IEXPECT_EQ(u64_popcount(UINT64_MAX << i), 64 - i);
3095 64 IEXPECT_EQ(u64_popcount(UINT64_MAX >> i), 64 - i);
3096 64 IEXPECT_EQ(u64_popcount(1ull << i), 1);
3097 }
3098 1 }
3099
3100 1 static void test_ctz(TestContext *ctx)
3101 {
3102 1 EXPECT_EQ(u32_ctz(1), 0);
3103 1 EXPECT_EQ(u32_ctz(11), 0);
3104 1 EXPECT_EQ(u32_ctz(127), 0);
3105 1 EXPECT_EQ(u32_ctz(128), 7);
3106 1 EXPECT_EQ(u32_ctz(129), 0);
3107 1 EXPECT_EQ(u32_ctz(130), 1);
3108 1 EXPECT_EQ(u32_ctz(255), 0);
3109 1 EXPECT_EQ(u32_ctz(UINT32_MAX), 0);
3110 1 EXPECT_EQ(u32_ctz(UINT32_MAX - 1), 1);
3111 1 EXPECT_EQ(u32_ctz(0xE10F02C9u), 0);
3112 1 EXPECT_EQ(u32_ctz(0xE10F02CCu), 2);
3113
3114 1 EXPECT_EQ(umax_ctz(1), 0);
3115 1 EXPECT_EQ(umax_ctz(11), 0);
3116 1 EXPECT_EQ(umax_ctz(127), 0);
3117 1 EXPECT_EQ(umax_ctz(128), 7);
3118 1 EXPECT_EQ(umax_ctz(129), 0);
3119 1 EXPECT_EQ(umax_ctz(130), 1);
3120 1 EXPECT_EQ(umax_ctz(255), 0);
3121 1 EXPECT_EQ(umax_ctz(0xE10F02C9u), 0);
3122 1 EXPECT_EQ(umax_ctz(0xE10F02CCu), 2);
3123 1 EXPECT_EQ(umax_ctz(0x8000000000000000ull), 63);
3124 1 EXPECT_EQ(umax_ctz(UINTMAX_MAX), 0);
3125 1 EXPECT_EQ(umax_ctz(UINTMAX_MAX - 1), 1);
3126 1 EXPECT_EQ(umax_ctz(UINTMAX_MAX - 7), 3);
3127 1 }
3128
3129 1 static void test_ffs(TestContext *ctx)
3130 {
3131 1 EXPECT_EQ(u32_ffs(0), 0);
3132 1 EXPECT_EQ(u32_ffs(1), 1);
3133 1 EXPECT_EQ(u32_ffs(6), 2);
3134 1 EXPECT_EQ(u32_ffs(8), 4);
3135 1 EXPECT_EQ(u32_ffs(255), 1);
3136 1 EXPECT_EQ(u32_ffs(256), 9);
3137 1 EXPECT_EQ(u32_ffs(UINT32_MAX), 1);
3138 1 EXPECT_EQ(u32_ffs(UINT32_MAX - 1), 2);
3139 1 EXPECT_EQ(u32_ffs(UINT32_MAX << 8), 9);
3140 1 EXPECT_EQ(u32_ffs(1u << 31), 32);
3141 1 EXPECT_EQ(u32_ffs(1u << 30), 31);
3142 1 EXPECT_EQ(u32_ffs(1u << 18), 19);
3143 1 }
3144
3145 1 static void test_lsbit(TestContext *ctx)
3146 {
3147 1 EXPECT_EQ(u32_lsbit(0), 0);
3148 1 EXPECT_EQ(u32_lsbit(1), 1);
3149 1 EXPECT_EQ(u32_lsbit(2), 2);
3150 1 EXPECT_EQ(u32_lsbit(3), 1);
3151 1 EXPECT_EQ(u32_lsbit(4), 4);
3152 1 EXPECT_EQ(u32_lsbit(255), 1);
3153 1 EXPECT_EQ(u32_lsbit(256), 256);
3154 1 EXPECT_EQ(u32_lsbit(257), 1);
3155 1 EXPECT_EQ(u32_lsbit(258), 2);
3156 1 EXPECT_EQ(u32_lsbit(1u << 31), 1u << 31);
3157 1 EXPECT_EQ(u32_lsbit(1u << 30), 1u << 30);
3158 1 EXPECT_EQ(u32_lsbit(7u << 30), 1u << 30);
3159 1 EXPECT_EQ(u32_lsbit(UINT32_MAX), 1);
3160 1 EXPECT_EQ(u32_lsbit(UINT32_MAX << 25), 1u << 25);
3161
3162
2/2
✓ Branch 23 → 17 taken 69 times.
✓ Branch 23 → 24 taken 1 time.
71 for (uint32_t i = 1; i < 70; i++) {
3163 69 uint32_t lsb = u32_lsbit(i);
3164 69 IEXPECT_TRUE(IS_POWER_OF_2(lsb));
3165 69 IEXPECT_TRUE(lsb & i);
3166 }
3167 1 }
3168
3169 1 static void test_msbit(TestContext *ctx)
3170 {
3171 1 EXPECT_EQ(size_msbit(0), 0);
3172 1 EXPECT_EQ(size_msbit(1), 1);
3173 1 EXPECT_EQ(size_msbit(2), 2);
3174 1 EXPECT_EQ(size_msbit(3), 2);
3175 1 EXPECT_EQ(size_msbit(4), 4);
3176 1 EXPECT_EQ(size_msbit(7), 4);
3177 1 EXPECT_EQ(size_msbit(8), 8);
3178 1 EXPECT_EQ(size_msbit(255), 128);
3179 1 EXPECT_EQ(size_msbit(256), 256);
3180 1 EXPECT_UINT_EQ(size_msbit(0x1FFFu), 0x1000u);
3181 1 EXPECT_UINT_EQ(size_msbit(0xFFFFu), 0x8000u);
3182
3183 1 const size_t max = SIZE_MAX;
3184 1 const size_t max_pow2 = ~(max >> 1);
3185 1 EXPECT_UINT_EQ(size_msbit(max), max_pow2);
3186 1 EXPECT_UINT_EQ(size_msbit(max - 1), max_pow2);
3187 1 EXPECT_UINT_EQ(size_msbit(max_pow2), max_pow2);
3188 1 EXPECT_UINT_EQ(size_msbit(max_pow2 - 1), max_pow2 >> 1);
3189 1 EXPECT_UINT_EQ(size_msbit(max_pow2 + 1), max_pow2);
3190
3191
2/2
✓ Branch 25 → 19 taken 69 times.
✓ Branch 25 → 26 taken 1 time.
71 for (size_t i = 1; i < 70; i++) {
3192 69 size_t msb = size_msbit(i);
3193 69 IEXPECT_TRUE(IS_POWER_OF_2(msb));
3194 69 IEXPECT_TRUE(msb & i);
3195 }
3196 1 }
3197
3198 1 static void test_clz(TestContext *ctx)
3199 {
3200 1 EXPECT_EQ(u64_clz(1), 63);
3201 1 EXPECT_EQ(u64_clz(2), 62);
3202 1 EXPECT_EQ(u64_clz(3), 62);
3203 1 EXPECT_EQ(u64_clz(1ULL << 10), 53);
3204 1 EXPECT_EQ(u64_clz(1ULL << 55), 8);
3205 1 EXPECT_EQ(u64_clz(1ULL << 63), 0);
3206 1 EXPECT_EQ(u64_clz(UINT64_MAX), 0);
3207 1 EXPECT_EQ(u64_clz(UINT64_MAX >> 1), 1);
3208 1 EXPECT_EQ(u64_clz(UINT64_MAX >> 3), 3);
3209 1 }
3210
3211 1 static void test_umax_bitwidth(TestContext *ctx)
3212 {
3213 1 EXPECT_EQ(umax_bitwidth(0), 0);
3214 1 EXPECT_EQ(umax_bitwidth(1), 1);
3215 1 EXPECT_EQ(umax_bitwidth(2), 2);
3216 1 EXPECT_EQ(umax_bitwidth(3), 2);
3217 1 EXPECT_EQ(umax_bitwidth(0x80), 8);
3218 1 EXPECT_EQ(umax_bitwidth(0xFF), 8);
3219 1 EXPECT_EQ(umax_bitwidth(0x10081), 17);
3220 1 EXPECT_EQ(umax_bitwidth(1ULL << 62), 63);
3221 1 EXPECT_EQ(umax_bitwidth(0xFFFFFFFFFFFFFFFFULL), 64);
3222 1 }
3223
3224 1 static void test_umax_count_base16_digits(TestContext *ctx)
3225 {
3226 1 EXPECT_EQ(umax_count_base16_digits(0x0), 1);
3227 1 EXPECT_EQ(umax_count_base16_digits(0x1), 1);
3228 1 EXPECT_EQ(umax_count_base16_digits(0x2), 1);
3229 1 EXPECT_EQ(umax_count_base16_digits(0x3), 1);
3230 1 EXPECT_EQ(umax_count_base16_digits(0x4), 1);
3231 1 EXPECT_EQ(umax_count_base16_digits(0x5), 1);
3232 1 EXPECT_EQ(umax_count_base16_digits(0x6), 1);
3233 1 EXPECT_EQ(umax_count_base16_digits(0x7), 1);
3234 1 EXPECT_EQ(umax_count_base16_digits(0x8), 1);
3235 1 EXPECT_EQ(umax_count_base16_digits(0x9), 1);
3236 1 EXPECT_EQ(umax_count_base16_digits(0xA), 1);
3237 1 EXPECT_EQ(umax_count_base16_digits(0xB), 1);
3238 1 EXPECT_EQ(umax_count_base16_digits(0xF), 1);
3239 1 EXPECT_EQ(umax_count_base16_digits(0x10), 2);
3240 1 EXPECT_EQ(umax_count_base16_digits(0x111), 3);
3241 1 EXPECT_EQ(umax_count_base16_digits(0xFF11), 4);
3242 1 EXPECT_EQ(umax_count_base16_digits(0x80000000ULL), 8);
3243 1 EXPECT_EQ(umax_count_base16_digits(0x800000000ULL), 9);
3244 1 EXPECT_EQ(umax_count_base16_digits(0X98EA412F0ULL), 9);
3245 1 EXPECT_EQ(umax_count_base16_digits(0x8000000000000000ULL), 16);
3246 1 EXPECT_EQ(umax_count_base16_digits(0xFFFFFFFFFFFFFFFFULL), 16);
3247 1 }
3248
3249 1 static void test_path_dirname_basename(TestContext *ctx)
3250 {
3251 1 static const struct {
3252 const char *path;
3253 const char *dirname;
3254 const char *basename;
3255 } tests[] = {
3256 {"/home/user/example.txt", "/home/user", "example.txt"},
3257 {"./../dir/example.txt", "./../dir", "example.txt"},
3258 {"example.txt", ".", "example.txt"},
3259 {"/usr/lib", "/usr", "lib"},
3260 {"/usr", "/", "usr"},
3261 {"usr", ".", "usr"},
3262 {"/", "/", ""},
3263 {".", ".", "."},
3264 {"..", ".", ".."},
3265 {"", ".", ""},
3266 // For edge case coverage only; see comment above path_basename()
3267 {"/usr/bin/", "/usr/bin", ""},
3268 };
3269
3270
2/2
✓ Branch 10 → 3 taken 11 times.
✓ Branch 10 → 11 taken 1 time.
12 FOR_EACH_I(i, tests) {
3271 11 EXPECT_STRVIEW_EQ_CSTRING(path_slice_dirname(tests[i].path), tests[i].dirname);
3272 11 EXPECT_STRVIEW_EQ_CSTRING(path_slice_basename(strview(tests[i].path)), tests[i].basename);
3273 11 IEXPECT_STREQ(path_basename(tests[i].path), tests[i].basename);
3274
3275 11 char *dir = path_dirname(tests[i].path);
3276 11 IEXPECT_STREQ(dir, tests[i].dirname);
3277 11 free(dir);
3278 }
3279
3280 1 EXPECT_STRVIEW_EQ_CSTRING(path_slice_basename(strview(NULL)), "");
3281 1 }
3282
3283 1 static void test_path_relative(TestContext *ctx)
3284 {
3285 1 static const struct {
3286 const char *cwd;
3287 const char *path;
3288 const char *result;
3289 } tests[] = { // NOTE: at most 2 ".." components allowed in relative name
3290 { "/", "/", "/" },
3291 { "/", "/file", "file" },
3292 { "/a/b/c/d", "/a/b/file", "../../file" },
3293 { "/a/b/c/d/e", "/a/b/file", "/a/b/file" },
3294 { "/a/foobar", "/a/foo/file", "../foo/file" },
3295 { "/home/user", "/home/userx", "../userx"},
3296 { "/home/user", "/home/use", "../use"},
3297 { "/home/user", "/home/user", "."},
3298 { "/home", "/home/user", "user"},
3299 };
3300
3301
2/2
✓ Branch 6 → 3 taken 9 times.
✓ Branch 6 → 7 taken 1 time.
10 FOR_EACH_I(i, tests) {
3302 9 char *result = path_relative(tests[i].path, tests[i].cwd);
3303 9 IEXPECT_STREQ(tests[i].result, result);
3304 9 free(result);
3305 }
3306 1 }
3307
3308 1 static void test_path_slice_relative(TestContext *ctx)
3309 {
3310 1 static const char abs[] = "/a/b/c/d";
3311 1 EXPECT_PTREQ(path_slice_relative(abs, "/a/b/c/d/e"), abs);
3312 1 EXPECT_PTREQ(path_slice_relative(abs, "/a/b/file"), abs);
3313 1 EXPECT_STREQ(path_slice_relative(abs, "/a/b/c/d"), ".");
3314 1 EXPECT_STREQ(path_slice_relative(abs, "/a/b/c"), "d");
3315 1 EXPECT_STREQ(path_slice_relative(abs, "/"), "a/b/c/d");
3316 1 EXPECT_PTREQ(path_slice_relative(abs, "/a/b/c"), abs + STRLEN("/a/b/c/"));
3317 1 EXPECT_STREQ(path_slice_relative("/", "/"), "/");
3318 1 EXPECT_STREQ(path_slice_relative("/aa/bb/ccX", "/aa/bb/cc"), "/aa/bb/ccX");
3319 1 }
3320
3321 1 static void test_short_filename_cwd(TestContext *ctx)
3322 {
3323 1 const StringView home = strview("/home/user");
3324 1 char *s = short_filename_cwd("/home/user", "/home/user", home);
3325 1 EXPECT_STREQ(s, ".");
3326 1 free(s);
3327
3328 1 s = short_filename_cwd("/home/use", "/home/user", home);
3329 1 EXPECT_STREQ(s, "../use");
3330 1 free(s);
3331
3332 1 s = short_filename_cwd("/a/b/c/d", "/a/x/y/file", home);
3333 1 EXPECT_STREQ(s, "/a/b/c/d");
3334 1 free(s);
3335
3336 1 s = short_filename_cwd("/home/user/file", "/home/user/cwd", home);
3337 1 EXPECT_STREQ(s, "~/file");
3338 1 free(s);
3339
3340 1 static const char abs[] = "/a/b";
3341 1 static const char cwd[] = "/a/x/c";
3342 1 char *rel = path_relative(abs, cwd);
3343 1 EXPECT_TRUE(strlen(abs) < strlen(rel));
3344 1 EXPECT_STREQ(rel, "../../b");
3345 1 free(rel);
3346 1 s = short_filename_cwd(abs, cwd, home);
3347 1 EXPECT_STREQ(s, "/a/b");
3348 1 free(s);
3349 1 }
3350
3351 1 static void test_short_filename(TestContext *ctx)
3352 {
3353 1 const StringView home = strview("/home/user");
3354 1 static const char rel[] = "test/main.c";
3355 1 char *abs = path_absolute(rel);
3356 1 ASSERT_NONNULL(abs);
3357 1 char *s = short_filename(abs, home);
3358 1 EXPECT_STREQ(s, rel);
3359 1 free(abs);
3360 1 free(s);
3361
3362 1 s = short_filename("/home/user/subdir/file.txt", home);
3363 1 EXPECT_STREQ(s, "~/subdir/file.txt");
3364 1 free(s);
3365
3366 1 s = short_filename("/x/y/z", home);
3367 1 EXPECT_STREQ(s, "/x/y/z");
3368 1 free(s);
3369 1 }
3370
3371 1 static void test_path_absolute(TestContext *ctx)
3372 {
3373 1 char *path = path_absolute("///dev///");
3374 1 EXPECT_STREQ(path, "/dev");
3375 1 free(path);
3376
3377 1 path = path_absolute("///dev///..///dev//");
3378 1 EXPECT_STREQ(path, "/dev");
3379 1 free(path);
3380
3381 1 path = path_absolute("///dev//n0nexist3nt-file");
3382 1 EXPECT_STREQ(path, "/dev/n0nexist3nt-file");
3383 1 free(path);
3384
3385 1 errno = 0;
3386 1 path = path_absolute("/dev/-n0n-existent-dir-[];/file");
3387 1 EXPECT_EQ(errno, ENOENT);
3388 1 EXPECT_STREQ(path, NULL);
3389 1 free(path);
3390
3391 1 path = path_absolute("///../..//./");
3392 1 EXPECT_STREQ(path, "/");
3393 1 free(path);
3394
3395 1 path = path_absolute("/");
3396 1 EXPECT_STREQ(path, "/");
3397 1 free(path);
3398
3399 1 path = path_absolute("");
3400 1 EXPECT_STREQ(path, NULL);
3401 1 free(path);
3402
3403 1 static const char linkpath[] = "./build/test/../test/test-symlink";
3404
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 22 taken 1 time.
1 if (symlink("../gen/platform.mk", linkpath) != 0) {
3405 TEST_FAIL("symlink() failed: %s", strerror(errno));
3406 return;
3407 }
3408 1 test_pass(ctx);
3409
3410 1 path = path_absolute(linkpath);
3411 1 EXPECT_EQ(unlink(linkpath), 0);
3412 1 ASSERT_NONNULL(path);
3413 1 EXPECT_STREQ(path_basename(path), "platform.mk");
3414 1 free(path);
3415 }
3416
3417 1 static void test_path_join(TestContext *ctx)
3418 {
3419 1 char *p = path_join("/", "file");
3420 1 EXPECT_STREQ(p, "/file");
3421 1 free(p);
3422 1 p = path_join("foo", "bar");
3423 1 EXPECT_STREQ(p, "foo/bar");
3424 1 free(p);
3425 1 p = path_join("foo/", "bar");
3426 1 EXPECT_STREQ(p, "foo/bar");
3427 1 free(p);
3428 1 p = path_join("", "bar");
3429 1 EXPECT_STREQ(p, "bar");
3430 1 free(p);
3431 1 p = path_join("foo", "");
3432 1 EXPECT_STREQ(p, "foo");
3433 1 free(p);
3434 1 p = path_join("", "");
3435 1 EXPECT_STREQ(p, "");
3436 1 free(p);
3437 1 p = path_join("/", "");
3438 1 EXPECT_STREQ(p, "/");
3439 1 free(p);
3440 1 p = path_join("/home/user", ".dte");
3441 1 EXPECT_STREQ(p, "/home/user/.dte");
3442 1 free(p);
3443 1 p = path_join("/home/user/", ".dte");
3444 1 EXPECT_STREQ(p, "/home/user/.dte");
3445 1 free(p);
3446 1 p = path_join("/home/user//", ".dte");
3447 1 EXPECT_STREQ(p, "/home/user//.dte");
3448 1 free(p);
3449 1 p = path_join(NULL, NULL);
3450 1 EXPECT_STREQ(p, "");
3451 1 free(p);
3452
3453 1 p = path_join_sv(strview("foo"), strview("bar"), true);
3454 1 EXPECT_STREQ(p, "foo/bar/");
3455 1 free(p);
3456 1 p = path_join_sv(strview("foo"), strview("bar"), false);
3457 1 EXPECT_STREQ(p, "foo/bar");
3458 1 free(p);
3459 1 p = path_join_sv(strview(""), strview(""), true);
3460 1 EXPECT_STREQ(p, "");
3461 1 free(p);
3462 1 p = path_join_sv(strview("/"), strview(""), true);
3463 1 EXPECT_STREQ(p, "/");
3464 1 free(p);
3465 1 p = path_join_sv(strview(""), strview("file"), true);
3466 1 EXPECT_STREQ(p, "file/");
3467 1 free(p);
3468 1 p = path_join_sv(strview(""), strview("file"), false);
3469 1 EXPECT_STREQ(p, "file");
3470 1 free(p);
3471 1 p = path_join_sv(strview(""), strview("file/"), true);
3472 1 EXPECT_STREQ(p, "file/");
3473 1 free(p);
3474 1 p = path_join_sv(strview(NULL), strview(NULL), false);
3475 1 EXPECT_STREQ(p, "");
3476 1 free(p);
3477 1 }
3478
3479 1 static void test_path_parent(TestContext *ctx)
3480 {
3481 1 StringView sv = strview("/a/foo/bar/etc/file");
3482 1 EXPECT_EQ(sv.length, 19);
3483 1 EXPECT_TRUE(path_parent(&sv));
3484 1 EXPECT_EQ(sv.length, 14);
3485 1 EXPECT_TRUE(path_parent(&sv));
3486 1 EXPECT_EQ(sv.length, 10);
3487 1 EXPECT_TRUE(path_parent(&sv));
3488 1 EXPECT_EQ(sv.length, 6);
3489 1 EXPECT_TRUE(path_parent(&sv));
3490 1 EXPECT_EQ(sv.length, 2);
3491 1 EXPECT_TRUE(path_parent(&sv));
3492 1 EXPECT_EQ(sv.length, 1);
3493 1 EXPECT_FALSE(path_parent(&sv));
3494 1 EXPECT_EQ(sv.length, 1);
3495
3496 1 StringView sv2 = strview("/etc/foo/x/y/");
3497 1 EXPECT_EQ(sv2.length, 13);
3498 1 EXPECT_TRUE(path_parent(&sv2));
3499 1 EXPECT_EQ(sv2.length, 10);
3500 1 EXPECT_TRUE(path_parent(&sv2));
3501 1 EXPECT_EQ(sv2.length, 8);
3502 1 EXPECT_TRUE(path_parent(&sv2));
3503 1 EXPECT_EQ(sv2.length, 4);
3504 1 EXPECT_TRUE(path_parent(&sv2));
3505 1 EXPECT_EQ(sv2.length, 1);
3506 1 EXPECT_FALSE(path_parent(&sv2));
3507 1 EXPECT_EQ(sv2.length, 1);
3508 1 }
3509
3510 1 static void test_wrapping_increment(TestContext *ctx)
3511 {
3512 1 EXPECT_EQ(wrapping_increment(0, 1), 0);
3513 1 EXPECT_EQ(wrapping_increment(3, 5), 4);
3514 1 EXPECT_EQ(wrapping_increment(4, 5), 0);
3515 1 EXPECT_EQ(wrapping_increment(0, 5), 1);
3516
3517
2/2
✓ Branch 15 → 13 taken 8 times.
✓ Branch 15 → 16 taken 1 time.
10 for (size_t m = 1; m < 9; m++) {
3518
2/2
✓ Branch 13 → 11 taken 36 times.
✓ Branch 13 → 14 taken 8 times.
44 for (size_t x = 0; x < m; x++) {
3519 36 EXPECT_EQ(wrapping_increment(x, m), (x + 1) % m);
3520 }
3521 }
3522 1 }
3523
3524 1 static void test_wrapping_decrement(TestContext *ctx)
3525 {
3526 1 EXPECT_EQ(wrapping_decrement(0, 1), 0);
3527 1 EXPECT_EQ(wrapping_decrement(1, 450), 0);
3528 1 EXPECT_EQ(wrapping_decrement(0, 450), 449);
3529 1 EXPECT_EQ(wrapping_decrement(449, 450), 448);
3530
3531
2/2
✓ Branch 19 → 11 taken 8 times.
✓ Branch 19 → 20 taken 1 time.
10 for (size_t m = 1; m < 9; m++) {
3532 8 EXPECT_EQ(wrapping_decrement(0, m), m - 1);
3533
2/2
✓ Branch 17 → 14 taken 28 times.
✓ Branch 17 → 18 taken 8 times.
44 for (size_t x = 1; x < m; x++) {
3534 28 EXPECT_EQ(wrapping_decrement(x, m), (x - 1) % m);
3535 }
3536 }
3537 1 }
3538
3539 1 static void test_saturating_increment(TestContext *ctx)
3540 {
3541 1 EXPECT_UINT_EQ(saturating_increment(0, 0), 0);
3542 1 EXPECT_UINT_EQ(saturating_increment(1, 1), 1);
3543 1 EXPECT_UINT_EQ(saturating_increment(6, 7), 7);
3544 1 EXPECT_UINT_EQ(saturating_increment(7, 7), 7);
3545
3546 1 const size_t m = SIZE_MAX;
3547 1 EXPECT_UINT_EQ(saturating_increment(m - 2, m), m - 1);
3548 1 EXPECT_UINT_EQ(saturating_increment(m - 1, m), m);
3549 1 EXPECT_UINT_EQ(saturating_increment(m, m), m);
3550 1 }
3551
3552 1 static void test_saturating_decrement(TestContext *ctx)
3553 {
3554 1 EXPECT_UINT_EQ(saturating_decrement(0), 0);
3555 1 EXPECT_UINT_EQ(saturating_decrement(1), 0);
3556 1 EXPECT_UINT_EQ(saturating_decrement(2), 1);
3557 1 EXPECT_UINT_EQ(saturating_decrement(3), 2);
3558
3559 1 const size_t m = SIZE_MAX;
3560 1 EXPECT_UINT_EQ(saturating_decrement(m), m - 1);
3561 1 }
3562
3563 1 static void test_saturating_subtract(TestContext *ctx)
3564 {
3565 1 EXPECT_UINT_EQ(saturating_subtract(0, 1), 0);
3566 1 EXPECT_UINT_EQ(saturating_subtract(1, 1), 0);
3567 1 EXPECT_UINT_EQ(saturating_subtract(2, 1), 1);
3568 1 EXPECT_UINT_EQ(saturating_subtract(191, 170), 21);
3569
3570 1 const size_t m = SIZE_MAX;
3571 1 EXPECT_UINT_EQ(saturating_subtract(m - 1, m - 2), 1);
3572 1 EXPECT_UINT_EQ(saturating_subtract(m - 1, m), 0);
3573 1 EXPECT_UINT_EQ(saturating_subtract(m, m), 0);
3574 1 EXPECT_UINT_EQ(saturating_subtract(m, m - 1), 1);
3575 1 EXPECT_UINT_EQ(saturating_subtract(m, m - 2), 2);
3576 1 EXPECT_UINT_EQ(saturating_subtract(0, m), 0);
3577 1 EXPECT_UINT_EQ(saturating_subtract(1, m), 0);
3578 1 EXPECT_UINT_EQ(saturating_subtract(m, 1), m - 1);
3579 1 }
3580
3581 1 static void test_size_multiply_overflows(TestContext *ctx)
3582 {
3583 1 size_t r = 0;
3584 1 EXPECT_FALSE(size_multiply_overflows(10, 20, &r));
3585 1 EXPECT_UINT_EQ(r, 200);
3586 1 EXPECT_FALSE(size_multiply_overflows(0, 0, &r));
3587 1 EXPECT_UINT_EQ(r, 0);
3588 1 EXPECT_FALSE(size_multiply_overflows(1, 0, &r));
3589 1 EXPECT_UINT_EQ(r, 0);
3590 1 EXPECT_FALSE(size_multiply_overflows(0, 1, &r));
3591 1 EXPECT_UINT_EQ(r, 0);
3592 1 EXPECT_FALSE(size_multiply_overflows(0, SIZE_MAX, &r));
3593 1 EXPECT_UINT_EQ(r, 0);
3594 1 EXPECT_FALSE(size_multiply_overflows(SIZE_MAX, 0, &r));
3595 1 EXPECT_UINT_EQ(r, 0);
3596 1 EXPECT_FALSE(size_multiply_overflows(1, SIZE_MAX, &r));
3597 1 EXPECT_UINT_EQ(r, SIZE_MAX);
3598 1 EXPECT_FALSE(size_multiply_overflows(2, SIZE_MAX / 3, &r));
3599 1 EXPECT_UINT_EQ(r, 2 * (SIZE_MAX / 3));
3600 1 EXPECT_TRUE(size_multiply_overflows(SIZE_MAX, 2, &r));
3601 1 EXPECT_TRUE(size_multiply_overflows(2, SIZE_MAX, &r));
3602 1 EXPECT_TRUE(size_multiply_overflows(3, SIZE_MAX / 2, &r));
3603 1 EXPECT_TRUE(size_multiply_overflows(32767, SIZE_MAX, &r));
3604 1 EXPECT_TRUE(size_multiply_overflows(SIZE_MAX, SIZE_MAX, &r));
3605 1 EXPECT_TRUE(size_multiply_overflows(SIZE_MAX, SIZE_MAX / 2, &r));
3606 1 }
3607
3608 1 static void test_size_add_overflows(TestContext *ctx)
3609 {
3610 1 size_t r = 0;
3611 1 EXPECT_FALSE(size_add_overflows(10, 20, &r));
3612 1 EXPECT_UINT_EQ(r, 30);
3613 1 EXPECT_FALSE(size_add_overflows(SIZE_MAX, 0, &r));
3614 1 EXPECT_UINT_EQ(r, SIZE_MAX);
3615 1 EXPECT_TRUE(size_add_overflows(SIZE_MAX, 1, &r));
3616 1 EXPECT_TRUE(size_add_overflows(SIZE_MAX, 16, &r));
3617 1 EXPECT_TRUE(size_add_overflows(SIZE_MAX, SIZE_MAX, &r));
3618 1 EXPECT_TRUE(size_add_overflows(SIZE_MAX, SIZE_MAX / 2, &r));
3619 1 }
3620
3621 1 static void test_xmul(TestContext *ctx)
3622 {
3623 1 const size_t halfmax = SIZE_MAX / 2;
3624 1 EXPECT_UINT_EQ(xmul(2, halfmax), 2 * halfmax);
3625 1 EXPECT_UINT_EQ(xmul(8, 8), 64);
3626 1 EXPECT_UINT_EQ(xmul(1, SIZE_MAX), SIZE_MAX);
3627 1 EXPECT_UINT_EQ(xmul(2000, 1), 2000);
3628 1 }
3629
3630 1 static void test_xadd(TestContext *ctx)
3631 {
3632 1 const size_t max = SIZE_MAX;
3633 1 EXPECT_UINT_EQ(xadd(max - 1, 1), max);
3634 1 EXPECT_UINT_EQ(xadd(8, 8), 16);
3635 1 EXPECT_UINT_EQ(xadd(0, 0), 0);
3636
3637 1 EXPECT_UINT_EQ(xadd3(max - 3, 2, 1), max);
3638 1 EXPECT_UINT_EQ(xadd3(11, 9, 5071), 5091);
3639 1 EXPECT_UINT_EQ(xadd3(0, 0, 0), 0);
3640 1 }
3641
3642 1 static void test_mem_intern(TestContext *ctx)
3643 {
3644 1 const char *ptrs[256];
3645 1 char str[8];
3646
3647
2/2
✓ Branch 6 → 3 taken 256 times.
✓ Branch 6 → 7 taken 1 time.
257 FOR_EACH_I(i, ptrs) {
3648 256 size_t len = buf_uint_to_str(i, str);
3649 256 ptrs[i] = mem_intern(str, len);
3650 }
3651
3652 // Note that hashset_insert() (and thus also mem_intern()) always
3653 // null-terminates, even if there was no '\0' within the length bound
3654 1 EXPECT_STREQ(ptrs[0], "0");
3655 1 EXPECT_STREQ(ptrs[1], "1");
3656 1 EXPECT_STREQ(ptrs[101], "101");
3657 1 EXPECT_STREQ(ptrs[255], "255");
3658
3659 1 EXPECT_FALSE(mem_is_intern(NULL, 0));
3660 1 EXPECT_FALSE(str_is_intern(NULL));
3661 1 EXPECT_FALSE(str_is_intern("1"));
3662 1 EXPECT_TRUE(str_is_intern(ptrs[1]));
3663
3664
2/2
✓ Branch 38 → 20 taken 256 times.
✓ Branch 38 → 39 taken 1 time.
258 FOR_EACH_I(i, ptrs) {
3665 256 size_t len = buf_uint_to_str(i, str);
3666 256 const char *intern = mem_intern(str, len);
3667 256 ASSERT_NONNULL(intern);
3668 256 EXPECT_PTREQ(intern, ptrs[i]);
3669 256 EXPECT_PTREQ(intern, mem_intern(intern, len));
3670 256 EXPECT_PTREQ(intern, str_intern(intern));
3671 256 EXPECT_TRUE(interned_strings_equal(intern, ptrs[i]));
3672
3673 256 EXPECT_TRUE(mem_is_intern(intern, len));
3674 256 EXPECT_TRUE(str_is_intern(intern));
3675 256 EXPECT_FALSE(mem_is_intern(str, len));
3676 256 EXPECT_FALSE(str_is_intern(str));
3677 }
3678 1 }
3679
3680 1 static void test_read_file(TestContext *ctx)
3681 {
3682 1 char *buf = NULL;
3683 1 ASSERT_EQ(read_file("/dev/null", &buf, 64), 0);
3684 1 ASSERT_NONNULL(buf);
3685 1 EXPECT_UINT_EQ((unsigned char)buf[0], '\0');
3686 1 free(buf);
3687
3688 1 buf = NULL;
3689 1 errno = 0;
3690 1 EXPECT_EQ(read_file("test/data/", &buf, 64), -1);
3691 1 EXPECT_EQ(errno, EISDIR);
3692 1 EXPECT_NULL(buf);
3693 1 free(buf);
3694
3695 1 buf = NULL;
3696 1 errno = 0;
3697 1 EXPECT_EQ(read_file("test/data/3lines.txt", &buf, 1), -1);
3698 1 EXPECT_EQ(errno, EFBIG);
3699 1 EXPECT_NULL(buf);
3700 1 free(buf);
3701
3702 1 ssize_t size = read_file("test/data/3lines.txt", &buf, 512);
3703 1 EXPECT_EQ(size, 26);
3704 1 ASSERT_NONNULL(buf);
3705 1 size_t pos = 0;
3706 1 const char *line = buf_next_line(buf, &pos, size);
3707 1 EXPECT_STREQ(line, "line #1");
3708 1 EXPECT_EQ(pos, 8);
3709 1 ASSERT_TRUE(pos < size);
3710 1 line = buf_next_line(buf, &pos, size);
3711 1 EXPECT_STREQ(line, " line #2");
3712 1 EXPECT_EQ(pos, 17);
3713 1 ASSERT_TRUE(pos < size);
3714 1 line = buf_next_line(buf, &pos, size);
3715 1 EXPECT_STREQ(line, " line #3");
3716 1 EXPECT_EQ3(pos, size, 26);
3717 1 free(buf);
3718 1 }
3719
3720 1 static void test_xfopen(TestContext *ctx)
3721 {
3722 1 static const char modes[][4] = {"a", "a+", "r", "r+", "w", "w+"};
3723
2/2
✓ Branch 10 → 3 taken 6 times.
✓ Branch 10 → 11 taken 1 time.
7 FOR_EACH_I(i, modes) {
3724 6 FILE *f = xfopen("/dev/null", modes[i], O_CLOEXEC, 0666);
3725 6 IEXPECT_TRUE(f && fclose(f) == 0);
3726 }
3727 1 }
3728
3729 1 static void test_xstdio(TestContext *ctx)
3730 {
3731 1 FILE *f = xfopen("/dev/null", "r+", O_CLOEXEC, 0666);
3732 1 ASSERT_NONNULL(f);
3733
3734 1 char buf[16];
3735 1 EXPECT_NULL(xfgets(buf, sizeof(buf), f));
3736 1 EXPECT_NE(xfputs("str", f), EOF);
3737 1 EXPECT_EQ(xfputc(' ', f), ' ');
3738 1 EXPECT_EQ(xfprintf(f, "fmt %d", 42), 6);
3739 1 EXPECT_EQ(xfflush(f), 0);
3740 1 EXPECT_EQ(fclose(f), 0);
3741 1 }
3742
3743 1 static void test_fd_set_cloexec(TestContext *ctx)
3744 {
3745 1 int fd = xopen("/dev/null", O_RDONLY, 0);
3746 1 ASSERT_TRUE(fd >= 0);
3747 1 int flags = fcntl(fd, F_GETFD);
3748 1 EXPECT_TRUE(flags >= 0);
3749 1 EXPECT_EQ(flags & FD_CLOEXEC, 0);
3750
3751 1 EXPECT_TRUE(fd_set_cloexec(fd, true));
3752 1 flags = fcntl(fd, F_GETFD);
3753 1 EXPECT_TRUE(flags > 0);
3754 1 EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
3755
3756 // This set of tests is repeated twice, in order to check the special
3757 // case where the F_SETFD operation can be omitted because FD_CLOEXEC
3758 // was already set as requested
3759
2/2
✓ Branch 19 → 13 taken 2 times.
✓ Branch 19 → 20 taken 1 time.
4 for (size_t i = 0; i < 2; i++) {
3760 2 IEXPECT_TRUE(fd_set_cloexec(fd, false));
3761 2 flags = fcntl(fd, F_GETFD);
3762 2 IEXPECT_TRUE(flags >= 0);
3763 2 IEXPECT_EQ(flags & FD_CLOEXEC, 0);
3764 }
3765
3766 1 xclose(fd);
3767 1 }
3768
3769 1 static void test_fd_set_nonblock(TestContext *ctx)
3770 {
3771 1 int fd = xopen("/dev/null", O_RDONLY, 0);
3772 1 ASSERT_TRUE(fd >= 0);
3773 1 int flags = fcntl(fd, F_GETFL);
3774 1 EXPECT_TRUE(flags >= 0);
3775 1 EXPECT_EQ(flags & O_NONBLOCK, 0);
3776
3777 1 EXPECT_TRUE(fd_set_nonblock(fd, true));
3778 1 flags = fcntl(fd, F_GETFL);
3779 1 EXPECT_TRUE(flags > 0);
3780 1 EXPECT_EQ(flags & O_NONBLOCK, O_NONBLOCK);
3781
3782
2/2
✓ Branch 19 → 13 taken 2 times.
✓ Branch 19 → 20 taken 1 time.
4 for (size_t i = 0; i < 2; i++) {
3783 2 IEXPECT_TRUE(fd_set_nonblock(fd, false));
3784 2 flags = fcntl(fd, F_GETFL);
3785 2 IEXPECT_TRUE(flags >= 0);
3786 2 IEXPECT_EQ(flags & O_NONBLOCK, 0);
3787 }
3788
3789 1 xclose(fd);
3790 1 }
3791
3792 1 static void test_fork_exec(TestContext *ctx)
3793 {
3794 1 int fd[3];
3795 1 fd[0] = xopen("/dev/null", O_RDWR | O_CLOEXEC, 0);
3796 1 ASSERT_TRUE(fd[0] > 0);
3797 1 fd[1] = fd[0];
3798 1 fd[2] = fd[0];
3799
3800 1 const char *argv[] = {"sh", "-c", "exit 95", NULL};
3801 1 pid_t pid = fork_exec(argv, fd, 0, 0, true);
3802 1 ASSERT_NE(pid, -1);
3803 1 int r = wait_child(pid);
3804 1 EXPECT_EQ(r, 95);
3805
3806 1 argv[0] = "sleep";
3807 1 argv[1] = "5";
3808 1 argv[2] = NULL;
3809 1 pid = fork_exec(argv, fd, 0, 0, true);
3810 1 ASSERT_NE(pid, -1);
3811 1 EXPECT_EQ(kill(pid, SIGINT), 0);
3812 1 r = wait_child(pid);
3813 1 EXPECT_TRUE(r >= 256);
3814 1 EXPECT_EQ(r >> 8, SIGINT);
3815
3816 1 EXPECT_EQ(xclose(fd[0]), 0);
3817 1 }
3818
3819 1 static void test_xmemmem(TestContext *ctx)
3820 {
3821 1 static const char haystack[] = "finding a needle in a haystack";
3822 1 const char *needle = xmemmem(haystack, sizeof(haystack), STRN("needle"));
3823 1 ASSERT_NONNULL(needle);
3824 1 EXPECT_PTREQ(needle, haystack + 10);
3825
3826 1 needle = xmemmem(haystack, sizeof(haystack), "\0", 1);
3827 1 ASSERT_NONNULL(needle);
3828 1 EXPECT_PTREQ(needle, haystack + sizeof(haystack) - 1);
3829
3830 1 needle = xmemmem(haystack, sizeof(haystack) - 1, "\0", 1);
3831 1 EXPECT_NULL(needle);
3832
3833 1 needle = xmemmem(haystack, sizeof(haystack), STRN("in "));
3834 1 ASSERT_NONNULL(needle);
3835 1 EXPECT_PTREQ(needle, haystack + 17);
3836
3837 1 needle = xmemmem(haystack, sizeof(haystack) - 1, STRN("haystack"));
3838 1 ASSERT_NONNULL(needle);
3839 1 EXPECT_PTREQ(needle, haystack + 22);
3840
3841 1 needle = xmemmem(haystack, sizeof(haystack) - 1, STRN("haystacks"));
3842 1 EXPECT_NULL(needle);
3843
3844 1 needle = xmemmem(haystack, sizeof(haystack), STRN("haystacks"));
3845 1 EXPECT_NULL(needle);
3846 1 }
3847
3848 1 static void test_xmemrchr(TestContext *ctx)
3849 {
3850 1 static const char str[] = "123456789 abcdefedcba 987654321";
3851 1 EXPECT_PTREQ(xmemrchr(NULL, '1', 0), NULL);
3852 1 EXPECT_PTREQ(xmemrchr(str, '9', sizeof(str) - 1), str + 22);
3853 1 EXPECT_PTREQ(xmemrchr(str, '1', sizeof(str) - 1), str + sizeof(str) - 2);
3854 1 EXPECT_PTREQ(xmemrchr(str, '1', sizeof(str) - 2), str);
3855 1 EXPECT_PTREQ(xmemrchr(str, '\0', sizeof(str)), str + sizeof(str) - 1);
3856 1 EXPECT_PTREQ(xmemrchr(str, '\0', sizeof(str) - 1), NULL);
3857 1 EXPECT_PTREQ(xmemrchr(str, 'z', sizeof(str) - 1), NULL);
3858 1 }
3859
3860 1 static void test_str_to_bitflags(TestContext *ctx)
3861 {
3862 1 static const char strs[][8] = {"zero", "one", "two", "three"};
3863 1 EXPECT_UINT_EQ(STR_TO_BITFLAGS("one,three", strs, true), 1 << 1 | 1 << 3);
3864 1 EXPECT_UINT_EQ(STR_TO_BITFLAGS("two,invalid,zero", strs, true), 1 << 2 | 1 << 0);
3865 1 EXPECT_UINT_EQ(STR_TO_BITFLAGS("two,invalid,zero", strs, false), 0);
3866 1 }
3867
3868 1 static void test_log_level_from_str(TestContext *ctx)
3869 {
3870 1 EXPECT_EQ(log_level_from_str("none"), LOG_LEVEL_NONE);
3871 1 EXPECT_EQ(log_level_from_str("crit"), LOG_LEVEL_CRITICAL);
3872 1 EXPECT_EQ(log_level_from_str("error"), LOG_LEVEL_ERROR);
3873 1 EXPECT_EQ(log_level_from_str("warning"), LOG_LEVEL_WARNING);
3874 1 EXPECT_EQ(log_level_from_str("notice"), LOG_LEVEL_NOTICE);
3875 1 EXPECT_EQ(log_level_from_str("info"), LOG_LEVEL_INFO);
3876 1 EXPECT_EQ(log_level_from_str("debug"), LOG_LEVEL_DEBUG);
3877 1 EXPECT_EQ(log_level_from_str("trace"), LOG_LEVEL_TRACE);
3878
3879 1 EXPECT_EQ(log_level_from_str("xyz"), LOG_LEVEL_INVALID);
3880 1 EXPECT_EQ(log_level_from_str(" "), LOG_LEVEL_INVALID);
3881 1 EXPECT_EQ(log_level_from_str("warn"), LOG_LEVEL_INVALID);
3882 1 EXPECT_EQ(log_level_from_str("errors"), LOG_LEVEL_INVALID);
3883
3884 1 LogLevel default_level = log_level_default();
3885 1 EXPECT_EQ(log_level_from_str(""), default_level);
3886 1 EXPECT_EQ(log_level_from_str(NULL), default_level);
3887 1 }
3888
3889 1 static void test_log_level_to_str(TestContext *ctx)
3890 {
3891 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_NONE), "none");
3892 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_CRITICAL), "crit");
3893 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_ERROR), "error");
3894 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_WARNING), "warning");
3895 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_NOTICE), "notice");
3896 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_INFO), "info");
3897 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_DEBUG), "debug");
3898 1 EXPECT_STREQ(log_level_to_str(LOG_LEVEL_TRACE), "trace");
3899 1 }
3900
3901 1 static void test_timespec_subtract(TestContext *ctx)
3902 {
3903 1 struct timespec a = {.tv_sec = 3, .tv_nsec = 5497};
3904 1 struct timespec b = {.tv_sec = 1, .tv_nsec = NS_PER_SECOND - 1};
3905 1 struct timespec r = timespec_subtract(&a, &b);
3906 1 EXPECT_EQ(r.tv_sec, 1);
3907 1 EXPECT_EQ(r.tv_nsec, 5498);
3908
3909 1 b.tv_nsec = 501;
3910 1 r = timespec_subtract(&a, &b);
3911 1 EXPECT_EQ(r.tv_sec, 2);
3912 1 EXPECT_EQ(r.tv_nsec, 4996);
3913 1 }
3914
3915 1 static void test_timespec_to_str(TestContext *ctx)
3916 {
3917 1 char buf[TIME_STR_BUFSIZE] = "";
3918 1 struct timespec ts = {.tv_sec = 0};
3919 1 EXPECT_TRUE(timespecs_equal(&ts, &ts));
3920
3921 1 errno = 0;
3922 1 ts.tv_nsec = NS_PER_SECOND;
3923 1 EXPECT_NULL(timespec_to_str(&ts, buf));
3924 1 EXPECT_EQ(errno, EINVAL);
3925
3926 1 errno = 0;
3927 1 ts.tv_nsec = -1;
3928 1 EXPECT_NULL(timespec_to_str(&ts, buf));
3929 1 EXPECT_EQ(errno, EINVAL);
3930
3931 // Note: $TZ is set to "UTC" in test_init()
3932 1 ts.tv_sec = 4321;
3933 1 ts.tv_nsec = 9876;
3934 1 const char *r = timespec_to_str(&ts, buf);
3935 1 EXPECT_STREQ(r, "1970-01-01 01:12:01.9876 +0000");
3936 1 EXPECT_PTREQ(r, buf);
3937
3938 1 ts.tv_sec = -1;
3939 1 ts.tv_nsec = NS_PER_SECOND - 1;
3940 1 r = timespec_to_str(&ts, buf);
3941 1 EXPECT_STREQ(r, "1969-12-31 23:59:59.999999999 +0000");
3942 1 }
3943
3944 1 static void test_progname(TestContext *ctx)
3945 {
3946 1 const char *const args[] = {"arg0", "", NULL};
3947 1 char **arg0 = (char**)args;
3948 1 char **arg1 = arg0 + 1;
3949 1 char **arg2 = arg0 + 2;
3950 1 EXPECT_STREQ(progname(1, arg0, "1"), "arg0");
3951 1 EXPECT_STREQ(progname(1, NULL, "2"), "2");
3952 1 EXPECT_STREQ(progname(0, arg0, "3"), "3");
3953 1 EXPECT_STREQ(progname(1, arg1, "4"), "4");
3954 1 EXPECT_STREQ(progname(1, arg2, "5"), "5");
3955 1 EXPECT_STREQ(progname(0, NULL, NULL), "_PROG_");
3956 1 }
3957
3958 static const TestEntry tests[] = {
3959 TEST(test_util_macros),
3960 TEST(test_is_power_of_2),
3961 TEST(test_xmalloc),
3962 TEST(test_xstreq),
3963 TEST(test_xstrrchr),
3964 TEST(test_xmempcpy),
3965 TEST(test_str_has_sv_prefix),
3966 TEST(test_str_has_prefix),
3967 TEST(test_hex_decode),
3968 TEST(test_hex_encode_byte),
3969 TEST(test_ascii),
3970 TEST(test_mem_equal),
3971 TEST(test_mem_equal_icase),
3972 TEST(test_base64_decode),
3973 TEST(test_base64_encode_block),
3974 TEST(test_base64_encode_final),
3975 TEST(test_string),
3976 TEST(test_string_next_alloc_size),
3977 TEST(test_string_view),
3978 TEST(test_strview_has_suffix),
3979 TEST(test_strview_remove_matching),
3980 TEST(test_strview_from_slice),
3981 TEST(test_get_delim),
3982 TEST(test_get_delim_str),
3983 TEST(test_strn_replace_byte),
3984 TEST(test_string_array_concat),
3985 TEST(test_size_str_width),
3986 TEST(test_buf_parse_uintmax),
3987 TEST(test_buf_parse_ulong),
3988 TEST(test_buf_parse_size),
3989 TEST(test_buf_parse_hex_uint),
3990 TEST(test_str_to_int),
3991 TEST(test_str_to_size),
3992 TEST(test_str_to_filepos),
3993 TEST(test_parse_file_line_col),
3994 TEST(test_buf_umax_to_hex_str),
3995 TEST(test_parse_filesize),
3996 TEST(test_umax_to_str),
3997 TEST(test_uint_to_str),
3998 TEST(test_ulong_to_str),
3999 TEST(test_buf_umax_to_str),
4000 TEST(test_buf_uint_to_str),
4001 TEST(test_buf_u8_to_str),
4002 TEST(test_file_permissions_to_str),
4003 TEST(test_human_readable_size),
4004 TEST(test_filesize_to_str),
4005 TEST(test_filesize_to_str_precise),
4006 TEST(test_u_char_size),
4007 TEST(test_u_char_width),
4008 TEST(test_u_to_lower),
4009 TEST(test_u_to_upper),
4010 TEST(test_u_is_lower),
4011 TEST(test_u_is_upper),
4012 TEST(test_u_is_ascii_upper),
4013 TEST(test_u_is_cntrl),
4014 TEST(test_u_is_unicode),
4015 TEST(test_u_is_zero_width),
4016 TEST(test_u_is_special_whitespace),
4017 TEST(test_u_is_unprintable),
4018 TEST(test_u_str_width),
4019 TEST(test_u_set_char_raw),
4020 TEST(test_u_set_char),
4021 TEST(test_u_make_printable),
4022 TEST(test_u_get_char),
4023 TEST(test_u_prev_char),
4024 TEST(test_u_skip_chars),
4025 TEST(test_ptr_array),
4026 TEST(test_ptr_array_move),
4027 TEST(test_ptr_array_insert),
4028 TEST(test_list),
4029 TEST(test_hashmap),
4030 TEST(test_hashset),
4031 TEST(test_intmap),
4032 TEST(test_next_multiple),
4033 TEST(test_next_pow2),
4034 TEST(test_popcount),
4035 TEST(test_ctz),
4036 TEST(test_ffs),
4037 TEST(test_lsbit),
4038 TEST(test_msbit),
4039 TEST(test_clz),
4040 TEST(test_umax_bitwidth),
4041 TEST(test_umax_count_base16_digits),
4042 TEST(test_path_dirname_basename),
4043 TEST(test_path_relative),
4044 TEST(test_path_slice_relative),
4045 TEST(test_short_filename_cwd),
4046 TEST(test_short_filename),
4047 TEST(test_path_absolute),
4048 TEST(test_path_join),
4049 TEST(test_path_parent),
4050 TEST(test_wrapping_increment),
4051 TEST(test_wrapping_decrement),
4052 TEST(test_saturating_increment),
4053 TEST(test_saturating_decrement),
4054 TEST(test_saturating_subtract),
4055 TEST(test_size_multiply_overflows),
4056 TEST(test_size_add_overflows),
4057 TEST(test_xmul),
4058 TEST(test_xadd),
4059 TEST(test_mem_intern),
4060 TEST(test_read_file),
4061 TEST(test_xfopen),
4062 TEST(test_xstdio),
4063 TEST(test_fd_set_cloexec),
4064 TEST(test_fd_set_nonblock),
4065 TEST(test_fork_exec),
4066 TEST(test_xmemmem),
4067 TEST(test_xmemrchr),
4068 TEST(test_str_to_bitflags),
4069 TEST(test_log_level_from_str),
4070 TEST(test_log_level_to_str),
4071 TEST(test_timespec_subtract),
4072 TEST(test_timespec_to_str),
4073 TEST(test_progname),
4074 };
4075
4076 const TestGroup util_tests = TEST_GROUP(tests);
4077