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