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