diff options
Diffstat (limited to 'libgo/go/strings/strings_test.go')
-rw-r--r-- | libgo/go/strings/strings_test.go | 182 |
1 files changed, 166 insertions, 16 deletions
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index fcef761da79..449fb502d64 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -6,9 +6,11 @@ package strings_test import ( "bytes" + "fmt" "io" "math/rand" "reflect" + "runtime" . "strings" "testing" "unicode" @@ -86,32 +88,44 @@ var indexTests = []IndexTest{ {"32145678", "01234567", -1}, {"01234567", "01234567", 0}, {"x01234567", "01234567", 1}, + {"x0123456x01234567", "01234567", 9}, {"xx01234567"[:9], "01234567", -1}, {"", "0123456789", -1}, {"3214567844", "0123456789", -1}, {"0123456789", "0123456789", 0}, {"x0123456789", "0123456789", 1}, + {"x012345678x0123456789", "0123456789", 11}, {"xyz0123456789"[:12], "0123456789", -1}, {"x01234567x89", "0123456789", -1}, {"", "0123456789012345", -1}, {"3214567889012345", "0123456789012345", -1}, {"0123456789012345", "0123456789012345", 0}, {"x0123456789012345", "0123456789012345", 1}, + {"x012345678901234x0123456789012345", "0123456789012345", 17}, {"", "01234567890123456789", -1}, {"32145678890123456789", "01234567890123456789", -1}, {"01234567890123456789", "01234567890123456789", 0}, {"x01234567890123456789", "01234567890123456789", 1}, + {"x0123456789012345678x01234567890123456789", "01234567890123456789", 21}, {"xyz01234567890123456789"[:22], "01234567890123456789", -1}, {"", "0123456789012345678901234567890", -1}, {"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1}, {"0123456789012345678901234567890", "0123456789012345678901234567890", 0}, {"x0123456789012345678901234567890", "0123456789012345678901234567890", 1}, + {"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32}, {"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1}, {"", "01234567890123456789012345678901", -1}, {"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1}, {"01234567890123456789012345678901", "01234567890123456789012345678901", 0}, {"x01234567890123456789012345678901", "01234567890123456789012345678901", 1}, + {"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33}, {"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1}, + {"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6}, + {"", "0123456789012345678901234567890123456789", -1}, + {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2}, + {"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1}, + {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1}, + {"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65}, } var lastIndexTests = []IndexTest{ @@ -139,10 +153,15 @@ var indexAnyTests = []IndexTest{ {"aaa", "a", 0}, {"abc", "xyz", -1}, {"abc", "xcz", 2}, - {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")}, + {"ab☺c", "x☺yz", 2}, + {"a☺b☻c☹d", "cx", len("a☺b☻")}, + {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")}, {"aRegExp*", ".(|)*+?^$[]", 7}, {dots + dots + dots, " ", -1}, + {"012abcba210", "\xffb", 4}, + {"012\x80bcb\x80210", "\xffb", 3}, } + var lastIndexAnyTests = []IndexTest{ {"", "", -1}, {"", "a", -1}, @@ -152,9 +171,13 @@ var lastIndexAnyTests = []IndexTest{ {"aaa", "a", 2}, {"abc", "xyz", -1}, {"abc", "ab", 1}, - {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")}, + {"ab☺c", "x☺yz", 2}, + {"a☺b☻c☹d", "cx", len("a☺b☻")}, + {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")}, {"a.RegExp*", ".(|)*+?^$[]", 8}, {dots + dots + dots, " ", -1}, + {"012abcba210", "\xffb", 6}, + {"012\x80bcb\x80210", "\xffb", 7}, } // Execute f on each test case. funcName should be the name of f; it's used @@ -227,22 +250,56 @@ func TestIndexRandom(t *testing.T) { } } -var indexRuneTests = []struct { - s string - rune rune - out int -}{ - {"a A x", 'A', 2}, - {"some_text=some_value", '=', 9}, - {"☺a", 'a', 3}, - {"a☻☺b", '☺', 4}, -} - func TestIndexRune(t *testing.T) { - for _, test := range indexRuneTests { - if actual := IndexRune(test.s, test.rune); actual != test.out { - t.Errorf("IndexRune(%q,%d)= %v; want %v", test.s, test.rune, actual, test.out) + tests := []struct { + in string + rune rune + want int + }{ + {"", 'a', -1}, + {"", '☺', -1}, + {"foo", '☹', -1}, + {"foo", 'o', 1}, + {"foo☺bar", '☺', 3}, + {"foo☺☻☹bar", '☹', 9}, + {"a A x", 'A', 2}, + {"some_text=some_value", '=', 9}, + {"☺a", 'a', 3}, + {"a☻☺b", '☺', 4}, + + // RuneError should match any invalid UTF-8 byte sequence. + {"�", '�', 0}, + {"\xff", '�', 0}, + {"☻x�", '�', len("☻x")}, + {"☻x\xe2\x98", '�', len("☻x")}, + {"☻x\xe2\x98�", '�', len("☻x")}, + {"☻x\xe2\x98x", '�', len("☻x")}, + + // Invalid rune values should never match. + {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1}, + {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair + {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1}, + } + for _, tt := range tests { + if got := IndexRune(tt.in, tt.rune); got != tt.want { + t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want) + } + } + + haystack := "test世界" + allocs := testing.AllocsPerRun(1000, func() { + if i := IndexRune(haystack, 's'); i != 2 { + t.Fatalf("'s' at %d; want 2", i) + } + if i := IndexRune(haystack, '世'); i != 4 { + t.Fatalf("'世' at %d; want 4", i) } + }) + if runtime.Compiler == "gccgo" { + t.Skip("skipping allocations test for gccgo until escape analysis is enabled") + } + if allocs != 0 && testing.CoverMode() == "" { + t.Errorf("expected no allocations, got %f", allocs) } } @@ -257,6 +314,17 @@ func BenchmarkIndexRune(b *testing.B) { } } +var benchmarkLongString = Repeat(" ", 100) + benchmarkString + +func BenchmarkIndexRuneLongString(b *testing.B) { + if got := IndexRune(benchmarkLongString, '☺'); got != 114 { + b.Fatalf("wrong index: expected 114, got=%d", got) + } + for i := 0; i < b.N; i++ { + IndexRune(benchmarkLongString, '☺') + } +} + func BenchmarkIndexRuneFastPath(b *testing.B) { if got := IndexRune(benchmarkString, 'v'); got != 17 { b.Fatalf("wrong index: expected 17, got=%d", got) @@ -613,6 +681,9 @@ var trimTests = []struct { {"Trim", "* listitem", " *", "listitem"}, {"Trim", `"quote"`, `"`, "quote"}, {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"}, + {"Trim", "\x80test\xff", "\xff", "test"}, + {"Trim", " Ġ ", " ", "Ġ"}, + {"Trim", " Ġİ0", "0 ", "Ġİ"}, //empty string tests {"Trim", "abba", "", "abba"}, {"Trim", "", "123", ""}, @@ -855,6 +926,54 @@ func TestRepeat(t *testing.T) { } } +func repeat(s string, count int) (err error) { + defer func() { + if r := recover(); r != nil { + switch v := r.(type) { + case error: + err = v + default: + err = fmt.Errorf("%s", v) + } + } + }() + + Repeat(s, count) + + return +} + +// See Issue golang.org/issue/16237 +func TestRepeatCatchesOverflow(t *testing.T) { + tests := [...]struct { + s string + count int + errStr string + }{ + 0: {"--", -2147483647, "negative"}, + 1: {"", int(^uint(0) >> 1), ""}, + 2: {"-", 10, ""}, + 3: {"gopher", 0, ""}, + 4: {"-", -1, "negative"}, + 5: {"--", -102, "negative"}, + 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"}, + } + + for i, tt := range tests { + err := repeat(tt.s, tt.count) + if tt.errStr == "" { + if err != nil { + t.Errorf("#%d panicked %v", i, err) + } + continue + } + + if err == nil || !Contains(err.Error(), tt.errStr) { + t.Errorf("#%d expected %q got %q", i, tt.errStr, err) + } + } +} + func runesEqual(a, b []rune) bool { if len(a) != len(b) { return false @@ -1290,6 +1409,9 @@ func benchmarkCountHard(b *testing.B, sep string) { func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, "<>") } func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, "</pre>") } func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, "<b>hello world</b>") } +func BenchmarkIndexHard4(b *testing.B) { + benchmarkIndexHard(b, "<pre><b>hello</b><strong>world</strong></pre>") +} func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, "<>") } func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, "</pre>") } @@ -1381,3 +1503,31 @@ func BenchmarkRepeat(b *testing.B) { Repeat("-", 80) } } + +func BenchmarkIndexAnyASCII(b *testing.B) { + x := Repeat("#", 4096) // Never matches set + cs := "0123456789abcdef" + for k := 1; k <= 4096; k <<= 4 { + for j := 1; j <= 16; j <<= 1 { + b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { + for i := 0; i < b.N; i++ { + IndexAny(x[:k], cs[:j]) + } + }) + } + } +} + +func BenchmarkTrimASCII(b *testing.B) { + cs := "0123456789abcdef" + for k := 1; k <= 4096; k <<= 4 { + for j := 1; j <= 16; j <<= 1 { + b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { + x := Repeat(cs[:j], k) // Always matches set + for i := 0; i < b.N; i++ { + Trim(x[:k], cs[:j]) + } + }) + } + } +} |