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