#include "test.h" void str_init_utf8(struct ct *t) { static char badtail[] = { 'a', (char)0x80 }; static char incomplete[] = { (char)0xea, (char)0xb0 }; static char overlong[] = { (char)0xc0, (char)0xaf }; static char outofrange[] = { (char)0xf4, (char)0x90, (char)0x80, (char)0x80, }; static char surrogate[] = { (char)0xed, (char)0xa0, (char)0x80, }; static char unexpected[] = { (char)0x80 }; static const struct { char *name; char *src; int n; int ok; char *want; } cases[] = { { "canonical Runeerror", "\xef\xbf\xbd", 3, 1, "\xef\xbf\xbd" }, { "incomplete", incomplete, sizeof incomplete, 0, "" }, { "unexpected continuation", unexpected, sizeof unexpected, 0, "" }, { "overlong", overlong, sizeof overlong, 0, "" }, { "surrogate", surrogate, sizeof surrogate, 0, "" }, { "out of range", outofrange, sizeof outofrange, 0, "" }, { "bad tail", badtail, sizeof badtail, 0, "" }, }; char full[Maxrunes+2]; Str s; int i; s = mkstr("A한😀"); CT_EQ_INT(t, 3, s.n); checkstr(t, "round trip", "A한😀", &s); for(i = 0; i < nelem(cases); i++){ memset(&s, 0xa5, sizeof s); if(sinit(&s, cases[i].src, cases[i].n) != cases[i].ok) CT_ERRORF(t, "%s: wrong validity", cases[i].name); checkstr(t, cases[i].name, cases[i].want, &s); } memset(full, 'a', sizeof full); full[sizeof full-1] = '\0'; CT_CHECK(t, !sinit(&s, full, strlen(full))); CT_EQ_INT(t, 0, s.n); } void str_edit_and_alias(struct ct *t) { Str s; int i; s = mkstr("ab"); sappend(&s, &s); checkstr(t, "self append", "abab", &s); for(i = 0; i < 40; i++) s.r[i] = 'a' + i % 26; s.n = 40; sappend(&s, &s); CT_EQ_INT(t, Maxrunes, s.n); for(i = 0; i < 24; i++) if(s.r[40+i] != s.r[i]) CT_ERRORF(t, "capped self append differs at rune %d", i); } void str_utf8_capacity(struct ct *t) { static const struct { int size; int n; char *want; } cases[] = { { 0, 0, nil }, { 1, 0, "" }, { 2, 1, "a" }, { 3, 1, "a" }, { 4, 1, "a" }, { 5, 4, "a한" }, { 6, 5, "a한b" }, }; char buf[16]; Str s; int i, n; s = mkstr("a한b"); for(i = 0; i < nelem(cases); i++){ memset(buf, 'Z', sizeof buf); n = stoutf(&s, buf, cases[i].size); if(n != cases[i].n) CT_ERRORF(t, "size %d: want length %d, got %d", cases[i].size, cases[i].n, n); if(cases[i].size == 0){ CT_EQ_INT(t, 'Z', buf[0]); continue; } if(strcmp(cases[i].want, buf) != 0) CT_ERRORF(t, "size %d: want \"%s\", got \"%s\"", cases[i].size, cases[i].want, buf); CT_EQ_INT(t, 'Z', buf[cases[i].size]); } s = mkstr("😀"); memset(buf, 'Z', sizeof buf); CT_EQ_INT(t, 0, stoutf(&s, buf, 4)); CT_EQ_STR(t, "", buf); CT_EQ_INT(t, 4, stoutf(&s, buf, 5)); CT_EQ_STR(t, "😀", buf); CT_EQ_INT(t, 'Z', buf[5]); } void str_invalid_and_full_appends(struct ct *t) { Str s; int i; CT_CHECK(t, !sinit(&s, nil, 1)); CT_EQ_INT(t, 0, s.n); CT_CHECK(t, !sinit(&s, "x", -1)); CT_EQ_INT(t, 0, s.n); for(i = 0; i < Maxrunes; i++) s.r[i] = 'a'; s.n = Maxrunes; sputr(&s, 'z'); CT_EQ_INT(t, Maxrunes, s.n); CT_EQ_INT(t, 'a', s.r[Maxrunes-1]); }