Source file
src/bytes/bytes_test.go
Documentation: bytes
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 {"TrimRight", "abba", "a", "abb"},
1255 {"Trim", "<tag>", "<>", "tag"},
1256 {"Trim", "* listitem", " *", "listitem"},
1257 {"Trim", `"quote"`, `"`, "quote"},
1258 {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
1259 {"Trim", "\x80test\xff", "\xff", "test"},
1260 {"Trim", " Ġ ", " ", "Ġ"},
1261 {"Trim", " Ġİ0", "0 ", "Ġİ"},
1262
1263 {"Trim", "abba", "", "abba"},
1264 {"Trim", "", "123", ""},
1265 {"Trim", "", "", ""},
1266 {"TrimLeft", "abba", "", "abba"},
1267 {"TrimLeft", "", "123", ""},
1268 {"TrimLeft", "", "", ""},
1269 {"TrimRight", "abba", "", "abba"},
1270 {"TrimRight", "", "123", ""},
1271 {"TrimRight", "", "", ""},
1272 {"TrimRight", "☺\xc0", "☺", "☺\xc0"},
1273 {"TrimPrefix", "aabb", "a", "abb"},
1274 {"TrimPrefix", "aabb", "b", "aabb"},
1275 {"TrimSuffix", "aabb", "a", "aabb"},
1276 {"TrimSuffix", "aabb", "b", "aab"},
1277 }
1278
1279 func TestTrim(t *testing.T) {
1280 for _, tc := range trimTests {
1281 name := tc.f
1282 var f func([]byte, string) []byte
1283 var fb func([]byte, []byte) []byte
1284 switch name {
1285 case "Trim":
1286 f = Trim
1287 case "TrimLeft":
1288 f = TrimLeft
1289 case "TrimRight":
1290 f = TrimRight
1291 case "TrimPrefix":
1292 fb = TrimPrefix
1293 case "TrimSuffix":
1294 fb = TrimSuffix
1295 default:
1296 t.Errorf("Undefined trim function %s", name)
1297 }
1298 var actual string
1299 if f != nil {
1300 actual = string(f([]byte(tc.in), tc.arg))
1301 } else {
1302 actual = string(fb([]byte(tc.in), []byte(tc.arg)))
1303 }
1304 if actual != tc.out {
1305 t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
1306 }
1307 }
1308 }
1309
1310 type predicate struct {
1311 f func(r rune) bool
1312 name string
1313 }
1314
1315 var isSpace = predicate{unicode.IsSpace, "IsSpace"}
1316 var isDigit = predicate{unicode.IsDigit, "IsDigit"}
1317 var isUpper = predicate{unicode.IsUpper, "IsUpper"}
1318 var isValidRune = predicate{
1319 func(r rune) bool {
1320 return r != utf8.RuneError
1321 },
1322 "IsValidRune",
1323 }
1324
1325 type TrimFuncTest struct {
1326 f predicate
1327 in string
1328 trimOut []byte
1329 leftOut []byte
1330 rightOut []byte
1331 }
1332
1333 func not(p predicate) predicate {
1334 return predicate{
1335 func(r rune) bool {
1336 return !p.f(r)
1337 },
1338 "not " + p.name,
1339 }
1340 }
1341
1342 var trimFuncTests = []TrimFuncTest{
1343 {isSpace, space + " hello " + space,
1344 []byte("hello"),
1345 []byte("hello " + space),
1346 []byte(space + " hello")},
1347 {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51",
1348 []byte("hello"),
1349 []byte("hello34\u0e50\u0e51"),
1350 []byte("\u0e50\u0e5212hello")},
1351 {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F",
1352 []byte("hello"),
1353 []byte("helloEF\u2C6F\u2C6FGH\u2C6F\u2C6F"),
1354 []byte("\u2C6F\u2C6F\u2C6F\u2C6FABCDhello")},
1355 {not(isSpace), "hello" + space + "hello",
1356 []byte(space),
1357 []byte(space + "hello"),
1358 []byte("hello" + space)},
1359 {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo",
1360 []byte("\u0e50\u0e521234\u0e50\u0e51"),
1361 []byte("\u0e50\u0e521234\u0e50\u0e51helo"),
1362 []byte("hello\u0e50\u0e521234\u0e50\u0e51")},
1363 {isValidRune, "ab\xc0a\xc0cd",
1364 []byte("\xc0a\xc0"),
1365 []byte("\xc0a\xc0cd"),
1366 []byte("ab\xc0a\xc0")},
1367 {not(isValidRune), "\xc0a\xc0",
1368 []byte("a"),
1369 []byte("a\xc0"),
1370 []byte("\xc0a")},
1371
1372
1373 {isSpace, "",
1374 nil,
1375 nil,
1376 []byte("")},
1377 {isSpace, " ",
1378 nil,
1379 nil,
1380 []byte("")},
1381 }
1382
1383 func TestTrimFunc(t *testing.T) {
1384 for _, tc := range trimFuncTests {
1385 trimmers := []struct {
1386 name string
1387 trim func(s []byte, f func(r rune) bool) []byte
1388 out []byte
1389 }{
1390 {"TrimFunc", TrimFunc, tc.trimOut},
1391 {"TrimLeftFunc", TrimLeftFunc, tc.leftOut},
1392 {"TrimRightFunc", TrimRightFunc, tc.rightOut},
1393 }
1394 for _, trimmer := range trimmers {
1395 actual := trimmer.trim([]byte(tc.in), tc.f.f)
1396 if actual == nil && trimmer.out != nil {
1397 t.Errorf("%s(%q, %q) = nil; want %q", trimmer.name, tc.in, tc.f.name, trimmer.out)
1398 }
1399 if actual != nil && trimmer.out == nil {
1400 t.Errorf("%s(%q, %q) = %q; want nil", trimmer.name, tc.in, tc.f.name, actual)
1401 }
1402 if !Equal(actual, trimmer.out) {
1403 t.Errorf("%s(%q, %q) = %q; want %q", trimmer.name, tc.in, tc.f.name, actual, trimmer.out)
1404 }
1405 }
1406 }
1407 }
1408
1409 type IndexFuncTest struct {
1410 in string
1411 f predicate
1412 first, last int
1413 }
1414
1415 var indexFuncTests = []IndexFuncTest{
1416 {"", isValidRune, -1, -1},
1417 {"abc", isDigit, -1, -1},
1418 {"0123", isDigit, 0, 3},
1419 {"a1b", isDigit, 1, 1},
1420 {space, isSpace, 0, len(space) - 3},
1421 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
1422 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
1423 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
1424
1425
1426 {"\x801", isDigit, 1, 1},
1427 {"\x80abc", isDigit, -1, -1},
1428 {"\xc0a\xc0", isValidRune, 1, 1},
1429 {"\xc0a\xc0", not(isValidRune), 0, 2},
1430 {"\xc0☺\xc0", not(isValidRune), 0, 4},
1431 {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
1432 {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
1433 {"a\xe0\x80cd", not(isValidRune), 1, 2},
1434 }
1435
1436 func TestIndexFunc(t *testing.T) {
1437 for _, tc := range indexFuncTests {
1438 first := IndexFunc([]byte(tc.in), tc.f.f)
1439 if first != tc.first {
1440 t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
1441 }
1442 last := LastIndexFunc([]byte(tc.in), tc.f.f)
1443 if last != tc.last {
1444 t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
1445 }
1446 }
1447 }
1448
1449 type ReplaceTest struct {
1450 in string
1451 old, new string
1452 n int
1453 out string
1454 }
1455
1456 var ReplaceTests = []ReplaceTest{
1457 {"hello", "l", "L", 0, "hello"},
1458 {"hello", "l", "L", -1, "heLLo"},
1459 {"hello", "x", "X", -1, "hello"},
1460 {"", "x", "X", -1, ""},
1461 {"radar", "r", "<r>", -1, "<r>ada<r>"},
1462 {"", "", "<>", -1, "<>"},
1463 {"banana", "a", "<>", -1, "b<>n<>n<>"},
1464 {"banana", "a", "<>", 1, "b<>nana"},
1465 {"banana", "a", "<>", 1000, "b<>n<>n<>"},
1466 {"banana", "an", "<>", -1, "b<><>a"},
1467 {"banana", "ana", "<>", -1, "b<>na"},
1468 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
1469 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
1470 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
1471 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
1472 {"banana", "", "<>", 1, "<>banana"},
1473 {"banana", "a", "a", -1, "banana"},
1474 {"banana", "a", "a", 1, "banana"},
1475 {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
1476 }
1477
1478 func TestReplace(t *testing.T) {
1479 for _, tt := range ReplaceTests {
1480 in := append([]byte(tt.in), "<spare>"...)
1481 in = in[:len(tt.in)]
1482 out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n)
1483 if s := string(out); s != tt.out {
1484 t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
1485 }
1486 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] {
1487 t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n)
1488 }
1489 if tt.n == -1 {
1490 out := ReplaceAll(in, []byte(tt.old), []byte(tt.new))
1491 if s := string(out); s != tt.out {
1492 t.Errorf("ReplaceAll(%q, %q, %q) = %q, want %q", tt.in, tt.old, tt.new, s, tt.out)
1493 }
1494 }
1495 }
1496 }
1497
1498 type TitleTest struct {
1499 in, out string
1500 }
1501
1502 var TitleTests = []TitleTest{
1503 {"", ""},
1504 {"a", "A"},
1505 {" aaa aaa aaa ", " Aaa Aaa Aaa "},
1506 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
1507 {"123a456", "123a456"},
1508 {"double-blind", "Double-Blind"},
1509 {"ÿøû", "Ÿøû"},
1510 {"with_underscore", "With_underscore"},
1511 {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
1512 }
1513
1514 func TestTitle(t *testing.T) {
1515 for _, tt := range TitleTests {
1516 if s := string(Title([]byte(tt.in))); s != tt.out {
1517 t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
1518 }
1519 }
1520 }
1521
1522 var ToTitleTests = []TitleTest{
1523 {"", ""},
1524 {"a", "A"},
1525 {" aaa aaa aaa ", " AAA AAA AAA "},
1526 {" Aaa Aaa Aaa ", " AAA AAA AAA "},
1527 {"123a456", "123A456"},
1528 {"double-blind", "DOUBLE-BLIND"},
1529 {"ÿøû", "ŸØÛ"},
1530 }
1531
1532 func TestToTitle(t *testing.T) {
1533 for _, tt := range ToTitleTests {
1534 if s := string(ToTitle([]byte(tt.in))); s != tt.out {
1535 t.Errorf("ToTitle(%q) = %q, want %q", tt.in, s, tt.out)
1536 }
1537 }
1538 }
1539
1540 var EqualFoldTests = []struct {
1541 s, t string
1542 out bool
1543 }{
1544 {"abc", "abc", true},
1545 {"ABcd", "ABcd", true},
1546 {"123abc", "123ABC", true},
1547 {"αβδ", "ΑΒΔ", true},
1548 {"abc", "xyz", false},
1549 {"abc", "XYZ", false},
1550 {"abcdefghijk", "abcdefghijX", false},
1551 {"abcdefghijk", "abcdefghij\u212A", true},
1552 {"abcdefghijK", "abcdefghij\u212A", true},
1553 {"abcdefghijkz", "abcdefghij\u212Ay", false},
1554 {"abcdefghijKz", "abcdefghij\u212Ay", false},
1555 }
1556
1557 func TestEqualFold(t *testing.T) {
1558 for _, tt := range EqualFoldTests {
1559 if out := EqualFold([]byte(tt.s), []byte(tt.t)); out != tt.out {
1560 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out)
1561 }
1562 if out := EqualFold([]byte(tt.t), []byte(tt.s)); out != tt.out {
1563 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out)
1564 }
1565 }
1566 }
1567
1568 func TestBufferGrowNegative(t *testing.T) {
1569 defer func() {
1570 if err := recover(); err == nil {
1571 t.Fatal("Grow(-1) should have panicked")
1572 }
1573 }()
1574 var b Buffer
1575 b.Grow(-1)
1576 }
1577
1578 func TestBufferTruncateNegative(t *testing.T) {
1579 defer func() {
1580 if err := recover(); err == nil {
1581 t.Fatal("Truncate(-1) should have panicked")
1582 }
1583 }()
1584 var b Buffer
1585 b.Truncate(-1)
1586 }
1587
1588 func TestBufferTruncateOutOfRange(t *testing.T) {
1589 defer func() {
1590 if err := recover(); err == nil {
1591 t.Fatal("Truncate(20) should have panicked")
1592 }
1593 }()
1594 var b Buffer
1595 b.Write(make([]byte, 10))
1596 b.Truncate(20)
1597 }
1598
1599 var containsTests = []struct {
1600 b, subslice []byte
1601 want bool
1602 }{
1603 {[]byte("hello"), []byte("hel"), true},
1604 {[]byte("日本語"), []byte("日本"), true},
1605 {[]byte("hello"), []byte("Hello, world"), false},
1606 {[]byte("東京"), []byte("京東"), false},
1607 }
1608
1609 func TestContains(t *testing.T) {
1610 for _, tt := range containsTests {
1611 if got := Contains(tt.b, tt.subslice); got != tt.want {
1612 t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want)
1613 }
1614 }
1615 }
1616
1617 var ContainsAnyTests = []struct {
1618 b []byte
1619 substr string
1620 expected bool
1621 }{
1622 {[]byte(""), "", false},
1623 {[]byte(""), "a", false},
1624 {[]byte(""), "abc", false},
1625 {[]byte("a"), "", false},
1626 {[]byte("a"), "a", true},
1627 {[]byte("aaa"), "a", true},
1628 {[]byte("abc"), "xyz", false},
1629 {[]byte("abc"), "xcz", true},
1630 {[]byte("a☺b☻c☹d"), "uvw☻xyz", true},
1631 {[]byte("aRegExp*"), ".(|)*+?^$[]", true},
1632 {[]byte(dots + dots + dots), " ", false},
1633 }
1634
1635 func TestContainsAny(t *testing.T) {
1636 for _, ct := range ContainsAnyTests {
1637 if ContainsAny(ct.b, ct.substr) != ct.expected {
1638 t.Errorf("ContainsAny(%s, %s) = %v, want %v",
1639 ct.b, ct.substr, !ct.expected, ct.expected)
1640 }
1641 }
1642 }
1643
1644 var ContainsRuneTests = []struct {
1645 b []byte
1646 r rune
1647 expected bool
1648 }{
1649 {[]byte(""), 'a', false},
1650 {[]byte("a"), 'a', true},
1651 {[]byte("aaa"), 'a', true},
1652 {[]byte("abc"), 'y', false},
1653 {[]byte("abc"), 'c', true},
1654 {[]byte("a☺b☻c☹d"), 'x', false},
1655 {[]byte("a☺b☻c☹d"), '☻', true},
1656 {[]byte("aRegExp*"), '*', true},
1657 }
1658
1659 func TestContainsRune(t *testing.T) {
1660 for _, ct := range ContainsRuneTests {
1661 if ContainsRune(ct.b, ct.r) != ct.expected {
1662 t.Errorf("ContainsRune(%q, %q) = %v, want %v",
1663 ct.b, ct.r, !ct.expected, ct.expected)
1664 }
1665 }
1666 }
1667
1668 var makeFieldsInput = func() []byte {
1669 x := make([]byte, 1<<20)
1670
1671 for i := range x {
1672 switch rand.Intn(10) {
1673 case 0:
1674 x[i] = ' '
1675 case 1:
1676 if i > 0 && x[i-1] == 'x' {
1677 copy(x[i-1:], "χ")
1678 break
1679 }
1680 fallthrough
1681 default:
1682 x[i] = 'x'
1683 }
1684 }
1685 return x
1686 }
1687
1688 var makeFieldsInputASCII = func() []byte {
1689 x := make([]byte, 1<<20)
1690
1691 for i := range x {
1692 if rand.Intn(10) == 0 {
1693 x[i] = ' '
1694 } else {
1695 x[i] = 'x'
1696 }
1697 }
1698 return x
1699 }
1700
1701 var bytesdata = []struct {
1702 name string
1703 data []byte
1704 }{
1705 {"ASCII", makeFieldsInputASCII()},
1706 {"Mixed", makeFieldsInput()},
1707 }
1708
1709 func BenchmarkFields(b *testing.B) {
1710 for _, sd := range bytesdata {
1711 b.Run(sd.name, func(b *testing.B) {
1712 for j := 1 << 4; j <= 1<<20; j <<= 4 {
1713 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) {
1714 b.ReportAllocs()
1715 b.SetBytes(int64(j))
1716 data := sd.data[:j]
1717 for i := 0; i < b.N; i++ {
1718 Fields(data)
1719 }
1720 })
1721 }
1722 })
1723 }
1724 }
1725
1726 func BenchmarkFieldsFunc(b *testing.B) {
1727 for _, sd := range bytesdata {
1728 b.Run(sd.name, func(b *testing.B) {
1729 for j := 1 << 4; j <= 1<<20; j <<= 4 {
1730 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) {
1731 b.ReportAllocs()
1732 b.SetBytes(int64(j))
1733 data := sd.data[:j]
1734 for i := 0; i < b.N; i++ {
1735 FieldsFunc(data, unicode.IsSpace)
1736 }
1737 })
1738 }
1739 })
1740 }
1741 }
1742
1743 func BenchmarkTrimSpace(b *testing.B) {
1744 tests := []struct {
1745 name string
1746 input []byte
1747 }{
1748 {"NoTrim", []byte("typical")},
1749 {"ASCII", []byte(" foo bar ")},
1750 {"SomeNonASCII", []byte(" \u2000\t\r\n x\t\t\r\r\ny\n \u3000 ")},
1751 {"JustNonASCII", []byte("\u2000\u2000\u2000☺☺☺☺\u3000\u3000\u3000")},
1752 }
1753 for _, test := range tests {
1754 b.Run(test.name, func(b *testing.B) {
1755 for i := 0; i < b.N; i++ {
1756 TrimSpace(test.input)
1757 }
1758 })
1759 }
1760 }
1761
1762 func BenchmarkToValidUTF8(b *testing.B) {
1763 tests := []struct {
1764 name string
1765 input []byte
1766 }{
1767 {"Valid", []byte("typical")},
1768 {"InvalidASCII", []byte("foo\xffbar")},
1769 {"InvalidNonASCII", []byte("日本語\xff日本語")},
1770 }
1771 replacement := []byte("\uFFFD")
1772 b.ResetTimer()
1773 for _, test := range tests {
1774 b.Run(test.name, func(b *testing.B) {
1775 for i := 0; i < b.N; i++ {
1776 ToValidUTF8(test.input, replacement)
1777 }
1778 })
1779 }
1780 }
1781
1782 func makeBenchInputHard() []byte {
1783 tokens := [...]string{
1784 "<a>", "<p>", "<b>", "<strong>",
1785 "</a>", "</p>", "</b>", "</strong>",
1786 "hello", "world",
1787 }
1788 x := make([]byte, 0, 1<<20)
1789 for {
1790 i := rand.Intn(len(tokens))
1791 if len(x)+len(tokens[i]) >= 1<<20 {
1792 break
1793 }
1794 x = append(x, tokens[i]...)
1795 }
1796 return x
1797 }
1798
1799 var benchInputHard = makeBenchInputHard()
1800
1801 func benchmarkIndexHard(b *testing.B, sep []byte) {
1802 for i := 0; i < b.N; i++ {
1803 Index(benchInputHard, sep)
1804 }
1805 }
1806
1807 func benchmarkLastIndexHard(b *testing.B, sep []byte) {
1808 for i := 0; i < b.N; i++ {
1809 LastIndex(benchInputHard, sep)
1810 }
1811 }
1812
1813 func benchmarkCountHard(b *testing.B, sep []byte) {
1814 for i := 0; i < b.N; i++ {
1815 Count(benchInputHard, sep)
1816 }
1817 }
1818
1819 func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, []byte("<>")) }
1820 func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, []byte("</pre>")) }
1821 func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, []byte("<b>hello world</b>")) }
1822 func BenchmarkIndexHard4(b *testing.B) {
1823 benchmarkIndexHard(b, []byte("<pre><b>hello</b><strong>world</strong></pre>"))
1824 }
1825
1826 func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, []byte("<>")) }
1827 func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, []byte("</pre>")) }
1828 func BenchmarkLastIndexHard3(b *testing.B) { benchmarkLastIndexHard(b, []byte("<b>hello world</b>")) }
1829
1830 func BenchmarkCountHard1(b *testing.B) { benchmarkCountHard(b, []byte("<>")) }
1831 func BenchmarkCountHard2(b *testing.B) { benchmarkCountHard(b, []byte("</pre>")) }
1832 func BenchmarkCountHard3(b *testing.B) { benchmarkCountHard(b, []byte("<b>hello world</b>")) }
1833
1834 func BenchmarkSplitEmptySeparator(b *testing.B) {
1835 for i := 0; i < b.N; i++ {
1836 Split(benchInputHard, nil)
1837 }
1838 }
1839
1840 func BenchmarkSplitSingleByteSeparator(b *testing.B) {
1841 sep := []byte("/")
1842 for i := 0; i < b.N; i++ {
1843 Split(benchInputHard, sep)
1844 }
1845 }
1846
1847 func BenchmarkSplitMultiByteSeparator(b *testing.B) {
1848 sep := []byte("hello")
1849 for i := 0; i < b.N; i++ {
1850 Split(benchInputHard, sep)
1851 }
1852 }
1853
1854 func BenchmarkSplitNSingleByteSeparator(b *testing.B) {
1855 sep := []byte("/")
1856 for i := 0; i < b.N; i++ {
1857 SplitN(benchInputHard, sep, 10)
1858 }
1859 }
1860
1861 func BenchmarkSplitNMultiByteSeparator(b *testing.B) {
1862 sep := []byte("hello")
1863 for i := 0; i < b.N; i++ {
1864 SplitN(benchInputHard, sep, 10)
1865 }
1866 }
1867
1868 func BenchmarkRepeat(b *testing.B) {
1869 for i := 0; i < b.N; i++ {
1870 Repeat([]byte("-"), 80)
1871 }
1872 }
1873
1874 func BenchmarkBytesCompare(b *testing.B) {
1875 for n := 1; n <= 2048; n <<= 1 {
1876 b.Run(fmt.Sprint(n), func(b *testing.B) {
1877 var x = make([]byte, n)
1878 var y = make([]byte, n)
1879
1880 for i := 0; i < n; i++ {
1881 x[i] = 'a'
1882 }
1883
1884 for i := 0; i < n; i++ {
1885 y[i] = 'a'
1886 }
1887
1888 b.ResetTimer()
1889 for i := 0; i < b.N; i++ {
1890 Compare(x, y)
1891 }
1892 })
1893 }
1894 }
1895
1896 func BenchmarkIndexAnyASCII(b *testing.B) {
1897 x := Repeat([]byte{'#'}, 2048)
1898 cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
1899 for k := 1; k <= 2048; k <<= 4 {
1900 for j := 1; j <= 64; j <<= 1 {
1901 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
1902 for i := 0; i < b.N; i++ {
1903 IndexAny(x[:k], cs[:j])
1904 }
1905 })
1906 }
1907 }
1908 }
1909
1910 func BenchmarkIndexAnyUTF8(b *testing.B) {
1911 x := Repeat([]byte{'#'}, 2048)
1912 cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
1913 for k := 1; k <= 2048; k <<= 4 {
1914 for j := 1; j <= 64; j <<= 1 {
1915 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
1916 for i := 0; i < b.N; i++ {
1917 IndexAny(x[:k], cs[:j])
1918 }
1919 })
1920 }
1921 }
1922 }
1923
1924 func BenchmarkLastIndexAnyASCII(b *testing.B) {
1925 x := Repeat([]byte{'#'}, 2048)
1926 cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
1927 for k := 1; k <= 2048; k <<= 4 {
1928 for j := 1; j <= 64; j <<= 1 {
1929 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
1930 for i := 0; i < b.N; i++ {
1931 LastIndexAny(x[:k], cs[:j])
1932 }
1933 })
1934 }
1935 }
1936 }
1937
1938 func BenchmarkLastIndexAnyUTF8(b *testing.B) {
1939 x := Repeat([]byte{'#'}, 2048)
1940 cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world."
1941 for k := 1; k <= 2048; k <<= 4 {
1942 for j := 1; j <= 64; j <<= 1 {
1943 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
1944 for i := 0; i < b.N; i++ {
1945 LastIndexAny(x[:k], cs[:j])
1946 }
1947 })
1948 }
1949 }
1950 }
1951
1952 func BenchmarkTrimASCII(b *testing.B) {
1953 cs := "0123456789abcdef"
1954 for k := 1; k <= 4096; k <<= 4 {
1955 for j := 1; j <= 16; j <<= 1 {
1956 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
1957 x := Repeat([]byte(cs[:j]), k)
1958 for i := 0; i < b.N; i++ {
1959 Trim(x[:k], cs[:j])
1960 }
1961 })
1962 }
1963 }
1964 }
1965
1966 func BenchmarkIndexPeriodic(b *testing.B) {
1967 key := []byte{1, 1}
1968 for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
1969 b.Run(fmt.Sprintf("IndexPeriodic%d", skip), func(b *testing.B) {
1970 buf := make([]byte, 1<<16)
1971 for i := 0; i < len(buf); i += skip {
1972 buf[i] = 1
1973 }
1974 for i := 0; i < b.N; i++ {
1975 Index(buf, key)
1976 }
1977 })
1978 }
1979 }
1980
View as plain text