OILS / mycpp / gc_str_test.cc View on Github | oilshell.org

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