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