github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/bytes/bytes_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 // For ease of reading, the test cases use strings that are converted to byte 40 // slices before invoking the functions. 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 for _, tt := range compareTests { 55 eql := Equal(tt.a, tt.b) 56 if eql != (tt.i == 0) { 57 t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql) 58 } 59 eql = EqualPortable(tt.a, tt.b) 60 if eql != (tt.i == 0) { 61 t.Errorf(`EqualPortable(%q, %q) = %v`, tt.a, tt.b, eql) 62 } 63 } 64 } 65 66 func TestEqualExhaustive(t *testing.T) { 67 var size = 128 68 if testing.Short() { 69 size = 32 70 } 71 a := make([]byte, size) 72 b := make([]byte, size) 73 b_init := make([]byte, size) 74 // randomish but deterministic data 75 for i := 0; i < size; i++ { 76 a[i] = byte(17 * i) 77 b_init[i] = byte(23*i + 100) 78 } 79 80 for len := 0; len <= size; len++ { 81 for x := 0; x <= size-len; x++ { 82 for y := 0; y <= size-len; y++ { 83 copy(b, b_init) 84 copy(b[y:y+len], a[x:x+len]) 85 if !Equal(a[x:x+len], b[y:y+len]) || !Equal(b[y:y+len], a[x:x+len]) { 86 t.Errorf("Equal(%d, %d, %d) = false", len, x, y) 87 } 88 } 89 } 90 } 91 } 92 93 // make sure Equal returns false for minimally different strings. The data 94 // is all zeros except for a single one in one location. 95 func TestNotEqual(t *testing.T) { 96 var size = 128 97 if testing.Short() { 98 size = 32 99 } 100 a := make([]byte, size) 101 b := make([]byte, size) 102 103 for len := 0; len <= size; len++ { 104 for x := 0; x <= size-len; x++ { 105 for y := 0; y <= size-len; y++ { 106 for diffpos := x; diffpos < x+len; diffpos++ { 107 a[diffpos] = 1 108 if Equal(a[x:x+len], b[y:y+len]) || Equal(b[y:y+len], a[x:x+len]) { 109 t.Errorf("NotEqual(%d, %d, %d, %d) = true", len, x, y, diffpos) 110 } 111 a[diffpos] = 0 112 } 113 } 114 } 115 } 116 } 117 118 var indexTests = []BinOpTest{ 119 {"", "", 0}, 120 {"", "a", -1}, 121 {"", "foo", -1}, 122 {"fo", "foo", -1}, 123 {"foo", "baz", -1}, 124 {"foo", "foo", 0}, 125 {"oofofoofooo", "f", 2}, 126 {"oofofoofooo", "foo", 4}, 127 {"barfoobarfoo", "foo", 3}, 128 {"foo", "", 0}, 129 {"foo", "o", 1}, 130 {"abcABCabc", "A", 3}, 131 // cases with one byte strings - test IndexByte and special case in Index() 132 {"", "a", -1}, 133 {"x", "a", -1}, 134 {"x", "x", 0}, 135 {"abc", "a", 0}, 136 {"abc", "b", 1}, 137 {"abc", "c", 2}, 138 {"abc", "x", -1}, 139 {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33}, 140 {"foofyfoobarfoobar", "y", 4}, 141 {"oooooooooooooooooooooo", "r", -1}, 142 // test fallback to Rabin-Karp. 143 {"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22}, 144 {"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1}, 145 } 146 147 var lastIndexTests = []BinOpTest{ 148 {"", "", 0}, 149 {"", "a", -1}, 150 {"", "foo", -1}, 151 {"fo", "foo", -1}, 152 {"foo", "foo", 0}, 153 {"foo", "f", 0}, 154 {"oofofoofooo", "f", 7}, 155 {"oofofoofooo", "foo", 7}, 156 {"barfoobarfoo", "foo", 9}, 157 {"foo", "", 3}, 158 {"foo", "o", 2}, 159 {"abcABCabc", "A", 3}, 160 {"abcABCabc", "a", 6}, 161 } 162 163 var indexAnyTests = []BinOpTest{ 164 {"", "", -1}, 165 {"", "a", -1}, 166 {"", "abc", -1}, 167 {"a", "", -1}, 168 {"a", "a", 0}, 169 {"aaa", "a", 0}, 170 {"abc", "xyz", -1}, 171 {"abc", "xcz", 2}, 172 {"ab☺c", "x☺yz", 2}, 173 {"a☺b☻c☹d", "cx", len("a☺b☻")}, 174 {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")}, 175 {"aRegExp*", ".(|)*+?^$[]", 7}, 176 {dots + dots + dots, " ", -1}, 177 {"012abcba210", "\xffb", 4}, 178 {"012\x80bcb\x80210", "\xffb", 3}, 179 } 180 181 var lastIndexAnyTests = []BinOpTest{ 182 {"", "", -1}, 183 {"", "a", -1}, 184 {"", "abc", -1}, 185 {"a", "", -1}, 186 {"a", "a", 0}, 187 {"aaa", "a", 2}, 188 {"abc", "xyz", -1}, 189 {"abc", "ab", 1}, 190 {"ab☺c", "x☺yz", 2}, 191 {"a☺b☻c☹d", "cx", len("a☺b☻")}, 192 {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")}, 193 {"a.RegExp*", ".(|)*+?^$[]", 8}, 194 {dots + dots + dots, " ", -1}, 195 {"012abcba210", "\xffb", 6}, 196 {"012\x80bcb\x80210", "\xffb", 7}, 197 } 198 199 // Execute f on each test case. funcName should be the name of f; it's used 200 // in failure reports. 201 func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) { 202 for _, test := range testCases { 203 a := []byte(test.a) 204 b := []byte(test.b) 205 actual := f(a, b) 206 if actual != test.i { 207 t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, b, actual, test.i) 208 } 209 } 210 } 211 212 func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) { 213 for _, test := range testCases { 214 a := []byte(test.a) 215 actual := f(a, test.b) 216 if actual != test.i { 217 t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i) 218 } 219 } 220 } 221 222 func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) } 223 func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) } 224 func TestIndexAny(t *testing.T) { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) } 225 func TestLastIndexAny(t *testing.T) { 226 runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) 227 } 228 229 func TestIndexByte(t *testing.T) { 230 for _, tt := range indexTests { 231 if len(tt.b) != 1 { 232 continue 233 } 234 a := []byte(tt.a) 235 b := tt.b[0] 236 pos := IndexByte(a, b) 237 if pos != tt.i { 238 t.Errorf(`IndexByte(%q, '%c') = %v`, tt.a, b, pos) 239 } 240 posp := IndexBytePortable(a, b) 241 if posp != tt.i { 242 t.Errorf(`indexBytePortable(%q, '%c') = %v`, tt.a, b, posp) 243 } 244 } 245 } 246 247 func TestLastIndexByte(t *testing.T) { 248 testCases := []BinOpTest{ 249 {"", "q", -1}, 250 {"abcdef", "q", -1}, 251 {"abcdefabcdef", "a", len("abcdef")}, // something in the middle 252 {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte 253 {"zabcdefabcdef", "z", 0}, // first byte 254 {"a☺b☻c☹d", "b", len("a☺")}, // non-ascii 255 } 256 for _, test := range testCases { 257 actual := LastIndexByte([]byte(test.a), test.b[0]) 258 if actual != test.i { 259 t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i) 260 } 261 } 262 } 263 264 // test a larger buffer with different sizes and alignments 265 func TestIndexByteBig(t *testing.T) { 266 var n = 1024 267 if testing.Short() { 268 n = 128 269 } 270 b := make([]byte, n) 271 for i := 0; i < n; i++ { 272 // different start alignments 273 b1 := b[i:] 274 for j := 0; j < len(b1); j++ { 275 b1[j] = 'x' 276 pos := IndexByte(b1, 'x') 277 if pos != j { 278 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 279 } 280 b1[j] = 0 281 pos = IndexByte(b1, 'x') 282 if pos != -1 { 283 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 284 } 285 } 286 // different end alignments 287 b1 = b[:i] 288 for j := 0; j < len(b1); j++ { 289 b1[j] = 'x' 290 pos := IndexByte(b1, 'x') 291 if pos != j { 292 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 293 } 294 b1[j] = 0 295 pos = IndexByte(b1, 'x') 296 if pos != -1 { 297 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 298 } 299 } 300 // different start and end alignments 301 b1 = b[i/2 : n-(i+1)/2] 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 } 316 317 // test a small index across all page offsets 318 func TestIndexByteSmall(t *testing.T) { 319 b := make([]byte, 5015) // bigger than a page 320 // Make sure we find the correct byte even when straddling a page. 321 for i := 0; i <= len(b)-15; i++ { 322 for j := 0; j < 15; j++ { 323 b[i+j] = byte(100 + j) 324 } 325 for j := 0; j < 15; j++ { 326 p := IndexByte(b[i:i+15], byte(100+j)) 327 if p != j { 328 t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 100+j, p) 329 } 330 } 331 for j := 0; j < 15; j++ { 332 b[i+j] = 0 333 } 334 } 335 // Make sure matches outside the slice never trigger. 336 for i := 0; i <= len(b)-15; i++ { 337 for j := 0; j < 15; j++ { 338 b[i+j] = 1 339 } 340 for j := 0; j < 15; j++ { 341 p := IndexByte(b[i:i+15], byte(0)) 342 if p != -1 { 343 t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 0, p) 344 } 345 } 346 for j := 0; j < 15; j++ { 347 b[i+j] = 0 348 } 349 } 350 } 351 352 func TestIndexRune(t *testing.T) { 353 tests := []struct { 354 in string 355 rune rune 356 want int 357 }{ 358 {"", 'a', -1}, 359 {"", '☺', -1}, 360 {"foo", '☹', -1}, 361 {"foo", 'o', 1}, 362 {"foo☺bar", '☺', 3}, 363 {"foo☺☻☹bar", '☹', 9}, 364 {"a A x", 'A', 2}, 365 {"some_text=some_value", '=', 9}, 366 {"☺a", 'a', 3}, 367 {"a☻☺b", '☺', 4}, 368 369 // RuneError should match any invalid UTF-8 byte sequence. 370 {"�", '�', 0}, 371 {"\xff", '�', 0}, 372 {"☻x�", '�', len("☻x")}, 373 {"☻x\xe2\x98", '�', len("☻x")}, 374 {"☻x\xe2\x98�", '�', len("☻x")}, 375 {"☻x\xe2\x98x", '�', len("☻x")}, 376 377 // Invalid rune values should never match. 378 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1}, 379 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair 380 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1}, 381 } 382 for _, tt := range tests { 383 if got := IndexRune([]byte(tt.in), tt.rune); got != tt.want { 384 t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want) 385 } 386 } 387 388 haystack := []byte("test世界") 389 allocs := testing.AllocsPerRun(1000, func() { 390 if i := IndexRune(haystack, 's'); i != 2 { 391 t.Fatalf("'s' at %d; want 2", i) 392 } 393 if i := IndexRune(haystack, '世'); i != 4 { 394 t.Fatalf("'世' at %d; want 4", i) 395 } 396 }) 397 if allocs != 0 { 398 t.Errorf("expected no allocations, got %f", allocs) 399 } 400 } 401 402 // test count of a single byte across page offsets 403 func TestCountByte(t *testing.T) { 404 b := make([]byte, 5015) // bigger than a page 405 windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128} 406 testCountWindow := func(i, window int) { 407 for j := 0; j < window; j++ { 408 b[i+j] = byte(100) 409 p := Count(b[i:i+window], []byte{100}) 410 if p != j+1 { 411 t.Errorf("TestCountByte.Count(%q, 100) = %d", b[i:i+window], p) 412 } 413 } 414 } 415 416 maxWnd := windows[len(windows)-1] 417 418 for i := 0; i <= 2*maxWnd; i++ { 419 for _, window := range windows { 420 if window > len(b[i:]) { 421 window = len(b[i:]) 422 } 423 testCountWindow(i, window) 424 for j := 0; j < window; j++ { 425 b[i+j] = byte(0) 426 } 427 } 428 } 429 for i := 4096 - (maxWnd + 1); i < len(b); i++ { 430 for _, window := range windows { 431 if window > len(b[i:]) { 432 window = len(b[i:]) 433 } 434 testCountWindow(i, window) 435 for j := 0; j < window; j++ { 436 b[i+j] = byte(0) 437 } 438 } 439 } 440 } 441 442 // Make sure we don't count bytes outside our window 443 func TestCountByteNoMatch(t *testing.T) { 444 b := make([]byte, 5015) 445 windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128} 446 for i := 0; i <= len(b); i++ { 447 for _, window := range windows { 448 if window > len(b[i:]) { 449 window = len(b[i:]) 450 } 451 // Fill the window with non-match 452 for j := 0; j < window; j++ { 453 b[i+j] = byte(100) 454 } 455 // Try to find something that doesn't exist 456 p := Count(b[i:i+window], []byte{0}) 457 if p != 0 { 458 t.Errorf("TestCountByteNoMatch(%q, 0) = %d", b[i:i+window], p) 459 } 460 for j := 0; j < window; j++ { 461 b[i+j] = byte(0) 462 } 463 } 464 } 465 } 466 467 var bmbuf []byte 468 469 func valName(x int) string { 470 if s := x >> 20; s<<20 == x { 471 return fmt.Sprintf("%dM", s) 472 } 473 if s := x >> 10; s<<10 == x { 474 return fmt.Sprintf("%dK", s) 475 } 476 return fmt.Sprint(x) 477 } 478 479 func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) { 480 for _, n := range sizes { 481 if isRaceBuilder && n > 4<<10 { 482 continue 483 } 484 b.Run(valName(n), func(b *testing.B) { 485 if len(bmbuf) < n { 486 bmbuf = make([]byte, n) 487 } 488 b.SetBytes(int64(n)) 489 f(b, n) 490 }) 491 } 492 } 493 494 var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20} 495 496 var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race") 497 498 func BenchmarkIndexByte(b *testing.B) { 499 benchBytes(b, indexSizes, bmIndexByte(IndexByte)) 500 } 501 502 func BenchmarkIndexBytePortable(b *testing.B) { 503 benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable)) 504 } 505 506 func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) { 507 return func(b *testing.B, n int) { 508 buf := bmbuf[0:n] 509 buf[n-1] = 'x' 510 for i := 0; i < b.N; i++ { 511 j := index(buf, 'x') 512 if j != n-1 { 513 b.Fatal("bad index", j) 514 } 515 } 516 buf[n-1] = '\x00' 517 } 518 } 519 520 func BenchmarkIndexRune(b *testing.B) { 521 benchBytes(b, indexSizes, bmIndexRune(IndexRune)) 522 } 523 524 func BenchmarkIndexRuneASCII(b *testing.B) { 525 benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune)) 526 } 527 528 func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) { 529 return func(b *testing.B, n int) { 530 buf := bmbuf[0:n] 531 buf[n-1] = 'x' 532 for i := 0; i < b.N; i++ { 533 j := index(buf, 'x') 534 if j != n-1 { 535 b.Fatal("bad index", j) 536 } 537 } 538 buf[n-1] = '\x00' 539 } 540 } 541 542 func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) { 543 return func(b *testing.B, n int) { 544 buf := bmbuf[0:n] 545 utf8.EncodeRune(buf[n-3:], '世') 546 for i := 0; i < b.N; i++ { 547 j := index(buf, '世') 548 if j != n-3 { 549 b.Fatal("bad index", j) 550 } 551 } 552 buf[n-3] = '\x00' 553 buf[n-2] = '\x00' 554 buf[n-1] = '\x00' 555 } 556 } 557 558 func BenchmarkEqual(b *testing.B) { 559 b.Run("0", func(b *testing.B) { 560 var buf [4]byte 561 buf1 := buf[0:0] 562 buf2 := buf[1:1] 563 for i := 0; i < b.N; i++ { 564 eq := Equal(buf1, buf2) 565 if !eq { 566 b.Fatal("bad equal") 567 } 568 } 569 }) 570 571 sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20} 572 benchBytes(b, sizes, bmEqual(Equal)) 573 } 574 575 func BenchmarkEqualPort(b *testing.B) { 576 sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20} 577 benchBytes(b, sizes, bmEqual(EqualPortable)) 578 } 579 580 func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) { 581 return func(b *testing.B, n int) { 582 if len(bmbuf) < 2*n { 583 bmbuf = make([]byte, 2*n) 584 } 585 buf1 := bmbuf[0:n] 586 buf2 := bmbuf[n : 2*n] 587 buf1[n-1] = 'x' 588 buf2[n-1] = 'x' 589 for i := 0; i < b.N; i++ { 590 eq := equal(buf1, buf2) 591 if !eq { 592 b.Fatal("bad equal") 593 } 594 } 595 buf1[n-1] = '\x00' 596 buf2[n-1] = '\x00' 597 } 598 } 599 600 func BenchmarkIndex(b *testing.B) { 601 benchBytes(b, indexSizes, func(b *testing.B, n int) { 602 buf := bmbuf[0:n] 603 buf[n-1] = 'x' 604 for i := 0; i < b.N; i++ { 605 j := Index(buf, buf[n-7:]) 606 if j != n-7 { 607 b.Fatal("bad index", j) 608 } 609 } 610 buf[n-1] = '\x00' 611 }) 612 } 613 614 func BenchmarkIndexEasy(b *testing.B) { 615 benchBytes(b, indexSizes, func(b *testing.B, n int) { 616 buf := bmbuf[0:n] 617 buf[n-1] = 'x' 618 buf[n-7] = 'x' 619 for i := 0; i < b.N; i++ { 620 j := Index(buf, buf[n-7:]) 621 if j != n-7 { 622 b.Fatal("bad index", j) 623 } 624 } 625 buf[n-1] = '\x00' 626 buf[n-7] = '\x00' 627 }) 628 } 629 630 func BenchmarkCount(b *testing.B) { 631 benchBytes(b, indexSizes, func(b *testing.B, n int) { 632 buf := bmbuf[0:n] 633 buf[n-1] = 'x' 634 for i := 0; i < b.N; i++ { 635 j := Count(buf, buf[n-7:]) 636 if j != 1 { 637 b.Fatal("bad count", j) 638 } 639 } 640 buf[n-1] = '\x00' 641 }) 642 } 643 644 func BenchmarkCountEasy(b *testing.B) { 645 benchBytes(b, indexSizes, func(b *testing.B, n int) { 646 buf := bmbuf[0:n] 647 buf[n-1] = 'x' 648 buf[n-7] = 'x' 649 for i := 0; i < b.N; i++ { 650 j := Count(buf, buf[n-7:]) 651 if j != 1 { 652 b.Fatal("bad count", j) 653 } 654 } 655 buf[n-1] = '\x00' 656 buf[n-7] = '\x00' 657 }) 658 } 659 660 func BenchmarkCountSingle(b *testing.B) { 661 benchBytes(b, indexSizes, func(b *testing.B, n int) { 662 buf := bmbuf[0:n] 663 step := 8 664 for i := 0; i < len(buf); i += step { 665 buf[i] = 1 666 } 667 expect := (len(buf) + (step - 1)) / step 668 for i := 0; i < b.N; i++ { 669 j := Count(buf, []byte{1}) 670 if j != expect { 671 b.Fatal("bad count", j, expect) 672 } 673 } 674 for i := 0; i < len(buf); i++ { 675 buf[i] = 0 676 } 677 }) 678 } 679 680 type ExplodeTest struct { 681 s string 682 n int 683 a []string 684 } 685 686 var explodetests = []ExplodeTest{ 687 {"", -1, []string{}}, 688 {abcd, -1, []string{"a", "b", "c", "d"}}, 689 {faces, -1, []string{"☺", "☻", "☹"}}, 690 {abcd, 2, []string{"a", "bcd"}}, 691 } 692 693 func TestExplode(t *testing.T) { 694 for _, tt := range explodetests { 695 a := SplitN([]byte(tt.s), nil, tt.n) 696 result := sliceOfString(a) 697 if !eq(result, tt.a) { 698 t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a) 699 continue 700 } 701 s := Join(a, []byte{}) 702 if string(s) != tt.s { 703 t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s) 704 } 705 } 706 } 707 708 type SplitTest struct { 709 s string 710 sep string 711 n int 712 a []string 713 } 714 715 var splittests = []SplitTest{ 716 {abcd, "a", 0, nil}, 717 {abcd, "a", -1, []string{"", "bcd"}}, 718 {abcd, "z", -1, []string{"abcd"}}, 719 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 720 {commas, ",", -1, []string{"1", "2", "3", "4"}}, 721 {dots, "...", -1, []string{"1", ".2", ".3", ".4"}}, 722 {faces, "☹", -1, []string{"☺☻", ""}}, 723 {faces, "~", -1, []string{faces}}, 724 {faces, "", -1, []string{"☺", "☻", "☹"}}, 725 {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}}, 726 {"1 2", " ", 3, []string{"1", "2"}}, 727 {"123", "", 2, []string{"1", "23"}}, 728 {"123", "", 17, []string{"1", "2", "3"}}, 729 } 730 731 func TestSplit(t *testing.T) { 732 for _, tt := range splittests { 733 a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n) 734 735 // Appending to the results should not change future results. 736 var x []byte 737 for _, v := range a { 738 x = append(v, 'z') 739 } 740 741 result := sliceOfString(a) 742 if !eq(result, tt.a) { 743 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) 744 continue 745 } 746 if tt.n == 0 { 747 continue 748 } 749 750 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { 751 t.Errorf("last appended result was %s; want %s", x, want) 752 } 753 754 s := Join(a, []byte(tt.sep)) 755 if string(s) != tt.s { 756 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 757 } 758 if tt.n < 0 { 759 b := Split([]byte(tt.s), []byte(tt.sep)) 760 if !reflect.DeepEqual(a, b) { 761 t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 762 } 763 } 764 if len(a) > 0 { 765 in, out := a[0], s 766 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] { 767 t.Errorf("Join(%#v, %q) didn't copy", a, tt.sep) 768 } 769 } 770 } 771 } 772 773 var splitaftertests = []SplitTest{ 774 {abcd, "a", -1, []string{"a", "bcd"}}, 775 {abcd, "z", -1, []string{"abcd"}}, 776 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 777 {commas, ",", -1, []string{"1,", "2,", "3,", "4"}}, 778 {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}}, 779 {faces, "☹", -1, []string{"☺☻☹", ""}}, 780 {faces, "~", -1, []string{faces}}, 781 {faces, "", -1, []string{"☺", "☻", "☹"}}, 782 {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}}, 783 {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}}, 784 {"1 2", " ", 3, []string{"1 ", "2"}}, 785 {"123", "", 2, []string{"1", "23"}}, 786 {"123", "", 17, []string{"1", "2", "3"}}, 787 } 788 789 func TestSplitAfter(t *testing.T) { 790 for _, tt := range splitaftertests { 791 a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n) 792 793 // Appending to the results should not change future results. 794 var x []byte 795 for _, v := range a { 796 x = append(v, 'z') 797 } 798 799 result := sliceOfString(a) 800 if !eq(result, tt.a) { 801 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) 802 continue 803 } 804 805 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { 806 t.Errorf("last appended result was %s; want %s", x, want) 807 } 808 809 s := Join(a, nil) 810 if string(s) != tt.s { 811 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 812 } 813 if tt.n < 0 { 814 b := SplitAfter([]byte(tt.s), []byte(tt.sep)) 815 if !reflect.DeepEqual(a, b) { 816 t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 817 } 818 } 819 } 820 } 821 822 type FieldsTest struct { 823 s string 824 a []string 825 } 826 827 var fieldstests = []FieldsTest{ 828 {"", []string{}}, 829 {" ", []string{}}, 830 {" \t ", []string{}}, 831 {" abc ", []string{"abc"}}, 832 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 833 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 834 {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}}, 835 {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}}, 836 {"\u2000\u2001\u2002", []string{}}, 837 {"\n™\t™\n", []string{"™", "™"}}, 838 {faces, []string{faces}}, 839 } 840 841 func TestFields(t *testing.T) { 842 for _, tt := range fieldstests { 843 b := []byte(tt.s) 844 a := Fields(b) 845 846 // Appending to the results should not change future results. 847 var x []byte 848 for _, v := range a { 849 x = append(v, 'z') 850 } 851 852 result := sliceOfString(a) 853 if !eq(result, tt.a) { 854 t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) 855 continue 856 } 857 858 if string(b) != tt.s { 859 t.Errorf("slice changed to %s; want %s", string(b), tt.s) 860 } 861 if len(tt.a) > 0 { 862 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { 863 t.Errorf("last appended result was %s; want %s", x, want) 864 } 865 } 866 } 867 } 868 869 func TestFieldsFunc(t *testing.T) { 870 for _, tt := range fieldstests { 871 a := FieldsFunc([]byte(tt.s), unicode.IsSpace) 872 result := sliceOfString(a) 873 if !eq(result, tt.a) { 874 t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a) 875 continue 876 } 877 } 878 pred := func(c rune) bool { return c == 'X' } 879 var fieldsFuncTests = []FieldsTest{ 880 {"", []string{}}, 881 {"XX", []string{}}, 882 {"XXhiXXX", []string{"hi"}}, 883 {"aXXbXXXcX", []string{"a", "b", "c"}}, 884 } 885 for _, tt := range fieldsFuncTests { 886 b := []byte(tt.s) 887 a := FieldsFunc(b, pred) 888 889 // Appending to the results should not change future results. 890 var x []byte 891 for _, v := range a { 892 x = append(v, 'z') 893 } 894 895 result := sliceOfString(a) 896 if !eq(result, tt.a) { 897 t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) 898 } 899 900 if string(b) != tt.s { 901 t.Errorf("slice changed to %s; want %s", b, tt.s) 902 } 903 if len(tt.a) > 0 { 904 if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { 905 t.Errorf("last appended result was %s; want %s", x, want) 906 } 907 } 908 } 909 } 910 911 // Test case for any function which accepts and returns a byte slice. 912 // For ease of creation, we write the byte slices as strings. 913 type StringTest struct { 914 in, out string 915 } 916 917 var upperTests = []StringTest{ 918 {"", ""}, 919 {"abc", "ABC"}, 920 {"AbC123", "ABC123"}, 921 {"azAZ09_", "AZAZ09_"}, 922 {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char 923 } 924 925 var lowerTests = []StringTest{ 926 {"", ""}, 927 {"abc", "abc"}, 928 {"AbC123", "abc123"}, 929 {"azAZ09_", "azaz09_"}, 930 {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char 931 } 932 933 const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000" 934 935 var trimSpaceTests = []StringTest{ 936 {"", ""}, 937 {"abc", "abc"}, 938 {space + "abc" + space, "abc"}, 939 {" ", ""}, 940 {" \t\r\n \t\t\r\r\n\n ", ""}, 941 {" \t\r\n x\t\t\r\r\n\n ", "x"}, 942 {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"}, 943 {"1 \t\r\n2", "1 \t\r\n2"}, 944 {" x\x80", "x\x80"}, 945 {" x\xc0", "x\xc0"}, 946 {"x \xc0\xc0 ", "x \xc0\xc0"}, 947 {"x \xc0", "x \xc0"}, 948 {"x \xc0 ", "x \xc0"}, 949 {"x \xc0\xc0 ", "x \xc0\xc0"}, 950 {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"}, 951 {"x ☺ ", "x ☺"}, 952 } 953 954 // Execute f on each test case. funcName should be the name of f; it's used 955 // in failure reports. 956 func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) { 957 for _, tc := range testCases { 958 actual := string(f([]byte(tc.in))) 959 if actual != tc.out { 960 t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out) 961 } 962 } 963 } 964 965 func tenRunes(r rune) string { 966 runes := make([]rune, 10) 967 for i := range runes { 968 runes[i] = r 969 } 970 return string(runes) 971 } 972 973 // User-defined self-inverse mapping function 974 func rot13(r rune) rune { 975 const step = 13 976 if r >= 'a' && r <= 'z' { 977 return ((r - 'a' + step) % 26) + 'a' 978 } 979 if r >= 'A' && r <= 'Z' { 980 return ((r - 'A' + step) % 26) + 'A' 981 } 982 return r 983 } 984 985 func TestMap(t *testing.T) { 986 // Run a couple of awful growth/shrinkage tests 987 a := tenRunes('a') 988 989 // 1. Grow. This triggers two reallocations in Map. 990 maxRune := func(r rune) rune { return unicode.MaxRune } 991 m := Map(maxRune, []byte(a)) 992 expect := tenRunes(unicode.MaxRune) 993 if string(m) != expect { 994 t.Errorf("growing: expected %q got %q", expect, m) 995 } 996 997 // 2. Shrink 998 minRune := func(r rune) rune { return 'a' } 999 m = Map(minRune, []byte(tenRunes(unicode.MaxRune))) 1000 expect = a 1001 if string(m) != expect { 1002 t.Errorf("shrinking: expected %q got %q", expect, m) 1003 } 1004 1005 // 3. Rot13 1006 m = Map(rot13, []byte("a to zed")) 1007 expect = "n gb mrq" 1008 if string(m) != expect { 1009 t.Errorf("rot13: expected %q got %q", expect, m) 1010 } 1011 1012 // 4. Rot13^2 1013 m = Map(rot13, Map(rot13, []byte("a to zed"))) 1014 expect = "a to zed" 1015 if string(m) != expect { 1016 t.Errorf("rot13: expected %q got %q", expect, m) 1017 } 1018 1019 // 5. Drop 1020 dropNotLatin := func(r rune) rune { 1021 if unicode.Is(unicode.Latin, r) { 1022 return r 1023 } 1024 return -1 1025 } 1026 m = Map(dropNotLatin, []byte("Hello, 세계")) 1027 expect = "Hello" 1028 if string(m) != expect { 1029 t.Errorf("drop: expected %q got %q", expect, m) 1030 } 1031 1032 // 6. Invalid rune 1033 invalidRune := func(r rune) rune { 1034 return utf8.MaxRune + 1 1035 } 1036 m = Map(invalidRune, []byte("x")) 1037 expect = "\uFFFD" 1038 if string(m) != expect { 1039 t.Errorf("invalidRune: expected %q got %q", expect, m) 1040 } 1041 } 1042 1043 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } 1044 1045 func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } 1046 1047 func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) } 1048 1049 type RepeatTest struct { 1050 in, out string 1051 count int 1052 } 1053 1054 var RepeatTests = []RepeatTest{ 1055 {"", "", 0}, 1056 {"", "", 1}, 1057 {"", "", 2}, 1058 {"-", "", 0}, 1059 {"-", "-", 1}, 1060 {"-", "----------", 10}, 1061 {"abc ", "abc abc abc ", 3}, 1062 } 1063 1064 func TestRepeat(t *testing.T) { 1065 for _, tt := range RepeatTests { 1066 tin := []byte(tt.in) 1067 tout := []byte(tt.out) 1068 a := Repeat(tin, tt.count) 1069 if !Equal(a, tout) { 1070 t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout) 1071 continue 1072 } 1073 } 1074 } 1075 1076 func repeat(b []byte, count int) (err error) { 1077 defer func() { 1078 if r := recover(); r != nil { 1079 switch v := r.(type) { 1080 case error: 1081 err = v 1082 default: 1083 err = fmt.Errorf("%s", v) 1084 } 1085 } 1086 }() 1087 1088 Repeat(b, count) 1089 1090 return 1091 } 1092 1093 // See Issue golang.org/issue/16237 1094 func TestRepeatCatchesOverflow(t *testing.T) { 1095 tests := [...]struct { 1096 s string 1097 count int 1098 errStr string 1099 }{ 1100 0: {"--", -2147483647, "negative"}, 1101 1: {"", int(^uint(0) >> 1), ""}, 1102 2: {"-", 10, ""}, 1103 3: {"gopher", 0, ""}, 1104 4: {"-", -1, "negative"}, 1105 5: {"--", -102, "negative"}, 1106 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"}, 1107 } 1108 1109 for i, tt := range tests { 1110 err := repeat([]byte(tt.s), tt.count) 1111 if tt.errStr == "" { 1112 if err != nil { 1113 t.Errorf("#%d panicked %v", i, err) 1114 } 1115 continue 1116 } 1117 1118 if err == nil || !strings.Contains(err.Error(), tt.errStr) { 1119 t.Errorf("#%d expected %q got %q", i, tt.errStr, err) 1120 } 1121 } 1122 } 1123 1124 func runesEqual(a, b []rune) bool { 1125 if len(a) != len(b) { 1126 return false 1127 } 1128 for i, r := range a { 1129 if r != b[i] { 1130 return false 1131 } 1132 } 1133 return true 1134 } 1135 1136 type RunesTest struct { 1137 in string 1138 out []rune 1139 lossy bool 1140 } 1141 1142 var RunesTests = []RunesTest{ 1143 {"", []rune{}, false}, 1144 {" ", []rune{32}, false}, 1145 {"ABC", []rune{65, 66, 67}, false}, 1146 {"abc", []rune{97, 98, 99}, false}, 1147 {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false}, 1148 {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true}, 1149 {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true}, 1150 } 1151 1152 func TestRunes(t *testing.T) { 1153 for _, tt := range RunesTests { 1154 tin := []byte(tt.in) 1155 a := Runes(tin) 1156 if !runesEqual(a, tt.out) { 1157 t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out) 1158 continue 1159 } 1160 if !tt.lossy { 1161 // can only test reassembly if we didn't lose information 1162 s := string(a) 1163 if s != tt.in { 1164 t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin) 1165 } 1166 } 1167 } 1168 } 1169 1170 type TrimTest struct { 1171 f string 1172 in, arg, out string 1173 } 1174 1175 var trimTests = []TrimTest{ 1176 {"Trim", "abba", "a", "bb"}, 1177 {"Trim", "abba", "ab", ""}, 1178 {"TrimLeft", "abba", "ab", ""}, 1179 {"TrimRight", "abba", "ab", ""}, 1180 {"TrimLeft", "abba", "a", "bba"}, 1181 {"TrimRight", "abba", "a", "abb"}, 1182 {"Trim", "<tag>", "<>", "tag"}, 1183 {"Trim", "* listitem", " *", "listitem"}, 1184 {"Trim", `"quote"`, `"`, "quote"}, 1185 {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"}, 1186 {"Trim", "\x80test\xff", "\xff", "test"}, 1187 {"Trim", " Ġ ", " ", "Ġ"}, 1188 {"Trim", " Ġİ0", "0 ", "Ġİ"}, 1189 //empty string tests 1190 {"Trim", "abba", "", "abba"}, 1191 {"Trim", "", "123", ""}, 1192 {"Trim", "", "", ""}, 1193 {"TrimLeft", "abba", "", "abba"}, 1194 {"TrimLeft", "", "123", ""}, 1195 {"TrimLeft", "", "", ""}, 1196 {"TrimRight", "abba", "", "abba"}, 1197 {"TrimRight", "", "123", ""}, 1198 {"TrimRight", "", "", ""}, 1199 {"TrimRight", "☺\xc0", "☺", "☺\xc0"}, 1200 {"TrimPrefix", "aabb", "a", "abb"}, 1201 {"TrimPrefix", "aabb", "b", "aabb"}, 1202 {"TrimSuffix", "aabb", "a", "aabb"}, 1203 {"TrimSuffix", "aabb", "b", "aab"}, 1204 } 1205 1206 func TestTrim(t *testing.T) { 1207 for _, tc := range trimTests { 1208 name := tc.f 1209 var f func([]byte, string) []byte 1210 var fb func([]byte, []byte) []byte 1211 switch name { 1212 case "Trim": 1213 f = Trim 1214 case "TrimLeft": 1215 f = TrimLeft 1216 case "TrimRight": 1217 f = TrimRight 1218 case "TrimPrefix": 1219 fb = TrimPrefix 1220 case "TrimSuffix": 1221 fb = TrimSuffix 1222 default: 1223 t.Errorf("Undefined trim function %s", name) 1224 } 1225 var actual string 1226 if f != nil { 1227 actual = string(f([]byte(tc.in), tc.arg)) 1228 } else { 1229 actual = string(fb([]byte(tc.in), []byte(tc.arg))) 1230 } 1231 if actual != tc.out { 1232 t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) 1233 } 1234 } 1235 } 1236 1237 type predicate struct { 1238 f func(r rune) bool 1239 name string 1240 } 1241 1242 var isSpace = predicate{unicode.IsSpace, "IsSpace"} 1243 var isDigit = predicate{unicode.IsDigit, "IsDigit"} 1244 var isUpper = predicate{unicode.IsUpper, "IsUpper"} 1245 var isValidRune = predicate{ 1246 func(r rune) bool { 1247 return r != utf8.RuneError 1248 }, 1249 "IsValidRune", 1250 } 1251 1252 type TrimFuncTest struct { 1253 f predicate 1254 in, out string 1255 } 1256 1257 func not(p predicate) predicate { 1258 return predicate{ 1259 func(r rune) bool { 1260 return !p.f(r) 1261 }, 1262 "not " + p.name, 1263 } 1264 } 1265 1266 var trimFuncTests = []TrimFuncTest{ 1267 {isSpace, space + " hello " + space, "hello"}, 1268 {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"}, 1269 {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"}, 1270 {not(isSpace), "hello" + space + "hello", space}, 1271 {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"}, 1272 {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"}, 1273 {not(isValidRune), "\xc0a\xc0", "a"}, 1274 } 1275 1276 func TestTrimFunc(t *testing.T) { 1277 for _, tc := range trimFuncTests { 1278 actual := string(TrimFunc([]byte(tc.in), tc.f.f)) 1279 if actual != tc.out { 1280 t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out) 1281 } 1282 } 1283 } 1284 1285 type IndexFuncTest struct { 1286 in string 1287 f predicate 1288 first, last int 1289 } 1290 1291 var indexFuncTests = []IndexFuncTest{ 1292 {"", isValidRune, -1, -1}, 1293 {"abc", isDigit, -1, -1}, 1294 {"0123", isDigit, 0, 3}, 1295 {"a1b", isDigit, 1, 1}, 1296 {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes 1297 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18}, 1298 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34}, 1299 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12}, 1300 1301 // tests of invalid UTF-8 1302 {"\x801", isDigit, 1, 1}, 1303 {"\x80abc", isDigit, -1, -1}, 1304 {"\xc0a\xc0", isValidRune, 1, 1}, 1305 {"\xc0a\xc0", not(isValidRune), 0, 2}, 1306 {"\xc0☺\xc0", not(isValidRune), 0, 4}, 1307 {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5}, 1308 {"ab\xc0a\xc0cd", not(isValidRune), 2, 4}, 1309 {"a\xe0\x80cd", not(isValidRune), 1, 2}, 1310 } 1311 1312 func TestIndexFunc(t *testing.T) { 1313 for _, tc := range indexFuncTests { 1314 first := IndexFunc([]byte(tc.in), tc.f.f) 1315 if first != tc.first { 1316 t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first) 1317 } 1318 last := LastIndexFunc([]byte(tc.in), tc.f.f) 1319 if last != tc.last { 1320 t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last) 1321 } 1322 } 1323 } 1324 1325 type ReplaceTest struct { 1326 in string 1327 old, new string 1328 n int 1329 out string 1330 } 1331 1332 var ReplaceTests = []ReplaceTest{ 1333 {"hello", "l", "L", 0, "hello"}, 1334 {"hello", "l", "L", -1, "heLLo"}, 1335 {"hello", "x", "X", -1, "hello"}, 1336 {"", "x", "X", -1, ""}, 1337 {"radar", "r", "<r>", -1, "<r>ada<r>"}, 1338 {"", "", "<>", -1, "<>"}, 1339 {"banana", "a", "<>", -1, "b<>n<>n<>"}, 1340 {"banana", "a", "<>", 1, "b<>nana"}, 1341 {"banana", "a", "<>", 1000, "b<>n<>n<>"}, 1342 {"banana", "an", "<>", -1, "b<><>a"}, 1343 {"banana", "ana", "<>", -1, "b<>na"}, 1344 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"}, 1345 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"}, 1346 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"}, 1347 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"}, 1348 {"banana", "", "<>", 1, "<>banana"}, 1349 {"banana", "a", "a", -1, "banana"}, 1350 {"banana", "a", "a", 1, "banana"}, 1351 {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"}, 1352 } 1353 1354 func TestReplace(t *testing.T) { 1355 for _, tt := range ReplaceTests { 1356 in := append([]byte(tt.in), "<spare>"...) 1357 in = in[:len(tt.in)] 1358 out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n) 1359 if s := string(out); s != tt.out { 1360 t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out) 1361 } 1362 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] { 1363 t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n) 1364 } 1365 if tt.n == -1 { 1366 out := ReplaceAll(in, []byte(tt.old), []byte(tt.new)) 1367 if s := string(out); s != tt.out { 1368 t.Errorf("ReplaceAll(%q, %q, %q) = %q, want %q", tt.in, tt.old, tt.new, s, tt.out) 1369 } 1370 } 1371 } 1372 } 1373 1374 type TitleTest struct { 1375 in, out string 1376 } 1377 1378 var TitleTests = []TitleTest{ 1379 {"", ""}, 1380 {"a", "A"}, 1381 {" aaa aaa aaa ", " Aaa Aaa Aaa "}, 1382 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "}, 1383 {"123a456", "123a456"}, 1384 {"double-blind", "Double-Blind"}, 1385 {"ÿøû", "Ÿøû"}, 1386 {"with_underscore", "With_underscore"}, 1387 {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"}, 1388 } 1389 1390 func TestTitle(t *testing.T) { 1391 for _, tt := range TitleTests { 1392 if s := string(Title([]byte(tt.in))); s != tt.out { 1393 t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out) 1394 } 1395 } 1396 } 1397 1398 var ToTitleTests = []TitleTest{ 1399 {"", ""}, 1400 {"a", "A"}, 1401 {" aaa aaa aaa ", " AAA AAA AAA "}, 1402 {" Aaa Aaa Aaa ", " AAA AAA AAA "}, 1403 {"123a456", "123A456"}, 1404 {"double-blind", "DOUBLE-BLIND"}, 1405 {"ÿøû", "ŸØÛ"}, 1406 } 1407 1408 func TestToTitle(t *testing.T) { 1409 for _, tt := range ToTitleTests { 1410 if s := string(ToTitle([]byte(tt.in))); s != tt.out { 1411 t.Errorf("ToTitle(%q) = %q, want %q", tt.in, s, tt.out) 1412 } 1413 } 1414 } 1415 1416 var EqualFoldTests = []struct { 1417 s, t string 1418 out bool 1419 }{ 1420 {"abc", "abc", true}, 1421 {"ABcd", "ABcd", true}, 1422 {"123abc", "123ABC", true}, 1423 {"αβδ", "ΑΒΔ", true}, 1424 {"abc", "xyz", false}, 1425 {"abc", "XYZ", false}, 1426 {"abcdefghijk", "abcdefghijX", false}, 1427 {"abcdefghijk", "abcdefghij\u212A", true}, 1428 {"abcdefghijK", "abcdefghij\u212A", true}, 1429 {"abcdefghijkz", "abcdefghij\u212Ay", false}, 1430 {"abcdefghijKz", "abcdefghij\u212Ay", false}, 1431 } 1432 1433 func TestEqualFold(t *testing.T) { 1434 for _, tt := range EqualFoldTests { 1435 if out := EqualFold([]byte(tt.s), []byte(tt.t)); out != tt.out { 1436 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out) 1437 } 1438 if out := EqualFold([]byte(tt.t), []byte(tt.s)); out != tt.out { 1439 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out) 1440 } 1441 } 1442 } 1443 1444 func TestBufferGrowNegative(t *testing.T) { 1445 defer func() { 1446 if err := recover(); err == nil { 1447 t.Fatal("Grow(-1) should have panicked") 1448 } 1449 }() 1450 var b Buffer 1451 b.Grow(-1) 1452 } 1453 1454 func TestBufferTruncateNegative(t *testing.T) { 1455 defer func() { 1456 if err := recover(); err == nil { 1457 t.Fatal("Truncate(-1) should have panicked") 1458 } 1459 }() 1460 var b Buffer 1461 b.Truncate(-1) 1462 } 1463 1464 func TestBufferTruncateOutOfRange(t *testing.T) { 1465 defer func() { 1466 if err := recover(); err == nil { 1467 t.Fatal("Truncate(20) should have panicked") 1468 } 1469 }() 1470 var b Buffer 1471 b.Write(make([]byte, 10)) 1472 b.Truncate(20) 1473 } 1474 1475 var containsTests = []struct { 1476 b, subslice []byte 1477 want bool 1478 }{ 1479 {[]byte("hello"), []byte("hel"), true}, 1480 {[]byte("日本語"), []byte("日本"), true}, 1481 {[]byte("hello"), []byte("Hello, world"), false}, 1482 {[]byte("東京"), []byte("京東"), false}, 1483 } 1484 1485 func TestContains(t *testing.T) { 1486 for _, tt := range containsTests { 1487 if got := Contains(tt.b, tt.subslice); got != tt.want { 1488 t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want) 1489 } 1490 } 1491 } 1492 1493 var ContainsAnyTests = []struct { 1494 b []byte 1495 substr string 1496 expected bool 1497 }{ 1498 {[]byte(""), "", false}, 1499 {[]byte(""), "a", false}, 1500 {[]byte(""), "abc", false}, 1501 {[]byte("a"), "", false}, 1502 {[]byte("a"), "a", true}, 1503 {[]byte("aaa"), "a", true}, 1504 {[]byte("abc"), "xyz", false}, 1505 {[]byte("abc"), "xcz", true}, 1506 {[]byte("a☺b☻c☹d"), "uvw☻xyz", true}, 1507 {[]byte("aRegExp*"), ".(|)*+?^$[]", true}, 1508 {[]byte(dots + dots + dots), " ", false}, 1509 } 1510 1511 func TestContainsAny(t *testing.T) { 1512 for _, ct := range ContainsAnyTests { 1513 if ContainsAny(ct.b, ct.substr) != ct.expected { 1514 t.Errorf("ContainsAny(%s, %s) = %v, want %v", 1515 ct.b, ct.substr, !ct.expected, ct.expected) 1516 } 1517 } 1518 } 1519 1520 var ContainsRuneTests = []struct { 1521 b []byte 1522 r rune 1523 expected bool 1524 }{ 1525 {[]byte(""), 'a', false}, 1526 {[]byte("a"), 'a', true}, 1527 {[]byte("aaa"), 'a', true}, 1528 {[]byte("abc"), 'y', false}, 1529 {[]byte("abc"), 'c', true}, 1530 {[]byte("a☺b☻c☹d"), 'x', false}, 1531 {[]byte("a☺b☻c☹d"), '☻', true}, 1532 {[]byte("aRegExp*"), '*', true}, 1533 } 1534 1535 func TestContainsRune(t *testing.T) { 1536 for _, ct := range ContainsRuneTests { 1537 if ContainsRune(ct.b, ct.r) != ct.expected { 1538 t.Errorf("ContainsRune(%q, %q) = %v, want %v", 1539 ct.b, ct.r, !ct.expected, ct.expected) 1540 } 1541 } 1542 } 1543 1544 var makeFieldsInput = func() []byte { 1545 x := make([]byte, 1<<20) 1546 // Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space. 1547 for i := range x { 1548 switch rand.Intn(10) { 1549 case 0: 1550 x[i] = ' ' 1551 case 1: 1552 if i > 0 && x[i-1] == 'x' { 1553 copy(x[i-1:], "χ") 1554 break 1555 } 1556 fallthrough 1557 default: 1558 x[i] = 'x' 1559 } 1560 } 1561 return x 1562 } 1563 1564 var makeFieldsInputASCII = func() []byte { 1565 x := make([]byte, 1<<20) 1566 // Input is ~10% space, rest ASCII non-space. 1567 for i := range x { 1568 if rand.Intn(10) == 0 { 1569 x[i] = ' ' 1570 } else { 1571 x[i] = 'x' 1572 } 1573 } 1574 return x 1575 } 1576 1577 var bytesdata = []struct { 1578 name string 1579 data []byte 1580 }{ 1581 {"ASCII", makeFieldsInputASCII()}, 1582 {"Mixed", makeFieldsInput()}, 1583 } 1584 1585 func BenchmarkFields(b *testing.B) { 1586 for _, sd := range bytesdata { 1587 b.Run(sd.name, func(b *testing.B) { 1588 for j := 1 << 4; j <= 1<<20; j <<= 4 { 1589 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) { 1590 b.ReportAllocs() 1591 b.SetBytes(int64(j)) 1592 data := sd.data[:j] 1593 for i := 0; i < b.N; i++ { 1594 Fields(data) 1595 } 1596 }) 1597 } 1598 }) 1599 } 1600 } 1601 1602 func BenchmarkFieldsFunc(b *testing.B) { 1603 for _, sd := range bytesdata { 1604 b.Run(sd.name, func(b *testing.B) { 1605 for j := 1 << 4; j <= 1<<20; j <<= 4 { 1606 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) { 1607 b.ReportAllocs() 1608 b.SetBytes(int64(j)) 1609 data := sd.data[:j] 1610 for i := 0; i < b.N; i++ { 1611 FieldsFunc(data, unicode.IsSpace) 1612 } 1613 }) 1614 } 1615 }) 1616 } 1617 } 1618 1619 func BenchmarkTrimSpace(b *testing.B) { 1620 s := []byte(" Some text. \n") 1621 for i := 0; i < b.N; i++ { 1622 TrimSpace(s) 1623 } 1624 } 1625 1626 func makeBenchInputHard() []byte { 1627 tokens := [...]string{ 1628 "<a>", "<p>", "<b>", "<strong>", 1629 "</a>", "</p>", "</b>", "</strong>", 1630 "hello", "world", 1631 } 1632 x := make([]byte, 0, 1<<20) 1633 for { 1634 i := rand.Intn(len(tokens)) 1635 if len(x)+len(tokens[i]) >= 1<<20 { 1636 break 1637 } 1638 x = append(x, tokens[i]...) 1639 } 1640 return x 1641 } 1642 1643 var benchInputHard = makeBenchInputHard() 1644 1645 func BenchmarkSplitEmptySeparator(b *testing.B) { 1646 for i := 0; i < b.N; i++ { 1647 Split(benchInputHard, nil) 1648 } 1649 } 1650 1651 func BenchmarkSplitSingleByteSeparator(b *testing.B) { 1652 sep := []byte("/") 1653 for i := 0; i < b.N; i++ { 1654 Split(benchInputHard, sep) 1655 } 1656 } 1657 1658 func BenchmarkSplitMultiByteSeparator(b *testing.B) { 1659 sep := []byte("hello") 1660 for i := 0; i < b.N; i++ { 1661 Split(benchInputHard, sep) 1662 } 1663 } 1664 1665 func BenchmarkSplitNSingleByteSeparator(b *testing.B) { 1666 sep := []byte("/") 1667 for i := 0; i < b.N; i++ { 1668 SplitN(benchInputHard, sep, 10) 1669 } 1670 } 1671 1672 func BenchmarkSplitNMultiByteSeparator(b *testing.B) { 1673 sep := []byte("hello") 1674 for i := 0; i < b.N; i++ { 1675 SplitN(benchInputHard, sep, 10) 1676 } 1677 } 1678 1679 func BenchmarkRepeat(b *testing.B) { 1680 for i := 0; i < b.N; i++ { 1681 Repeat([]byte("-"), 80) 1682 } 1683 } 1684 1685 func BenchmarkBytesCompare(b *testing.B) { 1686 for n := 1; n <= 2048; n <<= 1 { 1687 b.Run(fmt.Sprint(n), func(b *testing.B) { 1688 var x = make([]byte, n) 1689 var y = make([]byte, n) 1690 1691 for i := 0; i < n; i++ { 1692 x[i] = 'a' 1693 } 1694 1695 for i := 0; i < n; i++ { 1696 y[i] = 'a' 1697 } 1698 1699 b.ResetTimer() 1700 for i := 0; i < b.N; i++ { 1701 Compare(x, y) 1702 } 1703 }) 1704 } 1705 } 1706 1707 func BenchmarkIndexAnyASCII(b *testing.B) { 1708 x := Repeat([]byte{'#'}, 4096) // Never matches set 1709 cs := "0123456789abcdef" 1710 for k := 1; k <= 4096; k <<= 4 { 1711 for j := 1; j <= 16; j <<= 1 { 1712 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1713 for i := 0; i < b.N; i++ { 1714 IndexAny(x[:k], cs[:j]) 1715 } 1716 }) 1717 } 1718 } 1719 } 1720 1721 func BenchmarkTrimASCII(b *testing.B) { 1722 cs := "0123456789abcdef" 1723 for k := 1; k <= 4096; k <<= 4 { 1724 for j := 1; j <= 16; j <<= 1 { 1725 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1726 x := Repeat([]byte(cs[:j]), k) // Always matches set 1727 for i := 0; i < b.N; i++ { 1728 Trim(x[:k], cs[:j]) 1729 } 1730 }) 1731 } 1732 } 1733 } 1734 1735 func BenchmarkIndexPeriodic(b *testing.B) { 1736 key := []byte{1, 1} 1737 for _, skip := range [...]int{2, 4, 8, 16, 32, 64} { 1738 b.Run(fmt.Sprintf("IndexPeriodic%d", skip), func(b *testing.B) { 1739 buf := make([]byte, 1<<16) 1740 for i := 0; i < len(buf); i += skip { 1741 buf[i] = 1 1742 } 1743 for i := 0; i < b.N; i++ { 1744 Index(buf, key) 1745 } 1746 }) 1747 } 1748 }