Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/core/string/test_string.h
11353 views
1
/**************************************************************************/
2
/* test_string.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/string/ustring.h"
34
35
#include "tests/test_macros.h"
36
37
namespace TestString {
38
39
int u32scmp(const char32_t *l, const char32_t *r) {
40
for (; *l == *r && *l && *r; l++, r++) {
41
// Continue.
42
}
43
return *l - *r;
44
}
45
46
TEST_CASE("[String] Assign Latin-1 char string") {
47
String s = "Hello";
48
CHECK(u32scmp(s.get_data(), U"Hello") == 0);
49
}
50
51
TEST_CASE("[String] Assign from Latin-1 char string (operator=)") {
52
String s = "Dolly";
53
const String &t = s;
54
CHECK(u32scmp(t.get_data(), U"Dolly") == 0);
55
}
56
57
TEST_CASE("[String] Assign from Latin-1 char string (copycon)") {
58
String s("Sheep");
59
const String &t1(s);
60
CHECK(u32scmp(t1.get_data(), U"Sheep") == 0);
61
62
String t2 = String::latin1(Span("Sheep", 3));
63
CHECK(u32scmp(t2.get_data(), U"She") == 0);
64
}
65
66
TEST_CASE("[String] Assign from wchar_t string (operator=)") {
67
String s = L"Give me";
68
CHECK(u32scmp(s.get_data(), U"Give me") == 0);
69
}
70
71
TEST_CASE("[String] Assign from wchar_t string (copycon)") {
72
String s(L"Wool");
73
CHECK(u32scmp(s.get_data(), U"Wool") == 0);
74
}
75
76
TEST_CASE("[String] Assign from char32_t string (operator=)") {
77
String s = U"Give me";
78
CHECK(u32scmp(s.get_data(), U"Give me") == 0);
79
}
80
81
TEST_CASE("[String] Assign from char32_t string (copycon)") {
82
String s(U"Wool");
83
CHECK(u32scmp(s.get_data(), U"Wool") == 0);
84
}
85
86
TEST_CASE("[String] UTF8") {
87
/* how can i embed UTF in here? */
88
static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
89
static const uint8_t u8str[] = { 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
90
String expected = u32str;
91
String parsed;
92
Error err = parsed.append_utf8(expected.utf8().get_data());
93
CHECK(err == OK);
94
CHECK(parsed == u32str);
95
96
parsed.clear();
97
err = parsed.append_utf8((const char *)u8str);
98
CHECK(err == OK);
99
CHECK(parsed == u32str);
100
101
CharString cs = (const char *)u8str;
102
CHECK(String::utf8(cs) == parsed);
103
}
104
105
TEST_CASE("[String] UTF16") {
106
/* how can i embed UTF in here? */
107
static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
108
static const char16_t u16str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
109
String expected = u32str;
110
String parsed;
111
Error err = parsed.append_utf16(expected.utf16().get_data());
112
CHECK(err == OK);
113
CHECK(parsed == u32str);
114
115
parsed.clear();
116
err = parsed.append_utf16(u16str);
117
CHECK(err == OK);
118
CHECK(parsed == u32str);
119
120
Char16String cs = u16str;
121
CHECK(String::utf16(cs) == parsed);
122
}
123
124
TEST_CASE("[String] UTF8 with BOM") {
125
/* how can i embed UTF in here? */
126
static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
127
static const uint8_t u8str[] = { 0xEF, 0xBB, 0xBF, 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
128
String s;
129
Error err = s.append_utf8((const char *)u8str);
130
CHECK(err == OK);
131
CHECK(s == u32str);
132
133
CharString cs = (const char *)u8str;
134
CHECK(String::utf8(cs) == s);
135
}
136
137
TEST_CASE("[String] UTF16 with BOM") {
138
/* how can i embed UTF in here? */
139
static const char32_t u32str[] = { 0x0020, 0x0045, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
140
static const char16_t u16str[] = { 0xFEFF, 0x0020, 0x0045, 0x304A, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
141
static const char16_t u16str_swap[] = { 0xFFFE, 0x2000, 0x4500, 0x4A30, 0x0F36, 0x8830, 0x4630, 0x3CD8, 0xA4DF, 0 };
142
String s;
143
Error err = s.append_utf16(u16str);
144
CHECK(err == OK);
145
CHECK(s == u32str);
146
147
s.clear();
148
err = s.append_utf16(u16str_swap);
149
CHECK(err == OK);
150
CHECK(s == u32str);
151
152
Char16String cs = u16str;
153
CHECK(String::utf16(cs) == s);
154
155
cs = u16str_swap;
156
CHECK(String::utf16(cs) == s);
157
}
158
159
TEST_CASE("[String] Invalid UTF8 (non shortest form sequence)") {
160
ERR_PRINT_OFF
161
// Examples from the unicode standard : 3.9 Unicode Encoding Forms - Table 3.8.
162
static const uint8_t u8str[] = { 0xC0, 0xAF, 0xE0, 0x80, 0xBF, 0xF0, 0x81, 0x82, 0x41, 0 };
163
static const char32_t u32str[] = { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x41, 0 };
164
String s;
165
Error err = s.append_utf8((const char *)u8str);
166
CHECK(err == ERR_INVALID_DATA);
167
CHECK(s == u32str);
168
169
CharString cs = (const char *)u8str;
170
CHECK(String::utf8(cs) == s);
171
ERR_PRINT_ON
172
}
173
174
TEST_CASE("[String] Invalid UTF8 (ill formed sequences for surrogates)") {
175
ERR_PRINT_OFF
176
// Examples from the unicode standard : 3.9 Unicode Encoding Forms - Table 3.9.
177
static const uint8_t u8str[] = { 0xED, 0xA0, 0x80, 0xED, 0xBF, 0xBF, 0xED, 0xAF, 0x41, 0 };
178
static const char32_t u32str[] = { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x41, 0 };
179
String s;
180
Error err = s.append_utf8((const char *)u8str);
181
CHECK(err == ERR_INVALID_DATA);
182
CHECK(s == u32str);
183
184
CharString cs = (const char *)u8str;
185
CHECK(String::utf8(cs) == s);
186
ERR_PRINT_ON
187
}
188
189
TEST_CASE("[String] Invalid UTF8 (other ill formed sequences)") {
190
ERR_PRINT_OFF
191
// Examples from the unicode standard : 3.9 Unicode Encoding Forms - Table 3.10.
192
static const uint8_t u8str[] = { 0xF4, 0x91, 0x92, 0x93, 0xFF, 0x41, 0x80, 0xBF, 0x42, 0 };
193
static const char32_t u32str[] = { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x41, 0xFFFD, 0xFFFD, 0x42, 0 };
194
String s;
195
Error err = s.append_utf8((const char *)u8str);
196
CHECK(err == ERR_INVALID_DATA);
197
CHECK(s == u32str);
198
199
CharString cs = (const char *)u8str;
200
CHECK(String::utf8(cs) == s);
201
ERR_PRINT_ON
202
}
203
204
TEST_CASE("[String] Invalid UTF8 (truncated sequences)") {
205
ERR_PRINT_OFF
206
// Examples from the unicode standard : 3.9 Unicode Encoding Forms - Table 3.11.
207
static const uint8_t u8str[] = { 0xE1, 0x80, 0xE2, 0xF0, 0x91, 0x92, 0xF1, 0xBF, 0x41, 0 };
208
static const char32_t u32str[] = { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x41, 0 };
209
String s;
210
Error err = s.append_utf8((const char *)u8str);
211
CHECK(err == ERR_INVALID_DATA);
212
CHECK(s == u32str);
213
214
CharString cs = (const char *)u8str;
215
CHECK(String::utf8(cs) == s);
216
ERR_PRINT_ON
217
}
218
219
TEST_CASE("[String] Invalid UTF16 (non-standard)") {
220
ERR_PRINT_OFF
221
static const char16_t u16str[] = { 0x0045, 0x304A, 0x3088, 0x3046, 0xDFA4, 0 };
222
// + + + + unpaired
223
static const char32_t u32str[] = { 0x0045, 0x304A, 0x3088, 0x3046, 0xDFA4, 0 };
224
String s;
225
Error err = s.append_utf16(u16str);
226
CHECK(err == ERR_PARSE_ERROR);
227
CHECK(s == u32str);
228
229
Char16String cs = u16str;
230
CHECK(String::utf16(cs) == s);
231
ERR_PRINT_ON
232
}
233
234
TEST_CASE("[String] ASCII") {
235
String s = U"Primero Leche";
236
String t = s.ascii(false).get_data();
237
CHECK(s == t);
238
239
t = s.ascii(true).get_data();
240
CHECK(s == t);
241
}
242
243
TEST_CASE("[String] Comparisons (equal)") {
244
String s = "Test Compare";
245
CHECK(s == "Test Compare");
246
CHECK(s == U"Test Compare");
247
CHECK(s == L"Test Compare");
248
CHECK(s == String("Test Compare"));
249
250
CharString empty = "";
251
CharString cs = "Test Compare";
252
CHECK(!(empty == cs));
253
CHECK(!(cs == empty));
254
CHECK(cs == CharString("Test Compare"));
255
}
256
257
TEST_CASE("[String] Comparisons (not equal)") {
258
String s = "Test Compare";
259
CHECK(s != "Peanut");
260
CHECK(s != U"Coconut");
261
CHECK(s != L"Coconut");
262
CHECK(s != String("Butter"));
263
}
264
265
TEST_CASE("[String] Comparisons (operator <)") {
266
String s = "Bees";
267
CHECK(s < "Elephant");
268
CHECK(!(s < U"Amber"));
269
CHECK(!(s < L"Amber"));
270
CHECK(!(s < String("Beatrix")));
271
}
272
273
TEST_CASE("[String] Concatenation") {
274
String s;
275
276
s += "Have";
277
s += ' ';
278
s += 'a';
279
s += String(" ");
280
s = s + U"Nice";
281
s = s + " ";
282
s = s + String("Day");
283
284
CHECK(s == "Have a Nice Day");
285
}
286
287
TEST_CASE("[String] Testing size and length of string") {
288
// todo: expand this test to do more tests on size() as it is complicated under the hood.
289
CHECK(String("Mellon").size() == 7);
290
CHECK(String("Mellon1").size() == 8);
291
292
// length works fine and is easier to test
293
CHECK(String("Mellon").length() == 6);
294
CHECK(String("Mellon1").length() == 7);
295
CHECK(String("Mellon2").length() == 7);
296
CHECK(String("Mellon3").length() == 7);
297
}
298
299
TEST_CASE("[String] Testing for empty string") {
300
CHECK(!String("Mellon").is_empty());
301
// do this more than once, to check for string corruption
302
CHECK(String("").is_empty());
303
CHECK(String("").is_empty());
304
CHECK(String("").is_empty());
305
}
306
307
TEST_CASE("[String] Contains") {
308
String s = "C:\\Godot\\project\\string_test.tscn";
309
CHECK(s.contains(":\\"));
310
CHECK(s.contains("Godot"));
311
CHECK(s.contains(String("project\\string_test")));
312
CHECK(s.contains(String("\\string_test.tscn")));
313
314
CHECK(!s.contains("://"));
315
CHECK(!s.contains("Godoh"));
316
CHECK(!s.contains(String("project\\string test")));
317
CHECK(!s.contains(String("\\char_test.tscn")));
318
}
319
320
TEST_CASE("[String] Contains case insensitive") {
321
String s = "C:\\Godot\\project\\string_test.tscn";
322
CHECK(s.containsn("Godot"));
323
CHECK(s.containsn("godot"));
324
CHECK(s.containsn(String("Project\\string_test")));
325
CHECK(s.containsn(String("\\string_Test.tscn")));
326
327
CHECK(!s.containsn("Godoh"));
328
CHECK(!s.containsn("godoh"));
329
CHECK(!s.containsn(String("project\\string test")));
330
CHECK(!s.containsn(String("\\char_test.tscn")));
331
}
332
333
TEST_CASE("[String] Test chr") {
334
CHECK(String::chr('H') == "H");
335
CHECK(String::chr(0x3012)[0] == 0x3012);
336
ERR_PRINT_OFF
337
CHECK(String::chr(0xd812)[0] == 0xfffd); // Unpaired UTF-16 surrogate
338
CHECK(String::chr(0x20d812)[0] == 0xfffd); // Outside UTF-32 range
339
ERR_PRINT_ON
340
}
341
342
TEST_CASE("[String] Operator []") {
343
String a = "Kugar Sane";
344
a[0] = 'S';
345
a[6] = 'C';
346
CHECK(a == "Sugar Cane");
347
CHECK(a[1] == 'u');
348
CHECK(a.unicode_at(1) == 'u');
349
}
350
351
TEST_CASE("[String] Case function test") {
352
String a = "MoMoNgA";
353
354
CHECK(a.to_upper() == "MOMONGA");
355
CHECK(a.to_lower() == "momonga");
356
}
357
358
TEST_CASE("[String] Case compare function test") {
359
String a = "MoMoNgA";
360
361
CHECK(a.casecmp_to("momonga") != 0);
362
CHECK(a.nocasecmp_to("momonga") == 0);
363
}
364
365
TEST_CASE("[String] Natural compare function test") {
366
String a = "img2.png";
367
368
CHECK(a.nocasecmp_to("img10.png") > 0);
369
CHECK(a.naturalnocasecmp_to("img10.png") < 0);
370
}
371
372
TEST_CASE("[String] File compare function test") {
373
String a = "_img2.png";
374
String b = "img2.png";
375
376
CHECK(a.nocasecmp_to("img10.png") > 0);
377
CHECK_MESSAGE(a.filenocasecmp_to("img10.png") < 0, "Should sort before letters.");
378
CHECK_MESSAGE(a.filenocasecmp_to(".img10.png") > 0, "Should sort after period.");
379
CHECK(b.filenocasecmp_to("img3.png") < 0);
380
}
381
382
TEST_CASE("[String] hex_encode_buffer") {
383
static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0x8F, 0xE3 };
384
String s = String::hex_encode_buffer(u8str, 6);
385
CHECK(s == U"45e3818a8fe3");
386
}
387
388
TEST_CASE("[String] Substr") {
389
String s = "Killer Baby";
390
CHECK(s.substr(3, 4) == "ler ");
391
CHECK(s.substr(3) == "ler Baby");
392
}
393
394
TEST_CASE("[String] Find") {
395
String s = "Pretty Woman Woman";
396
MULTICHECK_STRING_EQ(s, find, "tty", 3);
397
MULTICHECK_STRING_EQ(s, find, "Revenge of the Monster Truck", -1);
398
MULTICHECK_STRING_INT_EQ(s, find, "Wo", 9, 13);
399
MULTICHECK_STRING_EQ(s, find, "", -1);
400
MULTICHECK_STRING_EQ(s, find, "Pretty Woman Woman", 0);
401
MULTICHECK_STRING_EQ(s, find, "WOMAN", -1);
402
MULTICHECK_STRING_INT_EQ(s, find, "", 9, -1);
403
404
MULTICHECK_STRING_EQ(s, rfind, "", -1);
405
MULTICHECK_STRING_EQ(s, rfind, "foo", -1);
406
MULTICHECK_STRING_EQ(s, rfind, "Pretty Woman Woman", 0);
407
MULTICHECK_STRING_EQ(s, rfind, "man", 15);
408
MULTICHECK_STRING_EQ(s, rfind, "WOMAN", -1);
409
MULTICHECK_STRING_INT_EQ(s, rfind, "", 15, -1);
410
}
411
412
TEST_CASE("[String] Find character") {
413
String s = "racecar";
414
CHECK_EQ(s.find_char('r'), 0);
415
CHECK_EQ(s.find_char('r', 1), 6);
416
CHECK_EQ(s.find_char('e'), 3);
417
CHECK_EQ(s.find_char('e', 4), -1);
418
419
CHECK_EQ(s.rfind_char('r'), 6);
420
CHECK_EQ(s.rfind_char('r', 5), 0);
421
CHECK_EQ(s.rfind_char('e'), 3);
422
CHECK_EQ(s.rfind_char('e', 2), -1);
423
}
424
425
TEST_CASE("[String] Find case insensitive") {
426
String s = "Pretty Whale Whale";
427
MULTICHECK_STRING_EQ(s, findn, "WHA", 7);
428
MULTICHECK_STRING_INT_EQ(s, findn, "WHA", 9, 13);
429
MULTICHECK_STRING_EQ(s, findn, "Revenge of the Monster SawFish", -1);
430
MULTICHECK_STRING_EQ(s, findn, "", -1);
431
MULTICHECK_STRING_EQ(s, findn, "wha", 7);
432
MULTICHECK_STRING_EQ(s, findn, "Wha", 7);
433
MULTICHECK_STRING_INT_EQ(s, findn, "", 3, -1);
434
435
MULTICHECK_STRING_EQ(s, rfindn, "WHA", 13);
436
MULTICHECK_STRING_EQ(s, rfindn, "", -1);
437
MULTICHECK_STRING_EQ(s, rfindn, "wha", 13);
438
MULTICHECK_STRING_EQ(s, rfindn, "Wha", 13);
439
MULTICHECK_STRING_INT_EQ(s, rfindn, "", 13, -1);
440
}
441
442
TEST_CASE("[String] Find MK") {
443
Vector<String> keys;
444
keys.push_back("sty");
445
keys.push_back("tty");
446
keys.push_back("man");
447
448
String s = "Pretty Woman";
449
int key = 0;
450
451
CHECK(s.findmk(keys, 0, &key) == 3);
452
CHECK(key == 1);
453
454
CHECK(s.findmk(keys, 5, &key) == 9);
455
CHECK(key == 2);
456
}
457
458
TEST_CASE("[String] Find and replace") {
459
String s = "Happy Birthday, Anna!";
460
MULTICHECK_STRING_STRING_EQ(s, replace, "Birthday", "Halloween", "Happy Halloween, Anna!");
461
MULTICHECK_STRING_STRING_EQ(s, replace_first, "y", "Y", "HappY Birthday, Anna!");
462
MULTICHECK_STRING_STRING_EQ(s, replacen, "Y", "Y", "HappY BirthdaY, Anna!");
463
}
464
465
TEST_CASE("[String] replace_char") {
466
String s = "Banana";
467
CHECK(s.replace_char('n', 'x') == "Baxaxa");
468
CHECK(s.replace_char('\0', 'x') == "Banana");
469
ERR_PRINT_OFF
470
CHECK(s.replace_char('n', '\0') == "Banana");
471
ERR_PRINT_ON
472
}
473
474
TEST_CASE("[String] replace_chars") {
475
String s = "Banana";
476
CHECK(s.replace_chars(String("Bn"), 'x') == "xaxaxa");
477
CHECK(s.replace_chars("Bn", 'x') == "xaxaxa");
478
CHECK(s.replace_chars(String(), 'x') == "Banana");
479
CHECK(s.replace_chars("", 'x') == "Banana");
480
ERR_PRINT_OFF
481
CHECK(s.replace_chars(String("Bn"), '\0') == "Banana");
482
CHECK(s.replace_chars("Bn", '\0') == "Banana");
483
ERR_PRINT_ON
484
}
485
486
TEST_CASE("[String] Insertion") {
487
String s = "Who is Frederic?";
488
s = s.insert(s.find("?"), " Chopin");
489
CHECK(s == "Who is Frederic Chopin?");
490
491
s = "foobar";
492
CHECK(s.insert(0, "X") == "Xfoobar");
493
CHECK(s.insert(-100, "X") == "foobar");
494
CHECK(s.insert(6, "X") == "foobarX");
495
CHECK(s.insert(100, "X") == "foobarX");
496
CHECK(s.insert(2, "") == "foobar");
497
498
s = "";
499
CHECK(s.insert(0, "abc") == "abc");
500
CHECK(s.insert(100, "abc") == "abc");
501
CHECK(s.insert(-100, "abc") == "");
502
CHECK(s.insert(0, "") == "");
503
}
504
505
TEST_CASE("[String] Erasing") {
506
String s = "Josephine is such a cute girl!";
507
s = s.erase(s.find("cute "), String("cute ").length());
508
CHECK(s == "Josephine is such a girl!");
509
}
510
511
TEST_CASE("[String] remove_char") {
512
String s = "Banana";
513
CHECK(s.remove_char('a') == "Bnn");
514
CHECK(s.remove_char('\0') == "Banana");
515
CHECK(s.remove_char('x') == "Banana");
516
}
517
518
TEST_CASE("[String] remove_chars") {
519
String s = "Banana";
520
CHECK(s.remove_chars("Ba") == "nn");
521
CHECK(s.remove_chars(String("Ba")) == "nn");
522
CHECK(s.remove_chars("") == "Banana");
523
CHECK(s.remove_chars(String()) == "Banana");
524
CHECK(s.remove_chars("xy") == "Banana");
525
CHECK(s.remove_chars(String("xy")) == "Banana");
526
}
527
528
TEST_CASE("[String] Number to string") {
529
CHECK(String::num(0) == "0.0"); // The method takes double, so always add zeros.
530
CHECK(String::num(0.0) == "0.0");
531
CHECK(String::num(-0.0) == "-0.0"); // Includes sign even for zero.
532
CHECK(String::num(3.141593) == "3.141593");
533
CHECK(String::num(3.141593, 3) == "3.142");
534
CHECK(String::num(42.100023, 4) == "42.1"); // No trailing zeros.
535
536
// String::num_int64 tests.
537
CHECK(String::num_int64(3141593) == "3141593");
538
CHECK(String::num_int64(-3141593) == "-3141593");
539
CHECK(String::num_int64(0xA141593, 16) == "a141593");
540
CHECK(String::num_int64(0xA141593, 16, true) == "A141593");
541
ERR_PRINT_OFF;
542
CHECK(String::num_int64(3141593, 1) == ""); // Invalid base < 2.
543
CHECK(String::num_int64(3141593, 37) == ""); // Invalid base > 36.
544
ERR_PRINT_ON;
545
546
// String::num_uint64 tests.
547
CHECK(String::num_uint64(4294967295) == "4294967295");
548
CHECK(String::num_uint64(0xF141593, 16) == "f141593");
549
CHECK(String::num_uint64(0xF141593, 16, true) == "F141593");
550
ERR_PRINT_OFF;
551
CHECK(String::num_uint64(4294967295, 1) == ""); // Invalid base < 2.
552
CHECK(String::num_uint64(4294967295, 37) == ""); // Invalid base > 36.
553
ERR_PRINT_ON;
554
555
// String::num_scientific tests.
556
CHECK(String::num_scientific(30000000.0) == "30000000");
557
CHECK(String::num_scientific(1234567890.0) == "1234567890");
558
CHECK(String::num_scientific(3e100) == "3e+100");
559
CHECK(String::num_scientific(7e-100) == "7e-100");
560
CHECK(String::num_scientific(Math::TAU) == "6.283185307179586");
561
CHECK(String::num_scientific(Math::INF) == "inf");
562
CHECK(String::num_scientific(-Math::INF) == "-inf");
563
CHECK(String::num_scientific(Math::NaN) == "nan");
564
CHECK(String::num_scientific(2.0) == "2");
565
CHECK(String::num_scientific(1.0) == "1");
566
CHECK(String::num_scientific(0.0) == "0");
567
CHECK(String::num_scientific(-0.0) == "-0");
568
569
// String::num_real tests.
570
CHECK(String::num_real(1.0) == "1.0");
571
CHECK(String::num_real(1.0, false) == "1");
572
CHECK(String::num_real(9.9) == "9.9");
573
CHECK(String::num_real(9.99) == "9.99");
574
CHECK(String::num_real(9.999) == "9.999");
575
CHECK(String::num_real(9.9999) == "9.9999");
576
CHECK(String::num_real(3.141593) == "3.141593");
577
CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros.
578
#ifdef REAL_T_IS_DOUBLE
579
CHECK_MESSAGE(String::num_real(real_t(123.456789)) == "123.456789", "Prints the appropriate amount of digits for real_t = double.");
580
CHECK_MESSAGE(String::num_real(real_t(-123.456789)) == "-123.456789", "Prints the appropriate amount of digits for real_t = double.");
581
CHECK_MESSAGE(String::num_real(real_t(Math::PI)) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double.");
582
CHECK_MESSAGE(String::num_real(real_t(3.1415f)) == "3.1414999961853", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double) and no trailing zero.");
583
#else
584
CHECK_MESSAGE(String::num_real(real_t(123.456789)) == "123.4568", "Prints the appropriate amount of digits for real_t = float.");
585
CHECK_MESSAGE(String::num_real(real_t(-123.456789)) == "-123.4568", "Prints the appropriate amount of digits for real_t = float.");
586
CHECK_MESSAGE(String::num_real(real_t(Math::PI)) == "3.141593", "Prints the appropriate amount of digits for real_t = float.");
587
CHECK_MESSAGE(String::num_real(real_t(3.1415f)) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float.");
588
#endif // REAL_T_IS_DOUBLE
589
590
// Checks doubles with many decimal places.
591
CHECK(String::num(0.0000012345432123454321, -1) == "0.00000123454321"); // -1 uses 14 as sane default.
592
CHECK(String::num(0.0000012345432123454321) == "0.00000123454321"); // -1 is the default value.
593
CHECK(String::num(-0.0000012345432123454321) == "-0.00000123454321");
594
CHECK(String::num(-10000.0000012345432123454321) == "-10000.0000012345");
595
CHECK(String::num(0.0000000000012345432123454321) == "0.00000000000123");
596
CHECK(String::num(0.0000000000012345432123454321, 3) == "0.0");
597
598
// Note: When relevant (remainder > 0.5), the last digit gets rounded up,
599
// which can also lead to not include a trailing zero, e.g. "...89" -> "...9".
600
CHECK(String::num(0.0000056789876567898765) == "0.00000567898766"); // Should round last digit.
601
CHECK(String::num(10000.000005678999999999) == "10000.000005679"); // We cut at ...789|99 which is rounded to ...79, so only 13 decimals.
602
CHECK(String::num(42.12999999, 6) == "42.13"); // Also happens with lower decimals count.
603
604
// 32 is MAX_DECIMALS. We can't reliably store that many so we can't compare against a string,
605
// but we can check that the string length is 34 (32 + 2 for "0.").
606
CHECK(String::num(0.00000123456789987654321123456789987654321, 32).length() == 34);
607
CHECK(String::num(0.00000123456789987654321123456789987654321, 42).length() == 34); // Should enforce MAX_DECIMALS.
608
CHECK(String::num(10000.00000123456789987654321123456789987654321, 42).length() == 38); // 32 decimals + "10000.".
609
}
610
611
TEST_CASE("[String] String to integer") {
612
static const char *nums[14] = { "1237461283", "- 22", "0", " - 1123412", "", "10_000_000", "-1_2_3_4", "10__000", " 1 2 34 ", "-0", "007", "--45", "---46", "-7-2" };
613
static const int num[14] = { 1237461283, -22, 0, -1123412, 0, 10000000, -1234, 10000, 1234, 0, 7, 45, -46, -72 };
614
615
for (int i = 0; i < 14; i++) {
616
CHECK(String(nums[i]).to_int() == num[i]);
617
}
618
CHECK(String("0b1011").to_int() == 1011); // Looks like a binary number, but to_int() handles this as a base-10 number, "b" is just ignored.
619
CHECK(String("0B1011").to_int() == 1011);
620
621
CHECK(String("0x1012").to_int() == 1012); // Looks like a hexadecimal number, but to_int() handles this as a base-10 number, "x" is just ignored.
622
CHECK(String("0X1012").to_int() == 1012);
623
624
ERR_PRINT_OFF
625
CHECK(String("999999999999999999999999999999999999999999999999999999999").to_int() == INT64_MAX); // Too large, largest possible is returned.
626
CHECK(String("-999999999999999999999999999999999999999999999999999999999").to_int() == INT64_MIN); // Too small, smallest possible is returned.
627
ERR_PRINT_ON
628
}
629
630
TEST_CASE("[String] Hex to integer") {
631
static const char *nums[13] = { "0xFFAE", "22", "0", "AADDAD", "0x7FFFFFFFFFFFFFFF", "-0xf", "", "000", "000f", "0xaA", "-ff", "-", "0XFFAE" };
632
static const int64_t num[13] = { 0xFFAE, 0x22, 0, 0xAADDAD, 0x7FFFFFFFFFFFFFFF, -0xf, 0, 0, 0xf, 0xaa, -0xff, 0x0, 0xFFAE };
633
634
for (int i = 0; i < 13; i++) {
635
CHECK(String(nums[i]).hex_to_int() == num[i]);
636
}
637
638
// Invalid hex strings should return 0.
639
static const char *invalid_nums[15] = { "qwerty", "QWERTY", "0xqwerty", "0x00qwerty", "qwerty00", "0x", "0x__", "__", "x12", "+", " ff", "ff ", "f f", "+ff", "--0x78" };
640
641
ERR_PRINT_OFF
642
for (int i = 0; i < 15; i++) {
643
CHECK(String(invalid_nums[i]).hex_to_int() == 0);
644
}
645
646
CHECK(String("0xFFFFFFFFFFFFFFFFFFFFFFF").hex_to_int() == INT64_MAX); // Too large, largest possible is returned.
647
CHECK(String("-0xFFFFFFFFFFFFFFFFFFFFFFF").hex_to_int() == INT64_MIN); // Too small, smallest possible is returned.
648
ERR_PRINT_ON
649
}
650
651
TEST_CASE("[String] Bin to integer") {
652
static const char *nums[11] = { "", "0", "0b0", "0b1", "0b", "1", "0b1010", "-0b11", "-1010", "0b0111111111111111111111111111111111111111111111111111111111111111", "0B1010" };
653
static const int64_t num[11] = { 0, 0, 0, 1, 0, 1, 10, -3, -10, 0x7FFFFFFFFFFFFFFF, 10 };
654
655
for (int i = 0; i < 11; i++) {
656
CHECK(String(nums[i]).bin_to_int() == num[i]);
657
}
658
659
// Invalid bin strings should return 0. The long "0x11...11" is just too long for a 64 bit int.
660
static const char *invalid_nums[16] = { "qwerty", "QWERTY", "0bqwerty", "0b00qwerty", "qwerty00", "0x__", "0b__", "__", "b12", "+", "-", "0x12ab", " 11", "11 ", "1 1", "--0b11" };
661
662
for (int i = 0; i < 16; i++) {
663
CHECK(String(invalid_nums[i]).bin_to_int() == 0);
664
}
665
666
ERR_PRINT_OFF
667
CHECK(String("0b111111111111111111111111111111111111111111111111111111111111111111111111111111111").bin_to_int() == INT64_MAX); // Too large, largest possible is returned.
668
CHECK(String("-0b111111111111111111111111111111111111111111111111111111111111111111111111111111111").bin_to_int() == INT64_MIN); // Too small, smallest possible is returned.
669
ERR_PRINT_ON
670
}
671
672
TEST_CASE("[String] String to float") {
673
static const char *nums[12] = { "-12348298412.2", "0.05", "2.0002", " -0.0001", "0", "000", "123", "0.0", "000.000", "000.007", "234__", "3..14" };
674
static const double num[12] = { -12348298412.2, 0.05, 2.0002, -0.0001, 0.0, 0.0, 123.0, 0.0, 0.0, 0.007, 234.0, 3.0 };
675
676
for (int i = 0; i < 12; i++) {
677
CHECK(!(Math::abs(String(nums[i]).to_float() - num[i]) > 0.00001));
678
}
679
680
// Invalid float strings should return 0.
681
static const char *invalid_nums[6] = { "qwerty", "qwerty123", "0xffff", "0b1010", "--3.13", "__345" };
682
683
for (int i = 0; i < 6; i++) {
684
CHECK(String(invalid_nums[i]).to_float() == 0);
685
}
686
687
// Very large exponents.
688
CHECK(String("1e308").to_float() == 1e308);
689
CHECK(String("-1e308").to_float() == -1e308);
690
691
// Exponent is so high that value is INFINITY/-INFINITY.
692
CHECK(String("1e309").to_float() == Math::INF);
693
CHECK(String("1e511").to_float() == Math::INF);
694
CHECK(String("-1e309").to_float() == -Math::INF);
695
CHECK(String("-1e511").to_float() == -Math::INF);
696
697
// Exponent is so high that a warning message is printed. Value is INFINITY/-INFINITY.
698
ERR_PRINT_OFF
699
CHECK(String("1e512").to_float() == Math::INF);
700
CHECK(String("-1e512").to_float() == -Math::INF);
701
ERR_PRINT_ON
702
}
703
704
TEST_CASE("[String] Slicing") {
705
String s = "Mars,Jupiter,Saturn,Uranus";
706
const char *slices[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
707
MULTICHECK_GET_SLICE(s, ",", slices);
708
}
709
710
TEST_CASE("[String] Begins with") {
711
// Test cases for true:
712
MULTICHECK_STRING_EQ(String("res://foobar"), begins_with, "res://", true);
713
MULTICHECK_STRING_EQ(String("abc"), begins_with, "abc", true);
714
MULTICHECK_STRING_EQ(String("abc"), begins_with, "", true);
715
MULTICHECK_STRING_EQ(String(""), begins_with, "", true);
716
717
// Test cases for false:
718
MULTICHECK_STRING_EQ(String("res"), begins_with, "res://", false);
719
MULTICHECK_STRING_EQ(String("abcdef"), begins_with, "foo", false);
720
MULTICHECK_STRING_EQ(String("abc"), begins_with, "ax", false);
721
MULTICHECK_STRING_EQ(String(""), begins_with, "abc", false);
722
723
// Test "const char *" version also with nullptr.
724
String s("foo");
725
bool state = s.begins_with(nullptr) == false;
726
CHECK_MESSAGE(state, "nullptr check failed");
727
728
String empty("");
729
state = empty.begins_with(nullptr) == false;
730
CHECK_MESSAGE(state, "nullptr check with empty string failed");
731
}
732
733
TEST_CASE("[String] Ends with") {
734
// Test cases for true:
735
MULTICHECK_STRING_EQ(String("res://foobar"), ends_with, "foobar", true);
736
MULTICHECK_STRING_EQ(String("abc"), ends_with, "abc", true);
737
MULTICHECK_STRING_EQ(String("abc"), ends_with, "", true);
738
MULTICHECK_STRING_EQ(String(""), ends_with, "", true);
739
740
// Test cases for false:
741
MULTICHECK_STRING_EQ(String("res"), ends_with, "res://", false);
742
MULTICHECK_STRING_EQ(String("abcdef"), ends_with, "foo", false);
743
MULTICHECK_STRING_EQ(String("abc"), ends_with, "ax", false);
744
MULTICHECK_STRING_EQ(String(""), ends_with, "abc", false);
745
746
// Test "const char *" version also with nullptr.
747
String s("foo");
748
bool state = s.ends_with(nullptr) == false;
749
CHECK_MESSAGE(state, "nullptr check failed");
750
751
String empty("");
752
state = empty.ends_with(nullptr) == false;
753
CHECK_MESSAGE(state, "nullptr check with empty string failed");
754
}
755
756
TEST_CASE("[String] Splitting") {
757
{
758
const String s = "Mars,Jupiter,Saturn,Uranus";
759
760
const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
761
MULTICHECK_SPLIT(s, split, ",", true, 2, slices_l, 3);
762
763
const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
764
MULTICHECK_SPLIT(s, rsplit, ",", true, 2, slices_r, 3);
765
}
766
767
{
768
const String s = "test";
769
const char *slices[4] = { "t", "e", "s", "t" };
770
MULTICHECK_SPLIT(s, split, "", true, 0, slices, 4);
771
}
772
773
{
774
const String s = "";
775
const char *slices[1] = { "" };
776
MULTICHECK_SPLIT(s, split, "", true, 0, slices, 1);
777
MULTICHECK_SPLIT(s, split, "", false, 0, slices, 0);
778
}
779
780
{
781
const String s = "Mars Jupiter Saturn Uranus";
782
const char *slices[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
783
Vector<String> l = s.split_spaces();
784
for (int i = 0; i < l.size(); i++) {
785
CHECK(l[i] == slices[i]);
786
}
787
}
788
{
789
const String s = "Mars Jupiter Saturn Uranus";
790
const char *slices[2] = { "Mars", "Jupiter Saturn Uranus" };
791
Vector<String> l = s.split_spaces(1);
792
for (int i = 0; i < l.size(); i++) {
793
CHECK(l[i] == slices[i]);
794
}
795
}
796
797
{
798
const String s = "1.2;2.3 4.5";
799
const double slices[3] = { 1.2, 2.3, 4.5 };
800
801
const Vector<double> d_arr = s.split_floats(";");
802
CHECK(d_arr.size() == 2);
803
for (int i = 0; i < d_arr.size(); i++) {
804
CHECK(Math::abs(d_arr[i] - slices[i]) <= 0.00001);
805
}
806
807
const Vector<String> keys = { ";", " " };
808
const Vector<float> f_arr = s.split_floats_mk(keys);
809
CHECK(f_arr.size() == 3);
810
for (int i = 0; i < f_arr.size(); i++) {
811
CHECK(Math::abs(f_arr[i] - slices[i]) <= 0.00001);
812
}
813
}
814
815
{
816
const String s = " -2.0 5";
817
const double slices[10] = { 0, -2, 0, 0, 0, 0, 0, 0, 0, 5 };
818
819
const Vector<double> arr = s.split_floats(" ");
820
CHECK(arr.size() == 10);
821
for (int i = 0; i < arr.size(); i++) {
822
CHECK(Math::abs(arr[i] - slices[i]) <= 0.00001);
823
}
824
825
const Vector<String> keys = { ";", " " };
826
const Vector<float> mk = s.split_floats_mk(keys);
827
CHECK(mk.size() == 10);
828
for (int i = 0; i < mk.size(); i++) {
829
CHECK(mk[i] == slices[i]);
830
}
831
}
832
833
{
834
const String s = "1;2 4";
835
const int slices[3] = { 1, 2, 4 };
836
837
const Vector<int> arr = s.split_ints(";");
838
CHECK(arr.size() == 2);
839
for (int i = 0; i < arr.size(); i++) {
840
CHECK(arr[i] == slices[i]);
841
}
842
843
const Vector<String> keys = { ";", " " };
844
const Vector<int> mk = s.split_ints_mk(keys);
845
CHECK(mk.size() == 3);
846
for (int i = 0; i < mk.size(); i++) {
847
CHECK(mk[i] == slices[i]);
848
}
849
}
850
}
851
852
TEST_CASE("[String] format") {
853
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
854
855
Dictionary value_dictionary;
856
value_dictionary["red"] = 10;
857
value_dictionary["green"] = 20;
858
value_dictionary["blue"] = "bla";
859
value_dictionary["alpha"] = 0.4;
860
String value = value_format.format(value_dictionary, "$_");
861
862
CHECK(value == "red=\"10\" green=\"20\" blue=\"bla\" alpha=\"0.4\"");
863
}
864
865
TEST_CASE("[String] sprintf") {
866
String format, output;
867
Array args;
868
bool error;
869
870
// %%
871
format = "fish %% frog";
872
args.clear();
873
output = format.sprintf(args, &error);
874
REQUIRE(error == false);
875
CHECK(output == String("fish % frog"));
876
///// Ints
877
878
// Int
879
format = "fish %d frog";
880
args.clear();
881
args.push_back(5);
882
output = format.sprintf(args, &error);
883
REQUIRE(error == false);
884
CHECK(output == String("fish 5 frog"));
885
886
// Int left padded with zeroes.
887
format = "fish %05d frog";
888
args.clear();
889
args.push_back(5);
890
output = format.sprintf(args, &error);
891
REQUIRE(error == false);
892
CHECK(output == String("fish 00005 frog"));
893
894
// Int left padded with spaces.
895
format = "fish %5d frog";
896
args.clear();
897
args.push_back(5);
898
output = format.sprintf(args, &error);
899
REQUIRE(error == false);
900
CHECK(output == String("fish 5 frog"));
901
902
// Int right padded with spaces.
903
format = "fish %-5d frog";
904
args.clear();
905
args.push_back(5);
906
output = format.sprintf(args, &error);
907
REQUIRE(error == false);
908
CHECK(output == String("fish 5 frog"));
909
910
// Int with sign (positive).
911
format = "fish %+d frog";
912
args.clear();
913
args.push_back(5);
914
output = format.sprintf(args, &error);
915
REQUIRE(error == false);
916
CHECK(output == String("fish +5 frog"));
917
918
// Negative int.
919
format = "fish %d frog";
920
args.clear();
921
args.push_back(-5);
922
output = format.sprintf(args, &error);
923
REQUIRE(error == false);
924
CHECK(output == String("fish -5 frog"));
925
926
// Negative int left padded with spaces.
927
format = "fish %5d frog";
928
args.clear();
929
args.push_back(-5);
930
output = format.sprintf(args, &error);
931
REQUIRE(error == false);
932
CHECK(output == String("fish -5 frog"));
933
934
// Negative int left padded with zeros.
935
format = "fish %05d frog";
936
args.clear();
937
args.push_back(-5);
938
output = format.sprintf(args, &error);
939
REQUIRE(error == false);
940
CHECK(output == String("fish -0005 frog"));
941
942
// Negative int right padded with spaces.
943
format = "fish %-5d frog";
944
args.clear();
945
args.push_back(-5);
946
output = format.sprintf(args, &error);
947
REQUIRE(error == false);
948
CHECK(output == String("fish -5 frog"));
949
950
// Negative int right padded with zeros. (0 ignored)
951
format = "fish %-05d frog";
952
args.clear();
953
args.push_back(-5);
954
ERR_PRINT_OFF; // Silence warning about 0 ignored.
955
output = format.sprintf(args, &error);
956
ERR_PRINT_ON;
957
REQUIRE(error == false);
958
CHECK(output == String("fish -5 frog"));
959
960
// Hex (lower)
961
format = "fish %x frog";
962
args.clear();
963
args.push_back(45);
964
output = format.sprintf(args, &error);
965
REQUIRE(error == false);
966
CHECK(output == String("fish 2d frog"));
967
968
// Hex (upper)
969
format = "fish %X frog";
970
args.clear();
971
args.push_back(45);
972
output = format.sprintf(args, &error);
973
REQUIRE(error == false);
974
CHECK(output == String("fish 2D frog"));
975
976
// Octal
977
format = "fish %o frog";
978
args.clear();
979
args.push_back(99);
980
output = format.sprintf(args, &error);
981
REQUIRE(error == false);
982
CHECK(output == String("fish 143 frog"));
983
984
///// Reals
985
986
// Real
987
format = "fish %f frog";
988
args.clear();
989
args.push_back(99.99);
990
output = format.sprintf(args, &error);
991
REQUIRE(error == false);
992
CHECK(output == String("fish 99.990000 frog"));
993
994
// Real left-padded.
995
format = "fish %11f frog";
996
args.clear();
997
args.push_back(99.99);
998
output = format.sprintf(args, &error);
999
REQUIRE(error == false);
1000
CHECK(output == String("fish 99.990000 frog"));
1001
1002
// Real (infinity) left-padded
1003
format = "fish %11f frog";
1004
args.clear();
1005
args.push_back(Math::INF);
1006
output = format.sprintf(args, &error);
1007
REQUIRE(error == false);
1008
CHECK(output == String("fish inf frog"));
1009
1010
// Real right-padded.
1011
format = "fish %-11f frog";
1012
args.clear();
1013
args.push_back(99.99);
1014
output = format.sprintf(args, &error);
1015
REQUIRE(error == false);
1016
CHECK(output == String("fish 99.990000 frog"));
1017
1018
// Real given int.
1019
format = "fish %f frog";
1020
args.clear();
1021
args.push_back(99);
1022
output = format.sprintf(args, &error);
1023
REQUIRE(error == false);
1024
CHECK(output == String("fish 99.000000 frog"));
1025
1026
// Real with sign (positive).
1027
format = "fish %+f frog";
1028
args.clear();
1029
args.push_back(99.99);
1030
output = format.sprintf(args, &error);
1031
REQUIRE(error == false);
1032
CHECK(output == String("fish +99.990000 frog"));
1033
1034
// Real with sign (negative zero).
1035
format = "fish %+f frog";
1036
args.clear();
1037
args.push_back(-0.0);
1038
output = format.sprintf(args, &error);
1039
REQUIRE(error == false);
1040
CHECK(output == String("fish -0.000000 frog"));
1041
1042
// Real with sign (positive zero).
1043
format = "fish %+f frog";
1044
args.clear();
1045
args.push_back(0.0);
1046
output = format.sprintf(args, &error);
1047
REQUIRE(error == false);
1048
CHECK(output == String("fish +0.000000 frog"));
1049
1050
// Real with 1 decimal.
1051
format = "fish %.1f frog";
1052
args.clear();
1053
args.push_back(99.99);
1054
output = format.sprintf(args, &error);
1055
REQUIRE(error == false);
1056
CHECK(output == String("fish 100.0 frog"));
1057
1058
// Real with 12 decimals.
1059
format = "fish %.12f frog";
1060
args.clear();
1061
args.push_back(99.99);
1062
output = format.sprintf(args, &error);
1063
REQUIRE(error == false);
1064
CHECK(output == String("fish 99.990000000000 frog"));
1065
1066
// Real with no decimals.
1067
format = "fish %.f frog";
1068
args.clear();
1069
args.push_back(99.99);
1070
output = format.sprintf(args, &error);
1071
REQUIRE(error == false);
1072
CHECK(output == String("fish 100 frog"));
1073
1074
// Negative real right padded with zeros. (0 ignored)
1075
format = "fish %-011f frog";
1076
args.clear();
1077
args.push_back(-99.99);
1078
ERR_PRINT_OFF; // Silence warning about 0 ignored.
1079
output = format.sprintf(args, &error);
1080
ERR_PRINT_ON;
1081
REQUIRE(error == false);
1082
CHECK(output == String("fish -99.990000 frog"));
1083
1084
///// Vectors
1085
1086
// Vector2
1087
format = "fish %v frog";
1088
args.clear();
1089
args.push_back(Variant(Vector2(19.99, 1.00)));
1090
output = format.sprintf(args, &error);
1091
REQUIRE(error == false);
1092
CHECK(output == String("fish (19.990000, 1.000000) frog"));
1093
1094
// Vector3
1095
format = "fish %v frog";
1096
args.clear();
1097
args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
1098
output = format.sprintf(args, &error);
1099
REQUIRE(error == false);
1100
CHECK(output == String("fish (19.990000, 1.000000, -2.050000) frog"));
1101
1102
// Vector4
1103
format = "fish %v frog";
1104
args.clear();
1105
args.push_back(Variant(Vector4(19.99, 1.00, -2.05, 5.5)));
1106
output = format.sprintf(args, &error);
1107
REQUIRE(error == false);
1108
CHECK(output == String("fish (19.990000, 1.000000, -2.050000, 5.500000) frog"));
1109
1110
// Vector with negative values.
1111
format = "fish %v frog";
1112
args.clear();
1113
args.push_back(Variant(Vector2(-19.99, -1.00)));
1114
output = format.sprintf(args, &error);
1115
REQUIRE(error == false);
1116
CHECK(output == String("fish (-19.990000, -1.000000) frog"));
1117
1118
// Vector left-padded.
1119
format = "fish %11v frog";
1120
args.clear();
1121
args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
1122
output = format.sprintf(args, &error);
1123
REQUIRE(error == false);
1124
CHECK(output == String("fish ( 19.990000, 1.000000, -2.050000) frog"));
1125
1126
// Vector left-padded with inf/nan
1127
format = "fish %11v frog";
1128
args.clear();
1129
args.push_back(Variant(Vector2(Math::INF, Math::NaN)));
1130
output = format.sprintf(args, &error);
1131
REQUIRE(error == false);
1132
CHECK(output == String("fish ( inf, nan) frog"));
1133
1134
// Vector right-padded.
1135
format = "fish %-11v frog";
1136
args.clear();
1137
args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
1138
output = format.sprintf(args, &error);
1139
REQUIRE(error == false);
1140
CHECK(output == String("fish (19.990000 , 1.000000 , -2.050000 ) frog"));
1141
1142
// Vector left-padded with zeros.
1143
format = "fish %011v frog";
1144
args.clear();
1145
args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
1146
output = format.sprintf(args, &error);
1147
REQUIRE(error == false);
1148
CHECK(output == String("fish (0019.990000, 0001.000000, -002.050000) frog"));
1149
1150
// Vector given Vector3i.
1151
format = "fish %v frog";
1152
args.clear();
1153
args.push_back(Variant(Vector3i(19, 1, -2)));
1154
output = format.sprintf(args, &error);
1155
REQUIRE(error == false);
1156
CHECK(output == String("fish (19.000000, 1.000000, -2.000000) frog"));
1157
1158
// Vector with 1 decimal.
1159
format = "fish %.1v frog";
1160
args.clear();
1161
args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
1162
output = format.sprintf(args, &error);
1163
REQUIRE(error == false);
1164
CHECK(output == String("fish (20.0, 1.0, -2.0) frog"));
1165
1166
// Vector with 12 decimals.
1167
format = "fish %.12v frog";
1168
args.clear();
1169
args.push_back(Variant(Vector3(19.00, 1.00, -2.00)));
1170
output = format.sprintf(args, &error);
1171
REQUIRE(error == false);
1172
CHECK(output == String("fish (19.000000000000, 1.000000000000, -2.000000000000) frog"));
1173
1174
// Vector with no decimals.
1175
format = "fish %.v frog";
1176
args.clear();
1177
args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
1178
output = format.sprintf(args, &error);
1179
REQUIRE(error == false);
1180
CHECK(output == String("fish (20, 1, -2) frog"));
1181
1182
///// Strings
1183
1184
// String
1185
format = "fish %s frog";
1186
args.clear();
1187
args.push_back("cheese");
1188
output = format.sprintf(args, &error);
1189
REQUIRE(error == false);
1190
CHECK(output == String("fish cheese frog"));
1191
1192
// String left-padded.
1193
format = "fish %10s frog";
1194
args.clear();
1195
args.push_back("cheese");
1196
output = format.sprintf(args, &error);
1197
REQUIRE(error == false);
1198
CHECK(output == String("fish cheese frog"));
1199
1200
// String right-padded.
1201
format = "fish %-10s frog";
1202
args.clear();
1203
args.push_back("cheese");
1204
output = format.sprintf(args, &error);
1205
REQUIRE(error == false);
1206
CHECK(output == String("fish cheese frog"));
1207
1208
///// Characters
1209
1210
// Character as string.
1211
format = "fish %c frog";
1212
args.clear();
1213
args.push_back("A");
1214
output = format.sprintf(args, &error);
1215
REQUIRE(error == false);
1216
CHECK(output == String("fish A frog"));
1217
1218
// Character as int.
1219
format = "fish %c frog";
1220
args.clear();
1221
args.push_back(65);
1222
output = format.sprintf(args, &error);
1223
REQUIRE(error == false);
1224
CHECK(output == String("fish A frog"));
1225
1226
///// Dynamic width
1227
1228
// String dynamic width.
1229
format = "fish %*s frog";
1230
args.clear();
1231
args.push_back(10);
1232
args.push_back("cheese");
1233
output = format.sprintf(args, &error);
1234
REQUIRE(error == false);
1235
REQUIRE(output == String("fish cheese frog"));
1236
1237
// Int dynamic width.
1238
format = "fish %*d frog";
1239
args.clear();
1240
args.push_back(10);
1241
args.push_back(99);
1242
output = format.sprintf(args, &error);
1243
REQUIRE(error == false);
1244
REQUIRE(output == String("fish 99 frog"));
1245
1246
// Float dynamic width.
1247
format = "fish %*.*f frog";
1248
args.clear();
1249
args.push_back(10);
1250
args.push_back(3);
1251
args.push_back(99.99);
1252
output = format.sprintf(args, &error);
1253
REQUIRE(error == false);
1254
CHECK(output == String("fish 99.990 frog"));
1255
1256
///// Errors
1257
1258
// More formats than arguments.
1259
format = "fish %s %s frog";
1260
args.clear();
1261
args.push_back("cheese");
1262
output = format.sprintf(args, &error);
1263
REQUIRE(error);
1264
CHECK(output == "not enough arguments for format string");
1265
1266
// More arguments than formats.
1267
format = "fish %s frog";
1268
args.clear();
1269
args.push_back("hello");
1270
args.push_back("cheese");
1271
output = format.sprintf(args, &error);
1272
REQUIRE(error);
1273
CHECK(output == "not all arguments converted during string formatting");
1274
1275
// Incomplete format.
1276
format = "fish %10";
1277
args.clear();
1278
args.push_back("cheese");
1279
output = format.sprintf(args, &error);
1280
REQUIRE(error);
1281
CHECK(output == "incomplete format");
1282
1283
// Bad character in format string.
1284
format = "fish %&f frog";
1285
args.clear();
1286
args.push_back("cheese");
1287
output = format.sprintf(args, &error);
1288
REQUIRE(error);
1289
CHECK(output == "unsupported format character");
1290
1291
// Too many decimals.
1292
format = "fish %2.2.2f frog";
1293
args.clear();
1294
args.push_back(99.99);
1295
output = format.sprintf(args, &error);
1296
REQUIRE(error);
1297
CHECK(output == "too many decimal points in format");
1298
1299
// * not a number or vector.
1300
format = "fish %*f frog";
1301
args.clear();
1302
args.push_back("cheese");
1303
args.push_back(99.99);
1304
output = format.sprintf(args, &error);
1305
REQUIRE(error);
1306
CHECK(output == "* wants number or vector");
1307
1308
// Character too long.
1309
format = "fish %c frog";
1310
args.clear();
1311
args.push_back("sc");
1312
output = format.sprintf(args, &error);
1313
REQUIRE(error);
1314
CHECK(output == "%c requires number or single-character string");
1315
1316
// Character bad type.
1317
format = "fish %c frog";
1318
args.clear();
1319
args.push_back(Array());
1320
output = format.sprintf(args, &error);
1321
REQUIRE(error);
1322
CHECK(output == "%c requires number or single-character string");
1323
}
1324
1325
TEST_CASE("[String] is_numeric") {
1326
CHECK(String("12").is_numeric());
1327
CHECK(String("1.2").is_numeric());
1328
CHECK(!String("AF").is_numeric());
1329
CHECK(String("-12").is_numeric());
1330
CHECK(String("-1.2").is_numeric());
1331
}
1332
1333
TEST_CASE("[String] pad") {
1334
String s = String("test");
1335
CHECK(s.lpad(10, "x") == U"xxxxxxtest");
1336
CHECK(s.rpad(10, "x") == U"testxxxxxx");
1337
1338
s = String("10.10");
1339
CHECK(s.pad_decimals(4) == U"10.1000");
1340
CHECK(s.pad_decimals(1) == U"10.1");
1341
CHECK(s.pad_zeros(4) == U"0010.10");
1342
CHECK(s.pad_zeros(1) == U"10.10");
1343
}
1344
1345
TEST_CASE("[String] is_subsequence_of") {
1346
String a = "is subsequence of";
1347
CHECK(String("sub").is_subsequence_of(a));
1348
CHECK(!String("Sub").is_subsequence_of(a));
1349
CHECK(String("Sub").is_subsequence_ofn(a));
1350
}
1351
1352
TEST_CASE("[String] is_lowercase") {
1353
CHECK(String("abcd1234 !@#$%^&*()_-=+,.<>/\\|[]{};':\"`~").is_lowercase());
1354
CHECK(String("").is_lowercase());
1355
CHECK(!String("abc_ABC").is_lowercase());
1356
}
1357
1358
TEST_CASE("[String] match") {
1359
CHECK(String("img1.png").match("*.png"));
1360
CHECK(!String("img1.jpeg").match("*.png"));
1361
CHECK(!String("img1.Png").match("*.png"));
1362
CHECK(String("img1.Png").matchn("*.png"));
1363
}
1364
1365
TEST_CASE("[String] IPVX address to string") {
1366
IPAddress ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
1367
IPAddress ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
1368
IPAddress ip2("fe80::52e5:49ff:fe93:1baf");
1369
IPAddress ip3("::ffff:192.168.0.1");
1370
String ip4 = "192.168.0.1";
1371
CHECK(ip4.is_valid_ip_address());
1372
1373
ip4 = "192.368.0.1";
1374
CHECK(!ip4.is_valid_ip_address());
1375
1376
String ip6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
1377
CHECK(ip6.is_valid_ip_address());
1378
1379
ip6 = "2001:0db8:85j3:0000:0000:8a2e:0370:7334";
1380
CHECK(!ip6.is_valid_ip_address());
1381
1382
ip6 = "2001:0db8:85f345:0000:0000:8a2e:0370:7334";
1383
CHECK(!ip6.is_valid_ip_address());
1384
1385
ip6 = "2001:0db8::0:8a2e:370:7334";
1386
CHECK(ip6.is_valid_ip_address());
1387
1388
ip6 = "::ffff:192.168.0.1";
1389
CHECK(ip6.is_valid_ip_address());
1390
}
1391
1392
TEST_CASE("[String] Capitalize against many strings") {
1393
String input = "2D";
1394
String output = "2d";
1395
CHECK(input.capitalize() == output);
1396
1397
input = "2d";
1398
output = "2d";
1399
CHECK(input.capitalize() == output);
1400
1401
input = "2db";
1402
output = "2 Db";
1403
CHECK(input.capitalize() == output);
1404
1405
input = "HTML5 Html5 html5 html_5";
1406
output = "Html 5 Html 5 Html 5 Html 5";
1407
CHECK(input.capitalize() == output);
1408
1409
input = "Node2D Node2d NODE2D NODE_2D node_2d";
1410
output = "Node 2d Node 2d Node 2d Node 2d Node 2d";
1411
CHECK(input.capitalize() == output);
1412
1413
input = "Node2DPosition";
1414
output = "Node 2d Position";
1415
CHECK(input.capitalize() == output);
1416
1417
input = "Number2Digits";
1418
output = "Number 2 Digits";
1419
CHECK(input.capitalize() == output);
1420
1421
input = "bytes2var";
1422
output = "Bytes 2 Var";
1423
CHECK(input.capitalize() == output);
1424
1425
input = "linear2db";
1426
output = "Linear 2 Db";
1427
CHECK(input.capitalize() == output);
1428
1429
input = "vector3";
1430
output = "Vector 3";
1431
CHECK(input.capitalize() == output);
1432
1433
input = "sha256";
1434
output = "Sha 256";
1435
CHECK(input.capitalize() == output);
1436
1437
input = "PascalCase";
1438
output = "Pascal Case";
1439
CHECK(input.capitalize() == output);
1440
1441
input = "PascalPascalCase";
1442
output = "Pascal Pascal Case";
1443
CHECK(input.capitalize() == output);
1444
1445
input = "snake_case";
1446
output = "Snake Case";
1447
CHECK(input.capitalize() == output);
1448
1449
input = "snake_snake_case";
1450
output = "Snake Snake Case";
1451
CHECK(input.capitalize() == output);
1452
1453
input = "kebab-case";
1454
output = "Kebab Case";
1455
CHECK(input.capitalize() == output);
1456
1457
input = "kebab-kebab-case";
1458
output = "Kebab Kebab Case";
1459
CHECK(input.capitalize() == output);
1460
1461
input = "sha256sum";
1462
output = "Sha 256 Sum";
1463
CHECK(input.capitalize() == output);
1464
1465
input = "cat2dog";
1466
output = "Cat 2 Dog";
1467
CHECK(input.capitalize() == output);
1468
1469
input = "function(name)";
1470
output = "Function(name)";
1471
CHECK(input.capitalize() == output);
1472
1473
input = "snake_case_function(snake_case_arg)";
1474
output = "Snake Case Function(snake Case Arg)";
1475
CHECK(input.capitalize() == output);
1476
1477
input = "snake_case_function( snake_case_arg )";
1478
output = "Snake Case Function( Snake Case Arg )";
1479
CHECK(input.capitalize() == output);
1480
1481
input = "kebab-case-function( kebab-case-arg )";
1482
output = "Kebab Case Function( Kebab Case Arg )";
1483
CHECK(input.capitalize() == output);
1484
1485
input = "kebab_case_function( kebab_case_arg )";
1486
output = "Kebab Case Function( Kebab Case Arg )";
1487
CHECK(input.capitalize() == output);
1488
1489
input = U"словоСлово_слово слово";
1490
output = U"Слово Слово Слово Слово";
1491
CHECK(input.capitalize() == output);
1492
1493
input = U"λέξηΛέξη_λέξη λέξη";
1494
output = U"Λέξη Λέξη Λέξη Λέξη";
1495
CHECK(input.capitalize() == output);
1496
1497
input = U"բառԲառ_բառ բառ";
1498
output = U"Բառ Բառ Բառ Բառ";
1499
CHECK(input.capitalize() == output);
1500
}
1501
1502
struct StringCasesTestCase {
1503
const char32_t *input;
1504
const char32_t *camel_case;
1505
const char32_t *pascal_case;
1506
const char32_t *snake_case;
1507
const char32_t *kebab_case;
1508
};
1509
1510
TEST_CASE("[String] Checking case conversion methods") {
1511
StringCasesTestCase test_cases[] = {
1512
/* clang-format off */
1513
{ U"2D", U"2d", U"2d", U"2d", U"2d" },
1514
{ U"2d", U"2d", U"2d", U"2d", U"2d" },
1515
{ U"2db", U"2Db", U"2Db", U"2_db", U"2-db" },
1516
{ U"Vector3", U"vector3", U"Vector3", U"vector_3", U"vector-3" },
1517
{ U"sha256", U"sha256", U"Sha256", U"sha_256", U"sha-256" },
1518
{ U"Node2D", U"node2d", U"Node2d", U"node_2d", U"node-2d" },
1519
{ U"RichTextLabel", U"richTextLabel", U"RichTextLabel", U"rich_text_label", U"rich-text-label" },
1520
{ U"HTML5", U"html5", U"Html5", U"html_5", U"html-5" },
1521
{ U"Node2DPosition", U"node2dPosition", U"Node2dPosition", U"node_2d_position", U"node-2d-position" },
1522
{ U"Number2Digits", U"number2Digits", U"Number2Digits", U"number_2_digits", U"number-2-digits" },
1523
{ U"get_property_list", U"getPropertyList", U"GetPropertyList", U"get_property_list", U"get-property-list" },
1524
{ U"get_camera_2d", U"getCamera2d", U"GetCamera2d", U"get_camera_2d", U"get-camera-2d" },
1525
{ U"_physics_process", U"physicsProcess", U"PhysicsProcess", U"_physics_process", U"-physics-process" },
1526
{ U"bytes2var", U"bytes2Var", U"Bytes2Var", U"bytes_2_var", U"bytes-2-var" },
1527
{ U"linear2db", U"linear2Db", U"Linear2Db", U"linear_2_db", U"linear-2-db" },
1528
{ U"sha256sum", U"sha256Sum", U"Sha256Sum", U"sha_256_sum", U"sha-256-sum" },
1529
{ U"camelCase", U"camelCase", U"CamelCase", U"camel_case", U"camel-case" },
1530
{ U"PascalCase", U"pascalCase", U"PascalCase", U"pascal_case", U"pascal-case" },
1531
{ U"snake_case", U"snakeCase", U"SnakeCase", U"snake_case", U"snake-case" },
1532
{ U"kebab-case", U"kebabCase", U"KebabCase", U"kebab_case", U"kebab-case" },
1533
{ U"Test TEST test", U"testTestTest", U"TestTestTest", U"test_test_test", U"test-test-test" },
1534
{ U"словоСлово_слово слово", U"словоСловоСловоСлово", U"СловоСловоСловоСлово", U"слово_слово_слово_слово", U"слово-слово-слово-слово" },
1535
{ U"λέξηΛέξη_λέξη λέξη", U"λέξηΛέξηΛέξηΛέξη", U"ΛέξηΛέξηΛέξηΛέξη", U"λέξη_λέξη_λέξη_λέξη", U"λέξη-λέξη-λέξη-λέξη" },
1536
{ U"բառԲառ_բառ բառ", U"բառԲառԲառԲառ", U"ԲառԲառԲառԲառ", U"բառ_բառ_բառ_բառ", U"բառ-բառ-բառ-բառ" },
1537
{ nullptr, nullptr, nullptr, nullptr, nullptr },
1538
/* clang-format on */
1539
};
1540
1541
int idx = 0;
1542
while (test_cases[idx].input != nullptr) {
1543
String input = test_cases[idx].input;
1544
CHECK(input.to_camel_case() == test_cases[idx].camel_case);
1545
CHECK(input.to_pascal_case() == test_cases[idx].pascal_case);
1546
CHECK(input.to_snake_case() == test_cases[idx].snake_case);
1547
CHECK(input.to_kebab_case() == test_cases[idx].kebab_case);
1548
idx++;
1549
}
1550
}
1551
1552
TEST_CASE("[String] Checking string is empty when it should be") {
1553
bool state = true;
1554
bool success;
1555
1556
String a = "";
1557
success = a[0] == 0;
1558
if (!success) {
1559
state = false;
1560
}
1561
String b = "Godot";
1562
success = b[b.size()] == 0;
1563
if (!success) {
1564
state = false;
1565
}
1566
const String c = "";
1567
success = c[0] == 0;
1568
if (!success) {
1569
state = false;
1570
}
1571
1572
const String d = "Godot";
1573
success = d[d.size()] == 0;
1574
if (!success) {
1575
state = false;
1576
}
1577
1578
CHECK(state);
1579
}
1580
1581
TEST_CASE("[String] lstrip and rstrip") {
1582
#define STRIP_TEST(x) \
1583
{ \
1584
bool success = x; \
1585
state = state && success; \
1586
}
1587
1588
bool state = true;
1589
1590
// strip none
1591
STRIP_TEST(String("abc").lstrip("") == "abc");
1592
STRIP_TEST(String("abc").rstrip("") == "abc");
1593
// strip one
1594
STRIP_TEST(String("abc").lstrip("a") == "bc");
1595
STRIP_TEST(String("abc").rstrip("c") == "ab");
1596
// strip lots
1597
STRIP_TEST(String("bababbababccc").lstrip("ab") == "ccc");
1598
STRIP_TEST(String("aaabcbcbcbbcbbc").rstrip("cb") == "aaa");
1599
// strip empty string
1600
STRIP_TEST(String("").lstrip("") == "");
1601
STRIP_TEST(String("").rstrip("") == "");
1602
// strip to empty string
1603
STRIP_TEST(String("abcabcabc").lstrip("bca") == "");
1604
STRIP_TEST(String("abcabcabc").rstrip("bca") == "");
1605
// don't strip wrong end
1606
STRIP_TEST(String("abc").lstrip("c") == "abc");
1607
STRIP_TEST(String("abca").lstrip("a") == "bca");
1608
STRIP_TEST(String("abc").rstrip("a") == "abc");
1609
STRIP_TEST(String("abca").rstrip("a") == "abc");
1610
// in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
1611
// and the same second as "ÿ" (\u00ff)
1612
STRIP_TEST(String::utf8("¿").lstrip(String::utf8("µÿ")) == String::utf8("¿"));
1613
STRIP_TEST(String::utf8("¿").rstrip(String::utf8("µÿ")) == String::utf8("¿"));
1614
STRIP_TEST(String::utf8("µ¿ÿ").lstrip(String::utf8("µÿ")) == String::utf8("¿ÿ"));
1615
STRIP_TEST(String::utf8("µ¿ÿ").rstrip(String::utf8("µÿ")) == String::utf8("µ¿"));
1616
1617
// the above tests repeated with additional superfluous strip chars
1618
1619
// strip none
1620
STRIP_TEST(String("abc").lstrip("qwjkl") == "abc");
1621
STRIP_TEST(String("abc").rstrip("qwjkl") == "abc");
1622
// strip one
1623
STRIP_TEST(String("abc").lstrip("qwajkl") == "bc");
1624
STRIP_TEST(String("abc").rstrip("qwcjkl") == "ab");
1625
// strip lots
1626
STRIP_TEST(String("bababbababccc").lstrip("qwabjkl") == "ccc");
1627
STRIP_TEST(String("aaabcbcbcbbcbbc").rstrip("qwcbjkl") == "aaa");
1628
// strip empty string
1629
STRIP_TEST(String("").lstrip("qwjkl") == "");
1630
STRIP_TEST(String("").rstrip("qwjkl") == "");
1631
// strip to empty string
1632
STRIP_TEST(String("abcabcabc").lstrip("qwbcajkl") == "");
1633
STRIP_TEST(String("abcabcabc").rstrip("qwbcajkl") == "");
1634
// don't strip wrong end
1635
STRIP_TEST(String("abc").lstrip("qwcjkl") == "abc");
1636
STRIP_TEST(String("abca").lstrip("qwajkl") == "bca");
1637
STRIP_TEST(String("abc").rstrip("qwajkl") == "abc");
1638
STRIP_TEST(String("abca").rstrip("qwajkl") == "abc");
1639
// in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
1640
// and the same second as "ÿ" (\u00ff)
1641
STRIP_TEST(String::utf8("¿").lstrip(String::utf8("qwaµÿjkl")) == String::utf8("¿"));
1642
STRIP_TEST(String::utf8("¿").rstrip(String::utf8("qwaµÿjkl")) == String::utf8("¿"));
1643
STRIP_TEST(String::utf8("µ¿ÿ").lstrip(String::utf8("qwaµÿjkl")) == String::utf8("¿ÿ"));
1644
STRIP_TEST(String::utf8("µ¿ÿ").rstrip(String::utf8("qwaµÿjkl")) == String::utf8("µ¿"));
1645
1646
CHECK(state);
1647
1648
#undef STRIP_TEST
1649
}
1650
1651
TEST_CASE("[String] Ensuring empty string into extend_utf8 passes empty string") {
1652
String empty;
1653
CHECK(empty.append_utf8(nullptr, -1) == ERR_INVALID_DATA);
1654
}
1655
1656
TEST_CASE("[String] Cyrillic to_lower()") {
1657
String upper = U"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
1658
String lower = U"абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
1659
1660
String test = upper.to_lower();
1661
1662
bool state = test == lower;
1663
1664
CHECK(state);
1665
}
1666
1667
TEST_CASE("[String] Count and countn functionality") {
1668
String s = String("");
1669
MULTICHECK_STRING_EQ(s, count, "Test", 0);
1670
1671
s = "Test";
1672
MULTICHECK_STRING_EQ(s, count, "", 0);
1673
1674
s = "Test";
1675
MULTICHECK_STRING_EQ(s, count, "test", 0);
1676
1677
s = "Test";
1678
MULTICHECK_STRING_EQ(s, count, "TEST", 0);
1679
1680
s = "TEST";
1681
MULTICHECK_STRING_EQ(s, count, "TEST", 1);
1682
1683
s = "Test";
1684
MULTICHECK_STRING_EQ(s, count, "Test", 1);
1685
1686
s = "aTest";
1687
MULTICHECK_STRING_EQ(s, count, "Test", 1);
1688
1689
s = "Testa";
1690
MULTICHECK_STRING_EQ(s, count, "Test", 1);
1691
1692
s = "TestTestTest";
1693
MULTICHECK_STRING_EQ(s, count, "Test", 3);
1694
1695
s = "TestTestTest";
1696
MULTICHECK_STRING_EQ(s, count, "TestTest", 1);
1697
1698
s = "TestGodotTestGodotTestGodot";
1699
MULTICHECK_STRING_EQ(s, count, "Test", 3);
1700
1701
s = "TestTestTestTest";
1702
MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 8, 1);
1703
1704
s = "TestTestTestTest";
1705
MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 12, 2);
1706
1707
s = "TestTestTestTest";
1708
MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 16, 3);
1709
1710
s = "TestTestTestTest";
1711
MULTICHECK_STRING_INT_EQ(s, count, "Test", 4, 3);
1712
1713
s = "Test";
1714
MULTICHECK_STRING_EQ(s, countn, "test", 1);
1715
1716
s = "Test";
1717
MULTICHECK_STRING_EQ(s, countn, "TEST", 1);
1718
1719
s = "testTest-Testatest";
1720
MULTICHECK_STRING_EQ(s, countn, "tEst", 4);
1721
1722
s = "testTest-TeStatest";
1723
MULTICHECK_STRING_INT_INT_EQ(s, countn, "tEsT", 4, 16, 2);
1724
}
1725
1726
TEST_CASE("[String] Bigrams") {
1727
String s = "abcd";
1728
Vector<String> bigr = s.bigrams();
1729
1730
CHECK(bigr.size() == 3);
1731
CHECK(bigr[0] == "ab");
1732
CHECK(bigr[1] == "bc");
1733
CHECK(bigr[2] == "cd");
1734
}
1735
1736
TEST_CASE("[String] c-escape/unescape") {
1737
String s = "\\1\a2\b\f3\n45\r6\t7\v8\'9\?0\"";
1738
CHECK(s.c_escape().c_unescape() == s);
1739
}
1740
1741
TEST_CASE("[String] indent") {
1742
static const char *input[] = {
1743
"",
1744
"aaa\nbbb",
1745
"\tcontains\n\tindent",
1746
"empty\n\nline",
1747
};
1748
static const char *expected[] = {
1749
"",
1750
"\taaa\n\tbbb",
1751
"\t\tcontains\n\t\tindent",
1752
"\tempty\n\n\tline",
1753
};
1754
1755
for (int i = 0; i < 3; i++) {
1756
CHECK(String(input[i]).indent("\t") == expected[i]);
1757
}
1758
}
1759
1760
TEST_CASE("[String] dedent") {
1761
String s = " aaa\n bbb";
1762
String t = "aaa\nbbb";
1763
CHECK(s.dedent() == t);
1764
}
1765
1766
TEST_CASE("[String] Path functions") {
1767
static const char *path[8] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc", "C:\\test.", "res://test", "user://test", "/.test" };
1768
static const char *base_dir[8] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot", "C:\\", "res://", "user://", "/" };
1769
static const char *base_name[8] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test", "C:\\test", "res://test", "user://test", "/" };
1770
static const char *ext[8] = { "tscn", "xscn", "scn", "doc", "", "", "", "test" };
1771
static const char *file[8] = { "test.tscn", "test.xscn", "test.scn", "test.doc", "test.", "test", "test", ".test" };
1772
static const char *simplified[8] = { "C:/Godot/project/test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot/test.doc", "C:/test.", "res://test", "user://test", "/.test" };
1773
static const bool abs[8] = { true, true, false, false, true, true, true, true };
1774
1775
for (int i = 0; i < 8; i++) {
1776
CHECK(String(path[i]).get_base_dir() == base_dir[i]);
1777
CHECK(String(path[i]).get_basename() == base_name[i]);
1778
CHECK(String(path[i]).get_extension() == ext[i]);
1779
CHECK(String(path[i]).get_file() == file[i]);
1780
CHECK(String(path[i]).is_absolute_path() == abs[i]);
1781
CHECK(String(path[i]).is_relative_path() != abs[i]);
1782
CHECK(String(path[i]).simplify_path() == String(simplified[i]));
1783
CHECK(String(path[i]).simplify_path().get_base_dir().path_join(file[i]) == String(path[i]).simplify_path());
1784
}
1785
1786
static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" };
1787
static const bool valid[3] = { true, false, false };
1788
for (int i = 0; i < 3; i++) {
1789
CHECK(String(file_name[i]).is_valid_filename() == valid[i]);
1790
}
1791
1792
CHECK(String("res://texture.png") == String("res://folder/../folder/../texture.png").simplify_path());
1793
CHECK(String("res://texture.png") == String("res://folder/sub/../../texture.png").simplify_path());
1794
CHECK(String("res://../../texture.png") == String("res://../../texture.png").simplify_path());
1795
}
1796
1797
TEST_CASE("[String] hash") {
1798
String a = "Test";
1799
String b = "Test";
1800
String c = "West";
1801
CHECK(a.hash() == b.hash());
1802
CHECK(a.hash() != c.hash());
1803
1804
CHECK(a.hash64() == b.hash64());
1805
CHECK(a.hash64() != c.hash64());
1806
}
1807
1808
TEST_CASE("[String] uri_encode/unescape") {
1809
String s = "Godot Engine:'docs'";
1810
String t = "Godot%20Engine%3A%27docs%27";
1811
1812
String x1 = "T%C4%93%C5%A1t";
1813
static const uint8_t u8str[] = { 0x54, 0xC4, 0x93, 0xC5, 0xA1, 0x74, 0x00 };
1814
String x2 = String::utf8((const char *)u8str);
1815
String x3 = U"Tēšt";
1816
String x4 = U"file+name";
1817
1818
CHECK(x1.uri_decode() == x2);
1819
CHECK(x1.uri_decode() == x3);
1820
CHECK((x1 + x3).uri_decode() == (x2 + x3)); // Mixed unicode and URL encoded string, e.g. GTK+ bookmark.
1821
CHECK(x2.uri_encode() == x1);
1822
CHECK(x3.uri_encode() == x1);
1823
1824
CHECK(s.uri_encode() == t);
1825
CHECK(t.uri_decode() == s);
1826
CHECK(x4.uri_file_decode() == x4);
1827
CHECK(x4.uri_decode() == U"file name");
1828
}
1829
1830
TEST_CASE("[String] xml_escape/unescape") {
1831
String s = "\"Test\" <test@test&'test'>";
1832
CHECK(s.xml_escape(true).xml_unescape() == s);
1833
CHECK(s.xml_escape(false).xml_unescape() == s);
1834
}
1835
1836
TEST_CASE("[String] xml_unescape") {
1837
// Named entities
1838
String input = "&quot;&amp;&apos;&lt;&gt;";
1839
CHECK(input.xml_unescape() == "\"&\'<>");
1840
1841
// Numeric entities
1842
input = "&#x41;&#66;";
1843
CHECK(input.xml_unescape() == "AB");
1844
1845
input = "&#0;&x#0;More text";
1846
String result = input.xml_unescape();
1847
// Didn't put in a leading NUL and terminate the string
1848
CHECK(input.length() > 0);
1849
CHECK(input[0] != '\0');
1850
// Entity should be left as-is if invalid
1851
CHECK(input.xml_unescape() == input);
1852
1853
// Check near char32_t range
1854
input = "&#xFFFFFFFF;";
1855
result = input.xml_unescape();
1856
CHECK(result.length() == 1);
1857
CHECK(result[0] == 0xFFFFFFFF);
1858
input = "&#4294967295;";
1859
result = input.xml_unescape();
1860
CHECK(result.length() == 1);
1861
CHECK(result[0] == 0xFFFFFFFF);
1862
1863
// Check out of range of char32_t
1864
input = "&#xFFFFFFFFF;";
1865
CHECK(input.xml_unescape() == input);
1866
input = "&#4294967296;";
1867
CHECK(input.xml_unescape() == input);
1868
1869
// Shouldn't consume without ending in a ';'
1870
input = "&#66";
1871
CHECK(input.xml_unescape() == input);
1872
input = "&#x41";
1873
CHECK(input.xml_unescape() == input);
1874
1875
// Invalid characters should make the entity ignored
1876
input = "&#x41SomeIrrelevantText;";
1877
CHECK(input.xml_unescape() == input);
1878
input = "&#66SomeIrrelevantText;";
1879
CHECK(input.xml_unescape() == input);
1880
}
1881
1882
TEST_CASE("[String] Strip escapes") {
1883
String s = "\t\tTest Test\r\n Test";
1884
CHECK(s.strip_escapes() == "Test Test Test");
1885
}
1886
1887
TEST_CASE("[String] Similarity") {
1888
String a = "Test";
1889
String b = "West";
1890
String c = "Toad";
1891
CHECK(a.similarity(b) > a.similarity(c));
1892
}
1893
1894
TEST_CASE("[String] Strip edges") {
1895
String s = "\t Test Test ";
1896
CHECK(s.strip_edges(true, false) == "Test Test ");
1897
CHECK(s.strip_edges(false, true) == "\t Test Test");
1898
CHECK(s.strip_edges(true, true) == "Test Test");
1899
}
1900
1901
TEST_CASE("[String] Trim") {
1902
String s = "aaaTestbbb";
1903
MULTICHECK_STRING_EQ(s, trim_prefix, "aaa", "Testbbb");
1904
MULTICHECK_STRING_EQ(s, trim_prefix, "Test", s);
1905
MULTICHECK_STRING_EQ(s, trim_prefix, "", s);
1906
MULTICHECK_STRING_EQ(s, trim_prefix, "aaaTestbbb", "");
1907
MULTICHECK_STRING_EQ(s, trim_prefix, "bbb", s);
1908
MULTICHECK_STRING_EQ(s, trim_prefix, "AAA", s);
1909
1910
MULTICHECK_STRING_EQ(s, trim_suffix, "bbb", "aaaTest");
1911
MULTICHECK_STRING_EQ(s, trim_suffix, "Test", s);
1912
MULTICHECK_STRING_EQ(s, trim_suffix, "", s);
1913
MULTICHECK_STRING_EQ(s, trim_suffix, "aaaTestbbb", "");
1914
MULTICHECK_STRING_EQ(s, trim_suffix, "aaa", s);
1915
MULTICHECK_STRING_EQ(s, trim_suffix, "BBB", s);
1916
}
1917
1918
TEST_CASE("[String] Right/Left") {
1919
String s = "aaaTestbbb";
1920
// ^
1921
CHECK(s.right(6) == "estbbb");
1922
CHECK(s.right(-6) == "tbbb");
1923
CHECK(s.left(6) == "aaaTes");
1924
CHECK(s.left(-6) == "aaaT");
1925
}
1926
1927
TEST_CASE("[String] Repeat") {
1928
String s = "abababab";
1929
String x = "ab";
1930
String t = x.repeat(4);
1931
CHECK(t == s);
1932
}
1933
1934
TEST_CASE("[String] Reverse") {
1935
String s = "Abcd";
1936
CHECK(s.reverse() == "dcbA");
1937
}
1938
1939
TEST_CASE("[String] SHA1/SHA256/MD5") {
1940
String s = "Godot";
1941
String sha1 = "a1e91f39b9fce6a9998b14bdbe2aa2b39dc2d201";
1942
static uint8_t sha1_buf[20] = {
1943
0xA1, 0xE9, 0x1F, 0x39, 0xB9, 0xFC, 0xE6, 0xA9, 0x99, 0x8B, 0x14, 0xBD, 0xBE, 0x2A, 0xA2, 0xB3,
1944
0x9D, 0xC2, 0xD2, 0x01
1945
};
1946
String sha256 = "2a02b2443f7985d89d09001086ae3dcfa6eb0f55c6ef170715d42328e16e6cb8";
1947
static uint8_t sha256_buf[32] = {
1948
0x2A, 0x02, 0xB2, 0x44, 0x3F, 0x79, 0x85, 0xD8, 0x9D, 0x09, 0x00, 0x10, 0x86, 0xAE, 0x3D, 0xCF,
1949
0xA6, 0xEB, 0x0F, 0x55, 0xC6, 0xEF, 0x17, 0x07, 0x15, 0xD4, 0x23, 0x28, 0xE1, 0x6E, 0x6C, 0xB8
1950
};
1951
String md5 = "4a336d087aeb0390da10ee2ea7cb87f8";
1952
static uint8_t md5_buf[16] = {
1953
0x4A, 0x33, 0x6D, 0x08, 0x7A, 0xEB, 0x03, 0x90, 0xDA, 0x10, 0xEE, 0x2E, 0xA7, 0xCB, 0x87, 0xF8
1954
};
1955
1956
PackedByteArray buf = s.sha1_buffer();
1957
CHECK(memcmp(sha1_buf, buf.ptr(), 20) == 0);
1958
CHECK(s.sha1_text() == sha1);
1959
1960
buf = s.sha256_buffer();
1961
CHECK(memcmp(sha256_buf, buf.ptr(), 32) == 0);
1962
CHECK(s.sha256_text() == sha256);
1963
1964
buf = s.md5_buffer();
1965
CHECK(memcmp(md5_buf, buf.ptr(), 16) == 0);
1966
CHECK(s.md5_text() == md5);
1967
}
1968
1969
TEST_CASE("[String] Join") {
1970
String comma = ", ";
1971
String empty = "";
1972
Vector<String> parts;
1973
1974
CHECK(comma.join(parts) == "");
1975
CHECK(empty.join(parts) == "");
1976
1977
parts.push_back("One");
1978
CHECK(comma.join(parts) == "One");
1979
CHECK(empty.join(parts) == "One");
1980
1981
parts.push_back("B");
1982
parts.push_back("C");
1983
CHECK(comma.join(parts) == "One, B, C");
1984
CHECK(empty.join(parts) == "OneBC");
1985
1986
parts.push_back("");
1987
CHECK(comma.join(parts) == "One, B, C, ");
1988
CHECK(empty.join(parts) == "OneBC");
1989
}
1990
1991
TEST_CASE("[String] Is_*") {
1992
static const char *data[] = { "-30", "100", "10.1", "10,1", "1e2", "1e-2", "1e2e3", "0xAB", "AB", "Test1", "1Test", "Test*1", "文字", "1E2", "1E-2" };
1993
static bool isnum[] = { true, true, true, false, false, false, false, false, false, false, false, false, false, false, false };
1994
static bool isint[] = { true, true, false, false, false, false, false, false, false, false, false, false, false, false, false };
1995
static bool ishex[] = { true, true, false, false, true, false, true, false, true, false, false, false, false, true, false };
1996
static bool ishex_p[] = { false, false, false, false, false, false, false, true, false, false, false, false, false, false, false };
1997
static bool isflt[] = { true, true, true, false, true, true, false, false, false, false, false, false, false, true, true };
1998
static bool isaid[] = { false, false, false, false, false, false, false, false, true, true, false, false, false, false, false };
1999
static bool isuid[] = { false, false, false, false, false, false, false, false, true, true, false, false, true, false, false };
2000
for (unsigned int i = 0; i < std_size(data); i++) {
2001
String s = String::utf8(data[i]);
2002
CHECK(s.is_numeric() == isnum[i]);
2003
CHECK(s.is_valid_int() == isint[i]);
2004
CHECK(s.is_valid_hex_number(false) == ishex[i]);
2005
CHECK(s.is_valid_hex_number(true) == ishex_p[i]);
2006
CHECK(s.is_valid_float() == isflt[i]);
2007
CHECK(s.is_valid_ascii_identifier() == isaid[i]);
2008
CHECK(s.is_valid_unicode_identifier() == isuid[i]);
2009
}
2010
}
2011
2012
TEST_CASE("[String] humanize_size") {
2013
CHECK(String::humanize_size(1000) == "1000 B");
2014
CHECK(String::humanize_size(1025) == "1.00 KiB");
2015
CHECK(String::humanize_size(1025300) == "1001.2 KiB");
2016
CHECK(String::humanize_size(100523550) == "95.86 MiB");
2017
CHECK(String::humanize_size(5345555000) == "4.97 GiB");
2018
}
2019
2020
TEST_CASE("[String] validate_node_name") {
2021
String numeric_only = "12345";
2022
CHECK(numeric_only.validate_node_name() == "12345");
2023
2024
String name_with_spaces = "Name with spaces";
2025
CHECK(name_with_spaces.validate_node_name() == "Name with spaces");
2026
2027
String name_with_kana = U"Name with kana ゴドツ";
2028
CHECK(name_with_kana.validate_node_name() == U"Name with kana ゴドツ");
2029
2030
String name_with_invalid_chars = "Name with invalid characters :.@%removed!";
2031
CHECK(name_with_invalid_chars.validate_node_name() == "Name with invalid characters ____removed!");
2032
}
2033
2034
TEST_CASE("[String] validate_ascii_identifier") {
2035
String empty_string;
2036
CHECK(empty_string.validate_ascii_identifier() == "_");
2037
2038
String numeric_only = "12345";
2039
CHECK(numeric_only.validate_ascii_identifier() == "_12345");
2040
2041
String name_with_spaces = "Name with spaces";
2042
CHECK(name_with_spaces.validate_ascii_identifier() == "Name_with_spaces");
2043
2044
String name_with_invalid_chars = U"Invalid characters:@*#&世界";
2045
CHECK(name_with_invalid_chars.validate_ascii_identifier() == "Invalid_characters_______");
2046
}
2047
2048
TEST_CASE("[String] validate_unicode_identifier") {
2049
String empty_string;
2050
CHECK(empty_string.validate_unicode_identifier() == "_");
2051
2052
String numeric_only = "12345";
2053
CHECK(numeric_only.validate_unicode_identifier() == "_12345");
2054
2055
String name_with_spaces = "Name with spaces";
2056
CHECK(name_with_spaces.validate_unicode_identifier() == "Name_with_spaces");
2057
2058
String name_with_invalid_chars = U"Invalid characters:@*#&世界";
2059
CHECK(name_with_invalid_chars.validate_unicode_identifier() == U"Invalid_characters_____世界");
2060
}
2061
2062
TEST_CASE("[String] Variant indexed get") {
2063
Variant s = String("abcd");
2064
bool valid = false;
2065
bool oob = true;
2066
2067
String r = s.get_indexed(1, valid, oob);
2068
2069
CHECK(valid);
2070
CHECK_FALSE(oob);
2071
CHECK_EQ(r, String("b"));
2072
}
2073
2074
TEST_CASE("[String] Variant validated indexed get") {
2075
Variant s = String("abcd");
2076
2077
Variant::ValidatedIndexedGetter getter = Variant::get_member_validated_indexed_getter(Variant::STRING);
2078
2079
Variant r;
2080
bool oob = true;
2081
getter(&s, 1, &r, &oob);
2082
2083
CHECK_FALSE(oob);
2084
CHECK_EQ(r, String("b"));
2085
}
2086
2087
TEST_CASE("[String] Variant ptr indexed get") {
2088
String s("abcd");
2089
2090
Variant::PTRIndexedGetter getter = Variant::get_member_ptr_indexed_getter(Variant::STRING);
2091
2092
String r;
2093
getter(&s, 1, &r);
2094
2095
CHECK_EQ(r, String("b"));
2096
}
2097
2098
TEST_CASE("[String] Variant indexed set") {
2099
Variant s = String("abcd");
2100
bool valid = false;
2101
bool oob = true;
2102
2103
s.set_indexed(1, String("z"), valid, oob);
2104
2105
CHECK(valid);
2106
CHECK_FALSE(oob);
2107
CHECK_EQ(s, String("azcd"));
2108
}
2109
2110
TEST_CASE("[String] Variant validated indexed set") {
2111
Variant s = String("abcd");
2112
2113
Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(Variant::STRING);
2114
2115
Variant v = String("z");
2116
bool oob = true;
2117
setter(&s, 1, &v, &oob);
2118
2119
CHECK_FALSE(oob);
2120
CHECK_EQ(s, String("azcd"));
2121
}
2122
2123
TEST_CASE("[String] Variant ptr indexed set") {
2124
String s("abcd");
2125
2126
Variant::PTRIndexedSetter setter = Variant::get_member_ptr_indexed_setter(Variant::STRING);
2127
2128
String v("z");
2129
setter(&s, 1, &v);
2130
2131
CHECK_EQ(s, String("azcd"));
2132
}
2133
2134
TEST_CASE("[String][URL] Parse URL") {
2135
#define CHECK_URL(m_url_to_parse, m_expected_schema, m_expected_host, m_expected_port, m_expected_path, m_expected_fragment, m_expected_error) \
2136
if (true) { \
2137
int port; \
2138
String url(m_url_to_parse), schema, host, path, fragment; \
2139
\
2140
CHECK_EQ(url.parse_url(schema, host, port, path, fragment), m_expected_error); \
2141
CHECK_EQ(schema, m_expected_schema); \
2142
CHECK_EQ(host, m_expected_host); \
2143
CHECK_EQ(path, m_expected_path); \
2144
CHECK_EQ(fragment, m_expected_fragment); \
2145
CHECK_EQ(port, m_expected_port); \
2146
} else \
2147
((void)0)
2148
2149
// All elements.
2150
CHECK_URL("https://www.example.com:8080/path/to/file.html#fragment", "https://", "www.example.com", 8080, "/path/to/file.html", "fragment", Error::OK);
2151
2152
// Valid URLs.
2153
CHECK_URL("https://godotengine.org", "https://", "godotengine.org", 0, "", "", Error::OK);
2154
CHECK_URL("https://godotengine.org/", "https://", "godotengine.org", 0, "/", "", Error::OK);
2155
CHECK_URL("godotengine.org/", "", "godotengine.org", 0, "/", "", Error::OK);
2156
CHECK_URL("HTTPS://godotengine.org/", "https://", "godotengine.org", 0, "/", "", Error::OK);
2157
CHECK_URL("https://GODOTENGINE.ORG/", "https://", "godotengine.org", 0, "/", "", Error::OK);
2158
CHECK_URL("http://godotengine.org", "http://", "godotengine.org", 0, "", "", Error::OK);
2159
CHECK_URL("https://godotengine.org:8080", "https://", "godotengine.org", 8080, "", "", Error::OK);
2160
CHECK_URL("https://godotengine.org/blog", "https://", "godotengine.org", 0, "/blog", "", Error::OK);
2161
CHECK_URL("https://godotengine.org/blog/", "https://", "godotengine.org", 0, "/blog/", "", Error::OK);
2162
CHECK_URL("https://docs.godotengine.org/en/stable", "https://", "docs.godotengine.org", 0, "/en/stable", "", Error::OK);
2163
CHECK_URL("https://docs.godotengine.org/en/stable/", "https://", "docs.godotengine.org", 0, "/en/stable/", "", Error::OK);
2164
CHECK_URL("https://me:[email protected]", "https://", "godotengine.org", 0, "", "", Error::OK);
2165
CHECK_URL("https://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/ipv6", "https://", "fedc:ba98:7654:3210:fedc:ba98:7654:3210", 0, "/ipv6", "", Error::OK);
2166
2167
// Scheme vs Fragment.
2168
CHECK_URL("google.com/#goto=http://redirect_url/", "", "google.com", 0, "/", "goto=http://redirect_url/", Error::OK);
2169
2170
// Invalid URLs.
2171
2172
// Invalid Scheme.
2173
CHECK_URL("https_://godotengine.org", "", "https_", 0, "//godotengine.org", "", Error::ERR_INVALID_PARAMETER);
2174
2175
// Multiple ports.
2176
CHECK_URL("https://godotengine.org:8080:433", "https://", "", 0, "", "", Error::ERR_INVALID_PARAMETER);
2177
// Missing ] on literal IPv6.
2178
CHECK_URL("https://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/ipv6", "https://", "", 0, "/ipv6", "", Error::ERR_INVALID_PARAMETER);
2179
// Missing host.
2180
CHECK_URL("https:///blog", "https://", "", 0, "/blog", "", Error::ERR_INVALID_PARAMETER);
2181
// Invalid ports.
2182
CHECK_URL("https://godotengine.org:notaport", "https://", "godotengine.org", 0, "", "", Error::ERR_INVALID_PARAMETER);
2183
CHECK_URL("https://godotengine.org:-8080", "https://", "godotengine.org", -8080, "", "", Error::ERR_INVALID_PARAMETER);
2184
CHECK_URL("https://godotengine.org:88888", "https://", "godotengine.org", 88888, "", "", Error::ERR_INVALID_PARAMETER);
2185
2186
#undef CHECK_URL
2187
}
2188
2189
TEST_CASE("[Stress][String] Empty via ' == String()'") {
2190
for (int i = 0; i < 100000; ++i) {
2191
String str = "Hello World!";
2192
if (str == String()) {
2193
continue;
2194
}
2195
}
2196
}
2197
2198
TEST_CASE("[Stress][String] Empty via `is_empty()`") {
2199
for (int i = 0; i < 100000; ++i) {
2200
String str = "Hello World!";
2201
if (str.is_empty()) {
2202
continue;
2203
}
2204
}
2205
}
2206
} // namespace TestString
2207
2208