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

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