OILS / mycpp / gc_str_test.cc View on Github | oils.pub

1582 lines, 936 significant
1#include "mycpp/gc_str.h"
2
3#include <limits.h> // INT_MAX
4
5#include "mycpp/comparators.h" // str_equals
6#include "mycpp/gc_alloc.h" // gHeap
7#include "mycpp/gc_builtins.h" // print()
8#include "mycpp/gc_list.h"
9#include "vendor/greatest.h"
10
11GLOBAL_STR(kSpace, " ");
12GLOBAL_STR(kStrFood, "food");
13GLOBAL_STR(kWithNull, "foo\0bar");
14
15static void ShowString(BigStr* s) {
16 int n = len(s);
17 fputs("(", stdout);
18 fwrite(s->data_, sizeof(char), n, stdout);
19 fputs(")\n", stdout);
20}
21
22static void ShowStringInt(BigStr* str, int i) {
23 printf("(%s) -> ", str->data_);
24 printf("(%d)\n", i);
25}
26
27static void ShowList(List<BigStr*>* list) {
28 for (ListIter<BigStr*> iter((list)); !iter.Done(); iter.Next()) {
29 BigStr* piece = iter.Value();
30 printf("(%.*s) ", len(piece), piece->data_);
31 }
32 printf("\n");
33}
34
35GLOBAL_STR(str4, "egg");
36
37TEST test_str_gc_header() {
38 ASSERT(str_equals(kEmptyString, kEmptyString));
39
40 BigStr* str1 = nullptr;
41 BigStr* str2 = nullptr;
42 StackRoots _roots({&str1, &str2});
43
44 str1 = StrFromC("");
45 str2 = StrFromC("one\0two", 7);
46
47 ASSERT_EQ_FMT(HeapTag::Opaque, ObjHeader::FromObject(str2)->heap_tag, "%d");
48 // ASSERT_EQ_FMT(kStrHeaderSize + 1, str1->header_.obj_len, "%d");
49 // ASSERT_EQ_FMT(kStrHeaderSize + 7 + 1, str2->header_.obj_len, "%d");
50
51 // Make sure they're on the heap
52#ifndef MARK_SWEEP
53 int diff1 = reinterpret_cast<char*>(str1) - gHeap.from_space_.begin_;
54 int diff2 = reinterpret_cast<char*>(str2) - gHeap.from_space_.begin_;
55 ASSERT(diff1 < 1024);
56 ASSERT(diff2 < 1024);
57#endif
58
59 ASSERT_EQ(0, len(str1));
60 ASSERT_EQ(7, len(str2));
61
62 // Global strings
63
64 ASSERT_EQ('e', str4->data_[0]);
65 ASSERT_EQ('g', str4->data_[1]);
66 ASSERT_EQ('g', str4->data_[2]);
67 ASSERT_EQ('\0', str4->data_[3]);
68 ASSERT_EQ(HeapTag::Global, ObjHeader::FromObject(str4)->heap_tag);
69 // ASSERT_EQ(16, str4->header_.obj_len);
70 ASSERT_EQ(3, len(str4));
71
72 PASS();
73}
74
75// Emulating the gc_heap API. COPIED from gc_heap_test.cc
76TEST test_str_creation() {
77 BigStr* s = StrFromC("foo");
78 ASSERT_EQ(3, len(s));
79 ASSERT_EQ(0, strcmp("foo", s->data_));
80
81 // String with internal NUL
82 BigStr* s2 = StrFromC("foo\0bar", 7);
83 ASSERT_EQ(7, len(s2));
84 ASSERT_EQ(0, memcmp("foo\0bar\0", s2->data_, 8));
85
86 BigStr* s3 = NewStr(1);
87 ASSERT_EQ(1, len(s3));
88 ASSERT_EQ('\0', s3->data_[1]); // NUL terminated
89
90 // Test truncating a string
91 //
92 // NOTE(Jesse): It's undefined to call `len()` after allocating with this
93 // function because it explicitly doesn't set the length!!
94 /* BigStr* s4 = mylib::OverAllocatedStr(7); */
95
96 BigStr* s4 = NewStr(7);
97 ASSERT_EQ(7, len(s4));
98 ASSERT_EQ('\0', s4->data_[7]);
99
100 // Hm annoying that we have to do a const_cast
101 memcpy(s4->data_, "foo", 3);
102 s4->MaybeShrink(3);
103 ASSERT_EQ('\0', s4->data_[3]);
104
105 ASSERT_EQ(3, len(s4));
106 ASSERT_EQ(0, strcmp("foo", s4->data_));
107
108 PASS();
109}
110
111TEST test_str_find() {
112 BigStr* s = StrFromC("abc-abc\xff");
113 ASSERT_EQ_FMT(-1, s->find(StrFromC("x")), "%d");
114 ASSERT_EQ_FMT(-1, s->rfind(StrFromC("x")), "%d");
115
116 // find() 1 byte
117 ASSERT_EQ_FMT(0, s->find(StrFromC("a")), "%d");
118 ASSERT_EQ_FMT(2, s->find(StrFromC("c")), "%d");
119
120 // find() from starting pos
121 ASSERT_EQ_FMT(4, s->find(StrFromC("a"), 4), "%d");
122 ASSERT_EQ_FMT(6, s->find(StrFromC("c"), 4), "%d");
123
124 ASSERT_EQ_FMT(-1, s->find(StrFromC("a"), 7), "%d");
125 ASSERT_EQ_FMT(-1, s->find(StrFromC("c"), 7), "%d");
126
127 // rfind() 1 byte
128 ASSERT_EQ_FMT(4, s->rfind(StrFromC("a")), "%d");
129 ASSERT_EQ_FMT(6, s->rfind(StrFromC("c")), "%d");
130
131 // end before finding it
132 ASSERT_EQ_FMT(-1, s->find(StrFromC("a"), 0, 0), "%d");
133 ASSERT_EQ_FMT(-1, s->find(StrFromC("c"), 0, 2), "%d");
134
135 // find multiple bytes
136 ASSERT_EQ_FMT(0, s->find(StrFromC("abc")), "%d");
137 ASSERT_EQ_FMT(4, s->find(StrFromC("abc"), 1), "%d");
138
139 // find empty string
140 ASSERT_EQ_FMT(0, s->find(kEmptyString), "%d");
141 ASSERT_EQ_FMT(5, s->find(kEmptyString, 5), "%d");
142
143 // Empty string not found in degenerate range
144 ASSERT_EQ_FMT(-1, s->find(kEmptyString, 5, 4), "%d");
145
146 ASSERT_EQ_FMT(5, s->find(kEmptyString, 5, 5), "%d");
147 ASSERT_EQ_FMT(5, s->find(kEmptyString, 5, 6), "%d");
148
149 // Not used by Oils
150 // ASSERT_EQ_FMT(4, s->rfind(StrFromC("abc")), "%d");
151
152 ASSERT_EQ_FMT(7, s->find(StrFromC("\xff")), "%d");
153 ASSERT_EQ_FMT(7, s->rfind(StrFromC("\xff")), "%d");
154 ASSERT_EQ_FMT(-1, s->rfind(StrFromC("\xfe")), "%d");
155
156 PASS();
157}
158
159TEST test_str_strip() {
160 printf("\n");
161
162 printf("------- BigStr::lstrip -------\n");
163
164 {
165 BigStr* result = (StrFromC("\n "))->lstrip();
166 ShowString(result);
167 ASSERT(str_equals(result, StrFromC("")));
168 }
169
170 // carriage return is space, consistent with JSON spec and lexing rules in
171 // frontend/lexer_def.py
172 {
173 BigStr* result = (StrFromC("\n\r #"))->lstrip();
174 ShowString(result);
175 ASSERT(str_equals(result, StrFromC("#")));
176 }
177
178 // but \v vertical tab is not
179 {
180 BigStr* result = (StrFromC("\v #"))->lstrip();
181 ShowString(result);
182 ASSERT(str_equals(result, StrFromC("\v #")));
183 }
184
185 {
186 BigStr* result = (StrFromC("\n #"))->lstrip();
187 ShowString(result);
188 ASSERT(str_equals(result, StrFromC("#")));
189 }
190
191 {
192 BigStr* result = (StrFromC("\n #"))->lstrip();
193 ShowString(result);
194 ASSERT(str_equals(result, StrFromC("#")));
195 }
196
197 {
198 BigStr* result = (StrFromC("#"))->lstrip(StrFromC("#"));
199 ShowString(result);
200 ASSERT(str_equals(result, StrFromC("")));
201 }
202
203 {
204 BigStr* result = (StrFromC("##### "))->lstrip(StrFromC("#"));
205 ShowString(result);
206 ASSERT(str_equals(result, StrFromC(" ")));
207 }
208
209 {
210 BigStr* result = (StrFromC("# "))->lstrip(StrFromC("#"));
211 ShowString(result);
212 ASSERT(str_equals(result, StrFromC(" ")));
213 }
214
215 {
216 BigStr* result = (StrFromC(" # "))->lstrip(StrFromC("#"));
217 ShowString(result);
218 ASSERT(str_equals(result, StrFromC(" # ")));
219 }
220
221 printf("------- BigStr::rstrip -------\n");
222
223 {
224 BigStr* result = (StrFromC(" \n"))->rstrip();
225 ShowString(result);
226 ASSERT(str_equals(result, StrFromC("")));
227 }
228
229 {
230 BigStr* result = (StrFromC("# \n"))->rstrip();
231 ShowString(result);
232 ASSERT(str_equals(result, StrFromC("#")));
233 }
234
235 {
236 BigStr* result = (StrFromC("# \n"))->rstrip();
237 ShowString(result);
238 ASSERT(str_equals(result, StrFromC("#")));
239 }
240
241 {
242 BigStr* s1 = StrFromC(" \n#");
243 BigStr* result = s1->rstrip();
244 ShowString(result);
245 ASSERT(str_equals(result, s1));
246 ASSERT_EQ(result, s1); // objects are identical
247 }
248
249 {
250 BigStr* result = (StrFromC("# \n"))->rstrip();
251 ShowString(result);
252 ASSERT(str_equals(result, StrFromC("#")));
253 }
254
255 {
256 BigStr* result = (StrFromC("#"))->rstrip(StrFromC("#"));
257 ShowString(result);
258 ASSERT(str_equals(result, StrFromC("")));
259 }
260
261 {
262 BigStr* result = (StrFromC(" #####"))->rstrip(StrFromC("#"));
263 ShowString(result);
264 ASSERT(str_equals(result, StrFromC(" ")));
265 }
266
267 {
268 BigStr* result = (StrFromC(" #"))->rstrip(StrFromC("#"));
269 ShowString(result);
270 ASSERT(str_equals(result, StrFromC(" ")));
271 }
272
273 {
274 BigStr* result = (StrFromC(" # "))->rstrip(StrFromC("#"));
275 ShowString(result);
276 ASSERT(str_equals(result, StrFromC(" # ")));
277 }
278
279 printf("------- BigStr::strip -------\n");
280
281 {
282 BigStr* result = (StrFromC(""))->strip();
283 ShowString(result);
284 ASSERT(str_equals(result, StrFromC("")));
285
286 ASSERT_EQ(result, kEmptyString); // identical objects
287 }
288
289 {
290 BigStr* result = (StrFromC(" "))->strip();
291 ShowString(result);
292 ASSERT(str_equals(result, StrFromC("")));
293
294 ASSERT_EQ(result, kEmptyString); // identical objects
295 }
296
297 {
298 BigStr* result = (StrFromC(" \n"))->strip();
299 ShowString(result);
300 ASSERT(str_equals(result, StrFromC("")));
301
302 ASSERT_EQ(result, kEmptyString); // identical objects
303 }
304
305 {
306 BigStr* result = (StrFromC(" ## "))->strip();
307 ShowString(result);
308 ASSERT(str_equals(result, StrFromC("##")));
309 }
310
311 {
312 BigStr* result = (StrFromC(" hi \n"))->strip();
313 ShowString(result);
314 ASSERT(str_equals(result, StrFromC("hi")));
315 }
316
317 ASSERT(str_equals0(" abc", StrFromC(" abc ")->rstrip()));
318 ASSERT(str_equals0(" def", StrFromC(" def")->rstrip()));
319
320 ASSERT(str_equals0("", kEmptyString->rstrip()));
321 ASSERT(str_equals0("", kEmptyString->strip()));
322
323 ASSERT(str_equals0("123", StrFromC(" 123 ")->strip()));
324 ASSERT(str_equals0("123", StrFromC(" 123")->strip()));
325 ASSERT(str_equals0("123", StrFromC("123 ")->strip()));
326
327 printf("---------- Done ----------\n");
328
329 PASS();
330}
331
332TEST test_rstrip() {
333 // rstrip() with multiple characters
334
335 BigStr* s;
336
337 s = StrFromC(" axx")->rstrip(StrFromC("x"));
338 ASSERT(str_equals0(" a", s));
339
340 s = StrFromC(" a ")->rstrip(StrFromC(" \t"));
341 ASSERT(str_equals0(" a", s));
342
343 s = StrFromC(" axx")->rstrip(StrFromC(" x"));
344 ASSERT(str_equals0(" a", s));
345
346 s = StrFromC(" a\t\t")->rstrip(StrFromC(" \t"));
347 ASSERT(str_equals0(" a", s));
348
349 // Empty string allowed too
350 s = StrFromC(" a\t\t")->rstrip(kEmptyString);
351 ASSERT(str_equals0(" a\t\t", s));
352
353 PASS();
354}
355
356TEST test_str_upper_lower() {
357 printf("\n");
358
359 printf("------- BigStr::upper -------\n");
360
361 {
362 BigStr* result = (StrFromC(""))->upper();
363 ShowString(result);
364 ASSERT(str_equals(result, StrFromC("")));
365 }
366
367 {
368 BigStr* result = (StrFromC("upper"))->upper();
369 ShowString(result);
370 ASSERT(str_equals(result, StrFromC("UPPER")));
371 }
372
373 {
374 BigStr* result = (StrFromC("upPer_uPper"))->upper();
375 ShowString(result);
376 ASSERT(str_equals(result, StrFromC("UPPER_UPPER")));
377 }
378
379 printf("------- BigStr::lower -------\n");
380
381 {
382 BigStr* result = (StrFromC(""))->lower();
383 ShowString(result);
384 ASSERT(str_equals(result, StrFromC("")));
385 }
386
387 {
388 BigStr* result = (StrFromC("LOWER"))->lower();
389 ShowString(result);
390 ASSERT(str_equals(result, StrFromC("lower")));
391 }
392
393 {
394 BigStr* result = (StrFromC("lOWeR_lowEr"))->lower();
395 ShowString(result);
396 ASSERT(str_equals(result, StrFromC("lower_lower")));
397 }
398
399 printf("---------- Done ----------\n");
400
401 PASS();
402}
403
404TEST test_str_replace() {
405 printf("\n");
406
407 BigStr* s0 = StrFromC("ab cd ab ef");
408
409 printf("----- BigStr::replace -------\n");
410
411 {
412 BigStr* s1 = s0->replace(StrFromC("ab"), StrFromC("--"));
413 ShowString(s1);
414 ASSERT(str_equals(s1, StrFromC("-- cd -- ef")));
415 }
416
417 {
418 BigStr* s1 = s0->replace(StrFromC("ab"), StrFromC("----"));
419 ShowString(s1);
420 ASSERT(str_equals(s1, StrFromC("---- cd ---- ef")));
421 }
422
423 {
424 BigStr* s1 = s0->replace(StrFromC("ab cd ab ef"), StrFromC("0"));
425 ShowString(s1);
426 ASSERT(str_equals(s1, StrFromC("0")));
427 }
428
429 {
430 BigStr* s1 = s0->replace(s0, StrFromC("0"));
431 ShowString(s1);
432 ASSERT(str_equals(s1, StrFromC("0")));
433 }
434
435 {
436 BigStr* s1 = s0->replace(StrFromC("no-match"), StrFromC("0"));
437 ShowString(s1);
438 ASSERT(str_equals(s1, StrFromC("ab cd ab ef")));
439 }
440
441 {
442 BigStr* s1 = s0->replace(StrFromC("ef"), StrFromC("0"));
443 ShowString(s1);
444 ASSERT(str_equals(s1, StrFromC("ab cd ab 0")));
445 }
446
447 {
448 BigStr* s1 = s0->replace(StrFromC("f"), StrFromC("0"));
449 ShowString(s1);
450 ASSERT(str_equals(s1, StrFromC("ab cd ab e0")));
451 }
452
453 {
454 s0 = StrFromC("ab ab ab");
455 BigStr* s1 = s0->replace(StrFromC("ab"), StrFromC("0"));
456 ShowString(s1);
457 ASSERT(str_equals(s1, StrFromC("0 0 0")));
458 }
459
460 {
461 s0 = StrFromC("ababab");
462 BigStr* s1 = s0->replace(StrFromC("ab"), StrFromC("0"));
463 ShowString(s1);
464 ASSERT(str_equals(s1, StrFromC("000")));
465 }
466
467 {
468 s0 = StrFromC("abababab");
469 BigStr* s1 = s0->replace(StrFromC("ab"), StrFromC("0"));
470 ShowString(s1);
471 ASSERT(str_equals(s1, StrFromC("0000")));
472 }
473
474 {
475 s0 = StrFromC("abc 123");
476 BigStr* s1 = s0->replace(StrFromC("abc"), StrFromC(""));
477 ShowString(s1);
478 ASSERT(str_equals(s1, StrFromC(" 123")));
479 }
480
481 {
482 s0 = StrFromC("abc 123");
483 BigStr* s1 = s0->replace(StrFromC("abc"), StrFromC(""));
484 ShowString(s1);
485 ASSERT(str_equals(s1, StrFromC(" 123")));
486 }
487
488 {
489 s0 = StrFromC("abc 123");
490 BigStr* s1 = s0->replace(StrFromC("abc"), StrFromC("abc"));
491 ShowString(s1);
492 ASSERT(str_equals(s1, StrFromC("abc 123")));
493 }
494
495 {
496 s0 = StrFromC("aaaa");
497 BigStr* s1 = s0->replace(StrFromC("aa"), StrFromC("bb"));
498 ShowString(s1);
499 ASSERT(str_equals(s1, StrFromC("bbbb")));
500 }
501
502 {
503 s0 = StrFromC("aaaaaa");
504 BigStr* s1 = s0->replace(StrFromC("aa"), StrFromC("bb"));
505 ShowString(s1);
506 ASSERT(str_equals(s1, StrFromC("bbbbbb")));
507 }
508
509 // Test NUL replacement
510 {
511 BigStr* s_null = StrFromC("abc\0bcd", 7);
512 ASSERT_EQ(7, len(s_null));
513
514 BigStr* re1 = s_null->replace(StrFromC("ab"), StrFromC("--"));
515 ASSERT_EQ_FMT(7, len(re1), "%d");
516 ASSERT(str_equals(StrFromC("--c\0bcd", 7), re1));
517
518 BigStr* re2 = s_null->replace(StrFromC("bc"), StrFromC("--"));
519 ASSERT_EQ_FMT(7, len(re2), "%d");
520 ASSERT(str_equals(StrFromC("a--\0--d", 7), re2));
521
522 BigStr* re3 = s_null->replace(StrFromC("\0", 1), StrFromC("__"));
523 ASSERT_EQ_FMT(8, len(re3), "%d");
524 ASSERT(str_equals(StrFromC("abc__bcd", 8), re3));
525 }
526
527 PASS();
528}
529
530TEST test_str_just() {
531 printf("\n");
532
533 printf("------- BigStr::ljust -------\n");
534
535 {
536 BigStr* result = (StrFromC(""))->ljust(0, StrFromC("_"));
537 ShowString(result);
538 ASSERT(str_equals(result, StrFromC("")));
539 }
540 {
541 BigStr* result = (StrFromC(""))->ljust(1, StrFromC("_"));
542 ShowString(result);
543 ASSERT(str_equals(result, StrFromC("_")));
544 }
545 {
546 BigStr* result = (StrFromC(""))->ljust(4, StrFromC("_"));
547 ShowString(result);
548 ASSERT(str_equals(result, StrFromC("____")));
549 }
550 {
551 BigStr* result = (StrFromC("x"))->ljust(0, StrFromC("_"));
552 ShowString(result);
553 ASSERT(str_equals(result, StrFromC("x")));
554 }
555 {
556 BigStr* result = (StrFromC("x"))->ljust(1, StrFromC("_"));
557 ShowString(result);
558 ASSERT(str_equals(result, StrFromC("x")));
559 }
560 {
561 BigStr* result = (StrFromC("x"))->ljust(2, StrFromC("_"));
562 ShowString(result);
563 ASSERT(str_equals(result, StrFromC("x_")));
564 }
565
566 {
567 BigStr* result = (StrFromC("xx"))->ljust(-1, StrFromC("_"));
568 ShowString(result);
569 ASSERT(str_equals(result, StrFromC("xx")));
570 }
571 {
572 BigStr* result = (StrFromC("xx"))->ljust(0, StrFromC("_"));
573 ShowString(result);
574 ASSERT(str_equals(result, StrFromC("xx")));
575 }
576 {
577 BigStr* result = (StrFromC("xx"))->ljust(1, StrFromC("_"));
578 ShowString(result);
579 ASSERT(str_equals(result, StrFromC("xx")));
580 }
581 {
582 BigStr* result = (StrFromC("xx"))->ljust(2, StrFromC("_"));
583 ShowString(result);
584 ASSERT(str_equals(result, StrFromC("xx")));
585 }
586 {
587 BigStr* result = (StrFromC("xx"))->ljust(4, StrFromC("_"));
588 ShowString(result);
589 ASSERT(str_equals(result, StrFromC("xx__")));
590 }
591
592 printf("------- BigStr::rjust -------\n");
593 {
594 BigStr* result = (StrFromC(""))->rjust(0, StrFromC("_"));
595 ShowString(result);
596 ASSERT(str_equals(result, StrFromC("")));
597 }
598 {
599 BigStr* result = (StrFromC(""))->rjust(1, StrFromC("_"));
600 ShowString(result);
601 ASSERT(str_equals(result, StrFromC("_")));
602 }
603 {
604 BigStr* result = (StrFromC(""))->rjust(4, StrFromC("_"));
605 ShowString(result);
606 ASSERT(str_equals(result, StrFromC("____")));
607 }
608 {
609 BigStr* result = (StrFromC("x"))->rjust(0, StrFromC("_"));
610 ShowString(result);
611 ASSERT(str_equals(result, StrFromC("x")));
612 }
613 {
614 BigStr* result = (StrFromC("x"))->rjust(1, StrFromC("_"));
615 ShowString(result);
616 ASSERT(str_equals(result, StrFromC("x")));
617 }
618 {
619 BigStr* result = (StrFromC("x"))->rjust(2, StrFromC("_"));
620 ShowString(result);
621 ASSERT(str_equals(result, StrFromC("_x")));
622 }
623
624 {
625 BigStr* result = (StrFromC("xx"))->rjust(-1, StrFromC("_"));
626 ShowString(result);
627 ASSERT(str_equals(result, StrFromC("xx")));
628 }
629 {
630 BigStr* result = (StrFromC("xx"))->rjust(0, StrFromC("_"));
631 ShowString(result);
632 ASSERT(str_equals(result, StrFromC("xx")));
633 }
634 {
635 BigStr* result = (StrFromC("xx"))->rjust(1, StrFromC("_"));
636 ShowString(result);
637 ASSERT(str_equals(result, StrFromC("xx")));
638 }
639 {
640 BigStr* result = (StrFromC("xx"))->rjust(2, StrFromC("_"));
641 ShowString(result);
642 ASSERT(str_equals(result, StrFromC("xx")));
643 }
644 {
645 BigStr* result = (StrFromC("xx"))->rjust(4, StrFromC("_"));
646 ShowString(result);
647 ASSERT(str_equals(result, StrFromC("__xx")));
648 }
649 printf("---------- Done ----------\n");
650
651 PASS();
652}
653
654TEST test_str_slice() {
655 printf("\n");
656
657 BigStr* s0 = StrFromC("abcdef");
658
659 printf("------- BigStr::slice -------\n");
660
661 { // Happy path
662 BigStr* s1 = s0->slice(0, 5);
663 ASSERT(str_equals(s1, StrFromC("abcde")));
664 ShowString(s1);
665 }
666 {
667 BigStr* s1 = s0->slice(1, 5);
668 ASSERT(str_equals(s1, StrFromC("bcde")));
669 ShowString(s1);
670 }
671 {
672 BigStr* s1 = s0->slice(0, 0);
673 ASSERT(str_equals(s1, StrFromC("")));
674 ShowString(s1);
675 }
676 {
677 BigStr* s1 = s0->slice(0, 6);
678 ASSERT(str_equals(s1, StrFromC("abcdef")));
679 ShowString(s1);
680 }
681 {
682 BigStr* s1 = s0->slice(-6, 6);
683 ASSERT(str_equals(s1, StrFromC("abcdef")));
684 ShowString(s1);
685 }
686 {
687 BigStr* s1 = s0->slice(0, -6);
688 ASSERT(str_equals(s1, StrFromC("")));
689 ShowString(s1);
690 }
691 {
692 BigStr* s1 = s0->slice(-6, -6);
693 ASSERT(str_equals(s1, StrFromC("")));
694 ShowString(s1);
695 }
696
697 {
698 BigStr* s1 = s0->slice(5, 6);
699 ASSERT(str_equals(s1, StrFromC("f")));
700 ShowString(s1);
701 }
702
703 {
704 BigStr* s1 = s0->slice(6, 6);
705 ASSERT(str_equals(s1, StrFromC("")));
706 ASSERT(kEmptyString == s1);
707 ShowString(s1);
708 }
709
710 {
711 BigStr* s1 = s0->slice(0, -7);
712 ASSERT(str_equals(s1, StrFromC("")));
713 ShowString(s1);
714 }
715
716 {
717 BigStr* s1 = s0->slice(-7, -7);
718 ASSERT(str_equals(s1, StrFromC("")));
719 ShowString(s1);
720 }
721
722 {
723 BigStr* s1 = s0->slice(-7, 0);
724 ASSERT(str_equals(s1, StrFromC("")));
725 ShowString(s1);
726 }
727
728 {
729 BigStr* s1 = s0->slice(6, 6);
730 ASSERT(str_equals(s1, StrFromC("")));
731 ShowString(s1);
732 }
733
734 {
735 BigStr* s1 = s0->slice(7, 7);
736 ASSERT(str_equals(s1, StrFromC("")));
737 ShowString(s1);
738 }
739
740 {
741 BigStr* s1 = s0->slice(6, 5);
742 ASSERT(str_equals(s1, StrFromC("")));
743 ShowString(s1);
744 }
745
746 {
747 BigStr* s1 = s0->slice(7, 5);
748 ASSERT(str_equals(s1, StrFromC("")));
749 ShowString(s1);
750 }
751
752 {
753 BigStr* s1 = s0->slice(7, 6);
754 ASSERT(str_equals(s1, StrFromC("")));
755 ShowString(s1);
756 }
757
758 {
759 BigStr* s1 = s0->slice(7, 7);
760 ASSERT(str_equals(s1, StrFromC("")));
761 ShowString(s1);
762 }
763
764 printf("---------- Done ----------\n");
765
766 // NOTE(Jesse): testing all permutations of boundary conditions for
767 // assertions
768 int max_len = (len(s0) + 2);
769 int min_len = -max_len;
770
771 for (int outer = min_len; outer <= max_len; ++outer) {
772 for (int inner = min_len; inner <= max_len; ++inner) {
773 s0->slice(outer, inner);
774 }
775 }
776
777 PASS();
778}
779
780TEST test_str_concat() {
781 printf("\n");
782
783 printf("------- str_concat -------\n");
784
785 {
786 BigStr* result = str_concat(StrFromC(""), StrFromC(""));
787 ShowString(result);
788 ASSERT(str_equals(result, StrFromC("")));
789 }
790 {
791 BigStr* result = str_concat(StrFromC("a"), StrFromC(""));
792 ShowString(result);
793 ASSERT(str_equals(result, StrFromC("a")));
794 }
795 {
796 BigStr* result = str_concat(StrFromC("aa"), StrFromC(""));
797 ShowString(result);
798 ASSERT(str_equals(result, StrFromC("aa")));
799 }
800 {
801 BigStr* result = str_concat(StrFromC(""), StrFromC("b"));
802 ShowString(result);
803 ASSERT(str_equals(result, StrFromC("b")));
804 }
805 {
806 BigStr* result = str_concat(StrFromC(""), StrFromC("bb"));
807 ShowString(result);
808 ASSERT(str_equals(result, StrFromC("bb")));
809 }
810 {
811 BigStr* result = str_concat(StrFromC("a"), StrFromC("b"));
812 ShowString(result);
813 ASSERT(str_equals(result, StrFromC("ab")));
814 }
815 {
816 BigStr* result = str_concat(StrFromC("aa"), StrFromC("b"));
817 ShowString(result);
818 ASSERT(str_equals(result, StrFromC("aab")));
819 }
820 {
821 BigStr* result = str_concat(StrFromC("a"), StrFromC("bb"));
822 ShowString(result);
823 ASSERT(str_equals(result, StrFromC("abb")));
824 }
825 {
826 BigStr* result = str_concat(StrFromC("aa"), StrFromC("bb"));
827 ShowString(result);
828 ASSERT(str_equals(result, StrFromC("aabb")));
829 }
830
831 printf("------- str_concat3 -------\n");
832
833 {
834 BigStr* result = str_concat3(StrFromC(""), StrFromC(""), StrFromC(""));
835 ShowString(result);
836 ASSERT(str_equals(result, StrFromC("")));
837 }
838 {
839 BigStr* result = str_concat3(StrFromC("a"), StrFromC(""), StrFromC(""));
840 ShowString(result);
841 ASSERT(str_equals(result, StrFromC("a")));
842 }
843 {
844 BigStr* result = str_concat3(StrFromC("a"), StrFromC("b"), StrFromC(""));
845 ShowString(result);
846 ASSERT(str_equals(result, StrFromC("ab")));
847 }
848 {
849 BigStr* result = str_concat3(StrFromC("a"), StrFromC("b"), StrFromC("c"));
850 ShowString(result);
851 ASSERT(str_equals(result, StrFromC("abc")));
852 }
853 {
854 BigStr* result = str_concat3(StrFromC("a"), StrFromC(""), StrFromC("c"));
855 ShowString(result);
856 ASSERT(str_equals(result, StrFromC("ac")));
857 }
858
859 {
860 BigStr* result = str_concat3(StrFromC("aa"), StrFromC(""), StrFromC(""));
861 ShowString(result);
862 ASSERT(str_equals(result, StrFromC("aa")));
863 }
864 {
865 BigStr* result = str_concat3(StrFromC("aa"), StrFromC("b"), StrFromC(""));
866 ShowString(result);
867 ASSERT(str_equals(result, StrFromC("aab")));
868 }
869 {
870 BigStr* result = str_concat3(StrFromC("aa"), StrFromC("b"), StrFromC("c"));
871 ShowString(result);
872 ASSERT(str_equals(result, StrFromC("aabc")));
873 }
874 {
875 BigStr* result = str_concat3(StrFromC("aa"), StrFromC(""), StrFromC("c"));
876 ShowString(result);
877 ASSERT(str_equals(result, StrFromC("aac")));
878 }
879
880 PASS();
881}
882
883TEST test_str_to_int() {
884 log("");
885 log("------- to_int -------");
886
887 {
888 BigStr* input = StrFromC("0");
889 int result = to_int(input);
890 ShowStringInt(input, result);
891 ASSERT(result == 0);
892 }
893 {
894 BigStr* input = StrFromC("1");
895 int result = to_int(input);
896 ShowStringInt(input, result);
897 ASSERT(result == 1);
898 }
899 {
900 BigStr* input = StrFromC("-1");
901 int result = to_int(input);
902 ShowStringInt(input, result);
903 ASSERT(result == -1);
904 }
905 {
906 BigStr* input = StrFromC("100");
907 int result = to_int(input);
908 ShowStringInt(input, result);
909 ASSERT(result == 100);
910 }
911 {
912 // one less than 0x7FFFFFFF, because that value can be LONG_MAX
913 BigStr* input = StrFromC("2147483646");
914 int result = to_int(input);
915 ShowStringInt(input, result);
916 ASSERT(result == 2147483646);
917 }
918 {
919 // one less than -0x7FFFFFFF - 1, because that value can be LONG_MIN
920 BigStr* input = StrFromC("-2147483647");
921 int result = to_int(input);
922 ShowStringInt(input, result);
923 ASSERT(result == -2147483647);
924 }
925
926 bool caught;
927 int z = 0;
928 caught = false;
929 try {
930 z = to_int(StrFromC("2147483648"));
931 log("z = %d", z);
932 } catch (ValueError*) {
933 caught = true;
934 }
935 ASSERT(caught);
936
937 caught = false;
938 try {
939 z = to_int(StrFromC("-2147483649"));
940 log("z = %d", z);
941 } catch (ValueError*) {
942 caught = true;
943 }
944 ASSERT(caught);
945
946 PASS();
947}
948
949TEST test_str_startswith() {
950 printf("------ BigStr::helpers ------\n");
951
952 ASSERT((StrFromC(""))->startswith(StrFromC("")) == true);
953 ASSERT((StrFromC(" "))->startswith(StrFromC("")) == true);
954 ASSERT((StrFromC(" "))->startswith(StrFromC(" ")) == true);
955
956 ASSERT((StrFromC(" "))->startswith(StrFromC(" ")) == true);
957
958 PASS();
959}
960
961TEST test_str_contains() {
962 bool b;
963 BigStr* s = nullptr;
964 BigStr* nul = nullptr;
965 StackRoots _roots({&s, &nul});
966
967 log(" str_contains");
968
969 s = StrFromC("foo\0 ", 5);
970 ASSERT(str_contains(s, kSpace));
971
972 // this ends with a NUL, but also has a NUL terinator.
973 nul = StrFromC("\0", 1);
974 ASSERT(str_contains(s, nul));
975 ASSERT(!str_contains(kSpace, nul));
976
977 b = str_contains(StrFromC("foo\0a", 5), StrFromC("a"));
978 ASSERT(b == true);
979
980 // this ends with a NUL, but also has a NUL terinator.
981 s = StrFromC("foo\0", 4);
982 b = str_contains(s, StrFromC("\0", 1));
983 ASSERT(b == true);
984
985 // Degenerate cases
986 b = str_contains(StrFromC(""), StrFromC(""));
987 ASSERT(b == true);
988 b = str_contains(StrFromC("foo"), StrFromC(""));
989 ASSERT(b == true);
990 b = str_contains(StrFromC(""), StrFromC("f"));
991 ASSERT(b == false);
992
993 // Short circuit
994 b = str_contains(StrFromC("foo"), StrFromC("too long"));
995 ASSERT(b == false);
996
997 b = str_contains(StrFromC("foo"), StrFromC("oo"));
998 ASSERT(b == true);
999
1000 b = str_contains(StrFromC("foo"), StrFromC("ood"));
1001 ASSERT(b == false);
1002
1003 b = str_contains(StrFromC("foo\0ab", 6), StrFromC("ab"));
1004 ASSERT(b == true);
1005
1006 PASS();
1007}
1008
1009TEST test_str_split() {
1010 printf("\n");
1011
1012 printf("------- BigStr::split -------\n");
1013
1014 {
1015 BigStr* s = StrFromC("abc def");
1016 // No split
1017 List<BigStr*>* parts = s->split(StrFromC("x"));
1018 ShowList(parts);
1019 ASSERT_EQ(1, len(parts));
1020 ASSERT_EQ(parts->at(0), s);
1021 }
1022
1023 {
1024 List<BigStr*>* parts = StrFromC("abc def")->split(StrFromC(" "));
1025 ShowList(parts);
1026 ASSERT_EQ(2, len(parts));
1027 ASSERT(items_equal(parts->at(0), StrFromC("abc")));
1028 ASSERT(items_equal(parts->at(1), StrFromC("def")));
1029 }
1030
1031 {
1032 List<BigStr*>* parts = StrFromC("###")->split(StrFromC("#"));
1033 ShowList(parts);
1034 ASSERT_EQ_FMT(4, len(parts), "%d");
1035 // Identical objects
1036 ASSERT_EQ(kEmptyString, parts->at(0));
1037 ASSERT_EQ(kEmptyString, parts->at(1));
1038 ASSERT_EQ(kEmptyString, parts->at(2));
1039 ASSERT_EQ(kEmptyString, parts->at(3));
1040 }
1041
1042 {
1043 List<BigStr*>* parts = StrFromC(" ### ")->split(StrFromC("#"));
1044 ShowList(parts);
1045 ASSERT_EQ(4, len(parts));
1046 ASSERT(items_equal(parts->at(0), StrFromC(" ")));
1047 ASSERT(items_equal(parts->at(1), StrFromC("")));
1048 ASSERT(items_equal(parts->at(2), StrFromC("")));
1049 ASSERT(items_equal(parts->at(3), StrFromC(" ")));
1050 }
1051
1052 {
1053 List<BigStr*>* parts = StrFromC(" # ")->split(StrFromC(" "));
1054 ShowList(parts);
1055 ASSERT_EQ(3, len(parts));
1056 ASSERT(items_equal(parts->at(0), StrFromC("")));
1057 ASSERT(items_equal(parts->at(1), StrFromC("#")));
1058 ASSERT(items_equal(parts->at(2), StrFromC("")));
1059 }
1060
1061 {
1062 List<BigStr*>* parts = StrFromC(" #")->split(StrFromC("#"));
1063 ShowList(parts);
1064 ASSERT_EQ(2, len(parts));
1065 ASSERT(items_equal(parts->at(0), StrFromC(" ")));
1066 ASSERT(items_equal(parts->at(1), StrFromC("")));
1067 }
1068
1069 {
1070 List<BigStr*>* parts = StrFromC("# #")->split(StrFromC("#"));
1071 ShowList(parts);
1072 ASSERT_EQ(3, len(parts));
1073 ASSERT(items_equal(parts->at(0), StrFromC("")));
1074 ASSERT(items_equal(parts->at(1), StrFromC(" ")));
1075 ASSERT(items_equal(parts->at(2), StrFromC("")));
1076 }
1077
1078 {
1079 List<BigStr*>* parts = StrFromC("")->split(StrFromC(" "));
1080 ShowList(parts);
1081 ASSERT_EQ(1, len(parts));
1082 ASSERT(items_equal(parts->at(0), StrFromC("")));
1083 }
1084
1085 {
1086 BigStr* s = StrFromC("a,b,c,d,e,f,g");
1087 List<BigStr*>* parts = s->split(StrFromC(","));
1088 ShowList(parts);
1089 ASSERT_EQ(7, len(parts));
1090 ASSERT(items_equal(parts->at(0), StrFromC("a")));
1091
1092 // ask for 3 splits
1093 parts = s->split(StrFromC(","), 3);
1094 ShowList(parts);
1095 ASSERT_EQ_FMT(4, len(parts), "%d");
1096 ASSERT(items_equal(parts->at(0), StrFromC("a")));
1097 ASSERT(items_equal(parts->at(1), StrFromC("b")));
1098 ASSERT(items_equal(parts->at(2), StrFromC("c")));
1099 ASSERT(items_equal(parts->at(3), StrFromC("d,e,f,g")));
1100
1101 // ask for 0 splits
1102 parts = s->split(StrFromC(","), 0);
1103 ShowList(parts);
1104 ASSERT_EQ(1, len(parts));
1105 // identical objects
1106 ASSERT_EQ(parts->at(0), s);
1107
1108 parts = StrFromC("###")->split(StrFromC("#"), 2);
1109 ShowList(parts);
1110 ASSERT_EQ(3, len(parts));
1111 ASSERT(items_equal(parts->at(0), StrFromC("")));
1112 ASSERT(items_equal(parts->at(1), StrFromC("")));
1113 ASSERT(items_equal(parts->at(2), StrFromC("#")));
1114 }
1115
1116 printf("---------- Done ----------\n");
1117
1118 PASS();
1119}
1120
1121TEST test_str_join() {
1122 printf("\n");
1123
1124 printf("-------- BigStr::join -------\n");
1125
1126 {
1127 BigStr* result = kEmptyString->join(Alloc<List<BigStr*>>());
1128 ShowString(result);
1129 ASSERT(items_equal(kEmptyString, result));
1130 ASSERT_EQ(kEmptyString, result); // pointers equal
1131 }
1132
1133 {
1134 BigStr* result = StrFromC("anything")->join(Alloc<List<BigStr*>>());
1135 ShowString(result);
1136 ASSERT(items_equal(kEmptyString, result));
1137 ASSERT_EQ(kEmptyString, result); // pointers equal
1138 }
1139
1140 {
1141 BigStr* one_string = StrFromC("one string");
1142 // NewList avoids std::initializer_list()
1143 BigStr* result = StrFromC("anything")->join(NewList<BigStr*>({one_string}));
1144 ShowString(result);
1145 ASSERT(items_equal(one_string, result));
1146 ASSERT_EQ(one_string, result); // pointers equal
1147 }
1148
1149 {
1150 BigStr* result = kEmptyString->join(
1151 NewList<BigStr*>({StrFromC("abc"), StrFromC("def")}));
1152 ShowString(result);
1153 ASSERT(items_equal(result, StrFromC("abcdef")));
1154 }
1155 {
1156 BigStr* result = (StrFromC(" "))
1157 ->join(NewList<BigStr*>(
1158 {StrFromC("abc"), StrFromC("def"), StrFromC("abc"),
1159 StrFromC("def"), StrFromC("abc"), StrFromC("def"),
1160 StrFromC("abc"), StrFromC("def")}));
1161 ShowString(result);
1162 ASSERT(items_equal(result, StrFromC("abc def abc def abc def abc def")));
1163 }
1164
1165 printf("---------- Done ----------\n");
1166
1167 PASS();
1168}
1169
1170TEST test_str_format() {
1171 // check trivial case
1172 ASSERT(str_equals(StrFromC("foo"), StrFormat("foo")));
1173
1174 // check %s
1175 ASSERT(str_equals(StrFromC("foo"), StrFormat("%s", StrFromC("foo"))));
1176 ASSERT(str_equals(StrFromC(" foo"),
1177 StrFormat("%17s", StrFromC("foo"))));
1178 ASSERT(str_equals(StrFromC("foo"), StrFormat("foo%s", StrFromC(""))));
1179
1180 // check that NUL bytes are preserved
1181 ASSERT(str_equals(StrFromC("foo b\0ar", 8),
1182 StrFormat("foo %s", StrFromC("b\0ar", 4))));
1183 ASSERT(str_equals(StrFromC("foo\0bar", 7),
1184 StrFormat(StrFromC("foo\0%s", 6), StrFromC("bar"))));
1185
1186 // check %d
1187 ASSERT(str_equals(StrFromC("12345"), StrFormat("%d", 12345)));
1188 ASSERT(str_equals(StrFromC(" 12345"), StrFormat("%17d", 12345)));
1189 ASSERT(str_equals(StrFromC("00000000000012345"), StrFormat("%017d", 12345)));
1190
1191 // check %o
1192 ASSERT(str_equals(StrFromC("30071"), StrFormat("%o", 12345)));
1193 ASSERT(str_equals(StrFromC(" 30071"), StrFormat("%17o", 12345)));
1194 ASSERT(str_equals(StrFromC("00000000000030071"), StrFormat("%017o", 12345)));
1195
1196 // check that %% escape works
1197 ASSERT(str_equals(StrFromC("%12345"), StrFormat("%%%d", 12345)));
1198 ASSERT(str_equals(StrFromC("%12345%%"), StrFormat("%%%d%%%%", 12345)));
1199
1200 // check that operators can be combined
1201 ASSERT(str_equals(StrFromC("ABC 1234DfooEF"),
1202 StrFormat("ABC%10dD%sEF", 1234, StrFromC("foo"))));
1203
1204 // check StrFormat(char*) == StrFormat(BigStr*)
1205 ASSERT(str_equals(StrFormat("%10d%s", 1234, StrFromC("foo")),
1206 StrFormat(StrFromC("%10d%s"), 1234, StrFromC("foo"))));
1207
1208 // check that %r behaves like repr()
1209 ASSERT(str_equals0("''", StrFormat("%r", kEmptyString)));
1210 ASSERT(str_equals0("\"'\"", StrFormat("%r", StrFromC("'"))));
1211 ASSERT(str_equals0("\"'single'\"", StrFormat("%r", StrFromC("'single'"))));
1212 ASSERT(str_equals0("'\"double\"'", StrFormat("%r", StrFromC("\"double\""))));
1213 ASSERT(str_equals0("'NUL \\x00 NUL'",
1214 StrFormat("%r", StrFromC("NUL \x00 NUL", 9))));
1215 ASSERT(str_equals0("'tab\\tline\\nline\\r\\n'",
1216 StrFormat("%r", StrFromC("tab\tline\nline\r\n"))));
1217 ASSERT(str_equals0("'high \\xff \\xfe high'",
1218 StrFormat("%r", StrFromC("high \xFF \xFE high"))));
1219
1220 // check that justification can be set with -
1221 ASSERT(str_equals0("foo ", StrFormat("%-5s", StrFromC("foo"))));
1222 ASSERT(str_equals0(" bar", StrFormat("%5s", StrFromC("bar"))));
1223
1224 PASS();
1225}
1226
1227// a very innovative hash function
1228unsigned coffee_hash(const char*, int) {
1229 return 0xc0ffeeu;
1230}
1231
1232TEST test_str_hash() {
1233 BigStr* s1 = StrFromC("a string");
1234 BigStr* s2 = StrFromC("a different string");
1235 unsigned h1 = s1->hash(fnv1);
1236 unsigned h2 = s2->hash(fnv1);
1237 ASSERT(h1 != h2);
1238
1239 // flag bit should be set and we should return the cached hash.
1240 ASSERT_EQ(h1, s1->hash(coffee_hash));
1241 ASSERT_EQ(h2, s2->hash(coffee_hash));
1242
1243 PASS();
1244}
1245
1246GLOBAL_STR(kStrFoo, "foo");
1247GLOBAL_STR(a, "a");
1248GLOBAL_STR(XX, "XX");
1249
1250TEST str_replace_test() {
1251 BigStr* o = nullptr;
1252 BigStr* _12 = nullptr;
1253 BigStr* _123 = nullptr;
1254 BigStr* s = nullptr;
1255 BigStr* foxo = nullptr;
1256 BigStr* expected = nullptr;
1257 StackRoots _roots({&o, &_12, &_123, &s, &foxo, &expected});
1258
1259 o = StrFromC("o");
1260 _12 = StrFromC("12");
1261 _123 = StrFromC("123");
1262
1263 s = kStrFood->replace(o, _12);
1264 ASSERT(str_equals0("f1212d", s));
1265 print(s);
1266
1267 s = kStrFoo->replace(o, _123);
1268 ASSERT(str_equals0("f123123", s));
1269 print(s);
1270
1271 foxo = StrFromC("foxo");
1272 s = foxo->replace(o, _123);
1273 ASSERT(str_equals0("f123x123", s));
1274 print(s);
1275
1276 s = kWithNull->replace(a, XX);
1277 print(s);
1278
1279 // Explicit length because of \0
1280 expected = StrFromC("foo\0bXXr", 8);
1281 ASSERT(str_equals(expected, s));
1282
1283 PASS();
1284}
1285
1286void Print(List<BigStr*>* parts) {
1287 log("---");
1288 log("len = %d", len(parts));
1289 for (int i = 0; i < len(parts); ++i) {
1290 printf("%d [", i);
1291 BigStr* s = parts->at(i);
1292 int n = len(s);
1293 fwrite(s->data_, sizeof(char), n, stdout);
1294 fputs("]\n", stdout);
1295 }
1296}
1297
1298TEST str_split_test() {
1299 BigStr* s = nullptr;
1300 BigStr* sep = nullptr;
1301 List<BigStr*>* parts = nullptr;
1302
1303 StackRoots _roots({&s, &sep, &parts});
1304 sep = StrFromC(":");
1305
1306 parts = kEmptyString->split(sep);
1307 ASSERT_EQ(1, len(parts));
1308 Print(parts);
1309
1310 s = StrFromC(":");
1311 parts = s->split(sep);
1312 ASSERT_EQ_FMT(2, len(parts), "%d");
1313 ASSERT(str_equals(kEmptyString, parts->at(0)));
1314 ASSERT(str_equals(kEmptyString, parts->at(1)));
1315 Print(parts);
1316
1317 s = StrFromC("::");
1318 parts = s->split(sep);
1319 ASSERT_EQ(3, len(parts));
1320 ASSERT(str_equals(kEmptyString, parts->at(0)));
1321 ASSERT(str_equals(kEmptyString, parts->at(1)));
1322 ASSERT(str_equals(kEmptyString, parts->at(2)));
1323 Print(parts);
1324
1325 s = StrFromC("a:b");
1326 parts = s->split(sep);
1327 ASSERT_EQ(2, len(parts));
1328 Print(parts);
1329 ASSERT(str_equals0("a", parts->at(0)));
1330 ASSERT(str_equals0("b", parts->at(1)));
1331
1332 s = StrFromC("abc:def:");
1333 parts = s->split(sep);
1334 ASSERT_EQ(3, len(parts));
1335 Print(parts);
1336 ASSERT(str_equals0("abc", parts->at(0)));
1337 ASSERT(str_equals0("def", parts->at(1)));
1338 ASSERT(str_equals(kEmptyString, parts->at(2)));
1339
1340 s = StrFromC(":abc:def:");
1341 parts = s->split(sep);
1342 ASSERT_EQ(4, len(parts));
1343 Print(parts);
1344
1345 s = StrFromC("abc:def:ghi");
1346 parts = s->split(sep);
1347 ASSERT_EQ(3, len(parts));
1348 Print(parts);
1349
1350 PASS();
1351}
1352
1353TEST str_methods_test() {
1354 log("char funcs");
1355 ASSERT(!(StrFromC(""))->isupper());
1356 ASSERT(!(StrFromC("a"))->isupper());
1357 ASSERT((StrFromC("A"))->isupper());
1358 ASSERT((StrFromC("AB"))->isupper());
1359
1360 ASSERT((StrFromC("abc"))->isalpha());
1361 ASSERT((StrFromC("3"))->isdigit());
1362 ASSERT(!(StrFromC(""))->isdigit());
1363
1364 log("slice()");
1365 ASSERT(str_equals0("f", kStrFood->at(0)));
1366
1367 ASSERT(str_equals0("d", kStrFood->at(-1)));
1368
1369 ASSERT(str_equals0("ood", kStrFood->slice(1)));
1370 ASSERT(str_equals0("oo", kStrFood->slice(1, 3)));
1371 ASSERT(str_equals0("oo", kStrFood->slice(1, -1)));
1372 ASSERT(str_equals0("o", kStrFood->slice(-3, -2)));
1373 ASSERT(str_equals0("fo", kStrFood->slice(-4, -2)));
1374
1375 BigStr* input = nullptr;
1376 BigStr* arg = nullptr;
1377 BigStr* expected = nullptr;
1378 BigStr* result = nullptr;
1379 StackRoots _roots({&input, &arg, &expected, &result});
1380
1381 log("startswith endswith");
1382
1383 // arg needs to be separate here because order of evaluation isn't defined!!!
1384 // CRASHES:
1385 // ASSERT(input->startswith(StrFromC("ab")));
1386 // Will this because a problem for mycpp? I think you have to detect this
1387 // case:
1388 // f(Alloc<Foo>(), new Alloc<Bar>())
1389 // Allocation can't happen INSIDE an arg list.
1390
1391 input = StrFromC("abc");
1392 ASSERT(input->startswith(kEmptyString));
1393 ASSERT(input->endswith(kEmptyString));
1394
1395 ASSERT(input->startswith(input));
1396 ASSERT(input->endswith(input));
1397
1398 arg = StrFromC("ab");
1399 ASSERT(input->startswith(arg));
1400 ASSERT(!input->endswith(arg));
1401
1402 arg = StrFromC("bc");
1403 ASSERT(!input->startswith(arg));
1404 ASSERT(input->endswith(arg));
1405
1406 log("rjust() and ljust()");
1407 input = StrFromC("13");
1408 ASSERT(str_equals0(" 13", input->rjust(4, kSpace)));
1409 ASSERT(str_equals0(" 13", input->rjust(3, kSpace)));
1410 ASSERT(str_equals0("13", input->rjust(2, kSpace)));
1411 ASSERT(str_equals0("13", input->rjust(1, kSpace)));
1412
1413 ASSERT(str_equals0("13 ", input->ljust(4, kSpace)));
1414 ASSERT(str_equals0("13 ", input->ljust(3, kSpace)));
1415 ASSERT(str_equals0("13", input->ljust(2, kSpace)));
1416 ASSERT(str_equals0("13", input->ljust(1, kSpace)));
1417
1418 log("join()");
1419
1420 List<BigStr*>* L1 = nullptr;
1421 List<BigStr*>* L2 = nullptr;
1422 List<BigStr*>* empty_list = nullptr;
1423 StackRoots _roots2({&L1, &L2, &empty_list});
1424
1425 L1 = NewList<BigStr*>(std::initializer_list<BigStr*>{kStrFood, kStrFoo});
1426
1427 // Join by empty string
1428 ASSERT(str_equals0("foodfoo", kEmptyString->join(L1)));
1429
1430 // Join by NUL
1431 expected = StrFromC("food\0foo", 8);
1432 arg = StrFromC("\0", 1);
1433 result = arg->join(L1);
1434 ASSERT(str_equals(expected, result));
1435
1436 // Singleton list
1437 L2 = NewList<BigStr*>(std::initializer_list<BigStr*>{kStrFoo});
1438 ASSERT(str_equals0("foo", kEmptyString->join(L2)));
1439
1440 // Empty list
1441 empty_list = NewList<BigStr*>(std::initializer_list<BigStr*>{});
1442
1443 result = kEmptyString->join(empty_list);
1444 ASSERT(str_equals(kEmptyString, result));
1445 ASSERT_EQ(0, len(result));
1446
1447 result = kSpace->join(empty_list);
1448 ASSERT(str_equals(kEmptyString, result));
1449 ASSERT_EQ(0, len(result));
1450
1451 PASS();
1452}
1453
1454TEST str_funcs_test() {
1455 BigStr* s = nullptr;
1456
1457 log("ord()");
1458 s = StrFromC("A");
1459 print(repr(s));
1460 ASSERT_EQ(65, ord(s));
1461
1462 log("chr()");
1463 ASSERT(str_equals(s, chr(65)));
1464
1465 log("str_concat()");
1466 ASSERT(str_equals0("foodfood", str_concat(kStrFood, kStrFood)));
1467 ASSERT(str_equals(kEmptyString, str_concat(kEmptyString, kEmptyString)));
1468
1469 log("str_repeat()");
1470
1471 // -1 is allowed by Python and used by Oil!
1472 s = StrFromC("abc");
1473 ASSERT(str_equals(kEmptyString, str_repeat(s, -1)));
1474 ASSERT(str_equals(kEmptyString, str_repeat(s, 0)));
1475
1476 ASSERT(str_equals(s, str_repeat(s, 1)));
1477
1478 ASSERT(str_equals0("abcabcabc", str_repeat(s, 3)));
1479
1480 log("repr()");
1481
1482 s = kEmptyString;
1483 print(repr(s));
1484 ASSERT(str_equals0("''", repr(s)));
1485
1486 s = StrFromC("'");
1487 print(repr(s));
1488 ASSERT(str_equals0("\"'\"", repr(s)));
1489
1490 s = StrFromC("'single'");
1491 ASSERT(str_equals0("\"'single'\"", repr(s)));
1492
1493 s = StrFromC("\"double\"");
1494 ASSERT(str_equals0("'\"double\"'", repr(s)));
1495
1496 // this one is truncated
1497 s = StrFromC("NUL \x00 NUL", 9);
1498 print(repr(s));
1499 ASSERT(str_equals0("'NUL \\x00 NUL'", repr(s)));
1500
1501 s = StrFromC("tab\tline\nline\r\n");
1502 print(repr(s));
1503 ASSERT(str_equals0("'tab\\tline\\nline\\r\\n'", repr(s)));
1504
1505 s = StrFromC("high \xFF \xFE high");
1506 print(repr(s));
1507 ASSERT(str_equals0("'high \\xff \\xfe high'", repr(s)));
1508
1509 PASS();
1510}
1511
1512TEST str_iters_test() {
1513 for (StrIter it(kStrFood); !it.Done(); it.Next()) {
1514 print(it.Value());
1515 }
1516
1517 PASS();
1518}
1519
1520// Also see mycpp/small_str_test.cc
1521TEST small_big_test() {
1522 // TODO:
1523 // Need GC rooting for these values
1524 // Make len() work
1525
1526 Str s(StrFromC("hello"));
1527 for (int i = 0; i < len(s); ++i) {
1528 Str ch = s.at(i);
1529 log("s[%d] = %s", i, ch.data());
1530 }
1531
1532 PASS();
1533}
1534
1535GREATEST_MAIN_DEFS();
1536
1537int main(int argc, char** argv) {
1538 gHeap.Init();
1539
1540 GREATEST_MAIN_BEGIN();
1541
1542 RUN_TEST(test_str_gc_header);
1543 RUN_TEST(test_str_creation);
1544
1545 // Members
1546 RUN_TEST(test_str_find);
1547 RUN_TEST(test_str_strip);
1548 RUN_TEST(test_rstrip);
1549 RUN_TEST(test_str_upper_lower);
1550 RUN_TEST(test_str_replace);
1551 RUN_TEST(test_str_just);
1552 RUN_TEST(test_str_slice);
1553
1554 // Free functions
1555 RUN_TEST(test_str_concat);
1556 RUN_TEST(test_str_to_int);
1557 RUN_TEST(test_str_contains);
1558
1559 RUN_TEST(test_str_startswith);
1560
1561 RUN_TEST(test_str_split);
1562 RUN_TEST(test_str_join);
1563
1564 RUN_TEST(test_str_format);
1565
1566 RUN_TEST(test_str_hash);
1567
1568 // Duplicate
1569 RUN_TEST(str_replace_test);
1570 RUN_TEST(str_split_test);
1571
1572 RUN_TEST(str_methods_test);
1573 RUN_TEST(str_funcs_test);
1574 RUN_TEST(str_iters_test);
1575
1576 RUN_TEST(small_big_test);
1577
1578 gHeap.CleanProcessExit();
1579
1580 GREATEST_MAIN_END();
1581 return 0;
1582}