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, Time)
938{
939 char aBuf[32] = "foobar";
940
941 EXPECT_EQ(str_time(-123456, ETimeFormat::MINS_CENTISECS, aBuf, sizeof(aBuf)), 5);
942 EXPECT_STREQ(aBuf, "00.00");
943
944 EXPECT_EQ(str_time(INT64_MAX, ETimeFormat::DAYS, aBuf, sizeof(aBuf)), 23);
945 EXPECT_STREQ(aBuf, "1067519911673d 00:09:18");
946
947 EXPECT_EQ(str_time(123456, ETimeFormat::DAYS, aBuf, sizeof(aBuf)), 5);
948 EXPECT_STREQ(aBuf, "20:34");
949 EXPECT_EQ(str_time(1234567, ETimeFormat::DAYS, aBuf, sizeof(aBuf)), 8);
950 EXPECT_STREQ(aBuf, "03:25:45");
951 EXPECT_EQ(str_time(12345678, ETimeFormat::DAYS, aBuf, sizeof(aBuf)), 11);
952 EXPECT_STREQ(aBuf, "1d 10:17:36");
953
954 EXPECT_EQ(str_time(123456, ETimeFormat::HOURS, aBuf, sizeof(aBuf)), 5);
955 EXPECT_STREQ(aBuf, "20:34");
956 EXPECT_EQ(str_time(1234567, ETimeFormat::HOURS, aBuf, sizeof(aBuf)), 8);
957 EXPECT_STREQ(aBuf, "03:25:45");
958 EXPECT_EQ(str_time(12345678, ETimeFormat::HOURS, aBuf, sizeof(aBuf)), 8);
959 EXPECT_STREQ(aBuf, "34:17:36");
960
961 EXPECT_EQ(str_time(123456, ETimeFormat::MINS, aBuf, sizeof(aBuf)), 5);
962 EXPECT_STREQ(aBuf, "20:34");
963 EXPECT_EQ(str_time(1234567, ETimeFormat::MINS, aBuf, sizeof(aBuf)), 6);
964 EXPECT_STREQ(aBuf, "205:45");
965 EXPECT_EQ(str_time(12345678, ETimeFormat::MINS, aBuf, sizeof(aBuf)), 7);
966 EXPECT_STREQ(aBuf, "2057:36");
967
968 EXPECT_EQ(str_time(123456, ETimeFormat::HOURS_CENTISECS, aBuf, sizeof(aBuf)), 8);
969 EXPECT_STREQ(aBuf, "20:34.56");
970 EXPECT_EQ(str_time(1234567, ETimeFormat::HOURS_CENTISECS, aBuf, sizeof(aBuf)), 11);
971 EXPECT_STREQ(aBuf, "03:25:45.67");
972 EXPECT_EQ(str_time(12345678, ETimeFormat::HOURS_CENTISECS, aBuf, sizeof(aBuf)), 11);
973 EXPECT_STREQ(aBuf, "34:17:36.78");
974
975 EXPECT_EQ(str_time(123456, ETimeFormat::MINS_CENTISECS, aBuf, sizeof(aBuf)), 8);
976 EXPECT_STREQ(aBuf, "20:34.56");
977 EXPECT_EQ(str_time(1234567, ETimeFormat::MINS_CENTISECS, aBuf, sizeof(aBuf)), 9);
978 EXPECT_STREQ(aBuf, "205:45.67");
979 EXPECT_EQ(str_time(12345678, ETimeFormat::MINS_CENTISECS, aBuf, sizeof(aBuf)), 10);
980 EXPECT_STREQ(aBuf, "2057:36.78");
981
982 EXPECT_EQ(str_time(123456, ETimeFormat::SECS_CENTISECS, aBuf, sizeof(aBuf)), 5);
983 EXPECT_STREQ(aBuf, "34.56");
984 EXPECT_EQ(str_time(1234567, ETimeFormat::SECS_CENTISECS, aBuf, sizeof(aBuf)), 5);
985 EXPECT_STREQ(aBuf, "45.67");
986 EXPECT_EQ(str_time(12345678, ETimeFormat::SECS_CENTISECS, aBuf, sizeof(aBuf)), 5);
987 EXPECT_STREQ(aBuf, "36.78");
988}
989
990TEST(Str, TimeFloat)
991{
992 char aBuf[64];
993 EXPECT_EQ(str_time_float(123456.78, ETimeFormat::DAYS, aBuf, sizeof(aBuf)), 11);
994 EXPECT_STREQ(aBuf, "1d 10:17:36");
995
996 EXPECT_EQ(str_time_float(12.16, ETimeFormat::HOURS_CENTISECS, aBuf, sizeof(aBuf)), 5);
997 EXPECT_STREQ(aBuf, "12.16");
998
999 EXPECT_EQ(str_time_float(22.995, ETimeFormat::MINS, aBuf, sizeof(aBuf)), 5);
1000 EXPECT_STREQ(aBuf, "00:22");
1001}
1002
1003TEST(Str, HasCc)
1004{
1005 EXPECT_FALSE(str_has_cc(""));
1006 EXPECT_FALSE(str_has_cc("a"));
1007 EXPECT_FALSE(str_has_cc("Merhaba dünya!"));
1008
1009 EXPECT_TRUE(str_has_cc("\n"));
1010 EXPECT_TRUE(str_has_cc("\r"));
1011 EXPECT_TRUE(str_has_cc("\t"));
1012 EXPECT_TRUE(str_has_cc("a\n"));
1013 EXPECT_TRUE(str_has_cc("a\rb"));
1014 EXPECT_TRUE(str_has_cc("\tb"));
1015 EXPECT_TRUE(str_has_cc("\n\n"));
1016 EXPECT_TRUE(str_has_cc("\x1C"));
1017 EXPECT_TRUE(str_has_cc("\x1D"));
1018 EXPECT_TRUE(str_has_cc("\x1E"));
1019 EXPECT_TRUE(str_has_cc("\x1F"));
1020}
1021
1022TEST(Str, SanitizeCc)
1023{
1024 TestInplace<str_sanitize_cc>(pInput: "", pOutput: "");
1025 TestInplace<str_sanitize_cc>(pInput: "a", pOutput: "a");
1026 TestInplace<str_sanitize_cc>(pInput: "Merhaba dünya!", pOutput: "Merhaba dünya!");
1027 TestInplace<str_sanitize_cc>(pInput: "\n", pOutput: " ");
1028 TestInplace<str_sanitize_cc>(pInput: "\r", pOutput: " ");
1029 TestInplace<str_sanitize_cc>(pInput: "\t", pOutput: " ");
1030 TestInplace<str_sanitize_cc>(pInput: "a\n", pOutput: "a ");
1031 TestInplace<str_sanitize_cc>(pInput: "a\rb", pOutput: "a b");
1032 TestInplace<str_sanitize_cc>(pInput: "\tb", pOutput: " b");
1033 TestInplace<str_sanitize_cc>(pInput: "\n\n", pOutput: " ");
1034 TestInplace<str_sanitize_cc>(pInput: "\x1C", pOutput: " ");
1035 TestInplace<str_sanitize_cc>(pInput: "\x1D", pOutput: " ");
1036 TestInplace<str_sanitize_cc>(pInput: "\x1E", pOutput: " ");
1037 TestInplace<str_sanitize_cc>(pInput: "\x1F", pOutput: " ");
1038}
1039
1040TEST(Str, Sanitize)
1041{
1042 TestInplace<str_sanitize>(pInput: "", pOutput: "");
1043 TestInplace<str_sanitize>(pInput: "a", pOutput: "a");
1044 TestInplace<str_sanitize>(pInput: "Merhaba dünya!", pOutput: "Merhaba dünya!");
1045 TestInplace<str_sanitize>(pInput: "\n", pOutput: "\n");
1046 TestInplace<str_sanitize>(pInput: "\r", pOutput: "\r");
1047 TestInplace<str_sanitize>(pInput: "\t", pOutput: "\t");
1048 TestInplace<str_sanitize>(pInput: "a\n", pOutput: "a\n");
1049 TestInplace<str_sanitize>(pInput: "a\rb", pOutput: "a\rb");
1050 TestInplace<str_sanitize>(pInput: "\tb", pOutput: "\tb");
1051 TestInplace<str_sanitize>(pInput: "\n\n", pOutput: "\n\n");
1052 TestInplace<str_sanitize>(pInput: "\x1C", pOutput: " ");
1053 TestInplace<str_sanitize>(pInput: "\x1D", pOutput: " ");
1054 TestInplace<str_sanitize>(pInput: "\x1E", pOutput: " ");
1055 TestInplace<str_sanitize>(pInput: "\x1F", pOutput: " ");
1056}
1057
1058TEST(Str, SanitizeFilename)
1059{
1060 TestInplace<str_sanitize_filename>(pInput: "", pOutput: "");
1061 TestInplace<str_sanitize_filename>(pInput: "a", pOutput: "a");
1062 TestInplace<str_sanitize_filename>(pInput: "Merhaba dünya!", pOutput: "Merhaba dünya!");
1063 TestInplace<str_sanitize_filename>(pInput: "привет Наташа", pOutput: "привет Наташа");
1064 TestInplace<str_sanitize_filename>(pInput: "ąçęįǫų", pOutput: "ąçęįǫų");
1065 TestInplace<str_sanitize_filename>(pInput: "DDNet最好了", pOutput: "DDNet最好了");
1066 TestInplace<str_sanitize_filename>(pInput: "aβい🐘", pOutput: "aβい🐘");
1067 TestInplace<str_sanitize_filename>(pInput: "foo.bar", pOutput: "foo.bar");
1068 TestInplace<str_sanitize_filename>(pInput: "foo.bar.baz", pOutput: "foo.bar.baz");
1069 TestInplace<str_sanitize_filename>(pInput: ".a..b...c....d", pOutput: ".a..b...c....d");
1070 TestInplace<str_sanitize_filename>(pInput: "\n", pOutput: " ");
1071 TestInplace<str_sanitize_filename>(pInput: "\r", pOutput: " ");
1072 TestInplace<str_sanitize_filename>(pInput: "\t", pOutput: " ");
1073 TestInplace<str_sanitize_filename>(pInput: "a\n", pOutput: "a ");
1074 TestInplace<str_sanitize_filename>(pInput: "a\rb", pOutput: "a b");
1075 TestInplace<str_sanitize_filename>(pInput: "\tb", pOutput: " b");
1076 TestInplace<str_sanitize_filename>(pInput: "\n\n", pOutput: " ");
1077 TestInplace<str_sanitize_filename>(pInput: "\x1C", pOutput: " ");
1078 TestInplace<str_sanitize_filename>(pInput: "\x1D", pOutput: " ");
1079 TestInplace<str_sanitize_filename>(pInput: "\x1E", pOutput: " ");
1080 TestInplace<str_sanitize_filename>(pInput: "\x1F", pOutput: " ");
1081 TestInplace<str_sanitize_filename>(pInput: "\u007F", pOutput: " ");
1082 TestInplace<str_sanitize_filename>(pInput: "\\", pOutput: " ");
1083 TestInplace<str_sanitize_filename>(pInput: "/", pOutput: " ");
1084 TestInplace<str_sanitize_filename>(pInput: "|", pOutput: " ");
1085 TestInplace<str_sanitize_filename>(pInput: ":", pOutput: " ");
1086 TestInplace<str_sanitize_filename>(pInput: "*", pOutput: " ");
1087 TestInplace<str_sanitize_filename>(pInput: "?", pOutput: " ");
1088 TestInplace<str_sanitize_filename>(pInput: "<", pOutput: " ");
1089 TestInplace<str_sanitize_filename>(pInput: ">", pOutput: " ");
1090 TestInplace<str_sanitize_filename>(pInput: "\"", pOutput: " ");
1091 TestInplace<str_sanitize_filename>(pInput: "\\/|:*?<>\"", pOutput: " ");
1092}
1093
1094TEST(Str, ValidFilename)
1095{
1096 EXPECT_TRUE(str_valid_filename("a"));
1097 EXPECT_TRUE(str_valid_filename("abc"));
1098 EXPECT_TRUE(str_valid_filename("abc abc"));
1099 EXPECT_TRUE(str_valid_filename("aa bb ccc dddd eeeee"));
1100 EXPECT_TRUE(str_valid_filename("öüä"));
1101 EXPECT_TRUE(str_valid_filename("привет Наташа"));
1102 EXPECT_TRUE(str_valid_filename("ąçęįǫų"));
1103 EXPECT_TRUE(str_valid_filename("DDNet最好了"));
1104 EXPECT_TRUE(str_valid_filename("aβい🐘"));
1105 EXPECT_TRUE(str_valid_filename("foo.bar"));
1106 EXPECT_TRUE(str_valid_filename("foo.bar.baz"));
1107 EXPECT_TRUE(str_valid_filename(".a..b...c....d"));
1108
1109 EXPECT_FALSE(str_valid_filename(""));
1110 EXPECT_FALSE(str_valid_filename("aa\nbb"));
1111 EXPECT_FALSE(str_valid_filename("aa\rbb"));
1112 EXPECT_FALSE(str_valid_filename("aa\tbb"));
1113 EXPECT_FALSE(str_valid_filename("aa\u001Cbb"));
1114 EXPECT_FALSE(str_valid_filename("aa\u001Dbb"));
1115 EXPECT_FALSE(str_valid_filename("aa\u001Ebb"));
1116 EXPECT_FALSE(str_valid_filename("aa\u001Fbb"));
1117 EXPECT_FALSE(str_valid_filename("aa\u007Fbb"));
1118 EXPECT_FALSE(str_valid_filename("aa\\bb"));
1119 EXPECT_FALSE(str_valid_filename("aa/bb"));
1120 EXPECT_FALSE(str_valid_filename("aa|bb"));
1121 EXPECT_FALSE(str_valid_filename("aa:bb"));
1122 EXPECT_FALSE(str_valid_filename("aa*bb"));
1123 EXPECT_FALSE(str_valid_filename("aa?bb"));
1124 EXPECT_FALSE(str_valid_filename("aa<bb"));
1125 EXPECT_FALSE(str_valid_filename("aa>bb"));
1126 EXPECT_FALSE(str_valid_filename("aa\"bb"));
1127 EXPECT_FALSE(str_valid_filename("\\/|:*?<>\""));
1128 EXPECT_FALSE(str_valid_filename("aa bb")); // EM QUAD
1129 EXPECT_FALSE(str_valid_filename("aa​bb")); // ZERO WIDTH SPACE
1130 EXPECT_FALSE(str_valid_filename(" abc"));
1131 EXPECT_FALSE(str_valid_filename(" abc"));
1132 EXPECT_FALSE(str_valid_filename("abc "));
1133 EXPECT_FALSE(str_valid_filename("abc "));
1134 EXPECT_FALSE(str_valid_filename("abc abc"));
1135 EXPECT_FALSE(str_valid_filename(" abc abc "));
1136 EXPECT_FALSE(str_valid_filename(" abc abc "));
1137 EXPECT_FALSE(str_valid_filename("abc."));
1138 EXPECT_FALSE(str_valid_filename("abc..."));
1139 EXPECT_FALSE(str_valid_filename("abc... "));
1140 EXPECT_FALSE(str_valid_filename("abc ..."));
1141
1142 // reserved names
1143 EXPECT_FALSE(str_valid_filename("con"));
1144 EXPECT_FALSE(str_valid_filename("CON"));
1145 EXPECT_FALSE(str_valid_filename("cOn"));
1146 EXPECT_FALSE(str_valid_filename("con.txt"));
1147 EXPECT_FALSE(str_valid_filename("con.tar.gz"));
1148 EXPECT_FALSE(str_valid_filename("CON.TAR.GZ"));
1149 EXPECT_FALSE(str_valid_filename("PRN"));
1150 EXPECT_FALSE(str_valid_filename("AUX"));
1151 EXPECT_FALSE(str_valid_filename("NUL"));
1152 EXPECT_FALSE(str_valid_filename("COM4"));
1153 EXPECT_FALSE(str_valid_filename("lpt²"));
1154 // reserved names allowed as prefix if not separated by period
1155 EXPECT_TRUE(str_valid_filename("console"));
1156 EXPECT_TRUE(str_valid_filename("console.log"));
1157 EXPECT_TRUE(str_valid_filename("console.tar.gz"));
1158 EXPECT_TRUE(str_valid_filename("Auxiliary"));
1159 EXPECT_TRUE(str_valid_filename("Null"));
1160 EXPECT_TRUE(str_valid_filename("Null.txt"));
1161}
1162
1163TEST(Str, CleanWhitespaces)
1164{
1165 TestInplace<str_clean_whitespaces>(pInput: "aa bb ccc dddd eeeee", pOutput: "aa bb ccc dddd eeeee");
1166 TestInplace<str_clean_whitespaces>(pInput: " ", pOutput: "");
1167 TestInplace<str_clean_whitespaces>(pInput: " aa", pOutput: "aa");
1168 TestInplace<str_clean_whitespaces>(pInput: "aa ", pOutput: "aa");
1169 TestInplace<str_clean_whitespaces>(pInput: " aa bb ccc dddd eeeee ", pOutput: "aa bb ccc dddd eeeee");
1170}
1171
1172TEST(Str, SkipToWhitespace)
1173{
1174 char aBuf[64];
1175 str_copy(dst&: aBuf, src: "");
1176 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf);
1177 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf);
1178 str_copy(dst&: aBuf, src: " a");
1179 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf);
1180 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf);
1181 str_copy(dst&: aBuf, src: "aaaa b");
1182 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1183 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1184 str_copy(dst&: aBuf, src: "aaaa\n\nb");
1185 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1186 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1187 str_copy(dst&: aBuf, src: "aaaa\r\rb");
1188 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1189 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1190 str_copy(dst&: aBuf, src: "aaaa\t\tb");
1191 EXPECT_EQ(str_skip_to_whitespace(aBuf), aBuf + 4);
1192 EXPECT_EQ(str_skip_to_whitespace_const(aBuf), aBuf + 4);
1193}
1194
1195TEST(Str, SkipWhitespaces)
1196{
1197 char aBuf[64];
1198 str_copy(dst&: aBuf, src: "");
1199 EXPECT_EQ(str_skip_whitespaces(aBuf), aBuf);
1200 EXPECT_EQ(str_skip_whitespaces_const(aBuf), aBuf);
1201 str_copy(dst&: aBuf, src: "aaaa");
1202 EXPECT_EQ(str_skip_whitespaces(aBuf), aBuf);
1203 EXPECT_EQ(str_skip_whitespaces_const(aBuf), aBuf);
1204 str_copy(dst&: aBuf, src: " \n\r\taaaa");
1205 EXPECT_EQ(str_skip_whitespaces(aBuf), aBuf + 4);
1206 EXPECT_EQ(str_skip_whitespaces_const(aBuf), aBuf + 4);
1207}
1208
1209TEST(Str, CompFilename)
1210{
1211 EXPECT_EQ(str_comp_filenames("a", "a"), 0);
1212 EXPECT_LT(str_comp_filenames("a", "b"), 0);
1213 EXPECT_GT(str_comp_filenames("b", "a"), 0);
1214 EXPECT_EQ(str_comp_filenames("A", "a"), 0);
1215 EXPECT_LT(str_comp_filenames("A", "b"), 0);
1216 EXPECT_GT(str_comp_filenames("b", "A"), 0);
1217 EXPECT_LT(str_comp_filenames("a", "B"), 0);
1218 EXPECT_GT(str_comp_filenames("B", "a"), 0);
1219 EXPECT_EQ(str_comp_filenames("1A", "1a"), 0);
1220 EXPECT_LT(str_comp_filenames("1a", "1B"), 0);
1221 EXPECT_GT(str_comp_filenames("1B", "1a"), 0);
1222 EXPECT_LT(str_comp_filenames("1a", "1b"), 0);
1223 EXPECT_GT(str_comp_filenames("1b", "1a"), 0);
1224 EXPECT_GT(str_comp_filenames("12a", "1B"), 0);
1225 EXPECT_LT(str_comp_filenames("1B", "12a"), 0);
1226 EXPECT_GT(str_comp_filenames("10a", "1B"), 0);
1227 EXPECT_LT(str_comp_filenames("1B", "10a"), 0);
1228 EXPECT_GT(str_comp_filenames("10a", "00B"), 0);
1229 EXPECT_LT(str_comp_filenames("00B", "10a"), 0);
1230 EXPECT_GT(str_comp_filenames("10a", "09B"), 0);
1231 EXPECT_LT(str_comp_filenames("09B", "10a"), 0);
1232 EXPECT_LT(str_comp_filenames("abc", "abcd"), 0);
1233 EXPECT_GT(str_comp_filenames("abcd", "abc"), 0);
1234 EXPECT_LT(str_comp_filenames("abc2", "abcd1"), 0);
1235 EXPECT_GT(str_comp_filenames("abcd1", "abc2"), 0);
1236 EXPECT_LT(str_comp_filenames("abc50", "abcd"), 0);
1237 EXPECT_GT(str_comp_filenames("abcd", "abc50"), 0);
1238 EXPECT_EQ(str_comp_filenames("file0", "file0"), 0);
1239 EXPECT_LT(str_comp_filenames("file0", "file1"), 0);
1240 EXPECT_GT(str_comp_filenames("file1", "file0"), 0);
1241 EXPECT_LT(str_comp_filenames("file1", "file09"), 0);
1242 EXPECT_GT(str_comp_filenames("file09", "file1"), 0);
1243 EXPECT_LT(str_comp_filenames("file1", "file009"), 0);
1244 EXPECT_GT(str_comp_filenames("file009", "file1"), 0);
1245 EXPECT_GT(str_comp_filenames("file10", "file00"), 0);
1246 EXPECT_LT(str_comp_filenames("file00", "file10"), 0);
1247 EXPECT_GT(str_comp_filenames("file10", "file09"), 0);
1248 EXPECT_LT(str_comp_filenames("file09", "file10"), 0);
1249 EXPECT_LT(str_comp_filenames("file13", "file37"), 0);
1250 EXPECT_GT(str_comp_filenames("file37", "file13"), 0);
1251 EXPECT_LT(str_comp_filenames("file1.ext", "file09.ext"), 0);
1252 EXPECT_GT(str_comp_filenames("file09.ext", "file1.ext"), 0);
1253 EXPECT_LT(str_comp_filenames("file1.ext", "file009.ext"), 0);
1254 EXPECT_GT(str_comp_filenames("file009.ext", "file1.ext"), 0);
1255 EXPECT_EQ(str_comp_filenames("file0.ext", "file0.ext"), 0);
1256 EXPECT_LT(str_comp_filenames("file13.ext", "file37.ext"), 0);
1257 EXPECT_GT(str_comp_filenames("file37.ext", "file13.ext"), 0);
1258 EXPECT_LT(str_comp_filenames("FILE13.EXT", "file37.ext"), 0);
1259 EXPECT_GT(str_comp_filenames("file37.ext", "FILE13.EXT"), 0);
1260 EXPECT_GT(str_comp_filenames("file10.ext", "file00.ext"), 0);
1261 EXPECT_LT(str_comp_filenames("file00.ext", "file10.ext"), 0);
1262 EXPECT_GT(str_comp_filenames("file10.ext", "file09.ext"), 0);
1263 EXPECT_LT(str_comp_filenames("file09.ext", "file10.ext"), 0);
1264 EXPECT_LT(str_comp_filenames("file42", "file1337"), 0);
1265 EXPECT_GT(str_comp_filenames("file1337", "file42"), 0);
1266 EXPECT_LT(str_comp_filenames("file42.ext", "file1337.ext"), 0);
1267 EXPECT_GT(str_comp_filenames("file1337.ext", "file42.ext"), 0);
1268 EXPECT_GT(str_comp_filenames("file4414520", "file2055"), 0);
1269 EXPECT_LT(str_comp_filenames("file4414520", "file205523151812419"), 0);
1270}
1271
1272TEST(Str, RightChar)
1273{
1274 const char *pStr = "a bb ccc dddd eeeee";
1275 EXPECT_EQ(str_rchr(pStr, 'a'), pStr);
1276 EXPECT_EQ(str_rchr(pStr, 'b'), pStr + 3);
1277 EXPECT_EQ(str_rchr(pStr, 'c'), pStr + 7);
1278 EXPECT_EQ(str_rchr(pStr, 'd'), pStr + 12);
1279 EXPECT_EQ(str_rchr(pStr, ' '), pStr + 19);
1280 EXPECT_EQ(str_rchr(pStr, 'e'), pStr + 24);
1281 EXPECT_EQ(str_rchr(pStr, '\0'), pStr + str_length(pStr));
1282 EXPECT_EQ(str_rchr(pStr, 'y'), nullptr);
1283}
1284
1285TEST(Str, CountChar)
1286{
1287 const char *pStr = "a bb ccc dddd eeeee";
1288 EXPECT_EQ(str_countchr(pStr, 'a'), 1);
1289 EXPECT_EQ(str_countchr(pStr, 'b'), 2);
1290 EXPECT_EQ(str_countchr(pStr, 'c'), 3);
1291 EXPECT_EQ(str_countchr(pStr, 'd'), 4);
1292 EXPECT_EQ(str_countchr(pStr, 'e'), 5);
1293 EXPECT_EQ(str_countchr(pStr, ' '), 10);
1294 EXPECT_EQ(str_countchr(pStr, '\0'), 0);
1295 EXPECT_EQ(str_countchr(pStr, 'y'), 0);
1296}
1297
1298TEST(Str, StrToInts)
1299{
1300 int aInts[8];
1301
1302 StrToInts(pInts: aInts, NumInts: 1, pStr: "a");
1303 EXPECT_EQ(aInts[0], 0xE1808000);
1304
1305 StrToInts(pInts: aInts, NumInts: 1, pStr: "ab");
1306 EXPECT_EQ(aInts[0], 0xE1E28000);
1307
1308 StrToInts(pInts: aInts, NumInts: 1, pStr: "abc");
1309 EXPECT_EQ(aInts[0], 0xE1E2E300);
1310
1311 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcd");
1312 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1313 EXPECT_EQ(aInts[1], 0x80808000);
1314
1315 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcde");
1316 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1317 EXPECT_EQ(aInts[1], 0xE5808000);
1318
1319 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcdef");
1320 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1321 EXPECT_EQ(aInts[1], 0xE5E68000);
1322
1323 StrToInts(pInts: aInts, NumInts: 2, pStr: "abcdefg");
1324 EXPECT_EQ(aInts[0], 0xE1E2E3E4);
1325 EXPECT_EQ(aInts[1], 0xE5E6E700);
1326
1327 StrToInts(pInts: aInts, NumInts: 2, pStr: "öüä");
1328 EXPECT_EQ(aInts[0], 0x4336433C);
1329 EXPECT_EQ(aInts[1], 0x43248000);
1330
1331 StrToInts(pInts: aInts, NumInts: 3, pStr: "aβい🐘");
1332 EXPECT_EQ(aInts[0], 0xE14E3263);
1333 EXPECT_EQ(aInts[1], 0x0104701F);
1334 EXPECT_EQ(aInts[2], 0x10188000);
1335
1336 // long padding
1337 StrToInts(pInts: aInts, NumInts: 4, pStr: "abc");
1338 EXPECT_EQ(aInts[0], 0xE1E2E380);
1339 EXPECT_EQ(aInts[1], 0x80808080);
1340 EXPECT_EQ(aInts[2], 0x80808080);
1341 EXPECT_EQ(aInts[3], 0x80808000);
1342}
1343
1344TEST(Str, IntsToStr)
1345{
1346 int aInts[8];
1347 char aStr[sizeof(aInts)];
1348
1349 aInts[0] = 0xE1808000;
1350 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1351 EXPECT_STREQ(aStr, "a");
1352
1353 aInts[0] = 0xE1E28000;
1354 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1355 EXPECT_STREQ(aStr, "ab");
1356
1357 aInts[0] = 0xE1E2E300;
1358 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1359 EXPECT_STREQ(aStr, "abc");
1360
1361 aInts[0] = 0xE1E2E3E4;
1362 aInts[1] = 0x80808000;
1363 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1364 EXPECT_STREQ(aStr, "abcd");
1365
1366 aInts[0] = 0xE1E2E3E4;
1367 aInts[1] = 0xE5808000;
1368 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1369 EXPECT_STREQ(aStr, "abcde");
1370
1371 aInts[0] = 0xE1E2E3E4;
1372 aInts[1] = 0xE5E68000;
1373 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1374 EXPECT_STREQ(aStr, "abcdef");
1375
1376 aInts[0] = 0xE1E2E3E4;
1377 aInts[1] = 0xE5E6E700;
1378 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1379 EXPECT_STREQ(aStr, "abcdefg");
1380
1381 aInts[0] = 0x4336433C;
1382 aInts[1] = 0x43248000;
1383 EXPECT_TRUE(IntsToStr(aInts, 2, aStr, std::size(aStr)));
1384 EXPECT_STREQ(aStr, "öüä");
1385
1386 aInts[0] = 0xE14E3263;
1387 aInts[1] = 0x0104701F;
1388 aInts[2] = 0x10188000;
1389 EXPECT_TRUE(IntsToStr(aInts, 3, aStr, std::size(aStr)));
1390 EXPECT_STREQ(aStr, "aβい🐘");
1391
1392 // long padding
1393 aInts[0] = 0xE1E2E380;
1394 aInts[1] = 0x80808080;
1395 aInts[2] = 0x80808080;
1396 aInts[3] = 0x80808000;
1397 EXPECT_TRUE(IntsToStr(aInts, 4, aStr, std::size(aStr)));
1398 EXPECT_STREQ(aStr, "abc");
1399
1400 // early null character (0x80)
1401 aInts[0] = 0xE1E2E380;
1402 aInts[1] = 0xE1E2E3E4;
1403 aInts[2] = 0xE1E2E3E4;
1404 aInts[3] = 0xE1E2E300;
1405 EXPECT_TRUE(IntsToStr(aInts, 4, aStr, std::size(aStr)));
1406 EXPECT_STREQ(aStr, "abc");
1407
1408 // invalid UTF-8
1409 aInts[0] = 0xE17FE200;
1410 EXPECT_FALSE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1411 EXPECT_STREQ(aStr, "");
1412
1413 // invalid UTF-8 (0x00 in string data, which is translated to '\x80')
1414 aInts[0] = 0xE100E200;
1415 EXPECT_FALSE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1416 EXPECT_STREQ(aStr, "");
1417
1418 // invalid UTF-8
1419 aInts[0] = 0xE1E2E36F;
1420 aInts[1] = 0x3F40E4E5;
1421 aInts[2] = 0xE67FE700;
1422 EXPECT_FALSE(IntsToStr(aInts, 3, aStr, std::size(aStr)));
1423 EXPECT_STREQ(aStr, "");
1424
1425 // invalid UTF-8 and missing null-terminator
1426 aInts[0] = 0x7F7F7F7F;
1427 EXPECT_FALSE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1428 EXPECT_STREQ(aStr, "");
1429
1430 // missing null-terminator at the end is ignored
1431 aInts[0] = 0xE1E2E3E4;
1432 EXPECT_TRUE(IntsToStr(aInts, 1, aStr, std::size(aStr)));
1433 EXPECT_STREQ(aStr, "abc");
1434
1435 // basic fuzzing: no input integer should result in invalid UTF-8 in the string
1436 for(int i = 0; i <= 0xFFFFFF; i += 7) // checking all values takes a bit too long
1437 {
1438 mem_zero(block: aStr, size: std::size(aStr));
1439 aInts[0] = 0xE1 << 24 | i;
1440 aInts[1] = i << 8 | 0xE2;
1441 aInts[2] = 0xE3 << 24 | i;
1442 const bool ConversionResult = IntsToStr(pInts: aInts, NumInts: 3, pStr: aStr, StrSize: std::size(aStr));
1443 // ensure null-termination before calling str_utf8_check
1444 ASSERT_TRUE(mem_has_null(aStr, std::size(aStr)));
1445 ASSERT_TRUE(str_utf8_check(aStr));
1446 ASSERT_TRUE(ConversionResult || aStr[0] == '\0');
1447 }
1448}
1449
1450#if defined(CONF_FAMILY_WINDOWS)
1451TEST(Str, WindowsUtf8WideConversion)
1452{
1453 const char *apUtf8Strings[] = {
1454 "",
1455 "abc",
1456 "a bb ccc dddd eeeee",
1457 "öüä",
1458 "привет Наташа",
1459 "ąçęįǫų",
1460 "DDNet最好了",
1461 "aβい🐘"};
1462 const wchar_t *apWideStrings[] = {
1463 L"",
1464 L"abc",
1465 L"a bb ccc dddd eeeee",
1466 L"öüä",
1467 L"привет Наташа",
1468 L"ąçęįǫų",
1469 L"DDNet最好了",
1470 L"aβい🐘"};
1471 static_assert(std::size(apUtf8Strings) == std::size(apWideStrings));
1472 for(size_t i = 0; i < std::size(apUtf8Strings); i++)
1473 {
1474 const std::optional<std::string> ConvertedUtf8 = windows_wide_to_utf8(apWideStrings[i]);
1475 const std::wstring ConvertedWide = windows_utf8_to_wide(apUtf8Strings[i]);
1476 ASSERT_TRUE(ConvertedUtf8.has_value());
1477 EXPECT_STREQ(ConvertedUtf8.value().c_str(), apUtf8Strings[i]);
1478 EXPECT_STREQ(ConvertedWide.c_str(), apWideStrings[i]);
1479 }
1480}
1481#endif
1482