Source file
src/bytes/bytes_test.go
1
2
3
4
5 package bytes_test
6
7 import (
8 . "bytes"
9 "fmt"
10 "internal/testenv"
11 "math/rand"
12 "reflect"
13 "strings"
14 "testing"
15 "unicode"
16 "unicode/utf8"
17 )
18
19 func eq(a, b []string) bool {
20 if len(a) != len(b) {
21 return false
22 }
23 for i := 0; i < len(a); i++ {
24 if a[i] != b[i] {
25 return false
26 }
27 }
28 return true
29 }
30
31 func sliceOfString(s [][]byte) []string {
32 result := make([]string, len(s))
33 for i, v := range s {
34 result[i] = string(v)
35 }
36 return result
37 }
38
39
40
41
42 var abcd = "abcd"
43 var faces = "☺☻☹"
44 var commas = "1,2,3,4"
45 var dots = "1....2....3....4"
46
47 type BinOpTest struct {
48 a string
49 b string
50 i int
51 }
52
53 func TestEqual(t *testing.T) {
54
55 allocs := testing.AllocsPerRun(10, func() {
56 for _, tt := range compareTests {
57 eql := Equal(tt.a, tt.b)
58 if eql != (tt.i == 0) {
59 t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
60 }
61 }
62 })
63 if allocs > 0 {
64 t.Errorf("Equal allocated %v times", allocs)
65 }
66 }
67
68 func TestEqualExhaustive(t *testing.T) {
69 var size = 128
70 if testing.Short() {
71 size = 32
72 }
73 a := make([]byte, size)
74 b := make([]byte, size)
75 b_init := make([]byte, size)
76
77 for i := 0; i < size; i++ {
78 a[i] = byte(17 * i)
79 b_init[i] = byte(23*i + 100)
80 }
81
82 for len := 0; len <= size; len++ {
83 for x := 0; x <= size-len; x++ {
84 for y := 0; y <= size-len; y++ {
85 copy(b, b_init)
86 copy(b[y:y+len], a[x:x+len])
87 if !Equal(a[x:x+len], b[y:y+len]) || !Equal(b[y:y+len], a[x:x+len]) {
88 t.Errorf("Equal(%d, %d, %d) = false", len, x, y)
89 }
90 }
91 }
92 }
93 }
94
95
96
97 func TestNotEqual(t *testing.T) {
98 var size = 128
99 if testing.Short() {
100 size = 32
101 }
102 a := make([]byte, size)
103 b := make([]byte, size)
104
105 for len := 0; len <= size; len++ {
106 for x := 0; x <= size-len; x++ {
107 for y := 0; y <= size-len; y++ {
108 for diffpos := x; diffpos < x+len; diffpos++ {
109 a[diffpos] = 1
110 if Equal(a[x:x+len], b[y:y+len]) || Equal(b[y:y+len], a[x:x+len]) {
111 t.Errorf("NotEqual(%d, %d, %d, %d) = true", len, x, y, diffpos)
112 }
113 a[diffpos] = 0
114 }
115 }
116 }
117 }
118 }
119
120 var indexTests = []BinOpTest{
121 {"", "", 0},
122 {"", "a", -1},
123 {"", "foo", -1},
124 {"fo", "foo", -1},
125 {"foo", "baz", -1},
126 {"foo", "foo", 0},
127 {"oofofoofooo", "f", 2},
128 {"oofofoofooo", "foo", 4},
129 {"barfoobarfoo", "foo", 3},
130 {"foo", "", 0},
131 {"foo", "o", 1},
132 {"abcABCabc", "A", 3},
133
134 {"", "a", -1},
135 {"x", "a", -1},
136 {"x", "x", 0},
137 {"abc", "a", 0},
138 {"abc", "b", 1},
139 {"abc", "c", 2},
140 {"abc", "x", -1},
141 {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
142 {"foofyfoobarfoobar", "y", 4},
143 {"oooooooooooooooooooooo", "r", -1},
144 {"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22},
145 {"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1},
146
147 {"000000000000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000001", 5},
148 }
149
150 var lastIndexTests = []BinOpTest{
151 {"", "", 0},
152 {"", "a", -1},
153 {"", "foo", -1},
154 {"fo", "foo", -1},
155 {"foo", "foo", 0},
156 {"foo", "f", 0},
157 {"oofofoofooo", "f", 7},
158 {"oofofoofooo", "foo", 7},
159 {"barfoobarfoo", "foo", 9},
160 {"foo", "", 3},
161 {"foo", "o", 2},
162 {"abcABCabc", "A", 3},
163 {"abcABCabc", "a", 6},
164 }
165
166 var indexAnyTests = []BinOpTest{
167 {"", "", -1},
168 {"", "a", -1},
169 {"", "abc", -1},
170 {"a", "", -1},
171 {"a", "a", 0},
172 {"\x80", "\xffb", 0},
173 {"aaa", "a", 0},
174 {"abc", "xyz", -1},
175 {"abc", "xcz", 2},
176 {"ab☺c", "x☺yz", 2},
177 {"a☺b☻c☹d", "cx", len("a☺b☻")},
178 {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
179 {"aRegExp*", ".(|)*+?^$[]", 7},
180 {dots + dots + dots, " ", -1},
181 {"012abcba210", "\xffb", 4},
182 {"012\x80bcb\x80210", "\xffb", 3},
183 {"0123456\xcf\x80abc", "\xcfb\x80", 10},
184 }
185
186 var lastIndexAnyTests = []BinOpTest{
187 {"", "", -1},
188 {"", "a", -1},
189 {"", "abc", -1},
190 {"a", "", -1},
191 {"a", "a", 0},
192 {"\x80", "\xffb", 0},
193 {"aaa", "a", 2},
194 {"abc", "xyz", -1},
195 {"abc", "ab", 1},
196 {"ab☺c", "x☺yz", 2},
197 {"a☺b☻c☹d", "cx", len("a☺b☻")},
198 {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
199 {"a.RegExp*", ".(|)*+?^$[]", 8},
200 {dots + dots + dots, " ", -1},
201 {"012abcba210", "\xffb", 6},
202 {"012\x80bcb\x80210", "\xffb", 7},
203 {"0123456\xcf\x80abc", "\xcfb\x80", 10},
204 }
205
206
207
208 func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) {
209 for _, test := range testCases {
210 a := []byte(test.a)
211 b := []byte(test.b)
212 actual := f(a, b)
213 if actual != test.i {
214 t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, b, actual, test.i)
215 }
216 }
217 var allocTests = []struct {
218 a []byte
219 b []byte
220 i int
221 }{
222
223 {[]byte("000000000000000000000000000000000000000000000000000000000000000000000001"), []byte("0000000000000000000000000000000000000000000000000000000000000000001"), 5},
224
225 {[]byte("000000000000000000000000000000000000000000000000000000000000000010000"), []byte("00000000000000000000000000000000000000000000000000000000000001"), 3},
226 }
227 allocs := testing.AllocsPerRun(100, func() {
228 if i := Index(allocTests[1].a, allocTests[1].b); i != allocTests[1].i {
229 t.Errorf("Index([]byte(%q), []byte(%q)) = %v; want %v", allocTests[1].a, allocTests[1].b, i, allocTests[1].i)
230 }
231 if i := LastIndex(allocTests[0].a, allocTests[0].b); i != allocTests[0].i {
232 t.Errorf("LastIndex([]byte(%q), []byte(%q)) = %v; want %v", allocTests[0].a, allocTests[0].b, i, allocTests[0].i)
233 }
234 })
235 if allocs != 0 {
236 t.Errorf("expected no allocations, got %f", allocs)
237 }
238 }
239
240 func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) {
241 for _, test := range testCases {
242 a := []byte(test.a)
243 actual := f(a, test.b)
244 if actual != test.i {
245 t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i)
246 }
247 }
248 }
249
250 func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
251 func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
252 func TestIndexAny(t *testing.T) { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) }
253 func TestLastIndexAny(t *testing.T) {
254 runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests)
255 }
256
257 func TestIndexByte(t *testing.T) {
258 for _, tt := range indexTests {
259 if len(tt.b) != 1 {
260 continue
261 }
262 a := []byte(tt.a)
263 b := tt.b[0]
264 pos := IndexByte(a, b)
265 if pos != tt.i {
266 t.Errorf(`IndexByte(%q, '%c') = %v`, tt.a, b, pos)
267 }
268 posp := IndexBytePortable(a, b)
269 if posp != tt.i {
270 t.Errorf(`indexBytePortable(%q, '%c') = %v`, tt.a, b, posp)
271 }
272 }
273 }
274
275 func TestLastIndexByte(t *testing.T) {
276 testCases := []BinOpTest{
277 {"", "q", -1},
278 {"abcdef", "q", -1},
279 {"abcdefabcdef", "a", len("abcdef")},
280 {"abcdefabcdef", "f", len("abcdefabcde")},
281 {"zabcdefabcdef", "z", 0},
282 {"a☺b☻c☹d", "b", len("a☺")},
283 }
284 for _, test := range testCases {
285 actual := LastIndexByte([]byte(test.a), test.b[0])
286 if actual != test.i {
287 t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i)
288 }
289 }
290 }
291
292
293 func TestIndexByteBig(t *testing.T) {
294 var n = 1024
295 if testing.Short() {
296 n = 128
297 }
298 b := make([]byte, n)
299 for i := 0; i < n; i++ {
300
301 b1 := b[i:]
302 for j := 0; j < len(b1); j++ {
303 b1[j] = 'x'
304 pos := IndexByte(b1, 'x')
305 if pos != j {
306 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
307 }
308 b1[j] = 0
309 pos = IndexByte(b1, 'x')
310 if pos != -1 {
311 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
312 }
313 }
314
315 b1 = b[:i]
316 for j := 0; j < len(b1); j++ {
317 b1[j] = 'x'
318 pos := IndexByte(b1, 'x')
319 if pos != j {
320 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
321 }
322 b1[j] = 0
323 pos = IndexByte(b1, 'x')
324 if pos != -1 {
325 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
326 }
327 }
328
329 b1 = b[i/2 : n-(i+1)/2]
330 for j := 0; j < len(b1); j++ {
331 b1[j] = 'x'
332 pos := IndexByte(b1, 'x')
333 if pos != j {
334 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
335 }
336 b1[j] = 0
337 pos = IndexByte(b1, 'x')
338 if pos != -1 {
339 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
340 }
341 }
342 }
343 }
344
345
346 func TestIndexByteSmall(t *testing.T) {
347 b := make([]byte, 5015)
348
349 for i := 0; i <= len(b)-15; i++ {
350 for j := 0; j < 15; j++ {
351 b[i+j] = byte(100 + j)
352 }
353 for j := 0; j < 15; j++ {
354 p := IndexByte(b[i:i+15], byte(100+j))
355 if p != j {
356 t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 100+j, p)
357 }
358 }
359 for j := 0; j < 15; j++ {
360 b[i+j] = 0
361 }
362 }
363
364 for i := 0; i <= len(b)-15; i++ {
365 for j := 0; j < 15; j++ {
366 b[i+j] = 1
367 }
368 for j := 0; j < 15; j++ {
369 p := IndexByte(b[i:i+15], byte(0))
370 if p != -1 {
371 t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 0, p)
372 }
373 }
374 for j := 0; j < 15; j++ {
375 b[i+j] = 0
376 }
377 }
378 }
379
380 func TestIndexRune(t *testing.T) {
381 tests := []struct {
382 in string
383 rune rune
384 want int
385 }{
386 {"", 'a', -1},
387 {"", '☺', -1},
388 {"foo", '☹', -1},
389 {"foo", 'o', 1},
390 {"foo☺bar", '☺', 3},
391 {"foo☺☻☹bar", '☹', 9},
392 {"a A x", 'A', 2},
393 {"some_text=some_value", '=', 9},
394 {"☺a", 'a', 3},
395 {"a☻☺b", '☺', 4},
396
397
398 {"�", '�', 0},
399 {"\xff", '�', 0},
400 {"☻x�", '�', len("☻x")},
401 {"☻x\xe2\x98", '�', len("☻x")},
402 {"☻x\xe2\x98�", '�', len("☻x")},
403 {"☻x\xe2\x98x", '�', len("☻x")},
404
405
406 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1},
407 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1},
408 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1},
409 }
410 for _, tt := range tests {
411 if got := IndexRune([]byte(tt.in), tt.rune); got != tt.want {
412 t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want)
413 }
414 }
415
416 haystack := []byte("test世界")
417 allocs := testing.AllocsPerRun(1000, func() {
418 if i := IndexRune(haystack, 's'); i != 2 {
419 t.Fatalf("'s' at %d; want 2", i)
420 }
421 if i := IndexRune(haystack, '世'); i != 4 {
422 t.Fatalf("'世' at %d; want 4", i)
423 }
424 })
425 if allocs != 0 {
426 t.Errorf("expected no allocations, got %f", allocs)
427 }
428 }
429
430
431 func TestCountByte(t *testing.T) {
432 b := make([]byte, 5015)
433 windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128}
434 testCountWindow := func(i, window int) {
435 for j := 0; j < window; j++ {
436 b[i+j] = byte(100)
437 p := Count(b[i:i+window], []byte{100})
438 if p != j+1 {
439 t.Errorf("TestCountByte.Count(%q, 100) = %d", b[i:i+window], p)
440 }
441 }
442 }
443
444 maxWnd := windows[len(windows)-1]
445
446 for i := 0; i <= 2*maxWnd; i++ {
447 for _, window := range windows {
448 if window > len(b[i:]) {
449 window = len(b[i:])
450 }
451 testCountWindow(i, window)
452 for j := 0; j < window; j++ {
453 b[i+j] = byte(0)
454 }
455 }
456 }
457 for i := 4096 - (maxWnd + 1); i < len(b); i++ {
458 for _, window := range windows {
459 if window > len(b[i:]) {
460 window = len(b[i:])
461 }
462 testCountWindow(i, window)
463 for j := 0; j < window; j++ {
464 b[i+j] = byte(0)
465 }
466 }
467 }
468 }
469
470
471 func TestCountByteNoMatch(t *testing.T) {
472 b := make([]byte, 5015)
473 windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128}
474 for i := 0; i <= len(b); i++ {
475 for _, window := range windows {
476 if window > len(b[i:]) {
477 window = len(b[i:])
478 }
479
480 for j := 0; j < window; j++ {
481 b[i+j] = byte(100)
482 }
483
484 p := Count(b[i:i+window], []byte{0})
485 if p != 0 {
486 t.Errorf("TestCountByteNoMatch(%q, 0) = %d", b[i:i+window], p)
487 }
488 for j := 0; j < window; j++ {
489 b[i+j] = byte(0)
490 }
491 }
492 }
493 }
494
495 var bmbuf []byte
496
497 func valName(x int) string {
498 if s := x >> 20; s<<20 == x {
499 return fmt.Sprintf("%dM", s)
500 }
501 if s := x >> 10; s<<10 == x {
502 return fmt.Sprintf("%dK", s)
503 }
504 return fmt.Sprint(x)
505 }
506
507 func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) {
508 for _, n := range sizes {
509 if isRaceBuilder && n > 4<<10 {
510 continue
511 }
512 b.Run(valName(n), func(b *testing.B) {
513 if len(bmbuf) < n {
514 bmbuf = make([]byte, n)
515 }
516 b.SetBytes(int64(n))
517 f(b, n)
518 })
519 }
520 }
521
522 var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20}
523
524 var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race")
525
526 func BenchmarkIndexByte(b *testing.B) {
527 benchBytes(b, indexSizes, bmIndexByte(IndexByte))
528 }
529
530 func BenchmarkIndexBytePortable(b *testing.B) {
531 benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable))
532 }
533
534 func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) {
535 return func(b *testing.B, n int) {
536 buf := bmbuf[0:n]
537 buf[n-1] = 'x'
538 for i := 0; i < b.N; i++ {
539 j := index(buf, 'x')
540 if j != n-1 {
541 b.Fatal("bad index", j)
542 }
543 }
544 buf[n-1] = '\x00'
545 }
546 }
547
548 func BenchmarkIndexRune(b *testing.B) {
549 benchBytes(b, indexSizes, bmIndexRune(IndexRune))
550 }
551
552 func BenchmarkIndexRuneASCII(b *testing.B) {
553 benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune))
554 }
555
556 func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) {
557 return func(b *testing.B, n int) {
558 buf := bmbuf[0:n]
559 buf[n-1] = 'x'
560 for i := 0; i < b.N; i++ {
561 j := index(buf, 'x')
562 if j != n-1 {
563 b.Fatal("bad index", j)
564 }
565 }
566 buf[n-1] = '\x00'
567 }
568 }
569
570 func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) {
571 return func(b *testing.B, n int) {
572 buf := bmbuf[0:n]
573 utf8.EncodeRune(buf[n-3:], '世')
574 for i := 0; i < b.N; i++ {
575 j := index(buf, '世')
576 if j != n-3 {
577 b.Fatal("bad index", j)
578 }
579 }
580 buf[n-3] = '\x00'
581 buf[n-2] = '\x00'
582 buf[n-1] = '\x00'
583 }
584 }
585
586 func BenchmarkEqual(b *testing.B) {
587 b.Run("0", func(b *testing.B) {
588 var buf [4]byte
589 buf1 := buf[0:0]
590 buf2 := buf[1:1]
591 for i := 0; i < b.N; i++ {
592 eq := Equal(buf1, buf2)
593 if !eq {
594 b.Fatal("bad equal")
595 }
596 }
597 })
598
599 sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20}
600 benchBytes(b, sizes, bmEqual(Equal))
601 }
602
603 func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
604 return func(b *testing.B, n int) {
605 if len(bmbuf) < 2*n {
606 bmbuf = make([]byte, 2*n)
607 }
608 buf1 := bmbuf[0:n]
609 buf2 := bmbuf[n : 2*n]
610 buf1[n-1] = 'x'
611 buf2[n-1] = 'x'
612 for i := 0; i < b.N; i++ {
613 eq := equal(buf1, buf2)
614 if !eq {
615 b.Fatal("bad equal")
616 }
617 }
618 buf1[n-1] = '\x00'
619 buf2[n-1] = '\x00'
620 }
621 }
622
623 func BenchmarkIndex(b *testing.B) {
624 benchBytes(b, indexSizes, func(b *testing.B, n int) {
625 buf := bmbuf[0:n]
626 buf[n-1] = 'x'
627 for i := 0; i < b.N; i++ {
628 j := Index(buf, buf[n-7:])
629 if j != n-7 {
630 b.Fatal("bad index", j)
631 }
632 }
633 buf[n-1] = '\x00'
634 })
635 }
636
637 func BenchmarkIndexEasy(b *testing.B) {
638 benchBytes(b, indexSizes, func(b *testing.B, n int) {
639 buf := bmbuf[0:n]
640 buf[n-1] = 'x'
641 buf[n-7] = 'x'
642 for i := 0; i < b.N; i++ {
643 j := Index(buf, buf[n-7:])
644 if j != n-7 {
645 b.Fatal("bad index", j)
646 }
647 }
648 buf[n-1] = '\x00'
649 buf[n-7] = '\x00'
650 })
651 }
652
653 func BenchmarkCount(b *testing.B) {
654 benchBytes(b, indexSizes, func(b *testing.B, n int) {
655 buf := bmbuf[0:n]
656 buf[n-1] = 'x'
657 for i := 0; i < b.N; i++ {
658 j := Count(buf, buf[n-7:])
659 if j != 1 {
660 b.Fatal("bad count", j)
661 }
662 }
663 buf[n-1] = '\x00'
664 })
665 }
666
667 func BenchmarkCountEasy(b *testing.B) {
668 benchBytes(b, indexSizes, func(b *testing.B, n int) {
669 buf := bmbuf[0:n]
670 buf[n-1] = 'x'
671 buf[n-7] = 'x'
672 for i := 0; i < b.N; i++ {
673 j := Count(buf, buf[n-7:])
674 if j != 1 {
675 b.Fatal("bad count", j)
676 }
677 }
678 buf[n-1] = '\x00'
679 buf[n-7] = '\x00'
680 })
681 }
682
683 func BenchmarkCountSingle(b *testing.B) {
684 benchBytes(b, indexSizes, func(b *testing.B, n int) {
685 buf := bmbuf[0:n]
686 step := 8
687 for i := 0; i < len(buf); i += step {
688 buf[i] = 1
689 }
690 expect := (len(buf) + (step - 1)) / step
691 for i := 0; i < b.N; i++ {
692 j := Count(buf, []byte{1})
693 if j != expect {
694 b.Fatal("bad count", j, expect)
695 }
696 }
697 for i := 0; i < len(buf); i++ {
698 buf[i] = 0
699 }
700 })
701 }
702
703 type SplitTest struct {
704 s string
705 sep string
706 n int
707 a []string
708 }
709
710 var splittests = []SplitTest{
711 {"", "", -1, []string{}},
712 {abcd, "a", 0, nil},
713 {abcd, "", 2, []string{"a", "bcd"}},
714 {abcd, "a", -1, []string{"", "bcd"}},
715 {abcd, "z", -1, []string{"abcd"}},
716 {abcd, "", -1, []string{"a", "b", "c", "d"}},
717 {commas, ",", -1, []string{"1", "2", "3", "4"}},
718 {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
719 {faces, "☹", -1, []string{"☺☻", ""}},
720 {faces, "~", -1, []string{faces}},
721 {faces, "", -1, []string{"☺", "☻", "☹"}},
722 {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
723 {"1 2", " ", 3, []string{"1", "2"}},
724 {"123", "", 2, []string{"1", "23"}},
725 {"123", "", 17, []string{"1", "2", "3"}},
726 }
727
728 func TestSplit(t *testing.T) {
729 for _, tt := range splittests {
730 a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n)
731
732
733 var x []byte
734 for _, v := range a {
735 x = append(v, 'z')
736 }
737
738 result := sliceOfString(a)
739 if !eq(result, tt.a) {
740 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
741 continue
742 }
743 if tt.n == 0 || len(a) == 0 {
744 continue
745 }
746
747 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
748 t.Errorf("last appended result was %s; want %s", x, want)
749 }
750
751 s := Join(a, []byte(tt.sep))
752 if string(s) != tt.s {
753 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
754 }
755 if tt.n < 0 {
756 b := Split([]byte(tt.s), []byte(tt.sep))
757 if !reflect.DeepEqual(a, b) {
758 t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
759 }
760 }
761 if len(a) > 0 {
762 in, out := a[0], s
763 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] {
764 t.Errorf("Join(%#v, %q) didn't copy", a, tt.sep)
765 }
766 }
767 }
768 }
769
770 var splitaftertests = []SplitTest{
771 {abcd, "a", -1, []string{"a", "bcd"}},
772 {abcd, "z", -1, []string{"abcd"}},
773 {abcd, "", -1, []string{"a", "b", "c", "d"}},
774 {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
775 {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
776 {faces, "☹", -1, []string{"☺☻☹", ""}},
777 {faces, "~", -1, []string{faces}},
778 {faces, "", -1, []string{"☺", "☻", "☹"}},
779 {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
780 {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
781 {"1 2", " ", 3, []string{"1 ", "2"}},
782 {"123", "", 2, []string{"1", "23"}},
783 {"123", "", 17, []string{"1", "2", "3"}},
784 }
785
786 func TestSplitAfter(t *testing.T) {
787 for _, tt := range splitaftertests {
788 a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n)
789
790
791 var x []byte
792 for _, v := range a {
793 x = append(v, 'z')
794 }
795
796 result := sliceOfString(a)
797 if !eq(result, tt.a) {
798 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
799 continue
800 }
801
802 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
803 t.Errorf("last appended result was %s; want %s", x, want)
804 }
805
806 s := Join(a, nil)
807 if string(s) != tt.s {
808 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
809 }
810 if tt.n < 0 {
811 b := SplitAfter([]byte(tt.s), []byte(tt.sep))
812 if !reflect.DeepEqual(a, b) {
813 t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
814 }
815 }
816 }
817 }
818
819 type FieldsTest struct {
820 s string
821 a []string
822 }
823
824 var fieldstests = []FieldsTest{
825 {"", []string{}},
826 {" ", []string{}},
827 {" \t ", []string{}},
828 {" abc ", []string{"abc"}},
829 {"1 2 3 4", []string{"1", "2", "3", "4"}},
830 {"1 2 3 4", []string{"1", "2", "3", "4"}},
831 {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
832 {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
833 {"\u2000\u2001\u2002", []string{}},
834 {"\n™\t™\n", []string{"™", "™"}},
835 {faces, []string{faces}},
836 }
837
838 func TestFields(t *testing.T) {
839 for _, tt := range fieldstests {
840 b := []byte(tt.s)
841 a := Fields(b)
842
843
844 var x []byte
845 for _, v := range a {
846 x = append(v, 'z')
847 }
848
849 result := sliceOfString(a)
850 if !eq(result, tt.a) {
851 t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
852 continue
853 }
854
855 if string(b) != tt.s {
856 t.Errorf("slice changed to %s; want %s", string(b), tt.s)
857 }
858 if len(tt.a) > 0 {
859 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
860 t.Errorf("last appended result was %s; want %s", x, want)
861 }
862 }
863 }
864 }
865
866 func TestFieldsFunc(t *testing.T) {
867 for _, tt := range fieldstests {
868 a := FieldsFunc([]byte(tt.s), unicode.IsSpace)
869 result := sliceOfString(a)
870 if !eq(result, tt.a) {
871 t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a)
872 continue
873 }
874 }
875 pred := func(c rune) bool { return c == 'X' }
876 var fieldsFuncTests = []FieldsTest{
877 {"", []string{}},
878 {"XX", []string{}},
879 {"XXhiXXX", []string{"hi"}},
880 {"aXXbXXXcX", []string{"a", "b", "c"}},
881 }
882 for _, tt := range fieldsFuncTests {
883 b := []byte(tt.s)
884 a := FieldsFunc(b, pred)
885
886
887 var x []byte
888 for _, v := range a {
889 x = append(v, 'z')
890 }
891
892 result := sliceOfString(a)
893 if !eq(result, tt.a) {
894 t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
895 }
896
897 if string(b) != tt.s {
898 t.Errorf("slice changed to %s; want %s", b, tt.s)
899 }
900 if len(tt.a) > 0 {
901 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
902 t.Errorf("last appended result was %s; want %s", x, want)
903 }
904 }
905 }
906 }
907
908
909
910 type StringTest struct {
911 in string
912 out []byte
913 }
914
915 var upperTests = []StringTest{
916 {"", []byte("")},
917 {"ONLYUPPER", []byte("ONLYUPPER")},
918 {"abc", []byte("ABC")},
919 {"AbC123", []byte("ABC123")},
920 {"azAZ09_", []byte("AZAZ09_")},
921 {"longStrinGwitHmixofsmaLLandcAps", []byte("LONGSTRINGWITHMIXOFSMALLANDCAPS")},
922 {"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", []byte("LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS")},
923 {"\u0250\u0250\u0250\u0250\u0250", []byte("\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F")},
924 {"a\u0080\U0010FFFF", []byte("A\u0080\U0010FFFF")},
925 }
926
927 var lowerTests = []StringTest{
928 {"", []byte("")},
929 {"abc", []byte("abc")},
930 {"AbC123", []byte("abc123")},
931 {"azAZ09_", []byte("azaz09_")},
932 {"longStrinGwitHmixofsmaLLandcAps", []byte("longstringwithmixofsmallandcaps")},
933 {"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", []byte("long\u0250string\u0250with\u0250nonascii\u0250chars")},
934 {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", []byte("\u0251\u0251\u0251\u0251\u0251")},
935 {"A\u0080\U0010FFFF", []byte("a\u0080\U0010FFFF")},
936 }
937
938 const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
939
940 var trimSpaceTests = []StringTest{
941 {"", nil},
942 {" a", []byte("a")},
943 {"b ", []byte("b")},
944 {"abc", []byte("abc")},
945 {space + "abc" + space, []byte("abc")},
946 {" ", nil},
947 {"\u3000 ", nil},
948 {" \u3000", nil},
949 {" \t\r\n \t\t\r\r\n\n ", nil},
950 {" \t\r\n x\t\t\r\r\n\n ", []byte("x")},
951 {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", []byte("x\t\t\r\r\ny")},
952 {"1 \t\r\n2", []byte("1 \t\r\n2")},
953 {" x\x80", []byte("x\x80")},
954 {" x\xc0", []byte("x\xc0")},
955 {"x \xc0\xc0 ", []byte("x \xc0\xc0")},
956 {"x \xc0", []byte("x \xc0")},
957 {"x \xc0 ", []byte("x \xc0")},
958 {"x \xc0\xc0 ", []byte("x \xc0\xc0")},
959 {"x ☺\xc0\xc0 ", []byte("x ☺\xc0\xc0")},
960 {"x ☺ ", []byte("x ☺")},
961 }
962
963
964
965 func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) {
966 for _, tc := range testCases {
967 actual := f([]byte(tc.in))
968 if actual == nil && tc.out != nil {
969 t.Errorf("%s(%q) = nil; want %q", funcName, tc.in, tc.out)
970 }
971 if actual != nil && tc.out == nil {
972 t.Errorf("%s(%q) = %q; want nil", funcName, tc.in, actual)
973 }
974 if !Equal(actual, tc.out) {
975 t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
976 }
977 }
978 }
979
980 func tenRunes(r rune) string {
981 runes := make([]rune, 10)
982 for i := range runes {
983 runes[i] = r
984 }
985 return string(runes)
986 }
987
988
989 func rot13(r rune) rune {
990 const step = 13
991 if r >= 'a' && r <= 'z' {
992 return ((r - 'a' + step) % 26) + 'a'
993 }
994 if r >= 'A' && r <= 'Z' {
995 return ((r - 'A' + step) % 26) + 'A'
996 }
997 return r
998 }
999
1000 func TestMap(t *testing.T) {
1001
1002 a := tenRunes('a')
1003
1004
1005 maxRune := func(r rune) rune { return unicode.MaxRune }
1006 m := Map(maxRune, []byte(a))
1007 expect := tenRunes(unicode.MaxRune)
1008 if string(m) != expect {
1009 t.Errorf("growing: expected %q got %q", expect, m)
1010 }
1011
1012
1013 minRune := func(r rune) rune { return 'a' }
1014 m = Map(minRune, []byte(tenRunes(unicode.MaxRune)))
1015 expect = a
1016 if string(m) != expect {
1017 t.Errorf("shrinking: expected %q got %q", expect, m)
1018 }
1019
1020
1021 m = Map(rot13, []byte("a to zed"))
1022 expect = "n gb mrq"
1023 if string(m) != expect {
1024 t.Errorf("rot13: expected %q got %q", expect, m)
1025 }
1026
1027
1028 m = Map(rot13, Map(rot13, []byte("a to zed")))
1029 expect = "a to zed"
1030 if string(m) != expect {
1031 t.Errorf("rot13: expected %q got %q", expect, m)
1032 }
1033
1034
1035 dropNotLatin := func(r rune) rune {
1036 if unicode.Is(unicode.Latin, r) {
1037 return r
1038 }
1039 return -1
1040 }
1041 m = Map(dropNotLatin, []byte("Hello, 세계"))
1042 expect = "Hello"
1043 if string(m) != expect {
1044 t.Errorf("drop: expected %q got %q", expect, m)
1045 }
1046
1047
1048 invalidRune := func(r rune) rune {
1049 return utf8.MaxRune + 1
1050 }
1051 m = Map(invalidRune, []byte("x"))
1052 expect = "\uFFFD"
1053 if string(m) != expect {
1054 t.Errorf("invalidRune: expected %q got %q", expect, m)
1055 }
1056 }
1057
1058 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
1059
1060 func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
1061
1062 func BenchmarkToUpper(b *testing.B) {
1063 for _, tc := range upperTests {
1064 tin := []byte(tc.in)
1065 b.Run(tc.in, func(b *testing.B) {
1066 for i := 0; i < b.N; i++ {
1067 actual := ToUpper(tin)
1068 if !Equal(actual, tc.out) {
1069 b.Errorf("ToUpper(%q) = %q; want %q", tc.in, actual, tc.out)
1070 }
1071 }
1072 })
1073 }
1074 }
1075
1076 func BenchmarkToLower(b *testing.B) {
1077 for _, tc := range lowerTests {
1078 tin := []byte(tc.in)
1079 b.Run(tc.in, func(b *testing.B) {
1080 for i := 0; i < b.N; i++ {
1081 actual := ToLower(tin)
1082 if !Equal(actual, tc.out) {
1083 b.Errorf("ToLower(%q) = %q; want %q", tc.in, actual, tc.out)
1084 }
1085 }
1086 })
1087 }
1088 }
1089
1090 var toValidUTF8Tests = []struct {
1091 in string
1092 repl string
1093 out string
1094 }{
1095 {"", "\uFFFD", ""},
1096 {"abc", "\uFFFD", "abc"},
1097 {"\uFDDD", "\uFFFD", "\uFDDD"},
1098 {"a\xffb", "\uFFFD", "a\uFFFDb"},
1099 {"a\xffb\uFFFD", "X", "aXb\uFFFD"},
1100 {"a☺\xffb☺\xC0\xAFc☺\xff", "", "a☺b☺c☺"},
1101 {"a☺\xffb☺\xC0\xAFc☺\xff", "日本語", "a☺日本語b☺日本語c☺日本語"},
1102 {"\xC0\xAF", "\uFFFD", "\uFFFD"},
1103 {"\xE0\x80\xAF", "\uFFFD", "\uFFFD"},
1104 {"\xed\xa0\x80", "abc", "abc"},
1105 {"\xed\xbf\xbf", "\uFFFD", "\uFFFD"},
1106 {"\xF0\x80\x80\xaf", "☺", "☺"},
1107 {"\xF8\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"},
1108 {"\xFC\x80\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"},
1109 }
1110
1111 func TestToValidUTF8(t *testing.T) {
1112 for _, tc := range toValidUTF8Tests {
1113 got := ToValidUTF8([]byte(tc.in), []byte(tc.repl))
1114 if !Equal(got, []byte(tc.out)) {
1115 t.Errorf("ToValidUTF8(%q, %q) = %q; want %q", tc.in, tc.repl, got, tc.out)
1116 }
1117 }
1118 }
1119
1120 func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
1121
1122 type RepeatTest struct {
1123 in, out string
1124 count int
1125 }
1126
1127 var RepeatTests = []RepeatTest{
1128 {"", "", 0},
1129 {"", "", 1},
1130 {"", "", 2},
1131 {"-", "", 0},
1132 {"-", "-", 1},
1133 {"-", "----------", 10},
1134 {"abc ", "abc abc abc ", 3},
1135 }
1136
1137 func TestRepeat(t *testing.T) {
1138 for _, tt := range RepeatTests {
1139 tin := []byte(tt.in)
1140 tout := []byte(tt.out)
1141 a := Repeat(tin, tt.count)
1142 if !Equal(a, tout) {
1143 t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout)
1144 continue
1145 }
1146 }
1147 }
1148
1149 func repeat(b []byte, count int) (err error) {
1150 defer func() {
1151 if r := recover(); r != nil {
1152 switch v := r.(type) {
1153 case error:
1154 err = v
1155 default:
1156 err = fmt.Errorf("%s", v)
1157 }
1158 }
1159 }()
1160
1161 Repeat(b, count)
1162
1163 return
1164 }
1165
1166
1167 func TestRepeatCatchesOverflow(t *testing.T) {
1168 tests := [...]struct {
1169 s string
1170 count int
1171 errStr string
1172 }{
1173 0: {"--", -2147483647, "negative"},
1174 1: {"", int(^uint(0) >> 1), ""},
1175 2: {"-", 10, ""},
1176 3: {"gopher", 0, ""},
1177 4: {"-", -1, "negative"},
1178 5: {"--", -102, "negative"},
1179 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
1180 }
1181
1182 for i, tt := range tests {
1183 err := repeat([]byte(tt.s), tt.count)
1184 if tt.errStr == "" {
1185 if err != nil {
1186 t.Errorf("#%d panicked %v", i, err)
1187 }
1188 continue
1189 }
1190
1191 if err == nil || !strings.Contains(err.Error(), tt.errStr) {
1192 t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
1193 }
1194 }
1195 }
1196
1197 func runesEqual(a, b []rune) bool {
1198 if len(a) != len(b) {
1199 return false
1200 }
1201 for i, r := range a {
1202 if r != b[i] {
1203 return false
1204 }
1205 }
1206 return true
1207 }
1208
1209 type RunesTest struct {
1210 in string
1211 out []rune
1212 lossy bool
1213 }
1214
1215 var RunesTests = []RunesTest{
1216 {"", []rune{}, false},
1217 {" ", []rune{32}, false},
1218 {"ABC", []rune{65, 66, 67}, false},
1219 {"abc", []rune{97, 98, 99}, false},
1220 {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false},
1221 {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true},
1222 {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true},
1223 }
1224
1225 func TestRunes(t *testing.T) {
1226 for _, tt := range RunesTests {
1227 tin := []byte(tt.in)
1228 a := Runes(tin)
1229 if !runesEqual(a, tt.out) {
1230 t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out)
1231 continue
1232 }
1233 if !tt.lossy {
1234
1235 s := string(a)
1236 if s != tt.in {
1237 t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin)
1238 }
1239 }
1240 }
1241 }
1242
1243 type TrimTest struct {
1244 f string
1245 in, arg, out string
1246 }
1247
1248 var trimTests = []TrimTest{
1249 {"Trim", "abba", "a", "bb"},
1250 {"Trim", "abba", "ab", ""},
1251 {"TrimLeft", "abba", "ab", ""},
1252 {"TrimRight", "abba", "ab", ""},
1253 {"TrimLeft", "abba", "a", "bba"},
1254 {"TrimLeft", "abba", "b", "abba"},
1255 {"TrimRight", "abba", "a", "abb"},
1256 {"TrimRight", "abba", "b", "abba"},
1257 {"Trim", "<tag>", "<>", "tag"},
1258 {"Trim", "* listitem", " *", "listitem"},
1259 {"Trim", `"quote"`, `"`, "quote"},
1260 {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
1261 {"Trim", "\x80test\xff", "\xff", "test"},
1262 {"Trim", " Ġ ", " ", "Ġ"},
1263 {"Trim", " Ġİ0", "0 ", "Ġİ"},
1264
1265 {"Trim", "abba", "", "abba"},
1266 {"Trim", "", "123", ""},
1267 {"Trim", "", "", ""},
1268 {"TrimLeft", "abba", "", "abba"},
1269 {"TrimLeft", "", "123", ""},
1270 {"TrimLeft", "", "", ""},
1271 {"TrimRight", "abba", "", "abba"},
1272 {"TrimRight", "", "123", ""},
1273 {"TrimRight", "", "", ""},
1274 {"TrimRight", "☺\xc0", "☺", "☺\xc0"},
1275 {"TrimPrefix", "aabb", "a", "abb"},
1276 {"TrimPrefix", "aabb", "b", "aabb"},
1277 {"TrimSuffix", "aabb", "a", "aabb"},
1278 {"TrimSuffix", "aabb", "b", "aab"},
1279 }
1280
1281 type TrimNilTest struct {
1282 f string
1283 in []byte
1284 arg string
1285 out []byte
1286 }
1287
1288 var trimNilTests = []TrimNilTest{
1289 {"Trim", nil, "", nil},
1290 {"Trim", []byte{}, "", nil},
1291 {"Trim", []byte{'a'}, "a", nil},
1292 {"Trim", []byte{'a', 'a'}, "a", nil},
1293 {"Trim", []byte{'a'}, "ab", nil},
1294 {"Trim", []byte{'a', 'b'}, "ab", nil},
1295 {"Trim", []byte("☺"), "☺", nil},
1296 {"TrimLeft", nil, "", nil},
1297 {"TrimLeft", []byte{}, "", nil},
1298 {"TrimLeft", []byte{'a'}, "a", nil},
1299 {"TrimLeft", []byte{'a', 'a'}, "a", nil},
1300 {"TrimLeft", []byte{'a'}, "ab", nil},
1301 {"TrimLeft", []byte{'a', 'b'}, "ab", nil},
1302 {"TrimLeft", []byte("☺"), "☺", nil},
1303 {"TrimRight", nil, "", nil},
1304 {"TrimRight", []byte{}, "", []byte{}},
1305 {"TrimRight", []byte{'a'}, "a", []byte{}},
1306 {"TrimRight", []byte{'a', 'a'}, "a", []byte{}},
1307 {"TrimRight", []byte{'a'}, "ab", []byte{}},
1308 {"TrimRight", []byte{'a', 'b'}, "ab", []byte{}},
1309 {"TrimRight", []byte("☺"), "☺", []byte{}},
1310 {"TrimPrefix", nil, "", nil},
1311 {"TrimPrefix", []byte{}, "", []byte{}},
1312 {"TrimPrefix", []byte{'a'}, "a", []byte{}},
1313 {"TrimPrefix", []byte("☺"), "☺", []byte{}},
1314 {"TrimSuffix", nil, "", nil},
1315 {"TrimSuffix", []byte{}, "", []byte{}},
1316 {"TrimSuffix", []byte{'a'}, "a", []byte{}},
1317 {"TrimSuffix", []byte("☺"), "☺", []byte{}},
1318 }
1319
1320 func TestTrim(t *testing.T) {
1321 toFn := func(name string) (func([]byte, string) []byte, func([]byte, []byte) []byte) {
1322 switch name {
1323 case "Trim":
1324 return Trim, nil
1325 case "TrimLeft":
1326 return TrimLeft, nil
1327 case "TrimRight":
1328 return TrimRight, nil
1329 case "TrimPrefix":
1330 return nil, TrimPrefix
1331 case "TrimSuffix":
1332 return nil, TrimSuffix
1333 default:
1334 t.Errorf("Undefined trim function %s", name)
1335 return nil, nil
1336 }
1337 }
1338
1339 for _, tc := range trimTests {
1340 name := tc.f
1341 f, fb := toFn(name)
1342 if f == nil && fb == nil {
1343 continue
1344 }
1345 var actual string
1346 if f != nil {
1347 actual = string(f([]byte(tc.in), tc.arg))
1348 } else {
1349 actual = string(fb([]byte(tc.in), []byte(tc.arg)))
1350 }
1351 if actual != tc.out {
1352 t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
1353 }
1354 }
1355
1356 for _, tc := range trimNilTests {
1357 name := tc.f
1358 f, fb := toFn(name)
1359 if f == nil && fb == nil {
1360 continue
1361 }
1362 var actual []byte
1363 if f != nil {
1364 actual = f(tc.in, tc.arg)
1365 } else {
1366 actual = fb(tc.in, []byte(tc.arg))
1367 }
1368 report := func(s []byte) string {
1369 if s == nil {
1370 return "nil"
1371 } else {
1372 return fmt.Sprintf("%q", s)
1373 }
1374 }
1375 if len(actual) != 0 {
1376 t.Errorf("%s(%s, %q) returned non-empty value", name, report(tc.in), tc.arg)
1377 } else {
1378 actualNil := actual == nil
1379 outNil := tc.out == nil
1380 if actualNil != outNil {
1381 t.Errorf("%s(%s, %q) got nil %t; want nil %t", name, report(tc.in), tc.arg, actualNil, outNil)
1382 }
1383 }
1384 }
1385 }
1386
1387 type predicate struct {
1388 f func(r rune) bool
1389 name string
1390 }
1391
1392 var isSpace = predicate{unicode.IsSpace, "IsSpace"}
1393 var isDigit = predicate{unicode.IsDigit, "IsDigit"}
1394 var isUpper = predicate{unicode.IsUpper, "IsUpper"}
1395 var isValidRune = predicate{
1396 func(r rune) bool {
1397 return r != utf8.RuneError
1398 },
1399 "IsValidRune",
1400 }
1401
1402 type TrimFuncTest struct {
1403 f predicate
1404 in string
1405 trimOut []byte
1406 leftOut []byte
1407 rightOut []byte
1408 }
1409
1410 func not(p predicate) predicate {
1411 return predicate{
1412 func(r rune) bool {
1413 return !p.f(r)
1414 },
1415 "not " + p.name,
1416 }
1417 }
1418
1419 var trimFuncTests = []TrimFuncTest{
1420 {isSpace, space + " hello " + space,
1421 []byte("hello"),
1422 []byte("hello " + space),
1423 []byte(space + " hello")},
1424 {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51",
1425 []byte("hello"),
1426 []byte("hello34\u0e50\u0e51"),
1427 []byte("\u0e50\u0e5212hello")},
1428 {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F",
1429 []byte("hello"),
1430 []byte("helloEF\u2C6F\u2C6FGH\u2C6F\u2C6F"),
1431 []byte("\u2C6F\u2C6F\u2C6F\u2C6FABCDhello")},
1432 {not(isSpace), "hello" + space + "hello",
1433 []byte(space),
1434 []byte(space + "hello"),
1435 []byte("hello" + space)},
1436 {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo",
1437 []byte("\u0e50\u0e521234\u0e50\u0e51"),
1438 []byte("\u0e50\u0e521234\u0e50\u0e51helo"),
1439 []byte("hello\u0e50\u0e521234\u0e50\u0e51")},
1440 {isValidRune, "ab\xc0a\xc0cd",
1441 []byte("\xc0a\xc0"),
1442 []byte("\xc0a\xc0cd"),
1443 []byte("ab\xc0a\xc0")},
1444 {not(isValidRune), "\xc0a\xc0",
1445 []byte("a"),
1446 []byte("a\xc0"),
1447 []byte("\xc0a")},
1448
1449
1450 {isSpace, "",
1451 nil,
1452 nil,
1453 []byte("")},
1454 {isSpace, " ",
1455 nil,
1456 nil,
1457 []byte("")},
1458 }
1459
1460 func TestTrimFunc(t *testing.T) {
1461 for _, tc := range trimFuncTests {
1462 trimmers := []struct {
1463 name string
1464 trim func(s []byte, f func(r rune) bool) []byte
1465 out []byte
1466 }{
1467 {"TrimFunc", TrimFunc, tc.trimOut},
1468 {"TrimLeftFunc", TrimLeftFunc, tc.leftOut},
1469 {"TrimRightFunc", TrimRightFunc, tc.rightOut},
1470 }
1471 for _, trimmer := range trimmers {
1472 actual := trimmer.trim([]byte(tc.in), tc.f.f)
1473 if actual == nil && trimmer.out != nil {
1474 t.Errorf("%s(%q, %q) = nil; want %q", trimmer.name, tc.in, tc.f.name, trimmer.out)
1475 }
1476 if actual != nil && trimmer.out == nil {
1477 t.Errorf("%s(%q, %q) = %q; want nil", trimmer.name, tc.in, tc.f.name, actual)
1478 }
1479 if !Equal(actual, trimmer.out) {
1480 t.Errorf("%s(%q, %q) = %q; want %q", trimmer.name, tc.in, tc.f.name, actual, trimmer.out)
1481 }
1482 }
1483 }
1484 }
1485
1486 type IndexFuncTest struct {
1487 in string
1488 f predicate
1489 first, last int
1490 }
1491
1492 var indexFuncTests = []IndexFuncTest{
1493 {"", isValidRune, -1, -1},
1494 {"abc", isDigit, -1, -1},
1495 {"0123", isDigit, 0, 3},
1496 {"a1b", isDigit, 1, 1},
1497 {space, isSpace, 0, len(space) - 3},
1498 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
1499 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
1500 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
1501
1502
1503 {"\x801", isDigit, 1, 1},
1504 {"\x80abc", isDigit, -1, -1},
1505 {"\xc0a\xc0", isValidRune, 1, 1},
1506 {"\xc0a\xc0", not(isValidRune), 0, 2},
1507 {"\xc0☺\xc0", not(isValidRune), 0, 4},
1508 {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
1509 {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
1510 {"a\xe0\x80cd", not(isValidRune), 1, 2},
1511 }
1512
1513 func TestIndexFunc(t *testing.T) {
1514 for _, tc := range indexFuncTests {
1515 first := IndexFunc([]byte(tc.in), tc.f.f)
1516 if first != tc.first {
1517 t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
1518 }
1519 last := LastIndexFunc([]byte(tc.in), tc.f.f)
1520 if last != tc.last {
1521 t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
1522 }
1523 }
1524 }
1525
1526 type ReplaceTest struct {
1527 in string
1528 old, new string
1529 n int
1530 out string
1531 }
1532
1533 var ReplaceTests = []ReplaceTest{
1534 {"hello", "l", "L", 0, "hello"},
1535 {"hello", "l", "L", -1, "heLLo"},
1536 {"hello", "x", "X", -1, "hello"},
1537 {"", "x", "X", -1, ""},
1538 {"radar", "r", "<r>", -1, "<r>ada<r>"},
1539 {"", "", "<>", -1, "<>"},
1540 {"banana", "a", "<>", -1, "b<>n<>n<>"},
1541 {"banana", "a", "<>", 1, "b<>nana"},
1542 {"banana", "a", "<>", 1000, "b<>n<>n<>"},
1543 {"banana", "an", "<>", -1, "b<><>a"},
1544 {"banana", "ana", "<>", -1, "b<>na"},
1545 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
1546 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
1547 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
1548 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
1549 {"banana", "", "<>", 1, "<>banana"},
1550 {"banana", "a", "a", -1, "banana"},
1551 {"banana", "a", "a", 1, "banana"},
1552 {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
1553 }
1554
1555 func TestReplace(t *testing.T) {
1556 for _, tt := range ReplaceTests {
1557 in := append([]byte(tt.in), "<spare>"...)
1558 in = in[:len(tt.in)]
1559 out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n)
1560 if s := string(out); s != tt.out {
1561 t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
1562 }
1563 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] {
1564 t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n)
1565 }
1566 if tt.n == -1 {
1567 out := ReplaceAll(in, []byte(tt.old), []byte(tt.new))
1568 if s := string(out); s != tt.out {
1569 t.Errorf("ReplaceAll(%q, %q, %q) = %q, want %q", tt.in, tt.old, tt.new, s, tt.out)
1570 }
1571 }
1572 }
1573 }
1574
1575 type TitleTest struct {
1576 in, out string
1577 }
1578
1579 var TitleTests = []TitleTest{
1580 {"", ""},
1581 {"a", "A"},
1582 {" aaa aaa aaa ", " Aaa Aaa Aaa "},
1583 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
1584 {"123a456", "123a456"},
1585 {"double-blind", "Double-Blind"},
1586 {"ÿøû", "Ÿøû"},
1587 {"with_underscore", "With_underscore"},
1588 {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
1589 }
1590
1591 func TestTitle(t *testing.T) {
1592 for _, tt := range TitleTests {
1593 if s := string(Title([]byte(tt.in))); s != tt.out {
1594 t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
1595 }
1596 }
1597 }
1598
1599 var ToTitleTests = []TitleTest{
1600 {"", ""},
1601 {"a", "A"},
1602 {" aaa aaa aaa ", " AAA AAA AAA "},
1603 {" Aaa Aaa Aaa ", " AAA AAA AAA "},
1604 {"123a456", "123A456"},
1605 {"double-blind", "DOUBLE-BLIND"},
1606 {"ÿøû", "ŸØÛ"},
1607 }
1608
1609 func TestToTitle(t *testing.T) {
1610 for _, tt := range ToTitleTests {
1611 if s := string(ToTitle([]byte(tt.in))); s != tt.out {
1612 t.Errorf("ToTitle(%q) = %q, want %q", tt.in, s, tt.out)
1613 }
1614 }
1615 }
1616
1617 var EqualFoldTests = []struct {
1618 s, t string
1619 out bool
1620 }{
1621 {"abc", "abc", true},
1622 {"ABcd", "ABcd", true},
1623 {"123abc", "123ABC", true},
1624 {"αβδ", "ΑΒΔ", true},
1625 {"abc", "xyz", false},
1626 {"abc", "XYZ", false},
1627 {"abcdefghijk", "abcdefghijX", false},
1628 {"abcdefghijk", "abcdefghij\u212A", true},
1629 {"abcdefghijK", "abcdefghij\u212A", true},
1630 {"abcdefghijkz", "abcdefghij\u212Ay", false},
1631 {"abcdefghijKz", "abcdefghij\u212Ay", false},
1632 }
1633
1634 func TestEqualFold(t *testing.T) {
1635 for _, tt := range EqualFoldTests {
1636 if out := EqualFold([]byte(tt.s), []byte(tt.t)); out != tt.out {
1637 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out)
1638 }
1639 if out := EqualFold([]byte(tt.t), []byte(tt.s)); out != tt.out {
1640 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out)
1641 }
1642 }
1643 }
1644
1645 var cutTests = []struct {
1646 s, sep string
1647 before, after string
1648 found bool
1649 }{
1650 {"abc", "b", "a", "c", true},
1651 {"abc", "a", "", "bc", true},
1652 {"abc", "c", "ab", "", true},
1653 {"abc", "abc", "", "", true},
1654 {"abc", "", "", "abc", true},
1655 {"abc", "d", "abc", "", false},
1656 {"", "d", "", "", false},
1657 {"", "", "", "", true},
1658 }
1659
1660 func TestCut(t *testing.T) {
1661 for _, tt := range cutTests {
1662 if before, after, found := Cut([]byte(tt.s), []byte(tt.sep)); string(before) != tt.before || string(after) != tt.after || found != tt.found {
1663 t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found)
1664 }
1665 }
1666 }
1667
1668 func TestBufferGrowNegative(t *testing.T) {
1669 defer func() {
1670 if err := recover(); err == nil {
1671 t.Fatal("Grow(-1) should have panicked")
1672 }
1673 }()
1674 var b Buffer
1675 b.Grow(-1)
1676 }
1677
1678 func TestBufferTruncateNegative(t *testing.T) {
1679 defer func() {
1680 if err := recover(); err == nil {
1681 t.Fatal("Truncate(-1) should have panicked")
1682 }
1683 }()
1684 var b Buffer
1685 b.Truncate(-1)
1686 }
1687
1688 func TestBufferTruncateOutOfRange(t *testing.T) {
1689 defer func() {
1690 if err := recover(); err == nil {
1691 t.Fatal("Truncate(20) should have panicked")
1692 }
1693 }()
1694 var b Buffer
1695 b.Write(make([]byte, 10))
1696 b.Truncate(20)
1697 }
1698
1699 var containsTests = []struct {
1700 b, subslice []byte
1701 want bool
1702 }{
1703 {[]byte("hello"), []byte("hel"), true},
1704 {[]byte("日本語"), []byte("日本"), true},
1705 {[]byte("hello"), []byte("Hello, world"), false},
1706 {[]byte("東京"), []byte("京東"), false},
1707 }
1708
1709 func TestContains(t *testing.T) {
1710 for _, tt := range containsTests {
1711 if got := Contains(tt.b, tt.subslice); got != tt.want {
1712 t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want)
1713 }
1714 }
1715 }
1716
1717 var ContainsAnyTests = []struct {
1718 b []byte
1719 substr string
1720 expected bool
1721 }{
1722 {[]byte(""), "", false},
1723 {[]byte(""), "a", false},
1724 {[]byte(""), "abc", false},
1725 {[]byte("a"), "", false},
1726 {[]byte("a"), "a", true},
1727 {[]byte("aaa"), "a", true},
1728 {[]byte("abc"), "xyz", false},
1729 {[]byte("abc"), "xcz", true},
1730 {[]byte("a☺b☻c☹d"), "uvw☻xyz", true},
1731 {[]byte("aRegExp*"), ".(|)*+?^$[]", true},
1732 {[]byte(dots + dots + dots), " ", false},
1733 }
1734
1735 func TestContainsAny(t *testing.T) {
1736 for _, ct := range ContainsAnyTests {
1737 if ContainsAny(ct.b, ct.substr) != ct.expected {
1738 t.Errorf("ContainsAny(%s, %s) = %v, want %v",
1739 ct.b, ct.substr, !ct.expected, ct.expected)
1740 }
1741 }
1742 }
1743
1744 var ContainsRuneTests = []struct {
1745 b []byte
1746 r rune
1747 expected bool
1748 }{
1749 {[]byte(""), 'a', false},
1750 {[]byte("a"), 'a', true},
1751 {[]byte("aaa"), 'a', true},
1752 {[]byte("abc"), 'y', false},
1753 {[]byte("abc"), 'c', true},
1754 {[]byte("a☺b☻c☹d"), 'x', false},
1755 {[]byte("a☺b☻c☹d"), '☻', true},
1756 {[]byte("aRegExp*"), '*', true},
1757 }
1758
1759 func TestContainsRune(t *testing.T) {
1760 for _, ct := range ContainsRuneTests {
1761 if ContainsRune(ct.b, ct.r) != ct.expected {
1762 t.Errorf("ContainsRune(%q, %q) = %v, want %v",
1763 ct.b, ct.r, !ct.expected, ct.expected)
1764 }
1765 }
1766 }
1767
1768 var makeFieldsInput = func() []byte {
1769 x := make([]byte, 1<<20)
1770
1771 for i := range x {
1772 switch rand.Intn(10) {
1773 case 0:
1774 x[i] = ' '
1775 case 1:
1776 if i > 0 && x[i-1] == 'x' {
1777 copy(x[i-1:], "χ")
1778 break
1779 }
1780 fallthrough
1781 default:
1782 x[i] = 'x'
1783 }
1784 }
1785 return x
1786 }
1787
1788 var makeFieldsInputASCII = func() []byte {
1789 x := make([]byte, 1<<20)
1790
1791 for i := range x {
1792 if rand.Intn(10) == 0 {
1793 x[i] = ' '
1794 } else {
1795 x[i] = 'x'
1796 }
1797 }
1798 return x
1799 }
1800
1801 var bytesdata = []struct {
1802 name string
1803 data []byte
1804 }{
1805 {"ASCII", makeFieldsInputASCII()},
1806 {"Mixed", makeFieldsInput()},
1807 }
1808
1809 func BenchmarkFields(b *testing.B) {
1810 for _, sd := range bytesdata {
1811 b.Run(sd.name, func(b *testing.B) {
1812 for j := 1 << 4; j <= 1<<20; j <<= 4 {
1813 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) {
1814 b.ReportAllocs()
1815 b.SetBytes(int64(j))
1816 data := sd.data[:j]
1817 for i := 0; i < b.N; i++ {
1818 Fields(data)
1819 }
1820 })
1821 }
1822 })
1823 }
1824 }
1825
1826 func BenchmarkFieldsFunc(b *testing.B) {
1827 for _, sd := range bytesdata {
1828 b.Run(sd.name, func(b *testing.B) {
1829 for j := 1 << 4; j <= 1<<20; j <<= 4 {
1830 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) {
1831 b.ReportAllocs()
1832 b.SetBytes(int64(j))
1833 data := sd.data[:j]
1834 for i := 0; i < b.N; i++ {
1835 FieldsFunc(data, unicode.IsSpace)
1836 }
1837 })
1838 }
1839 })
1840 }
1841 }
1842
1843 func BenchmarkTrimSpace(b *testing.B) {
1844 tests := []struct {
1845 name string
1846 input []byte
1847 }{
1848 {"NoTrim", []byte("typical")},
1849 {"ASCII", []byte(" foo bar ")},
1850 {"SomeNonASCII", []byte(" \u2000\t\r\n x\t\t\r\r\ny\n \u3000 ")},
1851 {"JustNonASCII", []byte("\u2000\u2000\u2000☺☺☺☺\u3000\u3000\u3000")},
1852 }
1853 for _, test := range tests {
1854 b.Run(test.name, func(b *testing.B) {
1855 for i := 0; i < b.N; i++ {
1856 TrimSpace(test.input)
1857 }
1858 })
1859 }
1860 }
1861
1862 func BenchmarkToValidUTF8(b *testing.B) {
1863 tests := []struct {
1864 name string
1865 input []byte
1866 }{
1867 {"Valid", []byte("typical")},
1868 {"InvalidASCII", []byte("foo\xffbar")},
1869 {"InvalidNonASCII", []byte("日本語\xff日本語")},
1870 }
1871 replacement := []byte("\uFFFD")
1872 b.ResetTimer()
1873 for _, test := range tests {
1874 b.Run(test.name, func(b *testing.B) {
1875 for i := 0; i < b.N; i++ {
1876 ToValidUTF8(test.input, replacement)
1877 }
1878 })
1879 }
1880 }
1881
1882 func makeBenchInputHard() []byte {
1883 tokens := [...]string{
1884 "<a>", "<p>", "<b>", "<strong>",
1885 "</a>", "</p>", "</b>", "</strong>",
1886 "hello", "world",
1887 }
1888 x := make([]byte, 0, 1<<20)
1889 for {
1890 i := rand.Intn(len(tokens))
1891 if len(x)+len(tokens[i]) >= 1<<20 {
1892 break
1893 }
1894 x = append(x, tokens[i]...)
1895 }
1896 return x
1897 }
1898
1899 var benchInputHard = makeBenchInputHard()
1900
1901 func benchmarkIndexHard(b *testing.B, sep []byte) {
1902 for i := 0; i < b.N; i++ {
1903 Index(benchInputHard, sep)
1904 }
1905 }
1906
1907 func benchmarkLastIndexHard(b *testing.B, sep []byte) {
1908 for i := 0; i < b.N; i++ {
1909 LastIndex(benchInputHard, sep)
1910 }
1911 }
1912
1913 func benchmarkCountHard(b *testing.B, sep []byte) {
1914 for i := 0; i < b.N; i++ {
1915 Count(benchInputHard, sep)
1916 }
1917 }
1918
1919 func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, []byte("<>")) }
1920 func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, []byte("</pre>")) }
1921 func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, []byte("<b>hello world</b>")) }
1922 func BenchmarkIndexHard4(b *testing.B) {
1923 benchmarkIndexHard(b, []byte("<pre><b>hello</b><strong>world</strong></pre>"))
1924 }
1925
1926 func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, []byte("<>")) }
1927 func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, []byte("</pre>")) }
1928 func BenchmarkLastIndexHard3(b *testing.B) { benchmarkLastIndexHard(b, []byte("<b>hello world</b>")) }
1929
1930 func BenchmarkCountHard1(b *testing.B) { benchmarkCountHard(b, []byte("<>")) }
1931 func BenchmarkCountHard2(b *testing.B) { benchmarkCountHard(b, []byte("</pre>")) }
1932 func BenchmarkCountHard3(b *testing.B) { benchmarkCountHard(b, []byte("<b>hello world</b>")) }
1933
1934 func BenchmarkSplitEmptySeparator(b *testing.B) {
1935 for i := 0; i < b.N; i++ {
1936 Split(benchInputHard, nil)
1937 }
1938 }
1939
1940 func BenchmarkSplitSingleByteSeparator(b *testing.B) {
1941 sep := []byte("/")
1942 for i := 0; i < b.N; i++ {
1943 Split(benchInputHard, sep)
1944 }
1945 }
1946
1947 func BenchmarkSplitMultiByteSeparator(b *testing.B) {
1948 sep := []byte("hello")
1949 for i := 0; i < b.N; i++ {
1950 Split(benchInputHard, sep)
1951 }
1952 }
1953
1954 func BenchmarkSplitNSingleByteSeparator(b *testing.B) {
1955 sep := []byte("/")
1956 for i := 0; i < b.N; i++ {
1957 SplitN(benchInputHard, sep, 10)
1958 }
1959 }
1960
1961 func BenchmarkSplitNMultiByteSeparator(b *testing.B) {
1962 sep := []byte("hello")
1963 for i := 0; i < b.N; i++ {
1964 SplitN(benchInputHard, sep, 10)
1965 }
1966 }
1967
1968 func BenchmarkRepeat(b *testing.B) {
1969 for i := 0; i < b.N; i++ {
1970 Repeat([]byte("-"), 80)
1971 }
1972 }
1973
1974 func BenchmarkBytesCompare(b *testing.B) {
1975 for n := 1; n <= 2048; n <<= 1 {
1976 b.Run(fmt.Sprint(n), func(b *testing.B) {
1977 var x = make([]byte, n)
1978 var y = make([]byte, n)
1979
1980 for i := 0; i < n; i++ {
1981 x[i] = 'a'
1982 }
1983
1984 for i := 0; i < n; i++ {
1985 y[i] = 'a'
1986 }
1987
1988 b.ResetTimer()
1989 for i := 0; i < b.N; i++ {
1990 Compare(x, y)
1991 }
1992 })
1993 }
1994 }
1995
1996 func BenchmarkIndexAnyASCII(b *testing.B) {
1997 x := Repeat([]byte{'#'}, 2048)
1998 cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
1999 for k := 1; k <= 2048; k <<= 4 {
2000 for j := 1; j <= 64; j <<= 1 {
2001 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
2002 for i := 0; i < b.N; i++ {
2003 IndexAny(x[:k], cs[:j])
2004 }
2005 })
2006 }
2007 }
2008 }
2009
2010 func BenchmarkIndexAnyUTF8(b *testing.B) {
2011 x := Repeat([]byte{'#'}, 2048)
2012 cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
2013 for k := 1; k <= 2048; k <<= 4 {
2014 for j := 1; j <= 64; j <<= 1 {
2015 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
2016 for i := 0; i < b.N; i++ {
2017 IndexAny(x[:k], cs[:j])
2018 }
2019 })
2020 }
2021 }
2022 }
2023
2024 func BenchmarkLastIndexAnyASCII(b *testing.B) {
2025 x := Repeat([]byte{'#'}, 2048)
2026 cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
2027 for k := 1; k <= 2048; k <<= 4 {
2028 for j := 1; j <= 64; j <<= 1 {
2029 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
2030 for i := 0; i < b.N; i++ {
2031 LastIndexAny(x[:k], cs[:j])
2032 }
2033 })
2034 }
2035 }
2036 }
2037
2038 func BenchmarkLastIndexAnyUTF8(b *testing.B) {
2039 x := Repeat([]byte{'#'}, 2048)
2040 cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
2041 for k := 1; k <= 2048; k <<= 4 {
2042 for j := 1; j <= 64; j <<= 1 {
2043 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
2044 for i := 0; i < b.N; i++ {
2045 LastIndexAny(x[:k], cs[:j])
2046 }
2047 })
2048 }
2049 }
2050 }
2051
2052 func BenchmarkTrimASCII(b *testing.B) {
2053 cs := "0123456789abcdef"
2054 for k := 1; k <= 4096; k <<= 4 {
2055 for j := 1; j <= 16; j <<= 1 {
2056 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
2057 x := Repeat([]byte(cs[:j]), k)
2058 for i := 0; i < b.N; i++ {
2059 Trim(x[:k], cs[:j])
2060 }
2061 })
2062 }
2063 }
2064 }
2065
2066 func BenchmarkTrimByte(b *testing.B) {
2067 x := []byte(" the quick brown fox ")
2068 for i := 0; i < b.N; i++ {
2069 Trim(x, " ")
2070 }
2071 }
2072
2073 func BenchmarkIndexPeriodic(b *testing.B) {
2074 key := []byte{1, 1}
2075 for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
2076 b.Run(fmt.Sprintf("IndexPeriodic%d", skip), func(b *testing.B) {
2077 buf := make([]byte, 1<<16)
2078 for i := 0; i < len(buf); i += skip {
2079 buf[i] = 1
2080 }
2081 for i := 0; i < b.N; i++ {
2082 Index(buf, key)
2083 }
2084 })
2085 }
2086 }
2087
View as plain text