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

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