diff options
Diffstat (limited to 'libgo/go/bytes/bytes_test.go')
-rw-r--r-- | libgo/go/bytes/bytes_test.go | 194 |
1 files changed, 178 insertions, 16 deletions
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index c48f662e10d..26eac5e08c6 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -7,8 +7,10 @@ package bytes_test import ( . "bytes" "fmt" + "internal/testenv" "math/rand" "reflect" + "strings" "testing" "unicode" "unicode/utf8" @@ -165,8 +167,12 @@ var indexAnyTests = []BinOpTest{ {"abc", "xyz", -1}, {"abc", "xcz", 2}, {"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 = []BinOpTest{ @@ -178,18 +184,13 @@ var lastIndexAnyTests = []BinOpTest{ {"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}, -} - -var indexRuneTests = []BinOpTest{ - {"", "a", -1}, - {"", "☺", -1}, - {"foo", "☹", -1}, - {"foo", "o", 1}, - {"foo☺bar", "☺", 3}, - {"foo☺☻☹bar", "☹", 9}, + {"012abcba210", "\xffb", 6}, + {"012\x80bcb\x80210", "\xffb", 7}, } // Execute f on each test case. funcName should be the name of f; it's used @@ -346,13 +347,52 @@ func TestIndexByteSmall(t *testing.T) { } func TestIndexRune(t *testing.T) { - for _, tt := range indexRuneTests { - a := []byte(tt.a) - r, _ := utf8.DecodeRuneInString(tt.b) - pos := IndexRune(a, r) - if pos != tt.i { - t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos) + 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([]byte(tt.in), tt.rune); got != tt.want { + t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want) + } + } + + haystack := []byte("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 allocs != 0 { + t.Errorf("expected no allocations, got %f", allocs) } } @@ -370,6 +410,9 @@ func valName(x int) string { func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) { for _, n := range sizes { + if isRaceBuilder && n > 4<<10 { + continue + } b.Run(valName(n), func(b *testing.B) { if len(bmbuf) < n { bmbuf = make([]byte, n) @@ -382,6 +425,8 @@ func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) { var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20} +var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race") + func BenchmarkIndexByte(b *testing.B) { benchBytes(b, indexSizes, bmIndexByte(IndexByte)) } @@ -404,6 +449,44 @@ func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) { } } +func BenchmarkIndexRune(b *testing.B) { + benchBytes(b, indexSizes, bmIndexRune(IndexRune)) +} + +func BenchmarkIndexRuneASCII(b *testing.B) { + benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune)) +} + +func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) { + return func(b *testing.B, n int) { + buf := bmbuf[0:n] + buf[n-1] = 'x' + for i := 0; i < b.N; i++ { + j := index(buf, 'x') + if j != n-1 { + b.Fatal("bad index", j) + } + } + buf[n-1] = '\x00' + } +} + +func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) { + return func(b *testing.B, n int) { + buf := bmbuf[0:n] + utf8.EncodeRune(buf[n-3:], '世') + for i := 0; i < b.N; i++ { + j := index(buf, '世') + if j != n-3 { + b.Fatal("bad index", j) + } + } + buf[n-3] = '\x00' + buf[n-2] = '\x00' + buf[n-1] = '\x00' + } +} + func BenchmarkEqual(b *testing.B) { b.Run("0", func(b *testing.B) { var buf [4]byte @@ -844,6 +927,54 @@ func TestRepeat(t *testing.T) { } } +func repeat(b []byte, 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(b, 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([]byte(tt.s), tt.count) + if tt.errStr == "" { + if err != nil { + t.Errorf("#%d panicked %v", i, err) + } + continue + } + + if err == nil || !strings.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 @@ -906,6 +1037,9 @@ var trimTests = []TrimTest{ {"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", ""}, @@ -1325,3 +1459,31 @@ func BenchmarkBytesCompare(b *testing.B) { }) } } + +func BenchmarkIndexAnyASCII(b *testing.B) { + x := Repeat([]byte{'#'}, 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([]byte(cs[:j]), k) // Always matches set + for i := 0; i < b.N; i++ { + Trim(x[:k], cs[:j]) + } + }) + } + } +} |