github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/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 var bmbuf []byte 400 401 func valName(x int) string { 402 if s := x >> 20; s<<20 == x { 403 return fmt.Sprintf("%dM", s) 404 } 405 if s := x >> 10; s<<10 == x { 406 return fmt.Sprintf("%dK", s) 407 } 408 return fmt.Sprint(x) 409 } 410 411 func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) { 412 for _, n := range sizes { 413 if isRaceBuilder && n > 4<<10 { 414 continue 415 } 416 b.Run(valName(n), func(b *testing.B) { 417 if len(bmbuf) < n { 418 bmbuf = make([]byte, n) 419 } 420 b.SetBytes(int64(n)) 421 f(b, n) 422 }) 423 } 424 } 425 426 var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20} 427 428 var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race") 429 430 func BenchmarkIndexByte(b *testing.B) { 431 benchBytes(b, indexSizes, bmIndexByte(IndexByte)) 432 } 433 434 func BenchmarkIndexBytePortable(b *testing.B) { 435 benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable)) 436 } 437 438 func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) { 439 return func(b *testing.B, n int) { 440 buf := bmbuf[0:n] 441 buf[n-1] = 'x' 442 for i := 0; i < b.N; i++ { 443 j := index(buf, 'x') 444 if j != n-1 { 445 b.Fatal("bad index", j) 446 } 447 } 448 buf[n-1] = '\x00' 449 } 450 } 451 452 func BenchmarkIndexRune(b *testing.B) { 453 benchBytes(b, indexSizes, bmIndexRune(IndexRune)) 454 } 455 456 func BenchmarkIndexRuneASCII(b *testing.B) { 457 benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune)) 458 } 459 460 func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) { 461 return func(b *testing.B, n int) { 462 buf := bmbuf[0:n] 463 buf[n-1] = 'x' 464 for i := 0; i < b.N; i++ { 465 j := index(buf, 'x') 466 if j != n-1 { 467 b.Fatal("bad index", j) 468 } 469 } 470 buf[n-1] = '\x00' 471 } 472 } 473 474 func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) { 475 return func(b *testing.B, n int) { 476 buf := bmbuf[0:n] 477 utf8.EncodeRune(buf[n-3:], '世') 478 for i := 0; i < b.N; i++ { 479 j := index(buf, '世') 480 if j != n-3 { 481 b.Fatal("bad index", j) 482 } 483 } 484 buf[n-3] = '\x00' 485 buf[n-2] = '\x00' 486 buf[n-1] = '\x00' 487 } 488 } 489 490 func BenchmarkEqual(b *testing.B) { 491 b.Run("0", func(b *testing.B) { 492 var buf [4]byte 493 buf1 := buf[0:0] 494 buf2 := buf[1:1] 495 for i := 0; i < b.N; i++ { 496 eq := Equal(buf1, buf2) 497 if !eq { 498 b.Fatal("bad equal") 499 } 500 } 501 }) 502 503 sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20} 504 benchBytes(b, sizes, bmEqual(Equal)) 505 } 506 507 func BenchmarkEqualPort(b *testing.B) { 508 sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20} 509 benchBytes(b, sizes, bmEqual(EqualPortable)) 510 } 511 512 func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) { 513 return func(b *testing.B, n int) { 514 if len(bmbuf) < 2*n { 515 bmbuf = make([]byte, 2*n) 516 } 517 buf1 := bmbuf[0:n] 518 buf2 := bmbuf[n : 2*n] 519 buf1[n-1] = 'x' 520 buf2[n-1] = 'x' 521 for i := 0; i < b.N; i++ { 522 eq := equal(buf1, buf2) 523 if !eq { 524 b.Fatal("bad equal") 525 } 526 } 527 buf1[n-1] = '\x00' 528 buf2[n-1] = '\x00' 529 } 530 } 531 532 func BenchmarkIndex(b *testing.B) { 533 benchBytes(b, indexSizes, func(b *testing.B, n int) { 534 buf := bmbuf[0:n] 535 buf[n-1] = 'x' 536 for i := 0; i < b.N; i++ { 537 j := Index(buf, buf[n-7:]) 538 if j != n-7 { 539 b.Fatal("bad index", j) 540 } 541 } 542 buf[n-1] = '\x00' 543 }) 544 } 545 546 func BenchmarkIndexEasy(b *testing.B) { 547 benchBytes(b, indexSizes, func(b *testing.B, n int) { 548 buf := bmbuf[0:n] 549 buf[n-1] = 'x' 550 buf[n-7] = 'x' 551 for i := 0; i < b.N; i++ { 552 j := Index(buf, buf[n-7:]) 553 if j != n-7 { 554 b.Fatal("bad index", j) 555 } 556 } 557 buf[n-1] = '\x00' 558 buf[n-7] = '\x00' 559 }) 560 } 561 562 func BenchmarkCount(b *testing.B) { 563 benchBytes(b, indexSizes, func(b *testing.B, n int) { 564 buf := bmbuf[0:n] 565 buf[n-1] = 'x' 566 for i := 0; i < b.N; i++ { 567 j := Count(buf, buf[n-7:]) 568 if j != 1 { 569 b.Fatal("bad count", j) 570 } 571 } 572 buf[n-1] = '\x00' 573 }) 574 } 575 576 func BenchmarkCountEasy(b *testing.B) { 577 benchBytes(b, indexSizes, func(b *testing.B, n int) { 578 buf := bmbuf[0:n] 579 buf[n-1] = 'x' 580 buf[n-7] = 'x' 581 for i := 0; i < b.N; i++ { 582 j := Count(buf, buf[n-7:]) 583 if j != 1 { 584 b.Fatal("bad count", j) 585 } 586 } 587 buf[n-1] = '\x00' 588 buf[n-7] = '\x00' 589 }) 590 } 591 592 type ExplodeTest struct { 593 s string 594 n int 595 a []string 596 } 597 598 var explodetests = []ExplodeTest{ 599 {"", -1, []string{}}, 600 {abcd, -1, []string{"a", "b", "c", "d"}}, 601 {faces, -1, []string{"☺", "☻", "☹"}}, 602 {abcd, 2, []string{"a", "bcd"}}, 603 } 604 605 func TestExplode(t *testing.T) { 606 for _, tt := range explodetests { 607 a := SplitN([]byte(tt.s), nil, tt.n) 608 result := sliceOfString(a) 609 if !eq(result, tt.a) { 610 t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a) 611 continue 612 } 613 s := Join(a, []byte{}) 614 if string(s) != tt.s { 615 t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s) 616 } 617 } 618 } 619 620 type SplitTest struct { 621 s string 622 sep string 623 n int 624 a []string 625 } 626 627 var splittests = []SplitTest{ 628 {abcd, "a", 0, nil}, 629 {abcd, "a", -1, []string{"", "bcd"}}, 630 {abcd, "z", -1, []string{"abcd"}}, 631 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 632 {commas, ",", -1, []string{"1", "2", "3", "4"}}, 633 {dots, "...", -1, []string{"1", ".2", ".3", ".4"}}, 634 {faces, "☹", -1, []string{"☺☻", ""}}, 635 {faces, "~", -1, []string{faces}}, 636 {faces, "", -1, []string{"☺", "☻", "☹"}}, 637 {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}}, 638 {"1 2", " ", 3, []string{"1", "2"}}, 639 {"123", "", 2, []string{"1", "23"}}, 640 {"123", "", 17, []string{"1", "2", "3"}}, 641 } 642 643 func TestSplit(t *testing.T) { 644 for _, tt := range splittests { 645 a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n) 646 result := sliceOfString(a) 647 if !eq(result, tt.a) { 648 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) 649 continue 650 } 651 if tt.n == 0 { 652 continue 653 } 654 s := Join(a, []byte(tt.sep)) 655 if string(s) != tt.s { 656 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 657 } 658 if tt.n < 0 { 659 b := Split([]byte(tt.s), []byte(tt.sep)) 660 if !reflect.DeepEqual(a, b) { 661 t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 662 } 663 } 664 if len(a) > 0 { 665 in, out := a[0], s 666 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] { 667 t.Errorf("Join(%#v, %q) didn't copy", a, tt.sep) 668 } 669 } 670 } 671 } 672 673 var splitaftertests = []SplitTest{ 674 {abcd, "a", -1, []string{"a", "bcd"}}, 675 {abcd, "z", -1, []string{"abcd"}}, 676 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 677 {commas, ",", -1, []string{"1,", "2,", "3,", "4"}}, 678 {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}}, 679 {faces, "☹", -1, []string{"☺☻☹", ""}}, 680 {faces, "~", -1, []string{faces}}, 681 {faces, "", -1, []string{"☺", "☻", "☹"}}, 682 {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}}, 683 {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}}, 684 {"1 2", " ", 3, []string{"1 ", "2"}}, 685 {"123", "", 2, []string{"1", "23"}}, 686 {"123", "", 17, []string{"1", "2", "3"}}, 687 } 688 689 func TestSplitAfter(t *testing.T) { 690 for _, tt := range splitaftertests { 691 a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n) 692 result := sliceOfString(a) 693 if !eq(result, tt.a) { 694 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) 695 continue 696 } 697 s := Join(a, nil) 698 if string(s) != tt.s { 699 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 700 } 701 if tt.n < 0 { 702 b := SplitAfter([]byte(tt.s), []byte(tt.sep)) 703 if !reflect.DeepEqual(a, b) { 704 t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 705 } 706 } 707 } 708 } 709 710 type FieldsTest struct { 711 s string 712 a []string 713 } 714 715 var fieldstests = []FieldsTest{ 716 {"", []string{}}, 717 {" ", []string{}}, 718 {" \t ", []string{}}, 719 {" abc ", []string{"abc"}}, 720 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 721 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 722 {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}}, 723 {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}}, 724 {"\u2000\u2001\u2002", []string{}}, 725 {"\n™\t™\n", []string{"™", "™"}}, 726 {faces, []string{faces}}, 727 } 728 729 func TestFields(t *testing.T) { 730 for _, tt := range fieldstests { 731 a := Fields([]byte(tt.s)) 732 result := sliceOfString(a) 733 if !eq(result, tt.a) { 734 t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) 735 continue 736 } 737 } 738 } 739 740 func TestFieldsFunc(t *testing.T) { 741 for _, tt := range fieldstests { 742 a := FieldsFunc([]byte(tt.s), unicode.IsSpace) 743 result := sliceOfString(a) 744 if !eq(result, tt.a) { 745 t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a) 746 continue 747 } 748 } 749 pred := func(c rune) bool { return c == 'X' } 750 var fieldsFuncTests = []FieldsTest{ 751 {"", []string{}}, 752 {"XX", []string{}}, 753 {"XXhiXXX", []string{"hi"}}, 754 {"aXXbXXXcX", []string{"a", "b", "c"}}, 755 } 756 for _, tt := range fieldsFuncTests { 757 a := FieldsFunc([]byte(tt.s), pred) 758 result := sliceOfString(a) 759 if !eq(result, tt.a) { 760 t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) 761 } 762 } 763 } 764 765 // Test case for any function which accepts and returns a byte slice. 766 // For ease of creation, we write the byte slices as strings. 767 type StringTest struct { 768 in, out string 769 } 770 771 var upperTests = []StringTest{ 772 {"", ""}, 773 {"abc", "ABC"}, 774 {"AbC123", "ABC123"}, 775 {"azAZ09_", "AZAZ09_"}, 776 {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char 777 } 778 779 var lowerTests = []StringTest{ 780 {"", ""}, 781 {"abc", "abc"}, 782 {"AbC123", "abc123"}, 783 {"azAZ09_", "azaz09_"}, 784 {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char 785 } 786 787 const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000" 788 789 var trimSpaceTests = []StringTest{ 790 {"", ""}, 791 {"abc", "abc"}, 792 {space + "abc" + space, "abc"}, 793 {" ", ""}, 794 {" \t\r\n \t\t\r\r\n\n ", ""}, 795 {" \t\r\n x\t\t\r\r\n\n ", "x"}, 796 {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"}, 797 {"1 \t\r\n2", "1 \t\r\n2"}, 798 {" x\x80", "x\x80"}, 799 {" x\xc0", "x\xc0"}, 800 {"x \xc0\xc0 ", "x \xc0\xc0"}, 801 {"x \xc0", "x \xc0"}, 802 {"x \xc0 ", "x \xc0"}, 803 {"x \xc0\xc0 ", "x \xc0\xc0"}, 804 {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"}, 805 {"x ☺ ", "x ☺"}, 806 } 807 808 // Execute f on each test case. funcName should be the name of f; it's used 809 // in failure reports. 810 func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) { 811 for _, tc := range testCases { 812 actual := string(f([]byte(tc.in))) 813 if actual != tc.out { 814 t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out) 815 } 816 } 817 } 818 819 func tenRunes(r rune) string { 820 runes := make([]rune, 10) 821 for i := range runes { 822 runes[i] = r 823 } 824 return string(runes) 825 } 826 827 // User-defined self-inverse mapping function 828 func rot13(r rune) rune { 829 const step = 13 830 if r >= 'a' && r <= 'z' { 831 return ((r - 'a' + step) % 26) + 'a' 832 } 833 if r >= 'A' && r <= 'Z' { 834 return ((r - 'A' + step) % 26) + 'A' 835 } 836 return r 837 } 838 839 func TestMap(t *testing.T) { 840 // Run a couple of awful growth/shrinkage tests 841 a := tenRunes('a') 842 843 // 1. Grow. This triggers two reallocations in Map. 844 maxRune := func(r rune) rune { return unicode.MaxRune } 845 m := Map(maxRune, []byte(a)) 846 expect := tenRunes(unicode.MaxRune) 847 if string(m) != expect { 848 t.Errorf("growing: expected %q got %q", expect, m) 849 } 850 851 // 2. Shrink 852 minRune := func(r rune) rune { return 'a' } 853 m = Map(minRune, []byte(tenRunes(unicode.MaxRune))) 854 expect = a 855 if string(m) != expect { 856 t.Errorf("shrinking: expected %q got %q", expect, m) 857 } 858 859 // 3. Rot13 860 m = Map(rot13, []byte("a to zed")) 861 expect = "n gb mrq" 862 if string(m) != expect { 863 t.Errorf("rot13: expected %q got %q", expect, m) 864 } 865 866 // 4. Rot13^2 867 m = Map(rot13, Map(rot13, []byte("a to zed"))) 868 expect = "a to zed" 869 if string(m) != expect { 870 t.Errorf("rot13: expected %q got %q", expect, m) 871 } 872 873 // 5. Drop 874 dropNotLatin := func(r rune) rune { 875 if unicode.Is(unicode.Latin, r) { 876 return r 877 } 878 return -1 879 } 880 m = Map(dropNotLatin, []byte("Hello, 세계")) 881 expect = "Hello" 882 if string(m) != expect { 883 t.Errorf("drop: expected %q got %q", expect, m) 884 } 885 886 // 6. Invalid rune 887 invalidRune := func(r rune) rune { 888 return utf8.MaxRune + 1 889 } 890 m = Map(invalidRune, []byte("x")) 891 expect = "\uFFFD" 892 if string(m) != expect { 893 t.Errorf("invalidRune: expected %q got %q", expect, m) 894 } 895 } 896 897 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } 898 899 func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } 900 901 func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) } 902 903 type RepeatTest struct { 904 in, out string 905 count int 906 } 907 908 var RepeatTests = []RepeatTest{ 909 {"", "", 0}, 910 {"", "", 1}, 911 {"", "", 2}, 912 {"-", "", 0}, 913 {"-", "-", 1}, 914 {"-", "----------", 10}, 915 {"abc ", "abc abc abc ", 3}, 916 } 917 918 func TestRepeat(t *testing.T) { 919 for _, tt := range RepeatTests { 920 tin := []byte(tt.in) 921 tout := []byte(tt.out) 922 a := Repeat(tin, tt.count) 923 if !Equal(a, tout) { 924 t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout) 925 continue 926 } 927 } 928 } 929 930 func repeat(b []byte, count int) (err error) { 931 defer func() { 932 if r := recover(); r != nil { 933 switch v := r.(type) { 934 case error: 935 err = v 936 default: 937 err = fmt.Errorf("%s", v) 938 } 939 } 940 }() 941 942 Repeat(b, count) 943 944 return 945 } 946 947 // See Issue golang.org/issue/16237 948 func TestRepeatCatchesOverflow(t *testing.T) { 949 tests := [...]struct { 950 s string 951 count int 952 errStr string 953 }{ 954 0: {"--", -2147483647, "negative"}, 955 1: {"", int(^uint(0) >> 1), ""}, 956 2: {"-", 10, ""}, 957 3: {"gopher", 0, ""}, 958 4: {"-", -1, "negative"}, 959 5: {"--", -102, "negative"}, 960 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"}, 961 } 962 963 for i, tt := range tests { 964 err := repeat([]byte(tt.s), tt.count) 965 if tt.errStr == "" { 966 if err != nil { 967 t.Errorf("#%d panicked %v", i, err) 968 } 969 continue 970 } 971 972 if err == nil || !strings.Contains(err.Error(), tt.errStr) { 973 t.Errorf("#%d expected %q got %q", i, tt.errStr, err) 974 } 975 } 976 } 977 978 func runesEqual(a, b []rune) bool { 979 if len(a) != len(b) { 980 return false 981 } 982 for i, r := range a { 983 if r != b[i] { 984 return false 985 } 986 } 987 return true 988 } 989 990 type RunesTest struct { 991 in string 992 out []rune 993 lossy bool 994 } 995 996 var RunesTests = []RunesTest{ 997 {"", []rune{}, false}, 998 {" ", []rune{32}, false}, 999 {"ABC", []rune{65, 66, 67}, false}, 1000 {"abc", []rune{97, 98, 99}, false}, 1001 {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false}, 1002 {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true}, 1003 {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true}, 1004 } 1005 1006 func TestRunes(t *testing.T) { 1007 for _, tt := range RunesTests { 1008 tin := []byte(tt.in) 1009 a := Runes(tin) 1010 if !runesEqual(a, tt.out) { 1011 t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out) 1012 continue 1013 } 1014 if !tt.lossy { 1015 // can only test reassembly if we didn't lose information 1016 s := string(a) 1017 if s != tt.in { 1018 t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin) 1019 } 1020 } 1021 } 1022 } 1023 1024 type TrimTest struct { 1025 f string 1026 in, arg, out string 1027 } 1028 1029 var trimTests = []TrimTest{ 1030 {"Trim", "abba", "a", "bb"}, 1031 {"Trim", "abba", "ab", ""}, 1032 {"TrimLeft", "abba", "ab", ""}, 1033 {"TrimRight", "abba", "ab", ""}, 1034 {"TrimLeft", "abba", "a", "bba"}, 1035 {"TrimRight", "abba", "a", "abb"}, 1036 {"Trim", "<tag>", "<>", "tag"}, 1037 {"Trim", "* listitem", " *", "listitem"}, 1038 {"Trim", `"quote"`, `"`, "quote"}, 1039 {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"}, 1040 {"Trim", "\x80test\xff", "\xff", "test"}, 1041 {"Trim", " Ġ ", " ", "Ġ"}, 1042 {"Trim", " Ġİ0", "0 ", "Ġİ"}, 1043 //empty string tests 1044 {"Trim", "abba", "", "abba"}, 1045 {"Trim", "", "123", ""}, 1046 {"Trim", "", "", ""}, 1047 {"TrimLeft", "abba", "", "abba"}, 1048 {"TrimLeft", "", "123", ""}, 1049 {"TrimLeft", "", "", ""}, 1050 {"TrimRight", "abba", "", "abba"}, 1051 {"TrimRight", "", "123", ""}, 1052 {"TrimRight", "", "", ""}, 1053 {"TrimRight", "☺\xc0", "☺", "☺\xc0"}, 1054 {"TrimPrefix", "aabb", "a", "abb"}, 1055 {"TrimPrefix", "aabb", "b", "aabb"}, 1056 {"TrimSuffix", "aabb", "a", "aabb"}, 1057 {"TrimSuffix", "aabb", "b", "aab"}, 1058 } 1059 1060 func TestTrim(t *testing.T) { 1061 for _, tc := range trimTests { 1062 name := tc.f 1063 var f func([]byte, string) []byte 1064 var fb func([]byte, []byte) []byte 1065 switch name { 1066 case "Trim": 1067 f = Trim 1068 case "TrimLeft": 1069 f = TrimLeft 1070 case "TrimRight": 1071 f = TrimRight 1072 case "TrimPrefix": 1073 fb = TrimPrefix 1074 case "TrimSuffix": 1075 fb = TrimSuffix 1076 default: 1077 t.Errorf("Undefined trim function %s", name) 1078 } 1079 var actual string 1080 if f != nil { 1081 actual = string(f([]byte(tc.in), tc.arg)) 1082 } else { 1083 actual = string(fb([]byte(tc.in), []byte(tc.arg))) 1084 } 1085 if actual != tc.out { 1086 t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) 1087 } 1088 } 1089 } 1090 1091 type predicate struct { 1092 f func(r rune) bool 1093 name string 1094 } 1095 1096 var isSpace = predicate{unicode.IsSpace, "IsSpace"} 1097 var isDigit = predicate{unicode.IsDigit, "IsDigit"} 1098 var isUpper = predicate{unicode.IsUpper, "IsUpper"} 1099 var isValidRune = predicate{ 1100 func(r rune) bool { 1101 return r != utf8.RuneError 1102 }, 1103 "IsValidRune", 1104 } 1105 1106 type TrimFuncTest struct { 1107 f predicate 1108 in, out string 1109 } 1110 1111 func not(p predicate) predicate { 1112 return predicate{ 1113 func(r rune) bool { 1114 return !p.f(r) 1115 }, 1116 "not " + p.name, 1117 } 1118 } 1119 1120 var trimFuncTests = []TrimFuncTest{ 1121 {isSpace, space + " hello " + space, "hello"}, 1122 {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"}, 1123 {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"}, 1124 {not(isSpace), "hello" + space + "hello", space}, 1125 {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"}, 1126 {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"}, 1127 {not(isValidRune), "\xc0a\xc0", "a"}, 1128 } 1129 1130 func TestTrimFunc(t *testing.T) { 1131 for _, tc := range trimFuncTests { 1132 actual := string(TrimFunc([]byte(tc.in), tc.f.f)) 1133 if actual != tc.out { 1134 t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out) 1135 } 1136 } 1137 } 1138 1139 type IndexFuncTest struct { 1140 in string 1141 f predicate 1142 first, last int 1143 } 1144 1145 var indexFuncTests = []IndexFuncTest{ 1146 {"", isValidRune, -1, -1}, 1147 {"abc", isDigit, -1, -1}, 1148 {"0123", isDigit, 0, 3}, 1149 {"a1b", isDigit, 1, 1}, 1150 {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes 1151 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18}, 1152 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34}, 1153 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12}, 1154 1155 // tests of invalid UTF-8 1156 {"\x801", isDigit, 1, 1}, 1157 {"\x80abc", isDigit, -1, -1}, 1158 {"\xc0a\xc0", isValidRune, 1, 1}, 1159 {"\xc0a\xc0", not(isValidRune), 0, 2}, 1160 {"\xc0☺\xc0", not(isValidRune), 0, 4}, 1161 {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5}, 1162 {"ab\xc0a\xc0cd", not(isValidRune), 2, 4}, 1163 {"a\xe0\x80cd", not(isValidRune), 1, 2}, 1164 } 1165 1166 func TestIndexFunc(t *testing.T) { 1167 for _, tc := range indexFuncTests { 1168 first := IndexFunc([]byte(tc.in), tc.f.f) 1169 if first != tc.first { 1170 t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first) 1171 } 1172 last := LastIndexFunc([]byte(tc.in), tc.f.f) 1173 if last != tc.last { 1174 t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last) 1175 } 1176 } 1177 } 1178 1179 type ReplaceTest struct { 1180 in string 1181 old, new string 1182 n int 1183 out string 1184 } 1185 1186 var ReplaceTests = []ReplaceTest{ 1187 {"hello", "l", "L", 0, "hello"}, 1188 {"hello", "l", "L", -1, "heLLo"}, 1189 {"hello", "x", "X", -1, "hello"}, 1190 {"", "x", "X", -1, ""}, 1191 {"radar", "r", "<r>", -1, "<r>ada<r>"}, 1192 {"", "", "<>", -1, "<>"}, 1193 {"banana", "a", "<>", -1, "b<>n<>n<>"}, 1194 {"banana", "a", "<>", 1, "b<>nana"}, 1195 {"banana", "a", "<>", 1000, "b<>n<>n<>"}, 1196 {"banana", "an", "<>", -1, "b<><>a"}, 1197 {"banana", "ana", "<>", -1, "b<>na"}, 1198 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"}, 1199 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"}, 1200 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"}, 1201 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"}, 1202 {"banana", "", "<>", 1, "<>banana"}, 1203 {"banana", "a", "a", -1, "banana"}, 1204 {"banana", "a", "a", 1, "banana"}, 1205 {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"}, 1206 } 1207 1208 func TestReplace(t *testing.T) { 1209 for _, tt := range ReplaceTests { 1210 in := append([]byte(tt.in), "<spare>"...) 1211 in = in[:len(tt.in)] 1212 out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n) 1213 if s := string(out); s != tt.out { 1214 t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out) 1215 } 1216 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] { 1217 t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n) 1218 } 1219 } 1220 } 1221 1222 type TitleTest struct { 1223 in, out string 1224 } 1225 1226 var TitleTests = []TitleTest{ 1227 {"", ""}, 1228 {"a", "A"}, 1229 {" aaa aaa aaa ", " Aaa Aaa Aaa "}, 1230 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "}, 1231 {"123a456", "123a456"}, 1232 {"double-blind", "Double-Blind"}, 1233 {"ÿøû", "Ÿøû"}, 1234 {"with_underscore", "With_underscore"}, 1235 {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"}, 1236 } 1237 1238 func TestTitle(t *testing.T) { 1239 for _, tt := range TitleTests { 1240 if s := string(Title([]byte(tt.in))); s != tt.out { 1241 t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out) 1242 } 1243 } 1244 } 1245 1246 var ToTitleTests = []TitleTest{ 1247 {"", ""}, 1248 {"a", "A"}, 1249 {" aaa aaa aaa ", " AAA AAA AAA "}, 1250 {" Aaa Aaa Aaa ", " AAA AAA AAA "}, 1251 {"123a456", "123A456"}, 1252 {"double-blind", "DOUBLE-BLIND"}, 1253 {"ÿøû", "ŸØÛ"}, 1254 } 1255 1256 func TestToTitle(t *testing.T) { 1257 for _, tt := range ToTitleTests { 1258 if s := string(ToTitle([]byte(tt.in))); s != tt.out { 1259 t.Errorf("ToTitle(%q) = %q, want %q", tt.in, s, tt.out) 1260 } 1261 } 1262 } 1263 1264 var EqualFoldTests = []struct { 1265 s, t string 1266 out bool 1267 }{ 1268 {"abc", "abc", true}, 1269 {"ABcd", "ABcd", true}, 1270 {"123abc", "123ABC", true}, 1271 {"αβδ", "ΑΒΔ", true}, 1272 {"abc", "xyz", false}, 1273 {"abc", "XYZ", false}, 1274 {"abcdefghijk", "abcdefghijX", false}, 1275 {"abcdefghijk", "abcdefghij\u212A", true}, 1276 {"abcdefghijK", "abcdefghij\u212A", true}, 1277 {"abcdefghijkz", "abcdefghij\u212Ay", false}, 1278 {"abcdefghijKz", "abcdefghij\u212Ay", false}, 1279 } 1280 1281 func TestEqualFold(t *testing.T) { 1282 for _, tt := range EqualFoldTests { 1283 if out := EqualFold([]byte(tt.s), []byte(tt.t)); out != tt.out { 1284 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out) 1285 } 1286 if out := EqualFold([]byte(tt.t), []byte(tt.s)); out != tt.out { 1287 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out) 1288 } 1289 } 1290 } 1291 1292 func TestBufferGrowNegative(t *testing.T) { 1293 defer func() { 1294 if err := recover(); err == nil { 1295 t.Fatal("Grow(-1) should have panicked") 1296 } 1297 }() 1298 var b Buffer 1299 b.Grow(-1) 1300 } 1301 1302 func TestBufferTruncateNegative(t *testing.T) { 1303 defer func() { 1304 if err := recover(); err == nil { 1305 t.Fatal("Truncate(-1) should have panicked") 1306 } 1307 }() 1308 var b Buffer 1309 b.Truncate(-1) 1310 } 1311 1312 func TestBufferTruncateOutOfRange(t *testing.T) { 1313 defer func() { 1314 if err := recover(); err == nil { 1315 t.Fatal("Truncate(20) should have panicked") 1316 } 1317 }() 1318 var b Buffer 1319 b.Write(make([]byte, 10)) 1320 b.Truncate(20) 1321 } 1322 1323 var containsTests = []struct { 1324 b, subslice []byte 1325 want bool 1326 }{ 1327 {[]byte("hello"), []byte("hel"), true}, 1328 {[]byte("日本語"), []byte("日本"), true}, 1329 {[]byte("hello"), []byte("Hello, world"), false}, 1330 {[]byte("東京"), []byte("京東"), false}, 1331 } 1332 1333 func TestContains(t *testing.T) { 1334 for _, tt := range containsTests { 1335 if got := Contains(tt.b, tt.subslice); got != tt.want { 1336 t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want) 1337 } 1338 } 1339 } 1340 1341 var ContainsAnyTests = []struct { 1342 b []byte 1343 substr string 1344 expected bool 1345 }{ 1346 {[]byte(""), "", false}, 1347 {[]byte(""), "a", false}, 1348 {[]byte(""), "abc", false}, 1349 {[]byte("a"), "", false}, 1350 {[]byte("a"), "a", true}, 1351 {[]byte("aaa"), "a", true}, 1352 {[]byte("abc"), "xyz", false}, 1353 {[]byte("abc"), "xcz", true}, 1354 {[]byte("a☺b☻c☹d"), "uvw☻xyz", true}, 1355 {[]byte("aRegExp*"), ".(|)*+?^$[]", true}, 1356 {[]byte(dots + dots + dots), " ", false}, 1357 } 1358 1359 func TestContainsAny(t *testing.T) { 1360 for _, ct := range ContainsAnyTests { 1361 if ContainsAny(ct.b, ct.substr) != ct.expected { 1362 t.Errorf("ContainsAny(%s, %s) = %v, want %v", 1363 ct.b, ct.substr, !ct.expected, ct.expected) 1364 } 1365 } 1366 } 1367 1368 var ContainsRuneTests = []struct { 1369 b []byte 1370 r rune 1371 expected bool 1372 }{ 1373 {[]byte(""), 'a', false}, 1374 {[]byte("a"), 'a', true}, 1375 {[]byte("aaa"), 'a', true}, 1376 {[]byte("abc"), 'y', false}, 1377 {[]byte("abc"), 'c', true}, 1378 {[]byte("a☺b☻c☹d"), 'x', false}, 1379 {[]byte("a☺b☻c☹d"), '☻', true}, 1380 {[]byte("aRegExp*"), '*', true}, 1381 } 1382 1383 func TestContainsRune(t *testing.T) { 1384 for _, ct := range ContainsRuneTests { 1385 if ContainsRune(ct.b, ct.r) != ct.expected { 1386 t.Errorf("ContainsRune(%q, %q) = %v, want %v", 1387 ct.b, ct.r, !ct.expected, ct.expected) 1388 } 1389 } 1390 } 1391 1392 var makeFieldsInput = func() []byte { 1393 x := make([]byte, 1<<20) 1394 // Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space. 1395 for i := range x { 1396 switch rand.Intn(10) { 1397 case 0: 1398 x[i] = ' ' 1399 case 1: 1400 if i > 0 && x[i-1] == 'x' { 1401 copy(x[i-1:], "χ") 1402 break 1403 } 1404 fallthrough 1405 default: 1406 x[i] = 'x' 1407 } 1408 } 1409 return x 1410 } 1411 1412 var fieldsInput = makeFieldsInput() 1413 1414 func BenchmarkFields(b *testing.B) { 1415 b.SetBytes(int64(len(fieldsInput))) 1416 for i := 0; i < b.N; i++ { 1417 Fields(fieldsInput) 1418 } 1419 } 1420 1421 func BenchmarkFieldsFunc(b *testing.B) { 1422 b.SetBytes(int64(len(fieldsInput))) 1423 for i := 0; i < b.N; i++ { 1424 FieldsFunc(fieldsInput, unicode.IsSpace) 1425 } 1426 } 1427 1428 func BenchmarkTrimSpace(b *testing.B) { 1429 s := []byte(" Some text. \n") 1430 for i := 0; i < b.N; i++ { 1431 TrimSpace(s) 1432 } 1433 } 1434 1435 func BenchmarkRepeat(b *testing.B) { 1436 for i := 0; i < b.N; i++ { 1437 Repeat([]byte("-"), 80) 1438 } 1439 } 1440 1441 func BenchmarkBytesCompare(b *testing.B) { 1442 for n := 1; n <= 2048; n <<= 1 { 1443 b.Run(fmt.Sprint(n), func(b *testing.B) { 1444 var x = make([]byte, n) 1445 var y = make([]byte, n) 1446 1447 for i := 0; i < n; i++ { 1448 x[i] = 'a' 1449 } 1450 1451 for i := 0; i < n; i++ { 1452 y[i] = 'a' 1453 } 1454 1455 b.ResetTimer() 1456 for i := 0; i < b.N; i++ { 1457 Compare(x, y) 1458 } 1459 }) 1460 } 1461 } 1462 1463 func BenchmarkIndexAnyASCII(b *testing.B) { 1464 x := Repeat([]byte{'#'}, 4096) // Never matches set 1465 cs := "0123456789abcdef" 1466 for k := 1; k <= 4096; k <<= 4 { 1467 for j := 1; j <= 16; j <<= 1 { 1468 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1469 for i := 0; i < b.N; i++ { 1470 IndexAny(x[:k], cs[:j]) 1471 } 1472 }) 1473 } 1474 } 1475 } 1476 1477 func BenchmarkTrimASCII(b *testing.B) { 1478 cs := "0123456789abcdef" 1479 for k := 1; k <= 4096; k <<= 4 { 1480 for j := 1; j <= 16; j <<= 1 { 1481 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1482 x := Repeat([]byte(cs[:j]), k) // Always matches set 1483 for i := 0; i < b.N; i++ { 1484 Trim(x[:k], cs[:j]) 1485 } 1486 }) 1487 } 1488 } 1489 }