1#include <base/mem.h>
2#include <base/str.h>
3#include <base/windows.h>
4
5#include <engine/server/server.h>
6
7#include <game/gamecore.h>
8
9#include <gtest/gtest.h>
10
11#include <limits>
12
13typedef void (*TStringArgumentFunction)(char *pStr);
14template<TStringArgumentFunction Func>
15static void TestInplace(const char *pInput, const char *pOutput)
16{
17 char aBuf[512];
18 str_copy(dst&: aBuf, src: pInput);
19 Func(aBuf);
20 EXPECT_STREQ(aBuf, pOutput);
21}
22
23TEST(Str, StrDelim)
24{
25 int Start, End;
26 // 0123456
27 // 01234567891111111
28 EXPECT_EQ(str_delimiters_around_offset("123;123456789;aaa", ";", 5, &Start, &End), true);
29 EXPECT_EQ(Start, 4);
30 EXPECT_EQ(End, 13);
31
32 EXPECT_EQ(str_delimiters_around_offset("123;123", ";", 1, &Start, &End), false);
33 EXPECT_EQ(Start, 0);
34 EXPECT_EQ(End, 3);
35
36 EXPECT_EQ(str_delimiters_around_offset("---foo---bar---baz---hello", "---", 1, &Start, &End), false);
37 EXPECT_EQ(Start, 0);
38 EXPECT_EQ(End, 0);
39
40 EXPECT_EQ(str_delimiters_around_offset("---foo---bar---baz---hello", "---", 2, &Start, &End), false);
41 EXPECT_EQ(Start, 0);
42 EXPECT_EQ(End, 0);
43
44 EXPECT_EQ(str_delimiters_around_offset("---foo---bar---baz---hello", "---", 3, &Start, &End), true);
45 EXPECT_EQ(Start, 3);
46 EXPECT_EQ(End, 6);
47
48 EXPECT_EQ(str_delimiters_around_offset("---foo---bar---baz---hello", "---", 4, &Start, &End), true);
49 EXPECT_EQ(Start, 3);
50 EXPECT_EQ(End, 6);
51
52 EXPECT_EQ(str_delimiters_around_offset("---foo---bar---baz---hello", "---", 9, &Start, &End), true);
53 EXPECT_EQ(Start, 9);
54 EXPECT_EQ(End, 12);
55
56 EXPECT_EQ(str_delimiters_around_offset("---foo---bar---baz---hello", "---", 22, &Start, &End), false);
57 EXPECT_EQ(Start, 21);
58 EXPECT_EQ(End, 26);
59
60 EXPECT_EQ(str_delimiters_around_offset("foo;;;;bar;;;;;;", ";", 2, &Start, &End), false);
61 EXPECT_EQ(Start, 0);
62 EXPECT_EQ(End, 3);
63
64 EXPECT_EQ(str_delimiters_around_offset("foo;;;;bar;;;;;;", ";", 3, &Start, &End), false);
65 EXPECT_EQ(Start, 0);
66 EXPECT_EQ(End, 3);
67
68 EXPECT_EQ(str_delimiters_around_offset("foo;;;;bar;;;;;;", ";", 4, &Start, &End), true);
69 EXPECT_EQ(Start, 4);
70 EXPECT_EQ(End, 4);
71
72 EXPECT_EQ(str_delimiters_around_offset("", ";", 4, &Start, &End), false);
73 EXPECT_EQ(Start, 0);
74 EXPECT_EQ(End, 0);
75}
76
77TEST(Str, StrIsNum)
78{
79 EXPECT_EQ(str_isnum('/'), false);
80 EXPECT_EQ(str_isnum('0'), true);
81 EXPECT_EQ(str_isnum('1'), true);
82 EXPECT_EQ(str_isnum('2'), true);
83 EXPECT_EQ(str_isnum('8'), true);
84 EXPECT_EQ(str_isnum('9'), true);
85 EXPECT_EQ(str_isnum(':'), false);
86 EXPECT_EQ(str_isnum(' '), false);
87}
88
89TEST(Str, StrIsAllNum)
90{
91 EXPECT_EQ(str_isallnum("/"), 0);
92 EXPECT_EQ(str_isallnum("0"), 1);
93 EXPECT_EQ(str_isallnum("1"), 1);
94 EXPECT_EQ(str_isallnum("2"), 1);
95 EXPECT_EQ(str_isallnum("8"), 1);
96 EXPECT_EQ(str_isallnum("9"), 1);
97 EXPECT_EQ(str_isallnum(":"), 0);
98 EXPECT_EQ(str_isallnum(" "), 0);
99
100 EXPECT_EQ(str_isallnum("123"), 1);
101 EXPECT_EQ(str_isallnum("123/"), 0);
102 EXPECT_EQ(str_isallnum("123:"), 0);
103}
104
105TEST(Str, Dist)
106{
107 EXPECT_EQ(str_utf8_dist("aaa", "aaa"), 0);
108 EXPECT_EQ(str_utf8_dist("123", "123"), 0);
109 EXPECT_EQ(str_utf8_dist("", ""), 0);
110 EXPECT_EQ(str_utf8_dist("a", "b"), 1);
111 EXPECT_EQ(str_utf8_dist("", "aaa"), 3);
112 EXPECT_EQ(str_utf8_dist("123", ""), 3);
113 EXPECT_EQ(str_utf8_dist("ä", ""), 1);
114 EXPECT_EQ(str_utf8_dist("Hëllö", "Hello"), 2);
115 // https://en.wikipedia.org/w/index.php?title=Levenshtein_distance&oldid=828480025#Example
116 EXPECT_EQ(str_utf8_dist("kitten", "sitting"), 3);
117 EXPECT_EQ(str_utf8_dist("flaw", "lawn"), 2);
118 EXPECT_EQ(str_utf8_dist("saturday", "sunday"), 3);
119}
120
121TEST(Str, Utf8Isspace)
122{
123 EXPECT_TRUE(str_utf8_isspace(0x200b)); // Zero-width space
124 EXPECT_TRUE(str_utf8_isspace(' '));
125 EXPECT_FALSE(str_utf8_isspace('a'));
126 // Control characters.
127 for(char c = 0; c < 0x20; c++)
128 {
129 EXPECT_TRUE(str_utf8_isspace(c));
130 }
131}
132
133TEST(Str, Utf8SkipWhitespaces)
134{
135 EXPECT_STREQ(str_utf8_skip_whitespaces("abc"), "abc");
136 EXPECT_STREQ(str_utf8_skip_whitespaces("abc "), "abc ");
137 EXPECT_STREQ(str_utf8_skip_whitespaces(" abc"), "abc");
138 EXPECT_STREQ(str_utf8_skip_whitespaces("\xe2\x80\x8b abc"), "abc");
139}
140
141TEST(Str, Utf8TrimRight)
142{
143 char A1[] = "abc";
144 str_utf8_trim_right(param: A1);
145 EXPECT_STREQ(A1, "abc");
146 char A2[] = " abc";
147 str_utf8_trim_right(param: A2);
148 EXPECT_STREQ(A2, " abc");
149 char A3[] = "abc ";
150 str_utf8_trim_right(param: A3);
151 EXPECT_STREQ(A3, "abc");
152 char A4[] = "abc \xe2\x80\x8b";
153 str_utf8_trim_right(param: A4);
154 EXPECT_STREQ(A4, "abc");
155}
156
157TEST(Str, Utf8CompConfusables)
158{
159 EXPECT_TRUE(str_utf8_comp_confusable("abc", "abc") == 0);
160 EXPECT_TRUE(str_utf8_comp_confusable("rn", "m") == 0);
161 EXPECT_TRUE(str_utf8_comp_confusable("m", "rn") == 0);
162 EXPECT_TRUE(str_utf8_comp_confusable("rna", "ma") == 0);
163 EXPECT_TRUE(str_utf8_comp_confusable("ma", "rna") == 0);
164 EXPECT_FALSE(str_utf8_comp_confusable("mA", "rna") == 0);
165 EXPECT_FALSE(str_utf8_comp_confusable("ma", "rnA") == 0);
166 EXPECT_TRUE(str_utf8_comp_confusable("arn", "am") == 0);
167 EXPECT_TRUE(str_utf8_comp_confusable("am", "arn") == 0);
168 EXPECT_FALSE(str_utf8_comp_confusable("Am", "arn") == 0);
169 EXPECT_FALSE(str_utf8_comp_confusable("am", "Arn") == 0);
170 EXPECT_TRUE(str_utf8_comp_confusable("l", "ӏ") == 0); // CYRILLIC SMALL LETTER PALOCHKA
171 EXPECT_TRUE(str_utf8_comp_confusable("i", "¡") == 0); // INVERTED EXCLAMATION MARK
172 EXPECT_FALSE(str_utf8_comp_confusable("o", "x") == 0);
173 EXPECT_TRUE(str_utf8_comp_confusable("aceiou", "ąçęįǫų") == 0);
174}
175
176TEST(Str, Utf8ToSkeleton)
177{
178 int aBuf[32];
179 EXPECT_EQ(str_utf8_to_skeleton("abc", aBuf, 0), 0);
180 EXPECT_EQ(str_utf8_to_skeleton("", aBuf, std::size(aBuf)), 0);
181 EXPECT_EQ(str_utf8_to_skeleton("abc", aBuf, std::size(aBuf)), 3);
182 EXPECT_EQ(aBuf[0], 'a');
183 EXPECT_EQ(aBuf[1], 'b');
184 EXPECT_EQ(aBuf[2], 'c');
185 EXPECT_EQ(str_utf8_to_skeleton("m", aBuf, std::size(aBuf)), 2);
186 EXPECT_EQ(aBuf[0], 'r');
187 EXPECT_EQ(aBuf[1], 'n');
188 EXPECT_EQ(str_utf8_to_skeleton("rn", aBuf, std::size(aBuf)), 2);
189 EXPECT_EQ(aBuf[0], 'r');
190 EXPECT_EQ(aBuf[1], 'n');
191 EXPECT_EQ(str_utf8_to_skeleton("ӏ", aBuf, std::size(aBuf)), 1); // CYRILLIC SMALL LETTER PALOCHKA
192 EXPECT_EQ(aBuf[0], 'i');
193 EXPECT_EQ(str_utf8_to_skeleton("¡", aBuf, std::size(aBuf)), 1); // INVERTED EXCLAMATION MARK
194 EXPECT_EQ(aBuf[0], 'i');
195 EXPECT_EQ(str_utf8_to_skeleton("ąçęįǫų", aBuf, std::size(aBuf)), 6);
196 EXPECT_EQ(aBuf[0], 'a');
197 EXPECT_EQ(aBuf[1], 'c');
198 EXPECT_EQ(aBuf[2], 'e');
199 EXPECT_EQ(aBuf[3], 'i');
200 EXPECT_EQ(aBuf[4], 'o');
201 EXPECT_EQ(aBuf[5], 'u');
202}
203
204TEST(Str, Utf8ToLowerCodepoint)
205{
206 EXPECT_TRUE(str_utf8_tolower_codepoint('A') == 'a');
207 EXPECT_TRUE(str_utf8_tolower_codepoint('z') == 'z');
208 EXPECT_TRUE(str_utf8_tolower_codepoint(192) == 224); // À -> à
209 EXPECT_TRUE(str_utf8_tolower_codepoint(7882) == 7883); // Ị -> ị
210}
211
212template<size_t BufferSize = 128>
213static void TestStrUtf8ToLower(const char *pInput, const char *pOutput)
214{
215 char aBuf[BufferSize];
216 str_utf8_tolower(pInput, aBuf, sizeof(aBuf));
217 EXPECT_STREQ(aBuf, pOutput);
218}
219
220TEST(Str, Utf8ToLower)
221{
222 // See https://stackoverflow.com/a/18689585
223 TestStrUtf8ToLower<>(pInput: "", pOutput: "");
224 TestStrUtf8ToLower<>(pInput: "a", pOutput: "a");
225 TestStrUtf8ToLower<>(pInput: "A", pOutput: "a");
226 TestStrUtf8ToLower<>(pInput: "z", pOutput: "z");
227 TestStrUtf8ToLower<>(pInput: "Z", pOutput: "z");
228 TestStrUtf8ToLower<>(pInput: "ABC", pOutput: "abc");
229 TestStrUtf8ToLower<>(pInput: "ÖÜÄẞ", pOutput: "öüäß");
230 TestStrUtf8ToLower<>(pInput: "Iİ", pOutput: "ii");
231 TestStrUtf8ToLower<>(pInput: "Ϊ", pOutput: "ϊ");
232 TestStrUtf8ToLower<>(pInput: "Į", pOutput: "į");
233 TestStrUtf8ToLower<>(pInput: "Җ", pOutput: "җ");
234 TestStrUtf8ToLower<>(pInput: "Ѹ", pOutput: "ѹ");
235 TestStrUtf8ToLower<>(pInput: "DŽ", pOutput: "dž");
236 TestStrUtf8ToLower<>(pInput: "ⒹⒹNET", pOutput: "ⓓⓓnet");
237 TestStrUtf8ToLower<>(pInput: "Ⱥ", pOutput: "ⱥ"); // lower case uses more bytes than upper case
238
239 TestStrUtf8ToLower<1>(pInput: "ABC", pOutput: "");
240 TestStrUtf8ToLower<2>(pInput: "ABC", pOutput: "a");
241 TestStrUtf8ToLower<3>(pInput: "ABC", pOutput: "ab");
242 TestStrUtf8ToLower<4>(pInput: "ABC", pOutput: "abc");
243
244 TestStrUtf8ToLower<1>(pInput: "ȺȺȺ", pOutput: "");
245 TestStrUtf8ToLower<2>(pInput: "ȺȺȺ", pOutput: "");
246 TestStrUtf8ToLower<3>(pInput: "ȺȺȺ", pOutput: "");
247 TestStrUtf8ToLower<4>(pInput: "ȺȺȺ", pOutput: "ⱥ");
248 TestStrUtf8ToLower<5>(pInput: "ȺȺȺ", pOutput: "ⱥ");
249 TestStrUtf8ToLower<6>(pInput: "ȺȺȺ", pOutput: "ⱥ");
250 TestStrUtf8ToLower<7>(pInput: "ȺȺȺ", pOutput: "ⱥⱥ");
251 TestStrUtf8ToLower<8>(pInput: "ȺȺȺ", pOutput: "ⱥⱥ");
252 TestStrUtf8ToLower<9>(pInput: "ȺȺȺ", pOutput: "ⱥⱥ");
253 TestStrUtf8ToLower<10>(pInput: "ȺȺȺ", pOutput: "ⱥⱥⱥ");
254 TestStrUtf8ToLower<11>(pInput: "ȺȺȺ", pOutput: "ⱥⱥⱥ");
255}
256
257TEST(Str, Utf8CompNocase)
258{
259 EXPECT_TRUE(str_utf8_comp_nocase("ÖlÜ", "ölü") == 0);
260 EXPECT_TRUE(str_utf8_comp_nocase("ÜlÖ", "ölü") > 0); // ü > ö
261 EXPECT_TRUE(str_utf8_comp_nocase("ÖlÜ", "ölüa") < 0); // NULL < a
262 EXPECT_TRUE(str_utf8_comp_nocase("ölüa", "ÖlÜ") > 0); // a < NULL
263
264#if (CHAR_MIN < 0)
265 const char a[2] = {CHAR_MIN, 0};
266 const char b[2] = {0, 0};
267 EXPECT_TRUE(str_utf8_comp_nocase(a, b) > 0);
268 EXPECT_TRUE(str_utf8_comp_nocase(b, a) < 0);
269#endif
270
271 EXPECT_TRUE(str_utf8_comp_nocase_num("ÖlÜ", "ölüa", 5) == 0);
272 EXPECT_TRUE(str_utf8_comp_nocase_num("ÖlÜ", "ölüa", 6) != 0);
273 EXPECT_TRUE(str_utf8_comp_nocase_num("a", "z", 0) == 0);
274 EXPECT_TRUE(str_utf8_comp_nocase_num("a", "z", 1) != 0);
275}
276
277TEST(Str, Utf8FindNocase)
278{
279 const char *pStr = "abc";
280 const char *pEnd;
281 EXPECT_EQ(str_utf8_find_nocase(pStr, "a", &pEnd), pStr);
282 EXPECT_EQ(pEnd, pStr + str_length("a"));
283 EXPECT_EQ(str_utf8_find_nocase(pStr, "b", &pEnd), pStr + str_length("a"));
284 EXPECT_EQ(pEnd, pStr + str_length("ab"));
285 EXPECT_EQ(str_utf8_find_nocase(pStr, "c", &pEnd), pStr + str_length("ab"));
286 EXPECT_EQ(pEnd, pStr + str_length("abc"));
287 EXPECT_EQ(str_utf8_find_nocase(pStr, "d", &pEnd), nullptr);
288 EXPECT_EQ(pEnd, nullptr);
289
290 EXPECT_EQ(str_utf8_find_nocase(pStr, "A", &pEnd), pStr);
291 EXPECT_EQ(pEnd, pStr + str_length("a"));
292 EXPECT_EQ(str_utf8_find_nocase(pStr, "B", &pEnd), pStr + str_length("a"));
293 EXPECT_EQ(pEnd, pStr + str_length("ab"));
294 EXPECT_EQ(str_utf8_find_nocase(pStr, "C", &pEnd), pStr + str_length("ab"));
295 EXPECT_EQ(pEnd, pStr + str_length("abc"));
296 EXPECT_EQ(str_utf8_find_nocase(pStr, "D", &pEnd), nullptr);
297 EXPECT_EQ(pEnd, nullptr);
298
299 pStr = "ÄÖÜ";
300 EXPECT_EQ(str_utf8_find_nocase(pStr, "ä", &pEnd), pStr);
301 EXPECT_EQ(pEnd, pStr + str_length("Ä"));
302 EXPECT_EQ(str_utf8_find_nocase(pStr, "ö", &pEnd), pStr + str_length("Ä"));
303 EXPECT_EQ(pEnd, pStr + str_length("ÄÖ"));
304 EXPECT_EQ(str_utf8_find_nocase(pStr, "ü", &pEnd), pStr + str_length("ÄÖ"));
305 EXPECT_EQ(pEnd, pStr + str_length("ÄÖÜ"));
306 EXPECT_EQ(str_utf8_find_nocase(pStr, "z", &pEnd), nullptr);
307 EXPECT_EQ(pEnd, nullptr);
308
309 // Both 'I' and 'İ' map to 'i'
310 pStr = "antimatter";
311 EXPECT_EQ(str_utf8_find_nocase(pStr, "I", &pEnd), pStr + str_length("ant"));
312 EXPECT_EQ(pEnd, pStr + str_length("anti"));
313 EXPECT_EQ(str_utf8_find_nocase(pStr, "İ", &pEnd), pStr + str_length("ant"));
314 EXPECT_EQ(pEnd, pStr + str_length("anti"));
315 pStr = "ANTIMATTER";
316 EXPECT_EQ(str_utf8_find_nocase(pStr, "i", &pEnd), pStr + str_length("ANT"));
317 EXPECT_EQ(pEnd, pStr + str_length("ANTI"));
318 pStr = "ANTİMATTER";
319 EXPECT_EQ(str_utf8_find_nocase(pStr, "i", &pEnd), pStr + str_length("ANT"));
320 EXPECT_EQ(pEnd, pStr + str_length("ANTİ"));
321}
322
323TEST(Str, Utf8FixTruncation)
324{
325 char aaBuf[][32] = {
326 "",
327 "\xff",
328 "abc",
329 "abc\xff",
330 "blub\xffxyz",
331 "привет Наташа\xff",
332 "до свидания\xffОлег",
333 };
334 const char *apExpected[] = {
335 "",
336 "",
337 "abc",
338 "abc",
339 "blub\xffxyz",
340 "привет Наташа",
341 "до свидания\xffОлег",
342 };
343 for(unsigned i = 0; i < std::size(aaBuf); i++)
344 {
345 EXPECT_EQ(str_utf8_fix_truncation(aaBuf[i]), str_length(apExpected[i]));
346 EXPECT_STREQ(aaBuf[i], apExpected[i]);
347 }
348}
349
350TEST(Str, Startswith)
351{
352 EXPECT_TRUE(str_startswith("abcdef", "abc"));
353 EXPECT_FALSE(str_startswith("abc", "abcdef"));
354
355 EXPECT_TRUE(str_startswith("xyz", ""));
356 EXPECT_FALSE(str_startswith("", "xyz"));
357
358 EXPECT_FALSE(str_startswith("house", "home"));
359 EXPECT_FALSE(str_startswith("blackboard", "board"));
360
361 EXPECT_TRUE(str_startswith("поплавать", "по"));
362 EXPECT_FALSE(str_startswith("плавать", "по"));
363
364 static const char ABCDEFG[] = "abcdefg";
365 static const char ABC[] = "abc";
366 EXPECT_EQ(str_startswith(ABCDEFG, ABC) - ABCDEFG, str_length(ABC));
367}
368
369TEST(Str, StartswithNocase)
370{
371 EXPECT_TRUE(str_startswith_nocase("Abcdef", "abc"));
372 EXPECT_FALSE(str_startswith_nocase("aBc", "abcdef"));
373
374 EXPECT_TRUE(str_startswith_nocase("xYz", ""));
375 EXPECT_FALSE(str_startswith_nocase("", "xYz"));
376
377 EXPECT_FALSE(str_startswith_nocase("house", "home"));
378 EXPECT_FALSE(str_startswith_nocase("Blackboard", "board"));
379
380 EXPECT_TRUE(str_startswith_nocase("поплавать", "по"));
381 EXPECT_FALSE(str_startswith_nocase("плавать", "по"));
382
383 static const char ABCDEFG[] = "aBcdefg";
384 static const char ABC[] = "abc";
385 EXPECT_EQ(str_startswith_nocase(ABCDEFG, ABC) - ABCDEFG, str_length(ABC));
386}
387
388TEST(Str, Endswith)
389{
390 EXPECT_TRUE(str_endswith("abcdef", "def"));
391 EXPECT_FALSE(str_endswith("def", "abcdef"));
392
393 EXPECT_TRUE(str_endswith("xyz", ""));
394 EXPECT_FALSE(str_endswith("", "xyz"));
395
396 EXPECT_FALSE(str_endswith("rhyme", "mine"));
397 EXPECT_FALSE(str_endswith("blackboard", "black"));
398
399 EXPECT_TRUE(str_endswith("люди", "юди"));
400 EXPECT_FALSE(str_endswith("люди", "любовь"));
401
402 static const char ABCDEFG[] = "abcdefg";
403 static const char DEFG[] = "defg";
404 EXPECT_EQ(str_endswith(ABCDEFG, DEFG) - ABCDEFG,
405 str_length(ABCDEFG) - str_length(DEFG));
406}
407
408TEST(StrFormat, Positional)
409{
410 char aBuf[256];
411
412 // normal
413 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s %s", "first", "second");
414 EXPECT_STREQ(aBuf, "first second");
415
416 // normal with positional arguments
417 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%1$s %2$s", "first", "second");
418 EXPECT_STREQ(aBuf, "first second");
419
420 // reverse
421 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%2$s %1$s", "first", "second");
422 EXPECT_STREQ(aBuf, "second first");
423
424 // duplicate
425 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%1$s %1$s %2$d %1$s %2$d", "str", 1);
426 EXPECT_STREQ(aBuf, "str str 1 str 1");
427}
428
429TEST(Str, EndswithNocase)
430{
431 EXPECT_TRUE(str_endswith_nocase("abcdef", "deF"));
432 EXPECT_FALSE(str_endswith_nocase("def", "abcdef"));
433
434 EXPECT_TRUE(str_endswith_nocase("xyz", ""));
435 EXPECT_FALSE(str_endswith_nocase("", "xyz"));
436
437 EXPECT_FALSE(str_endswith_nocase("rhyme", "minE"));
438 EXPECT_FALSE(str_endswith_nocase("blackboard", "black"));
439
440 EXPECT_TRUE(str_endswith_nocase("люди", "юди"));
441 EXPECT_FALSE(str_endswith_nocase("люди", "любовь"));
442
443 static const char ABCDEFG[] = "abcdefG";
444 static const char DEFG[] = "defg";
445 EXPECT_EQ(str_endswith_nocase(ABCDEFG, DEFG) - ABCDEFG,
446 str_length(ABCDEFG) - str_length(DEFG));
447}
448
449TEST(Str, HexEncode)
450{
451 char aOut[64];
452 const char *pData = "ABCD";
453 str_hex(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 0);
454 EXPECT_STREQ(aOut, "");
455 str_hex(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 1);
456 EXPECT_STREQ(aOut, "41 ");
457 str_hex(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 2);
458 EXPECT_STREQ(aOut, "41 42 ");
459 str_hex(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 3);
460 EXPECT_STREQ(aOut, "41 42 43 ");
461 str_hex(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4);
462 EXPECT_STREQ(aOut, "41 42 43 44 ");
463
464 str_hex(dst: aOut, dst_size: 1, data: pData, data_size: 4);
465 EXPECT_STREQ(aOut, "");
466 str_hex(dst: aOut, dst_size: 2, data: pData, data_size: 4);
467 EXPECT_STREQ(aOut, "");
468 str_hex(dst: aOut, dst_size: 3, data: pData, data_size: 4);
469 EXPECT_STREQ(aOut, "");
470 str_hex(dst: aOut, dst_size: 4, data: pData, data_size: 4);
471 EXPECT_STREQ(aOut, "41 ");
472 str_hex(dst: aOut, dst_size: 5, data: pData, data_size: 4);
473 EXPECT_STREQ(aOut, "41 ");
474 str_hex(dst: aOut, dst_size: 6, data: pData, data_size: 4);
475 EXPECT_STREQ(aOut, "41 ");
476 str_hex(dst: aOut, dst_size: 7, data: pData, data_size: 4);
477 EXPECT_STREQ(aOut, "41 42 ");
478 str_hex(dst: aOut, dst_size: 8, data: pData, data_size: 4);
479 EXPECT_STREQ(aOut, "41 42 ");
480}
481
482TEST(Str, HexEncodeCstyle)
483{
484 char aOut[128];
485 const char *pData = "ABCD";
486 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 0);
487 EXPECT_STREQ(aOut, "");
488 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 1);
489 EXPECT_STREQ(aOut, "0x41");
490 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 2);
491 EXPECT_STREQ(aOut, "0x41, 0x42");
492 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 3);
493 EXPECT_STREQ(aOut, "0x41, 0x42, 0x43");
494 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4);
495 EXPECT_STREQ(aOut, "0x41, 0x42, 0x43, 0x44");
496
497 str_hex_cstyle(dst: aOut, dst_size: 1, data: pData, data_size: 4);
498 EXPECT_STREQ(aOut, "");
499 str_hex_cstyle(dst: aOut, dst_size: 2, data: pData, data_size: 4);
500 EXPECT_STREQ(aOut, "");
501 str_hex_cstyle(dst: aOut, dst_size: 3, data: pData, data_size: 4);
502 EXPECT_STREQ(aOut, "");
503 str_hex_cstyle(dst: aOut, dst_size: 4, data: pData, data_size: 4);
504 EXPECT_STREQ(aOut, "");
505 str_hex_cstyle(dst: aOut, dst_size: 5, data: pData, data_size: 4);
506 EXPECT_STREQ(aOut, "");
507 str_hex_cstyle(dst: aOut, dst_size: 6, data: pData, data_size: 4);
508 EXPECT_STREQ(aOut, "");
509 str_hex_cstyle(dst: aOut, dst_size: 7, data: pData, data_size: 4);
510 EXPECT_STREQ(aOut, "0x41");
511 str_hex_cstyle(dst: aOut, dst_size: 12, data: pData, data_size: 4);
512 EXPECT_STREQ(aOut, "0x41");
513 str_hex_cstyle(dst: aOut, dst_size: 13, data: pData, data_size: 4);
514 EXPECT_STREQ(aOut, "0x41, 0x42");
515 str_hex_cstyle(dst: aOut, dst_size: 14, data: pData, data_size: 4);
516 EXPECT_STREQ(aOut, "0x41, 0x42");
517
518 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4, bytes_per_line: 1);
519 EXPECT_STREQ(aOut, "0x41,\n0x42,\n0x43,\n0x44");
520 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4, bytes_per_line: 2);
521 EXPECT_STREQ(aOut, "0x41, 0x42,\n0x43, 0x44");
522 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4, bytes_per_line: 3);
523 EXPECT_STREQ(aOut, "0x41, 0x42, 0x43,\n0x44");
524 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4, bytes_per_line: 4);
525 EXPECT_STREQ(aOut, "0x41, 0x42, 0x43, 0x44");
526 str_hex_cstyle(dst: aOut, dst_size: sizeof(aOut), data: pData, data_size: 4, bytes_per_line: 500);
527 EXPECT_STREQ(aOut, "0x41, 0x42, 0x43, 0x44");
528}
529
530TEST(Str, HexDecode)
531{
532 char aOut[5] = {'a', 'b', 'c', 'd', 0};
533 EXPECT_EQ(str_hex_decode(aOut, 0, ""), 0);
534 EXPECT_STREQ(aOut, "abcd");
535 EXPECT_EQ(str_hex_decode(aOut, 0, " "), 2);
536 EXPECT_STREQ(aOut, "abcd");
537 EXPECT_EQ(str_hex_decode(aOut, 1, "1"), 2);
538 EXPECT_STREQ(aOut + 1, "bcd");
539 EXPECT_EQ(str_hex_decode(aOut, 1, "41"), 0);
540 EXPECT_STREQ(aOut, "Abcd");
541 EXPECT_EQ(str_hex_decode(aOut, 1, "4x"), 1);
542 EXPECT_STREQ(aOut + 1, "bcd");
543 EXPECT_EQ(str_hex_decode(aOut, 1, "x1"), 1);
544 EXPECT_STREQ(aOut + 1, "bcd");
545 EXPECT_EQ(str_hex_decode(aOut, 1, "411"), 2);
546 EXPECT_STREQ(aOut + 1, "bcd");
547 EXPECT_EQ(str_hex_decode(aOut, 4, "41424344"), 0);
548 EXPECT_STREQ(aOut, "ABCD");
549}
550
551void StrBase64Str(char *pBuffer, int BufferSize, const char *pString)
552{
553 str_base64(dst: pBuffer, dst_size: BufferSize, data: pString, data_size: str_length(str: pString));
554}
555
556TEST(Str, Base64)
557{
558 char aBuf[128];
559 str_base64(dst: aBuf, dst_size: sizeof(aBuf), data: "\0", data_size: 1);
560 EXPECT_STREQ(aBuf, "AA==");
561 str_base64(dst: aBuf, dst_size: sizeof(aBuf), data: "\0\0", data_size: 2);
562 EXPECT_STREQ(aBuf, "AAA=");
563 str_base64(dst: aBuf, dst_size: sizeof(aBuf), data: "\0\0\0", data_size: 3);
564 EXPECT_STREQ(aBuf, "AAAA");
565
566 StrBase64Str(pBuffer: aBuf, BufferSize: sizeof(aBuf), pString: "");
567 EXPECT_STREQ(aBuf, "");
568
569 // https://en.wikipedia.org/w/index.php?title=Base64&oldid=1033503483#Output_padding
570 StrBase64Str(pBuffer: aBuf, BufferSize: sizeof(aBuf), pString: "pleasure.");
571 EXPECT_STREQ(aBuf, "cGxlYXN1cmUu");
572 StrBase64Str(pBuffer: aBuf, BufferSize: sizeof(aBuf), pString: "leasure.");
573 EXPECT_STREQ(aBuf, "bGVhc3VyZS4=");
574 StrBase64Str(pBuffer: aBuf, BufferSize: sizeof(aBuf), pString: "easure.");
575 EXPECT_STREQ(aBuf, "ZWFzdXJlLg==");
576 StrBase64Str(pBuffer: aBuf, BufferSize: sizeof(aBuf), pString: "asure.");
577 EXPECT_STREQ(aBuf, "YXN1cmUu");
578 StrBase64Str(pBuffer: aBuf, BufferSize: sizeof(aBuf), pString: "sure.");
579 EXPECT_STREQ(aBuf, "c3VyZS4=");
580
581 StrBase64Str(pBuffer: aBuf, BufferSize: 4, pString: "pleasure.");
582 EXPECT_STREQ(aBuf, "cGx");
583 StrBase64Str(pBuffer: aBuf, BufferSize: 5, pString: "pleasure.");
584 EXPECT_STREQ(aBuf, "cGxl");
585 StrBase64Str(pBuffer: aBuf, BufferSize: 6, pString: "pleasure.");
586 EXPECT_STREQ(aBuf, "cGxlY");
587}
588
589TEST(Str, Base64Decode)
590{
591 char aOut[17];
592 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
593 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), ""), 0);
594 EXPECT_STREQ(aOut, "XXXXXXXXXXXXXXXX");
595
596 // https://en.wikipedia.org/w/index.php?title=Base64&oldid=1033503483#Output_padding
597 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
598 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "cGxlYXN1cmUu"), 9);
599 EXPECT_STREQ(aOut, "pleasure.XXXXXXX");
600 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
601 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "bGVhc3VyZS4="), 8);
602 EXPECT_STREQ(aOut, "leasure.XXXXXXXX");
603 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
604 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "ZWFzdXJlLg=="), 7);
605 EXPECT_STREQ(aOut, "easure.XXXXXXXXX");
606 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
607 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "YXN1cmUu"), 6);
608 EXPECT_STREQ(aOut, "asure.XXXXXXXXXX");
609 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
610 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "c3VyZS4="), 5);
611 EXPECT_STREQ(aOut, "sure.XXXXXXXXXXX");
612 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
613 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "////"), 3);
614 EXPECT_STREQ(aOut, "\xff\xff\xffXXXXXXXXXXXXX");
615 str_copy(dst: aOut, src: "XXXXXXXXXXXXXXXX", dst_size: sizeof(aOut));
616 EXPECT_EQ(str_base64_decode(aOut, sizeof(aOut), "CQk+"), 3);
617 EXPECT_STREQ(aOut, " >XXXXXXXXXXXXX");
618}
619
620TEST(Str, Base64DecodeError)
621{
622 char aBuf[128];
623 // Wrong padding.
624 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "A"), 0);
625 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AA"), 0);
626 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AAA"), 0);
627 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "A==="), 0);
628 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "=AAA"), 0);
629 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "===="), 0);
630 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AAA=AAAA"), 0);
631 // Invalid characters.
632 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "----"), 0);
633 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "A---"), 0);
634 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AA--"), 0);
635 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AAA-"), 0);
636 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AAAA "), 0);
637 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "AAA "), 0);
638 // Invalid padding values.
639 EXPECT_LT(str_base64_decode(aBuf, sizeof(aBuf), "//=="), 0);
640 // Wrong output buffer size.
641 EXPECT_LT(str_base64_decode(aBuf, 2, "cGxlYXN1cmUu"), 0);
642 EXPECT_LT(str_base64_decode(aBuf, 3, "cGxlYXN1cmUu"), 0);
643 EXPECT_LT(str_base64_decode(aBuf, 4, "cGxlYXN1cmUu"), 0);
644}
645
646TEST(Str, Tokenize)
647{
648 char aTest[] = "GER,RUS,ZAF,BRA,CAN";
649 const char *apOut[] = {"GER", "RUS", "ZAF", "BRA", "CAN"};
650 char aBuf[4];
651
652 int n = 0;
653 for(const char *pTok = aTest; (pTok = str_next_token(str: pTok, delim: ",", buffer: aBuf, buffer_size: sizeof(aBuf)));)
654 EXPECT_STREQ(apOut[n++], aBuf);
655
656 char aTest2[] = "";
657 EXPECT_EQ(str_next_token(aTest2, ",", aBuf, sizeof(aBuf)), nullptr);
658
659 char aTest3[] = "+b";
660 str_next_token(str: aTest3, delim: "+", buffer: aBuf, buffer_size: sizeof(aBuf));
661 EXPECT_STREQ(aBuf, "b");
662}
663
664TEST(Str, InList)
665{
666 char aTest[] = "GER,RUS,ZAF,BRA,CAN";
667 EXPECT_TRUE(str_in_list(aTest, ",", "GER"));
668 EXPECT_TRUE(str_in_list(aTest, ",", "RUS"));
669 EXPECT_TRUE(str_in_list(aTest, ",", "ZAF"));
670 EXPECT_TRUE(str_in_list(aTest, ",", "BRA"));
671 EXPECT_TRUE(str_in_list(aTest, ",", "CAN"));
672
673 EXPECT_FALSE(str_in_list(aTest, ",", "CHN"));
674 EXPECT_FALSE(str_in_list(aTest, ",", "R,R"));
675
676 EXPECT_FALSE(str_in_list("abc,xyz", ",", "abcdef"));
677 EXPECT_FALSE(str_in_list("", ",", ""));
678 EXPECT_FALSE(str_in_list("", ",", "xyz"));
679
680 EXPECT_TRUE(str_in_list("FOO,,BAR", ",", ""));
681 EXPECT_TRUE(str_in_list("abc,,def", ",", "def"));
682}
683
684TEST(Str, Format)
685{
686 char aBuf[4];
687 EXPECT_EQ(str_format(aBuf, 4, "%d:", 9), 2);
688 EXPECT_STREQ(aBuf, "9:");
689 EXPECT_EQ(str_format(aBuf, 4, "%d: ", 9), 3);
690 EXPECT_STREQ(aBuf, "9: ");
691 EXPECT_EQ(str_format(aBuf, 4, "%d: ", 99), 3);
692 EXPECT_STREQ(aBuf, "99:");
693}
694
695TEST(Str, FormatNumber)
696{
697 char aBuf[16];
698 EXPECT_EQ(str_format(aBuf, sizeof(aBuf), "%d", 0), 1);
699 EXPECT_STREQ(aBuf, "0");
700 EXPECT_EQ(str_format(aBuf, sizeof(aBuf), "%d", std::numeric_limits<int>::min()), 11);
701 EXPECT_STREQ(aBuf, "-2147483648");
702 EXPECT_EQ(str_format(aBuf, sizeof(aBuf), "%d", std::numeric_limits<int>::max()), 10);
703 EXPECT_STREQ(aBuf, "2147483647");
704}
705
706TEST(Str, FormatTruncate)
707{
708 const char *pStr = "DDNet最好了";
709 char aBuf[64];
710 str_format(buffer: aBuf, buffer_size: 7, format: "%s", pStr);
711 EXPECT_STREQ(aBuf, "DDNet");
712 str_format(buffer: aBuf, buffer_size: 8, format: "%s", pStr);
713 EXPECT_STREQ(aBuf, "DDNet");
714 str_format(buffer: aBuf, buffer_size: 9, format: "%s", pStr);
715 EXPECT_STREQ(aBuf, "DDNet最");
716 str_format(buffer: aBuf, buffer_size: 10, format: "%s", pStr);
717 EXPECT_STREQ(aBuf, "DDNet最");
718 str_format(buffer: aBuf, buffer_size: 11, format: "%s", pStr);
719 EXPECT_STREQ(aBuf, "DDNet最");
720 str_format(buffer: aBuf, buffer_size: 12, format: "%s", pStr);
721 EXPECT_STREQ(aBuf, "DDNet最好");
722 str_format(buffer: aBuf, buffer_size: 13, format: "%s", pStr);
723 EXPECT_STREQ(aBuf, "DDNet最好");
724 str_format(buffer: aBuf, buffer_size: 14, format: "%s", pStr);
725 EXPECT_STREQ(aBuf, "DDNet最好");
726 str_format(buffer: aBuf, buffer_size: 15, format: "%s", pStr);
727 EXPECT_STREQ(aBuf, "DDNet最好了");
728 str_format(buffer: aBuf, buffer_size: 16, format: "%s", pStr);
729 EXPECT_STREQ(aBuf, "DDNet最好了");
730}
731
732TEST(Str, TrimWords)
733{
734 const char *pStr1 = "aa bb ccc dddd eeeee";
735 EXPECT_STREQ(str_trim_words(pStr1, 0), "aa bb ccc dddd eeeee");
736 EXPECT_STREQ(str_trim_words(pStr1, 1), "bb ccc dddd eeeee");
737 EXPECT_STREQ(str_trim_words(pStr1, 2), "ccc dddd eeeee");
738 EXPECT_STREQ(str_trim_words(pStr1, 3), "dddd eeeee");
739 EXPECT_STREQ(str_trim_words(pStr1, 4), "eeeee");
740 EXPECT_STREQ(str_trim_words(pStr1, 5), "");
741 EXPECT_STREQ(str_trim_words(pStr1, 100), "");
742 const char *pStr2 = " aaa bb ";
743 EXPECT_STREQ(str_trim_words(pStr2, 0), "aaa bb ");
744 EXPECT_STREQ(str_trim_words(pStr2, 1), "bb ");
745 EXPECT_STREQ(str_trim_words(pStr2, 2), "");
746 EXPECT_STREQ(str_trim_words(pStr2, 100), "");
747 const char *pStr3 = "\n\naa bb\t\tccc\r\n\r\ndddd";
748 EXPECT_STREQ(str_trim_words(pStr3, 0), "aa bb\t\tccc\r\n\r\ndddd");
749 EXPECT_STREQ(str_trim_words(pStr3, 1), "bb\t\tccc\r\n\r\ndddd");
750 EXPECT_STREQ(str_trim_words(pStr3, 2), "ccc\r\n\r\ndddd");
751 EXPECT_STREQ(str_trim_words(pStr3, 3), "dddd");
752 EXPECT_STREQ(str_trim_words(pStr3, 4), "");
753 EXPECT_STREQ(str_trim_words(pStr3, 100), "");
754 const char *pStr4 = "";
755 EXPECT_STREQ(str_trim_words(pStr4, 0), "");
756 EXPECT_STREQ(str_trim_words(pStr4, 1), "");
757 EXPECT_STREQ(str_trim_words(pStr4, 2), "");
758 const char *pStr5 = " ";
759 EXPECT_STREQ(str_trim_words(pStr5, 0), "");
760 EXPECT_STREQ(str_trim_words(pStr5, 1), "");
761 EXPECT_STREQ(str_trim_words(pStr5, 2), "");
762}
763
764TEST(Str, CopyNum)
765{
766 const char *pFoo = "Foobaré";
767 char aBuf[64];
768 str_utf8_truncate(dst: aBuf, dst_size: 3, src: pFoo, truncation_len: 1);
769 EXPECT_STREQ(aBuf, "F");
770 str_utf8_truncate(dst: aBuf, dst_size: 3, src: pFoo, truncation_len: 2);
771 EXPECT_STREQ(aBuf, "Fo");
772 str_utf8_truncate(dst: aBuf, dst_size: 3, src: pFoo, truncation_len: 3);
773 EXPECT_STREQ(aBuf, "Fo");
774 str_utf8_truncate(dst: aBuf, dst_size: sizeof(aBuf), src: pFoo, truncation_len: 6);
775 EXPECT_STREQ(aBuf, "Foobar");
776 str_utf8_truncate(dst: aBuf, dst_size: sizeof(aBuf), src: pFoo, truncation_len: 7);
777 EXPECT_STREQ(aBuf, "Foobaré");
778 str_utf8_truncate(dst: aBuf, dst_size: sizeof(aBuf), src: pFoo, truncation_len: 0);
779 EXPECT_STREQ(aBuf, "");
780
781 char aBuf2[8];
782 str_utf8_truncate(dst: aBuf2, dst_size: sizeof(aBuf2), src: pFoo, truncation_len: 7);
783 EXPECT_STREQ(aBuf2, "Foobar");
784 char aBuf3[9];
785 str_utf8_truncate(dst: aBuf3, dst_size: sizeof(aBuf3), src: pFoo, truncation_len: 7);
786 EXPECT_STREQ(aBuf3, "Foobaré");
787}
788
789TEST(Str, Copy)
790{
791 const char *pStr = "DDNet最好了";
792 char aBuf[64];
793 str_copy(dst: aBuf, src: pStr, dst_size: 7);
794 EXPECT_STREQ(aBuf, "DDNet");
795 str_copy(dst: aBuf, src: pStr, dst_size: 8);
796 EXPECT_STREQ(aBuf, "DDNet");
797 str_copy(dst: aBuf, src: pStr, dst_size: 9);
798 EXPECT_STREQ(aBuf, "DDNet最");
799 str_copy(dst: aBuf, src: pStr, dst_size: 10);
800 EXPECT_STREQ(aBuf, "DDNet最");
801 str_copy(dst: aBuf, src: pStr, dst_size: 11);
802 EXPECT_STREQ(aBuf, "DDNet最");
803 str_copy(dst: aBuf, src: pStr, dst_size: 12);
804 EXPECT_STREQ(aBuf, "DDNet最好");
805 str_copy(dst: aBuf, src: pStr, dst_size: 13);
806 EXPECT_STREQ(aBuf, "DDNet最好");
807 str_copy(dst: aBuf, src: pStr, dst_size: 14);
808 EXPECT_STREQ(aBuf, "DDNet最好");
809 str_copy(dst: aBuf, src: pStr, dst_size: 15);
810 EXPECT_STREQ(aBuf, "DDNet最好了");
811 str_copy(dst: aBuf, src: pStr, dst_size: 16);
812 EXPECT_STREQ(aBuf, "DDNet最好了");
813 str_copy(dst&: aBuf, src: pStr);
814 EXPECT_STREQ(aBuf, "DDNet最好了");
815}
816
817TEST(Str, Append)
818{
819 char aBuf[64];
820 aBuf[0] = '\0';
821 str_append(dst: aBuf, src: "DDNet最好了", dst_size: 7);
822 EXPECT_STREQ(aBuf, "DDNet");
823 str_append(dst: aBuf, src: "最", dst_size: 8);
824 EXPECT_STREQ(aBuf, "DDNet");
825 str_append(dst: aBuf, src: "最", dst_size: 9);
826 EXPECT_STREQ(aBuf, "DDNet最");
827 str_append(dst: aBuf, src: "好", dst_size: 10);
828 EXPECT_STREQ(aBuf, "DDNet最");
829 str_append(dst: aBuf, src: "好", dst_size: 11);
830 EXPECT_STREQ(aBuf, "DDNet最");
831 str_append(dst: aBuf, src: "好", dst_size: 12);
832 EXPECT_STREQ(aBuf, "DDNet最好");
833 str_append(dst: aBuf, src: "了", dst_size: 13);
834 EXPECT_STREQ(aBuf, "DDNet最好");
835 str_append(dst: aBuf, src: "了", dst_size: 14);
836 EXPECT_STREQ(aBuf, "DDNet最好");
837 str_append(dst: aBuf, src: "了", dst_size: 15);
838 EXPECT_STREQ(aBuf, "DDNet最好了");
839 str_append(dst: aBuf, src: "了", dst_size: 16);
840 EXPECT_STREQ(aBuf, "DDNet最好了");
841 aBuf[0] = '\0';
842 str_append(dst&: aBuf, src: "DDNet最好了");
843 EXPECT_STREQ(aBuf, "DDNet最好了");
844}
845
846TEST(Str, Utf8Stats)
847{
848 size_t Size, Count;
849
850 str_utf8_stats(str: "abc", max_size: 4, max_count: 3, size: &Size, count: &Count);
851 EXPECT_EQ(Size, 3);
852 EXPECT_EQ(Count, 3);
853
854 str_utf8_stats(str: "abc", max_size: 2, max_count: 3, size: &Size, count: &Count);
855 EXPECT_EQ(Size, 1);
856 EXPECT_EQ(Count, 1);
857
858 str_utf8_stats(str: "", max_size: 1, max_count: 0, size: &Size, count: &Count);
859 EXPECT_EQ(Size, 0);
860 EXPECT_EQ(Count, 0);
861
862 str_utf8_stats(str: "abcde", max_size: 6, max_count: 5, size: &Size, count: &Count);
863 EXPECT_EQ(Size, 5);
864 EXPECT_EQ(Count, 5);
865
866 str_utf8_stats(str: "любовь", max_size: 13, max_count: 6, size: &Size, count: &Count);
867 EXPECT_EQ(Size, 12);
868 EXPECT_EQ(Count, 6);
869
870 str_utf8_stats(str: "abc愛", max_size: 7, max_count: 4, size: &Size, count: &Count);
871 EXPECT_EQ(Size, 6);
872 EXPECT_EQ(Count, 4);
873
874 str_utf8_stats(str: "abc愛", max_size: 6, max_count: 4, size: &Size, count: &Count);
875 EXPECT_EQ(Size, 3);
876 EXPECT_EQ(Count, 3);
877
878 str_utf8_stats(str: "любовь", max_size: 13, max_count: 3, size: &Size, count: &Count);
879 EXPECT_EQ(Size, 6);
880 EXPECT_EQ(Count, 3);
881}
882
883TEST(Str, Utf8OffsetBytesToChars)
884{
885 EXPECT_EQ(str_utf8_offset_bytes_to_chars("", 0), 0);
886 EXPECT_EQ(str_utf8_offset_bytes_to_chars("", 100), 0);
887
888 EXPECT_EQ(str_utf8_offset_bytes_to_chars("abc", 0), 0);
889 EXPECT_EQ(str_utf8_offset_bytes_to_chars("abc", 1), 1);
890 EXPECT_EQ(str_utf8_offset_bytes_to_chars("abc", 2), 2);
891 EXPECT_EQ(str_utf8_offset_bytes_to_chars("abc", 3), 3);
892 EXPECT_EQ(str_utf8_offset_bytes_to_chars("abc", 100), 3);
893
894 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 0), 0);
895 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 2), 1);
896 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 4), 2);
897 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 6), 3);
898 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 8), 4);
899 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 10), 5);
900 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 12), 6);
901 EXPECT_EQ(str_utf8_offset_bytes_to_chars("любовь", 100), 6);
902
903 EXPECT_EQ(str_utf8_offset_bytes_to_chars("DDNet最好了", 5), 5);
904 EXPECT_EQ(str_utf8_offset_bytes_to_chars("DDNet最好了", 8), 6);
905 EXPECT_EQ(str_utf8_offset_bytes_to_chars("DDNet最好了", 11), 7);
906 EXPECT_EQ(str_utf8_offset_bytes_to_chars("DDNet最好了", 14), 8);
907 EXPECT_EQ(str_utf8_offset_bytes_to_chars("DDNet最好了", 100), 8);
908}
909
910TEST(Str, Utf8OffsetCharsToBytes)
911{
912 EXPECT_EQ(str_utf8_offset_chars_to_bytes("", 0), 0);
913 EXPECT_EQ(str_utf8_offset_chars_to_bytes("", 100), 0);
914
915 EXPECT_EQ(str_utf8_offset_chars_to_bytes("abc", 0), 0);
916 EXPECT_EQ(str_utf8_offset_chars_to_bytes("abc", 1), 1);
917 EXPECT_EQ(str_utf8_offset_chars_to_bytes("abc", 2), 2);
918 EXPECT_EQ(str_utf8_offset_chars_to_bytes("abc", 3), 3);
919 EXPECT_EQ(str_utf8_offset_chars_to_bytes("abc", 100), 3);
920
921 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 0), 0);
922 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 1), 2);
923 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 2), 4);
924 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 3), 6);
925 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 4), 8);
926 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 5), 10);
927 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 6), 12);
928 EXPECT_EQ(str_utf8_offset_chars_to_bytes("любовь", 100), 12);
929
930 EXPECT_EQ(str_utf8_offset_chars_to_bytes("DDNet最好了", 5), 5);
931 EXPECT_EQ(str_utf8_offset_chars_to_bytes("DDNet最好了", 6), 8);
932 EXPECT_EQ(str_utf8_offset_chars_to_bytes("DDNet最好了", 7), 11);
933 EXPECT_EQ(str_utf8_offset_chars_to_bytes("DDNet最好了", 8), 14);
934 EXPECT_EQ(str_utf8_offset_chars_to_bytes("DDNet最好了", 100), 14);
935}
936
937TEST(Str, HasCc)
938{
939 EXPECT_FALSE(str_has_cc(""));
940 EXPECT_FALSE(str_has_cc("a"));
941 EXPECT_FALSE(str_has_cc("Merhaba dünya!"));
942
943 EXPECT_TRUE(str_has_cc("\n"));
944 EXPECT_TRUE(str_has_cc("\r"));
945 EXPECT_TRUE(str_has_cc("\t"));
946 EXPECT_TRUE(str_has_cc("a\n"));
947 EXPECT_TRUE(str_has_cc("a\rb"));
948 EXPECT_TRUE(str_has_cc("\tb"));
949 EXPECT_TRUE(str_has_cc("\n\n"));
950 EXPECT_TRUE(str_has_cc("\x1C"));
951 EXPECT_TRUE(str_has_cc("\x1D"));
952 EXPECT_TRUE(str_has_cc("\x1E"));
953 EXPECT_TRUE(str_has_cc("\x1F"));
954}
955
956TEST(Str, SanitizeCc)
957{
958 TestInplace<str_sanitize_cc>(pInput: "", pOutput: "");
959 TestInplace<str_sanitize_cc>(pInput: "a", pOutput: "a");
960 TestInplace<str_sanitize_cc>(pInput: "Merhaba dünya!", pOutput: "Merhaba dünya!");
961 TestInplace<str_sanitize_cc>(pInput: "\n", pOutput: " ");
962 TestInplace<str_sanitize_cc>(pInput: "\r", pOutput: " ");
963 TestInplace<str_sanitize_cc>(pInput: "\t", pOutput: " ");
964 TestInplace<str_sanitize_cc>(pInput: "a\n", pOutput: "a ");
965 TestInplace<str_sanitize_cc>(pInput: "a\rb", pOutput: "a b");
966 TestInplace<str_sanitize_cc>(pInput: "\tb", pOutput: " b");
967 TestInplace<str_sanitize_cc>(pInput: "\n\n", pOutput: " ");
968 TestInplace<str_sanitize_cc>(pInput: "\x1C", pOutput: " ");
969 TestInplace<str_sanitize_cc>(pInput: "\x1D", pOutput: " ");
970 TestInplace<str_sanitize_cc>(pInput: "\x1E", pOutput: " ");
971 TestInplace<str_sanitize_cc>(pInput: "\x1F", pOutput: " ");
972}
973
974TEST(Str, Sanitize)
975{
976 TestInplace<str_sanitize>(pInput: "", pOutput: "");
977 TestInplace<str_sanitize>(pInput: "a", pOutput: "a");
978 TestInplace<str_sanitize>(pInput: "Merhaba dünya!", pOutput: "Merhaba dünya!");
979 TestInplace<str_sanitize>(pInput: "\n", pOutput: "\n");
980 TestInplace<str_sanitize>(pInput: "\r", pOutput: "\r");
981 TestInplace<str_sanitize>(pInput: "\t", pOutput: "\t");
982 TestInplace<str_sanitize>(pInput: "a\n", pOutput: "a\n");
983 TestInplace<str_sanitize>(pInput: "a\rb", pOutput: "a\rb");
984 TestInplace<str_sanitize>(pInput: "\tb", pOutput: "\tb");
985 TestInplace<str_sanitize>(pInput: "\n\n", pOutput: "\n\n");
986 TestInplace<str_sanitize>(pInput: "\x1C", pOutput: " ");
987 TestInplace<str_sanitize>(pInput: "\x1D", pOutput: " ");
988 TestInplace<str_sanitize>(pInput: "\x1E", pOutput: " ");
989 TestInplace<str_sanitize>(pInput: "\x1F", pOutput: " ");
990}
991
992TEST(Str, SanitizeFilename)
993{
994 TestInplace<str_sanitize_filename>(pInput: "", pOutput: "");
995 TestInplace<str_sanitize_filename>(pInput: "a", pOutput: "a");
996 TestInplace<str_sanitize_filename>(pInput: "Merhaba dünya!", pOutput: "Merhaba dünya!");
997 TestInplace<str_sanitize_filename>(pInput: "привет Наташа", pOutput: "привет Наташа");
998 TestInplace<str_sanitize_filename>(pInput: "ąçęįǫų", pOutput: "ąçęįǫų");
999 TestInplace<str_sanitize_filename>(pInput: "DDNet最好了", pOutput: "DDNet最好了");
1000 TestInplace<str_sanitize_filename>(pInput: "aβい🐘", pOutput: "aβい🐘");
1001 TestInplace<str_sanitize_filename>(pInput: "foo.bar", pOutput: "foo.bar");
1002 TestInplace<str_sanitize_filename>(pInput: "foo.bar.baz", pOutput: "foo.bar.baz");
1003 TestInplace<str_sanitize_filename>(pInput: ".a..b...c....d", pOutput: ".a..b...c....d");
1004 TestInplace<str_sanitize_filename>(pInput: "\n", pOutput: " ");
1005 TestInplace<str_sanitize_filename>(pInput: "\r", pOutput: " ");
1006 TestInplace<str_sanitize_filename>(pInput: "\t", pOutput: " ");
1007 TestInplace<str_sanitize_filename>(pInput: "a\n", pOutput: "a ");
1008 TestInplace<str_sanitize_filename>(pInput: "a\rb", pOutput: "a b");
1009 TestInplace<str_sanitize_filename>(pInput: "\tb", pOutput: " b");
1010 TestInplace<str_sanitize_filename>(pInput: "\n\n", pOutput: " ");
1011 TestInplace<str_sanitize_filename>(pInput: "\x1C", pOutput: " ");
1012 TestInplace<str_sanitize_filename>(pInput: "\x1D", pOutput: " ");
1013 TestInplace<str_sanitize_filename>(pInput: "\x1E", pOutput: " ");
1014 TestInplace<str_sanitize_filename>(pInput: "\x1F", pOutput: " ");
1015 TestInplace<str_sanitize_filename>(pInput: "\u007F", pOutput: " ");
1016 TestInplace<str_sanitize_filename>(pInput: "\\", pOutput: " ");
1017 TestInplace<str_sanitize_filename>(pInput: "/", pOutput: " ");
1018 TestInplace<str_sanitize_filename>(pInput: "|", pOutput: " ");
1019 TestInplace<str_sanitize_filename>(pInput: ":", pOutput: " ");
1020 TestInplace<str_sanitize_filename>(pInput: "*", pOutput: " ");
1021 TestInplace<str_sanitize_filename>(pInput: "?", pOutput: " ");
1022 TestInplace<str_sanitize_filename>(pInput: "<", pOutput: " ");
1023 TestInplace<str_sanitize_filename>(pInput: ">", pOutput: " ");
1024 TestInplace<str_sanitize_filename>(pInput: "\"", pOutput: " ");
1025 TestInplace<str_sanitize_filename>(pInput: "\\/|:*?<>\"", pOutput: " ");
1026}
1027
1028TEST(Str, ValidFilename)
1029{
1030 EXPECT_TRUE(str_valid_filename("a"));
1031 EXPECT_TRUE(str_valid_filename("abc"));
1032 EXPECT_TRUE(str_valid_filename("abc abc"));
1033 EXPECT_TRUE(str_valid_filename("aa bb ccc dddd eeeee"));
1034 EXPECT_TRUE(str_valid_filename("öüä"));
1035 EXPECT_TRUE(str_valid_filename("привет Наташа"));
1036 EXPECT_TRUE(str_valid_filename("ąçęįǫų"));
1037 EXPECT_TRUE(str_valid_filename("DDNet最好了"));
1038 EXPECT_TRUE(str_valid_filename("aβい🐘"));
1039 EXPECT_TRUE(str_valid_filename("foo.bar"));
1040 EXPECT_TRUE(str_valid_filename("foo.bar.baz"));
1041 EXPECT_TRUE(str_valid_filename(".a..b...c....d"));
1042
1043 EXPECT_FALSE(str_valid_filename(""));
1044 EXPECT_FALSE(str_valid_filename("aa\nbb"));
1045 EXPECT_FALSE(str_valid_filename("aa\rbb"));
1046 EXPECT_FALSE(str_valid_filename("aa\tbb"));
1047 EXPECT_FALSE(str_valid_filename("aa\u001Cbb"));
1048 EXPECT_FALSE(str_valid_filename("aa\u001Dbb"));
1049 EXPECT_FALSE(str_valid_filename("aa\u001Ebb"));
1050 EXPECT_FALSE(str_valid_filename("aa\u001Fbb"));
1051 EXPECT_FALSE(str_valid_filename("aa\u007Fbb"));
1052 EXPECT_FALSE(str_valid_filename("aa\\bb"));
1053 EXPECT_FALSE(str_valid_filename("aa/bb"));
1054 EXPECT_FALSE(str_valid_filename("aa|bb"));
1055 EXPECT_FALSE(str_valid_filename("aa:bb"));
1056 EXPECT_FALSE(str_valid_filename("aa*bb"));
1057 EXPECT_FALSE(str_valid_filename("aa?bb"));
1058 EXPECT_FALSE(str_valid_filename("aa<bb"));
1059 EXPECT_FALSE(str_valid_filename("aa>bb"));
1060 EXPECT_FALSE(str_valid_filename("aa\"bb"));
1061 EXPECT_FALSE(str_valid_filename("\\/|:*?<>\""));
1062 EXPECT_FALSE(str_valid_filename("aa bb")); // EM QUAD
1063 EXPECT_FALSE(str_valid_filename("aa​bb")); // ZERO WIDTH SPACE
1064 EXPECT_FALSE(str_valid_filename(" abc"));
1065 EXPECT_FALSE(str_valid_filename(" abc"));
1066 EXPECT_FALSE(str_valid_filename("abc "));
1067 EXPECT_FALSE(str_valid_filename("abc "));
1068 EXPECT_FALSE(str_valid_filename("abc abc"));
1069 EXPECT_FALSE(str_valid_filename(" abc abc "));
1070 EXPECT_FALSE(str_valid_filename(" abc abc "));
1071 EXPECT_FALSE(str_valid_filename("abc."));
1072 EXPECT_FALSE(str_valid_filename("abc..."));
1073 EXPECT_FALSE(str_valid_filename("abc... "));
1074 EXPECT_FALSE(str_valid_filename("abc ..."));
1075
1076 // reserved names
1077 EXPECT_FALSE(str_valid_filename("con"));
1078 EXPECT_FALSE(str_valid_filename("CON"));
1079 EXPECT_FALSE(str_valid_filename("cOn"));
1080 EXPECT_FALSE(str_valid_filename("con.txt"));
1081 EXPECT_FALSE(str_valid_filename("con.tar.gz"));
1082 EXPECT_FALSE(str_valid_filename("CON.TAR.GZ"));
1083 EXPECT_FALSE(str_valid_filename("PRN"));
1084 EXPECT_FALSE(str_valid_filename("AUX"));
1085 EXPECT_FALSE(str_valid_filename("NUL"));
1086 EXPECT_FALSE(str_valid_filename("COM4"));
1087 EXPECT_FALSE(str_valid_filename("lpt²"));
1088 // reserved names allowed as prefix if not separated by period
1089 EXPECT_TRUE(str_valid_filename("console"));
1090 EXPECT_TRUE(str_valid_filename("console.log"));
1091 EXPECT_TRUE(str_valid_filename("console.tar.gz"));
1092 EXPECT_TRUE(str_valid_filename("Auxiliary"));
1093 EXPECT_TRUE(str_valid_filename("Null"));
1094 EXPECT_TRUE(str_valid_filename("Null.txt"));
1095}
1096
1097TEST(Str, CleanWhitespaces)
1098{
1099 TestInplace<str_clean_whitespaces>(pInput: "aa bb ccc dddd eeeee", pOutput: "aa bb ccc dddd eeeee");
1100 TestInplace<str_clean_whitespaces>(pInput: " ", pOutput: "");
1101 TestInplace<str_clean_whitespaces>(pInput: " aa", pOutput: "aa");
1102 TestInplace<str_clean_whitespaces>(pInput: "aa ", pOutput: "aa");
1103 TestInplace<str_clean_whitespaces>(pInput: " aa bb ccc dddd eeeee ", pOutput: "aa bb ccc dddd eeeee");
1104}
1105
1106TEST(Str, SkipToWhitespace)
1107{
1108 char aBuf[64];
1109 str_copy(dst&: aBuf, src: "");
1110 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf);
1111 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf);
1112 str_copy(dst&: aBuf, src: " a");
1113 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf);
1114 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf);
1115 str_copy(dst&: aBuf, src: "aaaa b");
1116 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1117 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1118 str_copy(dst&: aBuf, src: "aaaa\n\nb");
1119 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1120 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1121 str_copy(dst&: aBuf, src: "aaaa\r\rb");
1122 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1123 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1124 str_copy(dst&: aBuf, src: "aaaa\t\tb");
1125 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1126 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1127}
1128
1129TEST(Str, SkipWhitespaces)
1130{
1131 char aBuf[64];
1132 str_copy(dst&: aBuf, src: "");
1133 EXPECT_EQ(str_skip_whitespaces(aBuf), aBuf);
1134 EXPECT_EQ(str_skip_whitespaces_const(aBuf), aBuf);
1135 str_copy(dst&: aBuf, src: "aaaa");
1136 EXPECT_EQ(str_skip_whitespaces(aBuf), aBuf);
1137 EXPECT_EQ(str_skip_whitespaces_const(aBuf), aBuf);
1138 str_copy(dst&: aBuf, src: " \n\r\taaaa");
1139 EXPECT_EQ(str_skip_whitespaces(aBuf), aBuf + 4);
1140 EXPECT_EQ(str_skip_whitespaces_const(aBuf), aBuf + 4);
1141}
1142
1143TEST(Str, CompFilename)
1144{
1145 EXPECT_EQ(str_comp_filenames("a", "a"), 0);
1146 EXPECT_LT(str_comp_filenames("a", "b"), 0);
1147 EXPECT_GT(str_comp_filenames("b", "a"), 0);
1148 EXPECT_EQ(str_comp_filenames("A", "a"), 0);
1149 EXPECT_LT(str_comp_filenames("A", "b"), 0);
1150 EXPECT_GT(str_comp_filenames("b", "A"), 0);
1151 EXPECT_LT(str_comp_filenames("a", "B"), 0);
1152 EXPECT_GT(str_comp_filenames("B", "a"), 0);
1153 EXPECT_EQ(str_comp_filenames("1A", "1a"), 0);
1154 EXPECT_LT(str_comp_filenames("1a", "1B"), 0);
1155 EXPECT_GT(str_comp_filenames("1B", "1a"), 0);
1156 EXPECT_LT(str_comp_filenames("1a", "1b"), 0);
1157 EXPECT_GT(str_comp_filenames("1b", "1a"), 0);
1158 EXPECT_GT(str_comp_filenames("12a", "1B"), 0);
1159 EXPECT_LT(str_comp_filenames("1B", "12a"), 0);
1160 EXPECT_GT(str_comp_filenames("10a", "1B"), 0);
1161 EXPECT_LT(str_comp_filenames("1B", "10a"), 0);
1162 EXPECT_GT(str_comp_filenames("10a", "00B"), 0);
1163 EXPECT_LT(str_comp_filenames("00B", "10a"), 0);
1164 EXPECT_GT(str_comp_filenames("10a", "09B"), 0);
1165 EXPECT_LT(str_comp_filenames("09B", "10a"), 0);
1166 EXPECT_LT(str_comp_filenames("abc", "abcd"), 0);
1167 EXPECT_GT(str_comp_filenames("abcd", "abc"), 0);
1168 EXPECT_LT(str_comp_filenames("abc2", "abcd1"), 0);
1169 EXPECT_GT(str_comp_filenames("abcd1", "abc2"), 0);
1170 EXPECT_LT(str_comp_filenames("abc50", "abcd"), 0);
1171 EXPECT_GT(str_comp_filenames("abcd", "abc50"), 0);
1172 EXPECT_EQ(str_comp_filenames("file0", "file0"), 0);
1173 EXPECT_LT(str_comp_filenames("file0", "file1"), 0);
1174 EXPECT_GT(str_comp_filenames("file1", "file0"), 0);
1175 EXPECT_LT(str_comp_filenames("file1", "file09"), 0);
1176 EXPECT_GT(str_comp_filenames("file09", "file1"), 0);
1177 EXPECT_LT(str_comp_filenames("file1", "file009"), 0);
1178 EXPECT_GT(str_comp_filenames("file009", "file1"), 0);
1179 EXPECT_GT(str_comp_filenames("file10", "file00"), 0);
1180 EXPECT_LT(str_comp_filenames("file00", "file10"), 0);
1181 EXPECT_GT(str_comp_filenames("file10", "file09"), 0);
1182 EXPECT_LT(str_comp_filenames("file09", "file10"), 0);
1183 EXPECT_LT(str_comp_filenames("file13", "file37"), 0);
1184 EXPECT_GT(str_comp_filenames("file37", "file13"), 0);
1185 EXPECT_LT(str_comp_filenames("file1.ext", "file09.ext"), 0);
1186 EXPECT_GT(str_comp_filenames("file09.ext", "file1.ext"), 0);
1187 EXPECT_LT(str_comp_filenames("file1.ext", "file009.ext"), 0);
1188 EXPECT_GT(str_comp_filenames("file009.ext", "file1.ext"), 0);
1189 EXPECT_EQ(str_comp_filenames("file0.ext", "file0.ext"), 0);
1190 EXPECT_LT(str_comp_filenames("file13.ext", "file37.ext"), 0);
1191 EXPECT_GT(str_comp_filenames("file37.ext", "file13.ext"), 0);
1192 EXPECT_LT(str_comp_filenames("FILE13.EXT", "file37.ext"), 0);
1193 EXPECT_GT(str_comp_filenames("file37.ext", "FILE13.EXT"), 0);
1194 EXPECT_GT(str_comp_filenames("file10.ext", "file00.ext"), 0);
1195 EXPECT_LT(str_comp_filenames("file00.ext", "file10.ext"), 0);
1196 EXPECT_GT(str_comp_filenames("file10.ext", "file09.ext"), 0);
1197 EXPECT_LT(str_comp_filenames("file09.ext", "file10.ext"), 0);
1198 EXPECT_LT(str_comp_filenames("file42", "file1337"), 0);
1199 EXPECT_GT(str_comp_filenames("file1337", "file42"), 0);
1200 EXPECT_LT(str_comp_filenames("file42.ext", "file1337.ext"), 0);
1201 EXPECT_GT(str_comp_filenames("file1337.ext", "file42.ext"), 0);
1202 EXPECT_GT(str_comp_filenames("file4414520", "file2055"), 0);
1203 EXPECT_LT(str_comp_filenames("file4414520", "file205523151812419"), 0);
1204}
1205
1206TEST(Str, RightChar)
1207{
1208 const char *pStr = "a bb ccc dddd eeeee";
1209 EXPECT_EQ(str_rchr(pStr, 'a'), pStr);
1210 EXPECT_EQ(str_rchr(pStr, 'b'), pStr + 3);
1211 EXPECT_EQ(str_rchr(pStr, 'c'), pStr + 7);
1212 EXPECT_EQ(str_rchr(pStr, 'd'), pStr + 12);
1213 EXPECT_EQ(str_rchr(pStr, ' '), pStr + 19);
1214 EXPECT_EQ(str_rchr(pStr, 'e'), pStr + 24);
1215 EXPECT_EQ(str_rchr(pStr, '\0'), pStr + str_length(pStr));
1216 EXPECT_EQ(str_rchr(pStr, 'y'), nullptr);
1217}
1218
1219TEST(Str, CountChar)
1220{
1221 const char *pStr = "a bb ccc dddd eeeee";
1222 EXPECT_EQ(str_countchr(pStr, 'a'), 1);
1223 EXPECT_EQ(str_countchr(pStr, 'b'), 2);
1224 EXPECT_EQ(str_countchr(pStr, 'c'), 3);
1225 EXPECT_EQ(str_countchr(pStr, 'd'), 4);
1226 EXPECT_EQ(str_countchr(pStr, 'e'), 5);
1227 EXPECT_EQ(str_countchr(pStr, ' '), 10);
1228 EXPECT_EQ(str_countchr(pStr, '\0'), 0);
1229 EXPECT_EQ(str_countchr(pStr, 'y'), 0);
1230}
1231
1232TEST(Str, StrToInts)
1233{
1234 int aInts[8];
1235
1236 StrToInts(pInts: aInts, NumInts: 1, pStr: "a");
1237 EXPECT_EQ(aInts[0], 0xE1808000);
1238
1239 StrToInts(pInts: aInts, NumInts: 1, pStr: "ab");
1240 EXPECT_EQ(aInts[0], 0xE1E28000);
1241
1242 StrToInts(pInts: aInts, NumInts: 1, pStr: "abc");
1243 EXPECT_EQ(aInts[0], 0xE1E2E300);
1244
1245 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcd");
1246 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1247 EXPECT_EQ(aInts[1], 0x80808000);
1248
1249 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcde");
1250 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1251 EXPECT_EQ(aInts[1], 0xE5808000);
1252
1253 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcdef");
1254 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1255 EXPECT_EQ(aInts[1], 0xE5E68000);
1256
1257 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcdefg");
1258 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1259 EXPECT_EQ(aInts[1], 0xE5E6E700);
1260
1261 StrToInts(pInts: aInts, NumInts: 2, pStr: "öüä");
1262 EXPECT_EQ(aInts[0], 0x4336433C);
1263 EXPECT_EQ(aInts[1], 0x43248000);
1264
1265 StrToInts(pInts: aInts, NumInts: 3, pStr: "aβい🐘");
1266 EXPECT_EQ(aInts[0], 0xE14E3263);
1267 EXPECT_EQ(aInts[1], 0x0104701F);
1268 EXPECT_EQ(aInts[2], 0x10188000);
1269
1270 // long padding
1271 StrToInts(pInts: aInts, NumInts: 4, pStr: "abc");
1272 EXPECT_EQ(aInts[0], 0xE1E2E380);
1273 EXPECT_EQ(aInts[1], 0x80808080);
1274 EXPECT_EQ(aInts[2], 0x80808080);
1275 EXPECT_EQ(aInts[3], 0x80808000);
1276}
1277
1278TEST(Str, IntsToStr)
1279{
1280 int aInts[8];
1281 char aStr[sizeof(aInts)];
1282
1283 aInts[0] = 0xE1808000;
1284 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1285 EXPECT_STREQ(aStr, "a");
1286
1287 aInts[0] = 0xE1E28000;
1288 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1289 EXPECT_STREQ(aStr, "ab");
1290
1291 aInts[0] = 0xE1E2E300;
1292 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1293 EXPECT_STREQ(aStr, "abc");
1294
1295 aInts[0] = 0xE1E2E3E4;
1296 aInts[1] = 0x80808000;
1297 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1298 EXPECT_STREQ(aStr, "abcd");
1299
1300 aInts[0] = 0xE1E2E3E4;
1301 aInts[1] = 0xE5808000;
1302 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1303 EXPECT_STREQ(aStr, "abcde");
1304
1305 aInts[0] = 0xE1E2E3E4;
1306 aInts[1] = 0xE5E68000;
1307 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1308 EXPECT_STREQ(aStr, "abcdef");
1309
1310 aInts[0] = 0xE1E2E3E4;
1311 aInts[1] = 0xE5E6E700;
1312 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1313 EXPECT_STREQ(aStr, "abcdefg");
1314
1315 aInts[0] = 0x4336433C;
1316 aInts[1] = 0x43248000;
1317 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1318 EXPECT_STREQ(aStr, "öüä");
1319
1320 aInts[0] = 0xE14E3263;
1321 aInts[1] = 0x0104701F;
1322 aInts[2] = 0x10188000;
1323 EXPECT_TRUE(IntsToStr(aInts, 3, aStr, std::size(aStr)));
1324 EXPECT_STREQ(aStr, "aβい🐘");
1325
1326 // long padding
1327 aInts[0] = 0xE1E2E380;
1328 aInts[1] = 0x80808080;
1329 aInts[2] = 0x80808080;
1330 aInts[3] = 0x80808000;
1331 EXPECT_TRUE(IntsToStr(aInts, 4, aStr, std::size(aStr)));
1332 EXPECT_STREQ(aStr, "abc");
1333
1334 // early null character (0x80)
1335 aInts[0] = 0xE1E2E380;
1336 aInts[1] = 0xE1E2E3E4;
1337 aInts[2] = 0xE1E2E3E4;
1338 aInts[3] = 0xE1E2E300;
1339 EXPECT_TRUE(IntsToStr(aInts, 4, aStr, std::size(aStr)));
1340 EXPECT_STREQ(aStr, "abc");
1341
1342 // invalid UTF-8
1343 aInts[0] = 0xE17FE200;
1344 EXPECT_FALSE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1345 EXPECT_STREQ(aStr, "");
1346
1347 // invalid UTF-8 (0x00 in string data, which is translated to '\x80')
1348 aInts[0] = 0xE100E200;
1349 EXPECT_FALSE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1350 EXPECT_STREQ(aStr, "");
1351
1352 // invalid UTF-8
1353 aInts[0] = 0xE1E2E36F;
1354 aInts[1] = 0x3F40E4E5;
1355 aInts[2] = 0xE67FE700;
1356 EXPECT_FALSE(IntsToStr(aInts, 3, aStr, std::size(aStr)));
1357 EXPECT_STREQ(aStr, "");
1358
1359 // invalid UTF-8 and missing null-terminator
1360 aInts[0] = 0x7F7F7F7F;
1361 EXPECT_FALSE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1362 EXPECT_STREQ(aStr, "");
1363
1364 // missing null-terminator at the end is ignored
1365 aInts[0] = 0xE1E2E3E4;
1366 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1367 EXPECT_STREQ(aStr, "abc");
1368
1369 // basic fuzzing: no input integer should result in invalid UTF-8 in the string
1370 for(int i = 0; i <= 0xFFFFFF; i += 7) // checking all values takes a bit too long
1371 {
1372 mem_zero(block: aStr, size: std::size(aStr));
1373 aInts[0] = 0xE1 << 24 | i;
1374 aInts[1] = i << 8 | 0xE2;
1375 aInts[2] = 0xE3 << 24 | i;
1376 const bool ConversionResult = IntsToStr(pInts: aInts, NumInts: 3, pStr: aStr, StrSize: std::size(aStr));
1377 // ensure null-termination before calling str_utf8_check
1378 ASSERT_TRUE(mem_has_null(aStr, std::size(aStr)));
1379 ASSERT_TRUE(str_utf8_check(aStr));
1380 ASSERT_TRUE(ConversionResult || aStr[0] == '\0');
1381 }
1382}
1383
1384#if defined(CONF_FAMILY_WINDOWS)
1385TEST(Str, WindowsUtf8WideConversion)
1386{
1387 const char *apUtf8Strings[] = {
1388 "",
1389 "abc",
1390 "a bb ccc dddd eeeee",
1391 "öüä",
1392 "привет Наташа",
1393 "ąçęįǫų",
1394 "DDNet最好了",
1395 "aβい🐘"};
1396 const wchar_t *apWideStrings[] = {
1397 L"",
1398 L"abc",
1399 L"a bb ccc dddd eeeee",
1400 L"öüä",
1401 L"привет Наташа",
1402 L"ąçęįǫų",
1403 L"DDNet最好了",
1404 L"aβい🐘"};
1405 static_assert(std::size(apUtf8Strings) == std::size(apWideStrings));
1406 for(size_t i = 0; i < std::size(apUtf8Strings); i++)
1407 {
1408 const std::optional<std::string> ConvertedUtf8 = windows_wide_to_utf8(apWideStrings[i]);
1409 const std::wstring ConvertedWide = windows_utf8_to_wide(apUtf8Strings[i]);
1410 ASSERT_TRUE(ConvertedUtf8.has_value());
1411 EXPECT_STREQ(ConvertedUtf8.value().c_str(), apUtf8Strings[i]);
1412 EXPECT_STREQ(ConvertedWide.c_str(), apWideStrings[i]);
1413 }
1414}
1415#endif
1416