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 "math/rand" 10 "reflect" 11 "testing" 12 "unicode" 13 "unicode/utf8" 14 ) 15 16 func eq(a, b []string) bool { 17 if len(a) != len(b) { 18 return false 19 } 20 for i := 0; i < len(a); i++ { 21 if a[i] != b[i] { 22 return false 23 } 24 } 25 return true 26 } 27 28 func sliceOfString(s [][]byte) []string { 29 result := make([]string, len(s)) 30 for i, v := range s { 31 result[i] = string(v) 32 } 33 return result 34 } 35 36 // For ease of reading, the test cases use strings that are converted to byte 37 // slices before invoking the functions. 38 39 var abcd = "abcd" 40 var faces = "" 41 var commas = "1,2,3,4" 42 var dots = "1....2....3....4" 43 44 type BinOpTest struct { 45 a string 46 b string 47 i int 48 } 49 50 var equalTests = []struct { 51 a, b []byte 52 i int 53 }{ 54 {[]byte(""), []byte(""), 0}, 55 {[]byte("a"), []byte(""), 1}, 56 {[]byte(""), []byte("a"), -1}, 57 {[]byte("abc"), []byte("abc"), 0}, 58 {[]byte("ab"), []byte("abc"), -1}, 59 {[]byte("abc"), []byte("ab"), 1}, 60 {[]byte("x"), []byte("ab"), 1}, 61 {[]byte("ab"), []byte("x"), -1}, 62 {[]byte("x"), []byte("a"), 1}, 63 {[]byte("b"), []byte("x"), -1}, 64 // test runtimememeq's chunked implementation 65 {[]byte("abcdefgh"), []byte("abcdefgh"), 0}, 66 {[]byte("abcdefghi"), []byte("abcdefghi"), 0}, 67 {[]byte("abcdefghi"), []byte("abcdefghj"), -1}, 68 // nil tests 69 {nil, nil, 0}, 70 {[]byte(""), nil, 0}, 71 {nil, []byte(""), 0}, 72 {[]byte("a"), nil, 1}, 73 {nil, []byte("a"), -1}, 74 } 75 76 func TestEqual(t *testing.T) { 77 for _, tt := range compareTests { 78 eql := Equal(tt.a, tt.b) 79 if eql != (tt.i == 0) { 80 t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql) 81 } 82 eql = EqualPortable(tt.a, tt.b) 83 if eql != (tt.i == 0) { 84 t.Errorf(`EqualPortable(%q, %q) = %v`, tt.a, tt.b, eql) 85 } 86 } 87 } 88 89 func TestEqualExhaustive(t *testing.T) { 90 var size = 128 91 if testing.Short() { 92 size = 32 93 } 94 a := make([]byte, size) 95 b := make([]byte, size) 96 b_init := make([]byte, size) 97 // randomish but deterministic data 98 for i := 0; i < size; i++ { 99 a[i] = byte(17 * i) 100 b_init[i] = byte(23*i + 100) 101 } 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 copy(b, b_init) 107 copy(b[y:y+len], a[x:x+len]) 108 if !Equal(a[x:x+len], b[y:y+len]) || !Equal(b[y:y+len], a[x:x+len]) { 109 t.Errorf("Equal(%d, %d, %d) = false", len, x, y) 110 } 111 } 112 } 113 } 114 } 115 116 // make sure Equal returns false for minimally different strings. The data 117 // is all zeros except for a single one in one location. 118 func TestNotEqual(t *testing.T) { 119 var size = 128 120 if testing.Short() { 121 size = 32 122 } 123 a := make([]byte, size) 124 b := make([]byte, size) 125 126 for len := 0; len <= size; len++ { 127 for x := 0; x <= size-len; x++ { 128 for y := 0; y <= size-len; y++ { 129 for diffpos := x; diffpos < x+len; diffpos++ { 130 a[diffpos] = 1 131 if Equal(a[x:x+len], b[y:y+len]) || Equal(b[y:y+len], a[x:x+len]) { 132 t.Errorf("NotEqual(%d, %d, %d, %d) = true", len, x, y, diffpos) 133 } 134 a[diffpos] = 0 135 } 136 } 137 } 138 } 139 } 140 141 var indexTests = []BinOpTest{ 142 {"", "", 0}, 143 {"", "a", -1}, 144 {"", "foo", -1}, 145 {"fo", "foo", -1}, 146 {"foo", "baz", -1}, 147 {"foo", "foo", 0}, 148 {"oofofoofooo", "f", 2}, 149 {"oofofoofooo", "foo", 4}, 150 {"barfoobarfoo", "foo", 3}, 151 {"foo", "", 0}, 152 {"foo", "o", 1}, 153 {"abcABCabc", "A", 3}, 154 // cases with one byte strings - test IndexByte and special case in Index() 155 {"", "a", -1}, 156 {"x", "a", -1}, 157 {"x", "x", 0}, 158 {"abc", "a", 0}, 159 {"abc", "b", 1}, 160 {"abc", "c", 2}, 161 {"abc", "x", -1}, 162 {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33}, 163 {"foofyfoobarfoobar", "y", 4}, 164 {"oooooooooooooooooooooo", "r", -1}, 165 } 166 167 var lastIndexTests = []BinOpTest{ 168 {"", "", 0}, 169 {"", "a", -1}, 170 {"", "foo", -1}, 171 {"fo", "foo", -1}, 172 {"foo", "foo", 0}, 173 {"foo", "f", 0}, 174 {"oofofoofooo", "f", 7}, 175 {"oofofoofooo", "foo", 7}, 176 {"barfoobarfoo", "foo", 9}, 177 {"foo", "", 3}, 178 {"foo", "o", 2}, 179 {"abcABCabc", "A", 3}, 180 {"abcABCabc", "a", 6}, 181 } 182 183 var indexAnyTests = []BinOpTest{ 184 {"", "", -1}, 185 {"", "a", -1}, 186 {"", "abc", -1}, 187 {"a", "", -1}, 188 {"a", "a", 0}, 189 {"aaa", "a", 0}, 190 {"abc", "xyz", -1}, 191 {"abc", "xcz", 2}, 192 {"abc", "xyz", 2}, 193 {"aRegExp*", ".(|)*+?^$[]", 7}, 194 {dots + dots + dots, " ", -1}, 195 } 196 197 var lastIndexAnyTests = []BinOpTest{ 198 {"", "", -1}, 199 {"", "a", -1}, 200 {"", "abc", -1}, 201 {"a", "", -1}, 202 {"a", "a", 0}, 203 {"aaa", "a", 2}, 204 {"abc", "xyz", -1}, 205 {"abc", "ab", 1}, 206 {"abcd", "uvwxyz", 2 + len("")}, 207 {"a.RegExp*", ".(|)*+?^$[]", 8}, 208 {dots + dots + dots, " ", -1}, 209 } 210 211 var indexRuneTests = []BinOpTest{ 212 {"", "a", -1}, 213 {"", "", -1}, 214 {"foo", "", -1}, 215 {"foo", "o", 1}, 216 {"foobar", "", 3}, 217 {"foobar", "", 9}, 218 } 219 220 // Execute f on each test case. funcName should be the name of f; it's used 221 // in failure reports. 222 func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) { 223 for _, test := range testCases { 224 a := []byte(test.a) 225 b := []byte(test.b) 226 actual := f(a, b) 227 if actual != test.i { 228 t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, b, actual, test.i) 229 } 230 } 231 } 232 233 func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) { 234 for _, test := range testCases { 235 a := []byte(test.a) 236 actual := f(a, test.b) 237 if actual != test.i { 238 t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i) 239 } 240 } 241 } 242 243 func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) } 244 func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) } 245 func TestIndexAny(t *testing.T) { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) } 246 func TestLastIndexAny(t *testing.T) { 247 runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) 248 } 249 250 func TestIndexByte(t *testing.T) { 251 for _, tt := range indexTests { 252 if len(tt.b) != 1 { 253 continue 254 } 255 a := []byte(tt.a) 256 b := tt.b[0] 257 pos := IndexByte(a, b) 258 if pos != tt.i { 259 t.Errorf(`IndexByte(%q, '%c') = %v`, tt.a, b, pos) 260 } 261 posp := IndexBytePortable(a, b) 262 if posp != tt.i { 263 t.Errorf(`indexBytePortable(%q, '%c') = %v`, tt.a, b, posp) 264 } 265 } 266 } 267 268 func TestLastIndexByte(t *testing.T) { 269 testCases := []BinOpTest{ 270 {"", "q", -1}, 271 {"abcdef", "q", -1}, 272 {"abcdefabcdef", "a", len("abcdef")}, // something in the middle 273 {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte 274 {"zabcdefabcdef", "z", 0}, // first byte 275 {"abcd", "b", len("a")}, // non-ascii 276 } 277 for _, test := range testCases { 278 actual := LastIndexByte([]byte(test.a), test.b[0]) 279 if actual != test.i { 280 t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i) 281 } 282 } 283 } 284 285 // test a larger buffer with different sizes and alignments 286 func TestIndexByteBig(t *testing.T) { 287 var n = 1024 288 if testing.Short() { 289 n = 128 290 } 291 b := make([]byte, n) 292 for i := 0; i < n; i++ { 293 // different start alignments 294 b1 := b[i:] 295 for j := 0; j < len(b1); j++ { 296 b1[j] = 'x' 297 pos := IndexByte(b1, 'x') 298 if pos != j { 299 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 300 } 301 b1[j] = 0 302 pos = IndexByte(b1, 'x') 303 if pos != -1 { 304 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 305 } 306 } 307 // different end alignments 308 b1 = b[:i] 309 for j := 0; j < len(b1); j++ { 310 b1[j] = 'x' 311 pos := IndexByte(b1, 'x') 312 if pos != j { 313 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 314 } 315 b1[j] = 0 316 pos = IndexByte(b1, 'x') 317 if pos != -1 { 318 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 319 } 320 } 321 // different start and end alignments 322 b1 = b[i/2 : n-(i+1)/2] 323 for j := 0; j < len(b1); j++ { 324 b1[j] = 'x' 325 pos := IndexByte(b1, 'x') 326 if pos != j { 327 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 328 } 329 b1[j] = 0 330 pos = IndexByte(b1, 'x') 331 if pos != -1 { 332 t.Errorf("IndexByte(%q, 'x') = %v", b1, pos) 333 } 334 } 335 } 336 } 337 338 func TestIndexRune(t *testing.T) { 339 for _, tt := range indexRuneTests { 340 a := []byte(tt.a) 341 r, _ := utf8.DecodeRuneInString(tt.b) 342 pos := IndexRune(a, r) 343 if pos != tt.i { 344 t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos) 345 } 346 } 347 } 348 349 var bmbuf []byte 350 351 func BenchmarkIndexByte32(b *testing.B) { bmIndexByte(b, IndexByte, 32) } 352 func BenchmarkIndexByte4K(b *testing.B) { bmIndexByte(b, IndexByte, 4<<10) } 353 func BenchmarkIndexByte4M(b *testing.B) { bmIndexByte(b, IndexByte, 4<<20) } 354 func BenchmarkIndexByte64M(b *testing.B) { bmIndexByte(b, IndexByte, 64<<20) } 355 func BenchmarkIndexBytePortable32(b *testing.B) { bmIndexByte(b, IndexBytePortable, 32) } 356 func BenchmarkIndexBytePortable4K(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<10) } 357 func BenchmarkIndexBytePortable4M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<20) } 358 func BenchmarkIndexBytePortable64M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 64<<20) } 359 360 func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) { 361 if len(bmbuf) < n { 362 bmbuf = make([]byte, n) 363 } 364 b.SetBytes(int64(n)) 365 buf := bmbuf[0:n] 366 buf[n-1] = 'x' 367 for i := 0; i < b.N; i++ { 368 j := index(buf, 'x') 369 if j != n-1 { 370 b.Fatal("bad index", j) 371 } 372 } 373 buf[n-1] = '\x00' 374 } 375 376 func BenchmarkEqual0(b *testing.B) { 377 var buf [4]byte 378 buf1 := buf[0:0] 379 buf2 := buf[1:1] 380 for i := 0; i < b.N; i++ { 381 eq := Equal(buf1, buf2) 382 if !eq { 383 b.Fatal("bad equal") 384 } 385 } 386 } 387 388 func BenchmarkEqual1(b *testing.B) { bmEqual(b, Equal, 1) } 389 func BenchmarkEqual6(b *testing.B) { bmEqual(b, Equal, 6) } 390 func BenchmarkEqual9(b *testing.B) { bmEqual(b, Equal, 9) } 391 func BenchmarkEqual15(b *testing.B) { bmEqual(b, Equal, 15) } 392 func BenchmarkEqual16(b *testing.B) { bmEqual(b, Equal, 16) } 393 func BenchmarkEqual20(b *testing.B) { bmEqual(b, Equal, 20) } 394 func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) } 395 func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) } 396 func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) } 397 func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) } 398 func BenchmarkEqualPort1(b *testing.B) { bmEqual(b, EqualPortable, 1) } 399 func BenchmarkEqualPort6(b *testing.B) { bmEqual(b, EqualPortable, 6) } 400 func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) } 401 func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) } 402 func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) } 403 func BenchmarkEqualPortable64M(b *testing.B) { bmEqual(b, EqualPortable, 64<<20) } 404 405 func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) { 406 if len(bmbuf) < 2*n { 407 bmbuf = make([]byte, 2*n) 408 } 409 b.SetBytes(int64(n)) 410 buf1 := bmbuf[0:n] 411 buf2 := bmbuf[n : 2*n] 412 buf1[n-1] = 'x' 413 buf2[n-1] = 'x' 414 for i := 0; i < b.N; i++ { 415 eq := equal(buf1, buf2) 416 if !eq { 417 b.Fatal("bad equal") 418 } 419 } 420 buf1[n-1] = '\x00' 421 buf2[n-1] = '\x00' 422 } 423 424 func BenchmarkIndex32(b *testing.B) { bmIndex(b, Index, 32) } 425 func BenchmarkIndex4K(b *testing.B) { bmIndex(b, Index, 4<<10) } 426 func BenchmarkIndex4M(b *testing.B) { bmIndex(b, Index, 4<<20) } 427 func BenchmarkIndex64M(b *testing.B) { bmIndex(b, Index, 64<<20) } 428 429 func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) { 430 if len(bmbuf) < n { 431 bmbuf = make([]byte, n) 432 } 433 b.SetBytes(int64(n)) 434 buf := bmbuf[0:n] 435 buf[n-1] = 'x' 436 for i := 0; i < b.N; i++ { 437 j := index(buf, buf[n-7:]) 438 if j != n-7 { 439 b.Fatal("bad index", j) 440 } 441 } 442 buf[n-1] = '\x00' 443 } 444 445 func BenchmarkIndexEasy32(b *testing.B) { bmIndexEasy(b, Index, 32) } 446 func BenchmarkIndexEasy4K(b *testing.B) { bmIndexEasy(b, Index, 4<<10) } 447 func BenchmarkIndexEasy4M(b *testing.B) { bmIndexEasy(b, Index, 4<<20) } 448 func BenchmarkIndexEasy64M(b *testing.B) { bmIndexEasy(b, Index, 64<<20) } 449 450 func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) { 451 if len(bmbuf) < n { 452 bmbuf = make([]byte, n) 453 } 454 b.SetBytes(int64(n)) 455 buf := bmbuf[0:n] 456 buf[n-1] = 'x' 457 buf[n-7] = 'x' 458 for i := 0; i < b.N; i++ { 459 j := index(buf, buf[n-7:]) 460 if j != n-7 { 461 b.Fatal("bad index", j) 462 } 463 } 464 buf[n-1] = '\x00' 465 buf[n-7] = '\x00' 466 } 467 468 func BenchmarkCount32(b *testing.B) { bmCount(b, Count, 32) } 469 func BenchmarkCount4K(b *testing.B) { bmCount(b, Count, 4<<10) } 470 func BenchmarkCount4M(b *testing.B) { bmCount(b, Count, 4<<20) } 471 func BenchmarkCount64M(b *testing.B) { bmCount(b, Count, 64<<20) } 472 473 func bmCount(b *testing.B, count func([]byte, []byte) int, n int) { 474 if len(bmbuf) < n { 475 bmbuf = make([]byte, n) 476 } 477 b.SetBytes(int64(n)) 478 buf := bmbuf[0:n] 479 buf[n-1] = 'x' 480 for i := 0; i < b.N; i++ { 481 j := count(buf, buf[n-7:]) 482 if j != 1 { 483 b.Fatal("bad count", j) 484 } 485 } 486 buf[n-1] = '\x00' 487 } 488 489 func BenchmarkCountEasy32(b *testing.B) { bmCountEasy(b, Count, 32) } 490 func BenchmarkCountEasy4K(b *testing.B) { bmCountEasy(b, Count, 4<<10) } 491 func BenchmarkCountEasy4M(b *testing.B) { bmCountEasy(b, Count, 4<<20) } 492 func BenchmarkCountEasy64M(b *testing.B) { bmCountEasy(b, Count, 64<<20) } 493 494 func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) { 495 if len(bmbuf) < n { 496 bmbuf = make([]byte, n) 497 } 498 b.SetBytes(int64(n)) 499 buf := bmbuf[0:n] 500 buf[n-1] = 'x' 501 buf[n-7] = 'x' 502 for i := 0; i < b.N; i++ { 503 j := count(buf, buf[n-7:]) 504 if j != 1 { 505 b.Fatal("bad count", j) 506 } 507 } 508 buf[n-1] = '\x00' 509 buf[n-7] = '\x00' 510 } 511 512 type ExplodeTest struct { 513 s string 514 n int 515 a []string 516 } 517 518 var explodetests = []ExplodeTest{ 519 {"", -1, []string{}}, 520 {abcd, -1, []string{"a", "b", "c", "d"}}, 521 {faces, -1, []string{"", "", ""}}, 522 {abcd, 2, []string{"a", "bcd"}}, 523 } 524 525 func TestExplode(t *testing.T) { 526 for _, tt := range explodetests { 527 a := SplitN([]byte(tt.s), nil, tt.n) 528 result := sliceOfString(a) 529 if !eq(result, tt.a) { 530 t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a) 531 continue 532 } 533 s := Join(a, []byte{}) 534 if string(s) != tt.s { 535 t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s) 536 } 537 } 538 } 539 540 type SplitTest struct { 541 s string 542 sep string 543 n int 544 a []string 545 } 546 547 var splittests = []SplitTest{ 548 {abcd, "a", 0, nil}, 549 {abcd, "a", -1, []string{"", "bcd"}}, 550 {abcd, "z", -1, []string{"abcd"}}, 551 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 552 {commas, ",", -1, []string{"1", "2", "3", "4"}}, 553 {dots, "...", -1, []string{"1", ".2", ".3", ".4"}}, 554 {faces, "", -1, []string{"", ""}}, 555 {faces, "~", -1, []string{faces}}, 556 {faces, "", -1, []string{"", "", ""}}, 557 {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}}, 558 {"1 2", " ", 3, []string{"1", "2"}}, 559 {"123", "", 2, []string{"1", "23"}}, 560 {"123", "", 17, []string{"1", "2", "3"}}, 561 } 562 563 func TestSplit(t *testing.T) { 564 for _, tt := range splittests { 565 a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n) 566 result := sliceOfString(a) 567 if !eq(result, tt.a) { 568 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) 569 continue 570 } 571 if tt.n == 0 { 572 continue 573 } 574 s := Join(a, []byte(tt.sep)) 575 if string(s) != tt.s { 576 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 577 } 578 if tt.n < 0 { 579 b := Split([]byte(tt.s), []byte(tt.sep)) 580 if !reflect.DeepEqual(a, b) { 581 t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 582 } 583 } 584 if len(a) > 0 { 585 in, out := a[0], s 586 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] { 587 t.Errorf("Join(%#v, %q) didn't copy", a, tt.sep) 588 } 589 } 590 } 591 } 592 593 var splitaftertests = []SplitTest{ 594 {abcd, "a", -1, []string{"a", "bcd"}}, 595 {abcd, "z", -1, []string{"abcd"}}, 596 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 597 {commas, ",", -1, []string{"1,", "2,", "3,", "4"}}, 598 {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}}, 599 {faces, "", -1, []string{"", ""}}, 600 {faces, "~", -1, []string{faces}}, 601 {faces, "", -1, []string{"", "", ""}}, 602 {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}}, 603 {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}}, 604 {"1 2", " ", 3, []string{"1 ", "2"}}, 605 {"123", "", 2, []string{"1", "23"}}, 606 {"123", "", 17, []string{"1", "2", "3"}}, 607 } 608 609 func TestSplitAfter(t *testing.T) { 610 for _, tt := range splitaftertests { 611 a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n) 612 result := sliceOfString(a) 613 if !eq(result, tt.a) { 614 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) 615 continue 616 } 617 s := Join(a, nil) 618 if string(s) != tt.s { 619 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 620 } 621 if tt.n < 0 { 622 b := SplitAfter([]byte(tt.s), []byte(tt.sep)) 623 if !reflect.DeepEqual(a, b) { 624 t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 625 } 626 } 627 } 628 } 629 630 type FieldsTest struct { 631 s string 632 a []string 633 } 634 635 var fieldstests = []FieldsTest{ 636 {"", []string{}}, 637 {" ", []string{}}, 638 {" \t ", []string{}}, 639 {" abc ", []string{"abc"}}, 640 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 641 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 642 {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}}, 643 {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}}, 644 {"\u2000\u2001\u2002", []string{}}, 645 {"\n\t\n", []string{"", ""}}, 646 {faces, []string{faces}}, 647 } 648 649 func TestFields(t *testing.T) { 650 for _, tt := range fieldstests { 651 a := Fields([]byte(tt.s)) 652 result := sliceOfString(a) 653 if !eq(result, tt.a) { 654 t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) 655 continue 656 } 657 } 658 } 659 660 func TestFieldsFunc(t *testing.T) { 661 for _, tt := range fieldstests { 662 a := FieldsFunc([]byte(tt.s), unicode.IsSpace) 663 result := sliceOfString(a) 664 if !eq(result, tt.a) { 665 t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a) 666 continue 667 } 668 } 669 pred := func(c rune) bool { return c == 'X' } 670 var fieldsFuncTests = []FieldsTest{ 671 {"", []string{}}, 672 {"XX", []string{}}, 673 {"XXhiXXX", []string{"hi"}}, 674 {"aXXbXXXcX", []string{"a", "b", "c"}}, 675 } 676 for _, tt := range fieldsFuncTests { 677 a := FieldsFunc([]byte(tt.s), pred) 678 result := sliceOfString(a) 679 if !eq(result, tt.a) { 680 t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) 681 } 682 } 683 } 684 685 // Test case for any function which accepts and returns a byte slice. 686 // For ease of creation, we write the byte slices as strings. 687 type StringTest struct { 688 in, out string 689 } 690 691 var upperTests = []StringTest{ 692 {"", ""}, 693 {"abc", "ABC"}, 694 {"AbC123", "ABC123"}, 695 {"azAZ09_", "AZAZ09_"}, 696 {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char 697 } 698 699 var lowerTests = []StringTest{ 700 {"", ""}, 701 {"abc", "abc"}, 702 {"AbC123", "abc123"}, 703 {"azAZ09_", "azaz09_"}, 704 {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char 705 } 706 707 const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000" 708 709 var trimSpaceTests = []StringTest{ 710 {"", ""}, 711 {"abc", "abc"}, 712 {space + "abc" + space, "abc"}, 713 {" ", ""}, 714 {" \t\r\n \t\t\r\r\n\n ", ""}, 715 {" \t\r\n x\t\t\r\r\n\n ", "x"}, 716 {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"}, 717 {"1 \t\r\n2", "1 \t\r\n2"}, 718 {" x\x80", "x\x80"}, 719 {" x\xc0", "x\xc0"}, 720 {"x \xc0\xc0 ", "x \xc0\xc0"}, 721 {"x \xc0", "x \xc0"}, 722 {"x \xc0 ", "x \xc0"}, 723 {"x \xc0\xc0 ", "x \xc0\xc0"}, 724 {"x \xc0\xc0 ", "x \xc0\xc0"}, 725 {"x ", "x "}, 726 } 727 728 // Execute f on each test case. funcName should be the name of f; it's used 729 // in failure reports. 730 func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) { 731 for _, tc := range testCases { 732 actual := string(f([]byte(tc.in))) 733 if actual != tc.out { 734 t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out) 735 } 736 } 737 } 738 739 func tenRunes(r rune) string { 740 runes := make([]rune, 10) 741 for i := range runes { 742 runes[i] = r 743 } 744 return string(runes) 745 } 746 747 // User-defined self-inverse mapping function 748 func rot13(r rune) rune { 749 const step = 13 750 if r >= 'a' && r <= 'z' { 751 return ((r - 'a' + step) % 26) + 'a' 752 } 753 if r >= 'A' && r <= 'Z' { 754 return ((r - 'A' + step) % 26) + 'A' 755 } 756 return r 757 } 758 759 func TestMap(t *testing.T) { 760 // Run a couple of awful growth/shrinkage tests 761 a := tenRunes('a') 762 763 // 1. Grow. This triggers two reallocations in Map. 764 maxRune := func(r rune) rune { return unicode.MaxRune } 765 m := Map(maxRune, []byte(a)) 766 expect := tenRunes(unicode.MaxRune) 767 if string(m) != expect { 768 t.Errorf("growing: expected %q got %q", expect, m) 769 } 770 771 // 2. Shrink 772 minRune := func(r rune) rune { return 'a' } 773 m = Map(minRune, []byte(tenRunes(unicode.MaxRune))) 774 expect = a 775 if string(m) != expect { 776 t.Errorf("shrinking: expected %q got %q", expect, m) 777 } 778 779 // 3. Rot13 780 m = Map(rot13, []byte("a to zed")) 781 expect = "n gb mrq" 782 if string(m) != expect { 783 t.Errorf("rot13: expected %q got %q", expect, m) 784 } 785 786 // 4. Rot13^2 787 m = Map(rot13, Map(rot13, []byte("a to zed"))) 788 expect = "a to zed" 789 if string(m) != expect { 790 t.Errorf("rot13: expected %q got %q", expect, m) 791 } 792 793 // 5. Drop 794 dropNotLatin := func(r rune) rune { 795 if unicode.Is(unicode.Latin, r) { 796 return r 797 } 798 return -1 799 } 800 m = Map(dropNotLatin, []byte("Hello, ")) 801 expect = "Hello" 802 if string(m) != expect { 803 t.Errorf("drop: expected %q got %q", expect, m) 804 } 805 806 // 6. Invalid rune 807 invalidRune := func(r rune) rune { 808 return utf8.MaxRune + 1 809 } 810 m = Map(invalidRune, []byte("x")) 811 expect = "\uFFFD" 812 if string(m) != expect { 813 t.Errorf("invalidRune: expected %q got %q", expect, m) 814 } 815 } 816 817 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } 818 819 func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } 820 821 func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) } 822 823 type RepeatTest struct { 824 in, out string 825 count int 826 } 827 828 var RepeatTests = []RepeatTest{ 829 {"", "", 0}, 830 {"", "", 1}, 831 {"", "", 2}, 832 {"-", "", 0}, 833 {"-", "-", 1}, 834 {"-", "----------", 10}, 835 {"abc ", "abc abc abc ", 3}, 836 } 837 838 func TestRepeat(t *testing.T) { 839 for _, tt := range RepeatTests { 840 tin := []byte(tt.in) 841 tout := []byte(tt.out) 842 a := Repeat(tin, tt.count) 843 if !Equal(a, tout) { 844 t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout) 845 continue 846 } 847 } 848 } 849 850 func runesEqual(a, b []rune) bool { 851 if len(a) != len(b) { 852 return false 853 } 854 for i, r := range a { 855 if r != b[i] { 856 return false 857 } 858 } 859 return true 860 } 861 862 type RunesTest struct { 863 in string 864 out []rune 865 lossy bool 866 } 867 868 var RunesTests = []RunesTest{ 869 {"", []rune{}, false}, 870 {" ", []rune{32}, false}, 871 {"ABC", []rune{65, 66, 67}, false}, 872 {"abc", []rune{97, 98, 99}, false}, 873 {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false}, 874 {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true}, 875 {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true}, 876 } 877 878 func TestRunes(t *testing.T) { 879 for _, tt := range RunesTests { 880 tin := []byte(tt.in) 881 a := Runes(tin) 882 if !runesEqual(a, tt.out) { 883 t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out) 884 continue 885 } 886 if !tt.lossy { 887 // can only test reassembly if we didn't lose information 888 s := string(a) 889 if s != tt.in { 890 t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin) 891 } 892 } 893 } 894 } 895 896 type TrimTest struct { 897 f string 898 in, arg, out string 899 } 900 901 var trimTests = []TrimTest{ 902 {"Trim", "abba", "a", "bb"}, 903 {"Trim", "abba", "ab", ""}, 904 {"TrimLeft", "abba", "ab", ""}, 905 {"TrimRight", "abba", "ab", ""}, 906 {"TrimLeft", "abba", "a", "bba"}, 907 {"TrimRight", "abba", "a", "abb"}, 908 {"Trim", "<tag>", "<>", "tag"}, 909 {"Trim", "* listitem", " *", "listitem"}, 910 {"Trim", `"quote"`, `"`, "quote"}, 911 {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"}, 912 //empty string tests 913 {"Trim", "abba", "", "abba"}, 914 {"Trim", "", "123", ""}, 915 {"Trim", "", "", ""}, 916 {"TrimLeft", "abba", "", "abba"}, 917 {"TrimLeft", "", "123", ""}, 918 {"TrimLeft", "", "", ""}, 919 {"TrimRight", "abba", "", "abba"}, 920 {"TrimRight", "", "123", ""}, 921 {"TrimRight", "", "", ""}, 922 {"TrimRight", "\xc0", "", "\xc0"}, 923 {"TrimPrefix", "aabb", "a", "abb"}, 924 {"TrimPrefix", "aabb", "b", "aabb"}, 925 {"TrimSuffix", "aabb", "a", "aabb"}, 926 {"TrimSuffix", "aabb", "b", "aab"}, 927 } 928 929 func TestTrim(t *testing.T) { 930 for _, tc := range trimTests { 931 name := tc.f 932 var f func([]byte, string) []byte 933 var fb func([]byte, []byte) []byte 934 switch name { 935 case "Trim": 936 f = Trim 937 case "TrimLeft": 938 f = TrimLeft 939 case "TrimRight": 940 f = TrimRight 941 case "TrimPrefix": 942 fb = TrimPrefix 943 case "TrimSuffix": 944 fb = TrimSuffix 945 default: 946 t.Errorf("Undefined trim function %s", name) 947 } 948 var actual string 949 if f != nil { 950 actual = string(f([]byte(tc.in), tc.arg)) 951 } else { 952 actual = string(fb([]byte(tc.in), []byte(tc.arg))) 953 } 954 if actual != tc.out { 955 t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) 956 } 957 } 958 } 959 960 type predicate struct { 961 f func(r rune) bool 962 name string 963 } 964 965 var isSpace = predicate{unicode.IsSpace, "IsSpace"} 966 var isDigit = predicate{unicode.IsDigit, "IsDigit"} 967 var isUpper = predicate{unicode.IsUpper, "IsUpper"} 968 var isValidRune = predicate{ 969 func(r rune) bool { 970 return r != utf8.RuneError 971 }, 972 "IsValidRune", 973 } 974 975 type TrimFuncTest struct { 976 f predicate 977 in, out string 978 } 979 980 func not(p predicate) predicate { 981 return predicate{ 982 func(r rune) bool { 983 return !p.f(r) 984 }, 985 "not " + p.name, 986 } 987 } 988 989 var trimFuncTests = []TrimFuncTest{ 990 {isSpace, space + " hello " + space, "hello"}, 991 {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"}, 992 {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"}, 993 {not(isSpace), "hello" + space + "hello", space}, 994 {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"}, 995 {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"}, 996 {not(isValidRune), "\xc0a\xc0", "a"}, 997 } 998 999 func TestTrimFunc(t *testing.T) { 1000 for _, tc := range trimFuncTests { 1001 actual := string(TrimFunc([]byte(tc.in), tc.f.f)) 1002 if actual != tc.out { 1003 t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out) 1004 } 1005 } 1006 } 1007 1008 type IndexFuncTest struct { 1009 in string 1010 f predicate 1011 first, last int 1012 } 1013 1014 var indexFuncTests = []IndexFuncTest{ 1015 {"", isValidRune, -1, -1}, 1016 {"abc", isDigit, -1, -1}, 1017 {"0123", isDigit, 0, 3}, 1018 {"a1b", isDigit, 1, 1}, 1019 {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes 1020 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18}, 1021 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34}, 1022 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12}, 1023 1024 // tests of invalid UTF-8 1025 {"\x801", isDigit, 1, 1}, 1026 {"\x80abc", isDigit, -1, -1}, 1027 {"\xc0a\xc0", isValidRune, 1, 1}, 1028 {"\xc0a\xc0", not(isValidRune), 0, 2}, 1029 {"\xc0\xc0", not(isValidRune), 0, 4}, 1030 {"\xc0\xc0\xc0", not(isValidRune), 0, 5}, 1031 {"ab\xc0a\xc0cd", not(isValidRune), 2, 4}, 1032 {"a\xe0\x80cd", not(isValidRune), 1, 2}, 1033 } 1034 1035 func TestIndexFunc(t *testing.T) { 1036 for _, tc := range indexFuncTests { 1037 first := IndexFunc([]byte(tc.in), tc.f.f) 1038 if first != tc.first { 1039 t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first) 1040 } 1041 last := LastIndexFunc([]byte(tc.in), tc.f.f) 1042 if last != tc.last { 1043 t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last) 1044 } 1045 } 1046 } 1047 1048 type ReplaceTest struct { 1049 in string 1050 old, new string 1051 n int 1052 out string 1053 } 1054 1055 var ReplaceTests = []ReplaceTest{ 1056 {"hello", "l", "L", 0, "hello"}, 1057 {"hello", "l", "L", -1, "heLLo"}, 1058 {"hello", "x", "X", -1, "hello"}, 1059 {"", "x", "X", -1, ""}, 1060 {"radar", "r", "<r>", -1, "<r>ada<r>"}, 1061 {"", "", "<>", -1, "<>"}, 1062 {"banana", "a", "<>", -1, "b<>n<>n<>"}, 1063 {"banana", "a", "<>", 1, "b<>nana"}, 1064 {"banana", "a", "<>", 1000, "b<>n<>n<>"}, 1065 {"banana", "an", "<>", -1, "b<><>a"}, 1066 {"banana", "ana", "<>", -1, "b<>na"}, 1067 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"}, 1068 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"}, 1069 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"}, 1070 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"}, 1071 {"banana", "", "<>", 1, "<>banana"}, 1072 {"banana", "a", "a", -1, "banana"}, 1073 {"banana", "a", "a", 1, "banana"}, 1074 {"", "", "<>", -1, "<><><><>"}, 1075 } 1076 1077 func TestReplace(t *testing.T) { 1078 for _, tt := range ReplaceTests { 1079 in := append([]byte(tt.in), "<spare>"...) 1080 in = in[:len(tt.in)] 1081 out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n) 1082 if s := string(out); s != tt.out { 1083 t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out) 1084 } 1085 if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] { 1086 t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n) 1087 } 1088 } 1089 } 1090 1091 type TitleTest struct { 1092 in, out string 1093 } 1094 1095 var TitleTests = []TitleTest{ 1096 {"", ""}, 1097 {"a", "A"}, 1098 {" aaa aaa aaa ", " Aaa Aaa Aaa "}, 1099 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "}, 1100 {"123a456", "123a456"}, 1101 {"double-blind", "Double-Blind"}, 1102 {"", ""}, 1103 {"with_underscore", "With_underscore"}, 1104 {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"}, 1105 } 1106 1107 func TestTitle(t *testing.T) { 1108 for _, tt := range TitleTests { 1109 if s := string(Title([]byte(tt.in))); s != tt.out { 1110 t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out) 1111 } 1112 } 1113 } 1114 1115 var ToTitleTests = []TitleTest{ 1116 {"", ""}, 1117 {"a", "A"}, 1118 {" aaa aaa aaa ", " AAA AAA AAA "}, 1119 {" Aaa Aaa Aaa ", " AAA AAA AAA "}, 1120 {"123a456", "123A456"}, 1121 {"double-blind", "DOUBLE-BLIND"}, 1122 {"", ""}, 1123 } 1124 1125 func TestToTitle(t *testing.T) { 1126 for _, tt := range ToTitleTests { 1127 if s := string(ToTitle([]byte(tt.in))); s != tt.out { 1128 t.Errorf("ToTitle(%q) = %q, want %q", tt.in, s, tt.out) 1129 } 1130 } 1131 } 1132 1133 var EqualFoldTests = []struct { 1134 s, t string 1135 out bool 1136 }{ 1137 {"abc", "abc", true}, 1138 {"ABcd", "ABcd", true}, 1139 {"123abc", "123ABC", true}, 1140 {"", "", true}, 1141 {"abc", "xyz", false}, 1142 {"abc", "XYZ", false}, 1143 {"abcdefghijk", "abcdefghijX", false}, 1144 {"abcdefghijk", "abcdefghij\u212A", true}, 1145 {"abcdefghijK", "abcdefghij\u212A", true}, 1146 {"abcdefghijkz", "abcdefghij\u212Ay", false}, 1147 {"abcdefghijKz", "abcdefghij\u212Ay", false}, 1148 } 1149 1150 func TestEqualFold(t *testing.T) { 1151 for _, tt := range EqualFoldTests { 1152 if out := EqualFold([]byte(tt.s), []byte(tt.t)); out != tt.out { 1153 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out) 1154 } 1155 if out := EqualFold([]byte(tt.t), []byte(tt.s)); out != tt.out { 1156 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out) 1157 } 1158 } 1159 } 1160 1161 func TestBufferGrowNegative(t *testing.T) { 1162 defer func() { 1163 if err := recover(); err == nil { 1164 t.Fatal("Grow(-1) should have panicked") 1165 } 1166 }() 1167 var b Buffer 1168 b.Grow(-1) 1169 } 1170 1171 func TestBufferTruncateNegative(t *testing.T) { 1172 defer func() { 1173 if err := recover(); err == nil { 1174 t.Fatal("Truncate(-1) should have panicked") 1175 } 1176 }() 1177 var b Buffer 1178 b.Truncate(-1) 1179 } 1180 1181 func TestBufferTruncateOutOfRange(t *testing.T) { 1182 defer func() { 1183 if err := recover(); err == nil { 1184 t.Fatal("Truncate(20) should have panicked") 1185 } 1186 }() 1187 var b Buffer 1188 b.Write(make([]byte, 10)) 1189 b.Truncate(20) 1190 } 1191 1192 var containsTests = []struct { 1193 b, subslice []byte 1194 want bool 1195 }{ 1196 {[]byte("hello"), []byte("hel"), true}, 1197 {[]byte(""), []byte(""), true}, 1198 {[]byte("hello"), []byte("Hello, world"), false}, 1199 {[]byte(""), []byte(""), false}, 1200 } 1201 1202 func TestContains(t *testing.T) { 1203 for _, tt := range containsTests { 1204 if got := Contains(tt.b, tt.subslice); got != tt.want { 1205 t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want) 1206 } 1207 } 1208 } 1209 1210 var makeFieldsInput = func() []byte { 1211 x := make([]byte, 1<<20) 1212 // Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space. 1213 for i := range x { 1214 switch rand.Intn(10) { 1215 case 0: 1216 x[i] = ' ' 1217 case 1: 1218 if i > 0 && x[i-1] == 'x' { 1219 copy(x[i-1:], "") 1220 break 1221 } 1222 fallthrough 1223 default: 1224 x[i] = 'x' 1225 } 1226 } 1227 return x 1228 } 1229 1230 var fieldsInput = makeFieldsInput() 1231 1232 func BenchmarkFields(b *testing.B) { 1233 b.SetBytes(int64(len(fieldsInput))) 1234 for i := 0; i < b.N; i++ { 1235 Fields(fieldsInput) 1236 } 1237 } 1238 1239 func BenchmarkFieldsFunc(b *testing.B) { 1240 b.SetBytes(int64(len(fieldsInput))) 1241 for i := 0; i < b.N; i++ { 1242 FieldsFunc(fieldsInput, unicode.IsSpace) 1243 } 1244 } 1245 1246 func BenchmarkTrimSpace(b *testing.B) { 1247 s := []byte(" Some text. \n") 1248 for i := 0; i < b.N; i++ { 1249 TrimSpace(s) 1250 } 1251 } 1252 1253 func BenchmarkRepeat(b *testing.B) { 1254 for i := 0; i < b.N; i++ { 1255 Repeat([]byte("-"), 80) 1256 } 1257 } 1258