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