github.com/m10x/go/src@v0.0.0-20220112094212-ba61592315da/strings/strings_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 strings_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "math/rand" 12 "reflect" 13 "strconv" 14 . "strings" 15 "testing" 16 "unicode" 17 "unicode/utf8" 18 "unsafe" 19 ) 20 21 func eq(a, b []string) bool { 22 if len(a) != len(b) { 23 return false 24 } 25 for i := 0; i < len(a); i++ { 26 if a[i] != b[i] { 27 return false 28 } 29 } 30 return true 31 } 32 33 var abcd = "abcd" 34 var faces = "☺☻☹" 35 var commas = "1,2,3,4" 36 var dots = "1....2....3....4" 37 38 type IndexTest struct { 39 s string 40 sep string 41 out int 42 } 43 44 var indexTests = []IndexTest{ 45 {"", "", 0}, 46 {"", "a", -1}, 47 {"", "foo", -1}, 48 {"fo", "foo", -1}, 49 {"foo", "foo", 0}, 50 {"oofofoofooo", "f", 2}, 51 {"oofofoofooo", "foo", 4}, 52 {"barfoobarfoo", "foo", 3}, 53 {"foo", "", 0}, 54 {"foo", "o", 1}, 55 {"abcABCabc", "A", 3}, 56 // cases with one byte strings - test special case in Index() 57 {"", "a", -1}, 58 {"x", "a", -1}, 59 {"x", "x", 0}, 60 {"abc", "a", 0}, 61 {"abc", "b", 1}, 62 {"abc", "c", 2}, 63 {"abc", "x", -1}, 64 // test special cases in Index() for short strings 65 {"", "ab", -1}, 66 {"bc", "ab", -1}, 67 {"ab", "ab", 0}, 68 {"xab", "ab", 1}, 69 {"xab"[:2], "ab", -1}, 70 {"", "abc", -1}, 71 {"xbc", "abc", -1}, 72 {"abc", "abc", 0}, 73 {"xabc", "abc", 1}, 74 {"xabc"[:3], "abc", -1}, 75 {"xabxc", "abc", -1}, 76 {"", "abcd", -1}, 77 {"xbcd", "abcd", -1}, 78 {"abcd", "abcd", 0}, 79 {"xabcd", "abcd", 1}, 80 {"xyabcd"[:5], "abcd", -1}, 81 {"xbcqq", "abcqq", -1}, 82 {"abcqq", "abcqq", 0}, 83 {"xabcqq", "abcqq", 1}, 84 {"xyabcqq"[:6], "abcqq", -1}, 85 {"xabxcqq", "abcqq", -1}, 86 {"xabcqxq", "abcqq", -1}, 87 {"", "01234567", -1}, 88 {"32145678", "01234567", -1}, 89 {"01234567", "01234567", 0}, 90 {"x01234567", "01234567", 1}, 91 {"x0123456x01234567", "01234567", 9}, 92 {"xx01234567"[:9], "01234567", -1}, 93 {"", "0123456789", -1}, 94 {"3214567844", "0123456789", -1}, 95 {"0123456789", "0123456789", 0}, 96 {"x0123456789", "0123456789", 1}, 97 {"x012345678x0123456789", "0123456789", 11}, 98 {"xyz0123456789"[:12], "0123456789", -1}, 99 {"x01234567x89", "0123456789", -1}, 100 {"", "0123456789012345", -1}, 101 {"3214567889012345", "0123456789012345", -1}, 102 {"0123456789012345", "0123456789012345", 0}, 103 {"x0123456789012345", "0123456789012345", 1}, 104 {"x012345678901234x0123456789012345", "0123456789012345", 17}, 105 {"", "01234567890123456789", -1}, 106 {"32145678890123456789", "01234567890123456789", -1}, 107 {"01234567890123456789", "01234567890123456789", 0}, 108 {"x01234567890123456789", "01234567890123456789", 1}, 109 {"x0123456789012345678x01234567890123456789", "01234567890123456789", 21}, 110 {"xyz01234567890123456789"[:22], "01234567890123456789", -1}, 111 {"", "0123456789012345678901234567890", -1}, 112 {"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1}, 113 {"0123456789012345678901234567890", "0123456789012345678901234567890", 0}, 114 {"x0123456789012345678901234567890", "0123456789012345678901234567890", 1}, 115 {"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32}, 116 {"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1}, 117 {"", "01234567890123456789012345678901", -1}, 118 {"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1}, 119 {"01234567890123456789012345678901", "01234567890123456789012345678901", 0}, 120 {"x01234567890123456789012345678901", "01234567890123456789012345678901", 1}, 121 {"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33}, 122 {"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1}, 123 {"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6}, 124 {"", "0123456789012345678901234567890123456789", -1}, 125 {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2}, 126 {"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1}, 127 {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1}, 128 {"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65}, 129 // test fallback to Rabin-Karp. 130 {"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22}, 131 {"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1}, 132 } 133 134 var lastIndexTests = []IndexTest{ 135 {"", "", 0}, 136 {"", "a", -1}, 137 {"", "foo", -1}, 138 {"fo", "foo", -1}, 139 {"foo", "foo", 0}, 140 {"foo", "f", 0}, 141 {"oofofoofooo", "f", 7}, 142 {"oofofoofooo", "foo", 7}, 143 {"barfoobarfoo", "foo", 9}, 144 {"foo", "", 3}, 145 {"foo", "o", 2}, 146 {"abcABCabc", "A", 3}, 147 {"abcABCabc", "a", 6}, 148 } 149 150 var indexAnyTests = []IndexTest{ 151 {"", "", -1}, 152 {"", "a", -1}, 153 {"", "abc", -1}, 154 {"a", "", -1}, 155 {"a", "a", 0}, 156 {"\x80", "\xffb", 0}, 157 {"aaa", "a", 0}, 158 {"abc", "xyz", -1}, 159 {"abc", "xcz", 2}, 160 {"ab☺c", "x☺yz", 2}, 161 {"a☺b☻c☹d", "cx", len("a☺b☻")}, 162 {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")}, 163 {"aRegExp*", ".(|)*+?^$[]", 7}, 164 {dots + dots + dots, " ", -1}, 165 {"012abcba210", "\xffb", 4}, 166 {"012\x80bcb\x80210", "\xffb", 3}, 167 {"0123456\xcf\x80abc", "\xcfb\x80", 10}, 168 } 169 170 var lastIndexAnyTests = []IndexTest{ 171 {"", "", -1}, 172 {"", "a", -1}, 173 {"", "abc", -1}, 174 {"a", "", -1}, 175 {"a", "a", 0}, 176 {"\x80", "\xffb", 0}, 177 {"aaa", "a", 2}, 178 {"abc", "xyz", -1}, 179 {"abc", "ab", 1}, 180 {"ab☺c", "x☺yz", 2}, 181 {"a☺b☻c☹d", "cx", len("a☺b☻")}, 182 {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")}, 183 {"a.RegExp*", ".(|)*+?^$[]", 8}, 184 {dots + dots + dots, " ", -1}, 185 {"012abcba210", "\xffb", 6}, 186 {"012\x80bcb\x80210", "\xffb", 7}, 187 {"0123456\xcf\x80abc", "\xcfb\x80", 10}, 188 } 189 190 // Execute f on each test case. funcName should be the name of f; it's used 191 // in failure reports. 192 func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) { 193 for _, test := range testCases { 194 actual := f(test.s, test.sep) 195 if actual != test.out { 196 t.Errorf("%s(%q,%q) = %v; want %v", funcName, test.s, test.sep, actual, test.out) 197 } 198 } 199 } 200 201 func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) } 202 func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) } 203 func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) } 204 func TestLastIndexAny(t *testing.T) { 205 runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) 206 } 207 208 func TestIndexByte(t *testing.T) { 209 for _, tt := range indexTests { 210 if len(tt.sep) != 1 { 211 continue 212 } 213 pos := IndexByte(tt.s, tt.sep[0]) 214 if pos != tt.out { 215 t.Errorf(`IndexByte(%q, %q) = %v; want %v`, tt.s, tt.sep[0], pos, tt.out) 216 } 217 } 218 } 219 220 func TestLastIndexByte(t *testing.T) { 221 testCases := []IndexTest{ 222 {"", "q", -1}, 223 {"abcdef", "q", -1}, 224 {"abcdefabcdef", "a", len("abcdef")}, // something in the middle 225 {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte 226 {"zabcdefabcdef", "z", 0}, // first byte 227 {"a☺b☻c☹d", "b", len("a☺")}, // non-ascii 228 } 229 for _, test := range testCases { 230 actual := LastIndexByte(test.s, test.sep[0]) 231 if actual != test.out { 232 t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out) 233 } 234 } 235 } 236 237 func simpleIndex(s, sep string) int { 238 n := len(sep) 239 for i := n; i <= len(s); i++ { 240 if s[i-n:i] == sep { 241 return i - n 242 } 243 } 244 return -1 245 } 246 247 func TestIndexRandom(t *testing.T) { 248 const chars = "abcdefghijklmnopqrstuvwxyz0123456789" 249 for times := 0; times < 10; times++ { 250 for strLen := 5 + rand.Intn(5); strLen < 140; strLen += 10 { // Arbitrary 251 s1 := make([]byte, strLen) 252 for i := range s1 { 253 s1[i] = chars[rand.Intn(len(chars))] 254 } 255 s := string(s1) 256 for i := 0; i < 50; i++ { 257 begin := rand.Intn(len(s) + 1) 258 end := begin + rand.Intn(len(s)+1-begin) 259 sep := s[begin:end] 260 if i%4 == 0 { 261 pos := rand.Intn(len(sep) + 1) 262 sep = sep[:pos] + "A" + sep[pos:] 263 } 264 want := simpleIndex(s, sep) 265 res := Index(s, sep) 266 if res != want { 267 t.Errorf("Index(%s,%s) = %d; want %d", s, sep, res, want) 268 } 269 } 270 } 271 } 272 } 273 274 func TestIndexRune(t *testing.T) { 275 tests := []struct { 276 in string 277 rune rune 278 want int 279 }{ 280 {"", 'a', -1}, 281 {"", '☺', -1}, 282 {"foo", '☹', -1}, 283 {"foo", 'o', 1}, 284 {"foo☺bar", '☺', 3}, 285 {"foo☺☻☹bar", '☹', 9}, 286 {"a A x", 'A', 2}, 287 {"some_text=some_value", '=', 9}, 288 {"☺a", 'a', 3}, 289 {"a☻☺b", '☺', 4}, 290 291 // RuneError should match any invalid UTF-8 byte sequence. 292 {"�", '�', 0}, 293 {"\xff", '�', 0}, 294 {"☻x�", '�', len("☻x")}, 295 {"☻x\xe2\x98", '�', len("☻x")}, 296 {"☻x\xe2\x98�", '�', len("☻x")}, 297 {"☻x\xe2\x98x", '�', len("☻x")}, 298 299 // Invalid rune values should never match. 300 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1}, 301 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair 302 {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1}, 303 } 304 for _, tt := range tests { 305 if got := IndexRune(tt.in, tt.rune); got != tt.want { 306 t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want) 307 } 308 } 309 310 haystack := "test世界" 311 allocs := testing.AllocsPerRun(1000, func() { 312 if i := IndexRune(haystack, 's'); i != 2 { 313 t.Fatalf("'s' at %d; want 2", i) 314 } 315 if i := IndexRune(haystack, '世'); i != 4 { 316 t.Fatalf("'世' at %d; want 4", i) 317 } 318 }) 319 if allocs != 0 && testing.CoverMode() == "" { 320 t.Errorf("expected no allocations, got %f", allocs) 321 } 322 } 323 324 const benchmarkString = "some_text=some☺value" 325 326 func BenchmarkIndexRune(b *testing.B) { 327 if got := IndexRune(benchmarkString, '☺'); got != 14 { 328 b.Fatalf("wrong index: expected 14, got=%d", got) 329 } 330 for i := 0; i < b.N; i++ { 331 IndexRune(benchmarkString, '☺') 332 } 333 } 334 335 var benchmarkLongString = Repeat(" ", 100) + benchmarkString 336 337 func BenchmarkIndexRuneLongString(b *testing.B) { 338 if got := IndexRune(benchmarkLongString, '☺'); got != 114 { 339 b.Fatalf("wrong index: expected 114, got=%d", got) 340 } 341 for i := 0; i < b.N; i++ { 342 IndexRune(benchmarkLongString, '☺') 343 } 344 } 345 346 func BenchmarkIndexRuneFastPath(b *testing.B) { 347 if got := IndexRune(benchmarkString, 'v'); got != 17 { 348 b.Fatalf("wrong index: expected 17, got=%d", got) 349 } 350 for i := 0; i < b.N; i++ { 351 IndexRune(benchmarkString, 'v') 352 } 353 } 354 355 func BenchmarkIndex(b *testing.B) { 356 if got := Index(benchmarkString, "v"); got != 17 { 357 b.Fatalf("wrong index: expected 17, got=%d", got) 358 } 359 for i := 0; i < b.N; i++ { 360 Index(benchmarkString, "v") 361 } 362 } 363 364 func BenchmarkLastIndex(b *testing.B) { 365 if got := Index(benchmarkString, "v"); got != 17 { 366 b.Fatalf("wrong index: expected 17, got=%d", got) 367 } 368 for i := 0; i < b.N; i++ { 369 LastIndex(benchmarkString, "v") 370 } 371 } 372 373 func BenchmarkIndexByte(b *testing.B) { 374 if got := IndexByte(benchmarkString, 'v'); got != 17 { 375 b.Fatalf("wrong index: expected 17, got=%d", got) 376 } 377 for i := 0; i < b.N; i++ { 378 IndexByte(benchmarkString, 'v') 379 } 380 } 381 382 type SplitTest struct { 383 s string 384 sep string 385 n int 386 a []string 387 } 388 389 var splittests = []SplitTest{ 390 {"", "", -1, []string{}}, 391 {abcd, "", 2, []string{"a", "bcd"}}, 392 {abcd, "", 4, []string{"a", "b", "c", "d"}}, 393 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 394 {faces, "", -1, []string{"☺", "☻", "☹"}}, 395 {faces, "", 3, []string{"☺", "☻", "☹"}}, 396 {faces, "", 17, []string{"☺", "☻", "☹"}}, 397 {"☺�☹", "", -1, []string{"☺", "�", "☹"}}, 398 {abcd, "a", 0, nil}, 399 {abcd, "a", -1, []string{"", "bcd"}}, 400 {abcd, "z", -1, []string{"abcd"}}, 401 {commas, ",", -1, []string{"1", "2", "3", "4"}}, 402 {dots, "...", -1, []string{"1", ".2", ".3", ".4"}}, 403 {faces, "☹", -1, []string{"☺☻", ""}}, 404 {faces, "~", -1, []string{faces}}, 405 {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}}, 406 {"1 2", " ", 3, []string{"1", "2"}}, 407 } 408 409 func TestSplit(t *testing.T) { 410 for _, tt := range splittests { 411 a := SplitN(tt.s, tt.sep, tt.n) 412 if !eq(a, tt.a) { 413 t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a) 414 continue 415 } 416 if tt.n == 0 { 417 continue 418 } 419 s := Join(a, tt.sep) 420 if s != tt.s { 421 t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s) 422 } 423 if tt.n < 0 { 424 b := Split(tt.s, tt.sep) 425 if !reflect.DeepEqual(a, b) { 426 t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 427 } 428 } 429 } 430 } 431 432 var splitaftertests = []SplitTest{ 433 {abcd, "a", -1, []string{"a", "bcd"}}, 434 {abcd, "z", -1, []string{"abcd"}}, 435 {abcd, "", -1, []string{"a", "b", "c", "d"}}, 436 {commas, ",", -1, []string{"1,", "2,", "3,", "4"}}, 437 {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}}, 438 {faces, "☹", -1, []string{"☺☻☹", ""}}, 439 {faces, "~", -1, []string{faces}}, 440 {faces, "", -1, []string{"☺", "☻", "☹"}}, 441 {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}}, 442 {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}}, 443 {"1 2", " ", 3, []string{"1 ", "2"}}, 444 {"123", "", 2, []string{"1", "23"}}, 445 {"123", "", 17, []string{"1", "2", "3"}}, 446 } 447 448 func TestSplitAfter(t *testing.T) { 449 for _, tt := range splitaftertests { 450 a := SplitAfterN(tt.s, tt.sep, tt.n) 451 if !eq(a, tt.a) { 452 t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a) 453 continue 454 } 455 s := Join(a, "") 456 if s != tt.s { 457 t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) 458 } 459 if tt.n < 0 { 460 b := SplitAfter(tt.s, tt.sep) 461 if !reflect.DeepEqual(a, b) { 462 t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) 463 } 464 } 465 } 466 } 467 468 type FieldsTest struct { 469 s string 470 a []string 471 } 472 473 var fieldstests = []FieldsTest{ 474 {"", []string{}}, 475 {" ", []string{}}, 476 {" \t ", []string{}}, 477 {"\u2000", []string{}}, 478 {" abc ", []string{"abc"}}, 479 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 480 {"1 2 3 4", []string{"1", "2", "3", "4"}}, 481 {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}}, 482 {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}}, 483 {"\u2000\u2001\u2002", []string{}}, 484 {"\n™\t™\n", []string{"™", "™"}}, 485 {"\n\u20001™2\u2000 \u2001 ™", []string{"1™2", "™"}}, 486 {"\n1\uFFFD \uFFFD2\u20003\uFFFD4", []string{"1\uFFFD", "\uFFFD2", "3\uFFFD4"}}, 487 {"1\xFF\u2000\xFF2\xFF \xFF", []string{"1\xFF", "\xFF2\xFF", "\xFF"}}, 488 {faces, []string{faces}}, 489 } 490 491 func TestFields(t *testing.T) { 492 for _, tt := range fieldstests { 493 a := Fields(tt.s) 494 if !eq(a, tt.a) { 495 t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) 496 continue 497 } 498 } 499 } 500 501 var FieldsFuncTests = []FieldsTest{ 502 {"", []string{}}, 503 {"XX", []string{}}, 504 {"XXhiXXX", []string{"hi"}}, 505 {"aXXbXXXcX", []string{"a", "b", "c"}}, 506 } 507 508 func TestFieldsFunc(t *testing.T) { 509 for _, tt := range fieldstests { 510 a := FieldsFunc(tt.s, unicode.IsSpace) 511 if !eq(a, tt.a) { 512 t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a) 513 continue 514 } 515 } 516 pred := func(c rune) bool { return c == 'X' } 517 for _, tt := range FieldsFuncTests { 518 a := FieldsFunc(tt.s, pred) 519 if !eq(a, tt.a) { 520 t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) 521 } 522 } 523 } 524 525 // Test case for any function which accepts and returns a single string. 526 type StringTest struct { 527 in, out string 528 } 529 530 // Execute f on each test case. funcName should be the name of f; it's used 531 // in failure reports. 532 func runStringTests(t *testing.T, f func(string) string, funcName string, testCases []StringTest) { 533 for _, tc := range testCases { 534 actual := f(tc.in) 535 if actual != tc.out { 536 t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out) 537 } 538 } 539 } 540 541 var upperTests = []StringTest{ 542 {"", ""}, 543 {"ONLYUPPER", "ONLYUPPER"}, 544 {"abc", "ABC"}, 545 {"AbC123", "ABC123"}, 546 {"azAZ09_", "AZAZ09_"}, 547 {"longStrinGwitHmixofsmaLLandcAps", "LONGSTRINGWITHMIXOFSMALLANDCAPS"}, 548 {"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", "LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS"}, 549 {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char 550 {"a\u0080\U0010FFFF", "A\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune 551 } 552 553 var lowerTests = []StringTest{ 554 {"", ""}, 555 {"abc", "abc"}, 556 {"AbC123", "abc123"}, 557 {"azAZ09_", "azaz09_"}, 558 {"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"}, 559 {"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"}, 560 {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char 561 {"A\u0080\U0010FFFF", "a\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune 562 } 563 564 const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000" 565 566 var trimSpaceTests = []StringTest{ 567 {"", ""}, 568 {"abc", "abc"}, 569 {space + "abc" + space, "abc"}, 570 {" ", ""}, 571 {" \t\r\n \t\t\r\r\n\n ", ""}, 572 {" \t\r\n x\t\t\r\r\n\n ", "x"}, 573 {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"}, 574 {"1 \t\r\n2", "1 \t\r\n2"}, 575 {" x\x80", "x\x80"}, 576 {" x\xc0", "x\xc0"}, 577 {"x \xc0\xc0 ", "x \xc0\xc0"}, 578 {"x \xc0", "x \xc0"}, 579 {"x \xc0 ", "x \xc0"}, 580 {"x \xc0\xc0 ", "x \xc0\xc0"}, 581 {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"}, 582 {"x ☺ ", "x ☺"}, 583 } 584 585 func tenRunes(ch rune) string { 586 r := make([]rune, 10) 587 for i := range r { 588 r[i] = ch 589 } 590 return string(r) 591 } 592 593 // User-defined self-inverse mapping function 594 func rot13(r rune) rune { 595 step := rune(13) 596 if r >= 'a' && r <= 'z' { 597 return ((r - 'a' + step) % 26) + 'a' 598 } 599 if r >= 'A' && r <= 'Z' { 600 return ((r - 'A' + step) % 26) + 'A' 601 } 602 return r 603 } 604 605 func TestMap(t *testing.T) { 606 // Run a couple of awful growth/shrinkage tests 607 a := tenRunes('a') 608 // 1. Grow. This triggers two reallocations in Map. 609 maxRune := func(rune) rune { return unicode.MaxRune } 610 m := Map(maxRune, a) 611 expect := tenRunes(unicode.MaxRune) 612 if m != expect { 613 t.Errorf("growing: expected %q got %q", expect, m) 614 } 615 616 // 2. Shrink 617 minRune := func(rune) rune { return 'a' } 618 m = Map(minRune, tenRunes(unicode.MaxRune)) 619 expect = a 620 if m != expect { 621 t.Errorf("shrinking: expected %q got %q", expect, m) 622 } 623 624 // 3. Rot13 625 m = Map(rot13, "a to zed") 626 expect = "n gb mrq" 627 if m != expect { 628 t.Errorf("rot13: expected %q got %q", expect, m) 629 } 630 631 // 4. Rot13^2 632 m = Map(rot13, Map(rot13, "a to zed")) 633 expect = "a to zed" 634 if m != expect { 635 t.Errorf("rot13: expected %q got %q", expect, m) 636 } 637 638 // 5. Drop 639 dropNotLatin := func(r rune) rune { 640 if unicode.Is(unicode.Latin, r) { 641 return r 642 } 643 return -1 644 } 645 m = Map(dropNotLatin, "Hello, 세계") 646 expect = "Hello" 647 if m != expect { 648 t.Errorf("drop: expected %q got %q", expect, m) 649 } 650 651 // 6. Identity 652 identity := func(r rune) rune { 653 return r 654 } 655 orig := "Input string that we expect not to be copied." 656 m = Map(identity, orig) 657 if (*reflect.StringHeader)(unsafe.Pointer(&orig)).Data != 658 (*reflect.StringHeader)(unsafe.Pointer(&m)).Data { 659 t.Error("unexpected copy during identity map") 660 } 661 662 // 7. Handle invalid UTF-8 sequence 663 replaceNotLatin := func(r rune) rune { 664 if unicode.Is(unicode.Latin, r) { 665 return r 666 } 667 return utf8.RuneError 668 } 669 m = Map(replaceNotLatin, "Hello\255World") 670 expect = "Hello\uFFFDWorld" 671 if m != expect { 672 t.Errorf("replace invalid sequence: expected %q got %q", expect, m) 673 } 674 675 // 8. Check utf8.RuneSelf and utf8.MaxRune encoding 676 encode := func(r rune) rune { 677 switch r { 678 case utf8.RuneSelf: 679 return unicode.MaxRune 680 case unicode.MaxRune: 681 return utf8.RuneSelf 682 } 683 return r 684 } 685 s := string(rune(utf8.RuneSelf)) + string(utf8.MaxRune) 686 r := string(utf8.MaxRune) + string(rune(utf8.RuneSelf)) // reverse of s 687 m = Map(encode, s) 688 if m != r { 689 t.Errorf("encoding not handled correctly: expected %q got %q", r, m) 690 } 691 m = Map(encode, r) 692 if m != s { 693 t.Errorf("encoding not handled correctly: expected %q got %q", s, m) 694 } 695 696 // 9. Check mapping occurs in the front, middle and back 697 trimSpaces := func(r rune) rune { 698 if unicode.IsSpace(r) { 699 return -1 700 } 701 return r 702 } 703 m = Map(trimSpaces, " abc 123 ") 704 expect = "abc123" 705 if m != expect { 706 t.Errorf("trimSpaces: expected %q got %q", expect, m) 707 } 708 } 709 710 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } 711 712 func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } 713 714 var toValidUTF8Tests = []struct { 715 in string 716 repl string 717 out string 718 }{ 719 {"", "\uFFFD", ""}, 720 {"abc", "\uFFFD", "abc"}, 721 {"\uFDDD", "\uFFFD", "\uFDDD"}, 722 {"a\xffb", "\uFFFD", "a\uFFFDb"}, 723 {"a\xffb\uFFFD", "X", "aXb\uFFFD"}, 724 {"a☺\xffb☺\xC0\xAFc☺\xff", "", "a☺b☺c☺"}, 725 {"a☺\xffb☺\xC0\xAFc☺\xff", "日本語", "a☺日本語b☺日本語c☺日本語"}, 726 {"\xC0\xAF", "\uFFFD", "\uFFFD"}, 727 {"\xE0\x80\xAF", "\uFFFD", "\uFFFD"}, 728 {"\xed\xa0\x80", "abc", "abc"}, 729 {"\xed\xbf\xbf", "\uFFFD", "\uFFFD"}, 730 {"\xF0\x80\x80\xaf", "☺", "☺"}, 731 {"\xF8\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"}, 732 {"\xFC\x80\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"}, 733 } 734 735 func TestToValidUTF8(t *testing.T) { 736 for _, tc := range toValidUTF8Tests { 737 got := ToValidUTF8(tc.in, tc.repl) 738 if got != tc.out { 739 t.Errorf("ToValidUTF8(%q, %q) = %q; want %q", tc.in, tc.repl, got, tc.out) 740 } 741 } 742 } 743 744 func BenchmarkToUpper(b *testing.B) { 745 for _, tc := range upperTests { 746 b.Run(tc.in, func(b *testing.B) { 747 for i := 0; i < b.N; i++ { 748 actual := ToUpper(tc.in) 749 if actual != tc.out { 750 b.Errorf("ToUpper(%q) = %q; want %q", tc.in, actual, tc.out) 751 } 752 } 753 }) 754 } 755 } 756 757 func BenchmarkToLower(b *testing.B) { 758 for _, tc := range lowerTests { 759 b.Run(tc.in, func(b *testing.B) { 760 for i := 0; i < b.N; i++ { 761 actual := ToLower(tc.in) 762 if actual != tc.out { 763 b.Errorf("ToLower(%q) = %q; want %q", tc.in, actual, tc.out) 764 } 765 } 766 }) 767 } 768 } 769 770 func BenchmarkMapNoChanges(b *testing.B) { 771 identity := func(r rune) rune { 772 return r 773 } 774 for i := 0; i < b.N; i++ { 775 Map(identity, "Some string that won't be modified.") 776 } 777 } 778 779 func TestSpecialCase(t *testing.T) { 780 lower := "abcçdefgğhıijklmnoöprsştuüvyz" 781 upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ" 782 u := ToUpperSpecial(unicode.TurkishCase, upper) 783 if u != upper { 784 t.Errorf("Upper(upper) is %s not %s", u, upper) 785 } 786 u = ToUpperSpecial(unicode.TurkishCase, lower) 787 if u != upper { 788 t.Errorf("Upper(lower) is %s not %s", u, upper) 789 } 790 l := ToLowerSpecial(unicode.TurkishCase, lower) 791 if l != lower { 792 t.Errorf("Lower(lower) is %s not %s", l, lower) 793 } 794 l = ToLowerSpecial(unicode.TurkishCase, upper) 795 if l != lower { 796 t.Errorf("Lower(upper) is %s not %s", l, lower) 797 } 798 } 799 800 func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) } 801 802 var trimTests = []struct { 803 f string 804 in, arg, out string 805 }{ 806 {"Trim", "abba", "a", "bb"}, 807 {"Trim", "abba", "ab", ""}, 808 {"TrimLeft", "abba", "ab", ""}, 809 {"TrimRight", "abba", "ab", ""}, 810 {"TrimLeft", "abba", "a", "bba"}, 811 {"TrimLeft", "abba", "b", "abba"}, 812 {"TrimRight", "abba", "a", "abb"}, 813 {"TrimRight", "abba", "b", "abba"}, 814 {"Trim", "<tag>", "<>", "tag"}, 815 {"Trim", "* listitem", " *", "listitem"}, 816 {"Trim", `"quote"`, `"`, "quote"}, 817 {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"}, 818 {"Trim", "\x80test\xff", "\xff", "test"}, 819 {"Trim", " Ġ ", " ", "Ġ"}, 820 {"Trim", " Ġİ0", "0 ", "Ġİ"}, 821 //empty string tests 822 {"Trim", "abba", "", "abba"}, 823 {"Trim", "", "123", ""}, 824 {"Trim", "", "", ""}, 825 {"TrimLeft", "abba", "", "abba"}, 826 {"TrimLeft", "", "123", ""}, 827 {"TrimLeft", "", "", ""}, 828 {"TrimRight", "abba", "", "abba"}, 829 {"TrimRight", "", "123", ""}, 830 {"TrimRight", "", "", ""}, 831 {"TrimRight", "☺\xc0", "☺", "☺\xc0"}, 832 {"TrimPrefix", "aabb", "a", "abb"}, 833 {"TrimPrefix", "aabb", "b", "aabb"}, 834 {"TrimSuffix", "aabb", "a", "aabb"}, 835 {"TrimSuffix", "aabb", "b", "aab"}, 836 } 837 838 func TestTrim(t *testing.T) { 839 for _, tc := range trimTests { 840 name := tc.f 841 var f func(string, string) string 842 switch name { 843 case "Trim": 844 f = Trim 845 case "TrimLeft": 846 f = TrimLeft 847 case "TrimRight": 848 f = TrimRight 849 case "TrimPrefix": 850 f = TrimPrefix 851 case "TrimSuffix": 852 f = TrimSuffix 853 default: 854 t.Errorf("Undefined trim function %s", name) 855 } 856 actual := f(tc.in, tc.arg) 857 if actual != tc.out { 858 t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) 859 } 860 } 861 } 862 863 func BenchmarkTrim(b *testing.B) { 864 b.ReportAllocs() 865 866 for i := 0; i < b.N; i++ { 867 for _, tc := range trimTests { 868 name := tc.f 869 var f func(string, string) string 870 switch name { 871 case "Trim": 872 f = Trim 873 case "TrimLeft": 874 f = TrimLeft 875 case "TrimRight": 876 f = TrimRight 877 case "TrimPrefix": 878 f = TrimPrefix 879 case "TrimSuffix": 880 f = TrimSuffix 881 default: 882 b.Errorf("Undefined trim function %s", name) 883 } 884 actual := f(tc.in, tc.arg) 885 if actual != tc.out { 886 b.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) 887 } 888 } 889 } 890 } 891 892 func BenchmarkToValidUTF8(b *testing.B) { 893 tests := []struct { 894 name string 895 input string 896 }{ 897 {"Valid", "typical"}, 898 {"InvalidASCII", "foo\xffbar"}, 899 {"InvalidNonASCII", "日本語\xff日本語"}, 900 } 901 replacement := "\uFFFD" 902 b.ResetTimer() 903 for _, test := range tests { 904 b.Run(test.name, func(b *testing.B) { 905 for i := 0; i < b.N; i++ { 906 ToValidUTF8(test.input, replacement) 907 } 908 }) 909 } 910 } 911 912 type predicate struct { 913 f func(rune) bool 914 name string 915 } 916 917 var isSpace = predicate{unicode.IsSpace, "IsSpace"} 918 var isDigit = predicate{unicode.IsDigit, "IsDigit"} 919 var isUpper = predicate{unicode.IsUpper, "IsUpper"} 920 var isValidRune = predicate{ 921 func(r rune) bool { 922 return r != utf8.RuneError 923 }, 924 "IsValidRune", 925 } 926 927 func not(p predicate) predicate { 928 return predicate{ 929 func(r rune) bool { 930 return !p.f(r) 931 }, 932 "not " + p.name, 933 } 934 } 935 936 var trimFuncTests = []struct { 937 f predicate 938 in string 939 trimOut string 940 leftOut string 941 rightOut string 942 }{ 943 {isSpace, space + " hello " + space, 944 "hello", 945 "hello " + space, 946 space + " hello"}, 947 {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", 948 "hello", 949 "hello34\u0e50\u0e51", 950 "\u0e50\u0e5212hello"}, 951 {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", 952 "hello", 953 "helloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", 954 "\u2C6F\u2C6F\u2C6F\u2C6FABCDhello"}, 955 {not(isSpace), "hello" + space + "hello", 956 space, 957 space + "hello", 958 "hello" + space}, 959 {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", 960 "\u0e50\u0e521234\u0e50\u0e51", 961 "\u0e50\u0e521234\u0e50\u0e51helo", 962 "hello\u0e50\u0e521234\u0e50\u0e51"}, 963 {isValidRune, "ab\xc0a\xc0cd", 964 "\xc0a\xc0", 965 "\xc0a\xc0cd", 966 "ab\xc0a\xc0"}, 967 {not(isValidRune), "\xc0a\xc0", 968 "a", 969 "a\xc0", 970 "\xc0a"}, 971 {isSpace, "", 972 "", 973 "", 974 ""}, 975 {isSpace, " ", 976 "", 977 "", 978 ""}, 979 } 980 981 func TestTrimFunc(t *testing.T) { 982 for _, tc := range trimFuncTests { 983 trimmers := []struct { 984 name string 985 trim func(s string, f func(r rune) bool) string 986 out string 987 }{ 988 {"TrimFunc", TrimFunc, tc.trimOut}, 989 {"TrimLeftFunc", TrimLeftFunc, tc.leftOut}, 990 {"TrimRightFunc", TrimRightFunc, tc.rightOut}, 991 } 992 for _, trimmer := range trimmers { 993 actual := trimmer.trim(tc.in, tc.f.f) 994 if actual != trimmer.out { 995 t.Errorf("%s(%q, %q) = %q; want %q", trimmer.name, tc.in, tc.f.name, actual, trimmer.out) 996 } 997 } 998 } 999 } 1000 1001 var indexFuncTests = []struct { 1002 in string 1003 f predicate 1004 first, last int 1005 }{ 1006 {"", isValidRune, -1, -1}, 1007 {"abc", isDigit, -1, -1}, 1008 {"0123", isDigit, 0, 3}, 1009 {"a1b", isDigit, 1, 1}, 1010 {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes 1011 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18}, 1012 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34}, 1013 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12}, 1014 1015 // tests of invalid UTF-8 1016 {"\x801", isDigit, 1, 1}, 1017 {"\x80abc", isDigit, -1, -1}, 1018 {"\xc0a\xc0", isValidRune, 1, 1}, 1019 {"\xc0a\xc0", not(isValidRune), 0, 2}, 1020 {"\xc0☺\xc0", not(isValidRune), 0, 4}, 1021 {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5}, 1022 {"ab\xc0a\xc0cd", not(isValidRune), 2, 4}, 1023 {"a\xe0\x80cd", not(isValidRune), 1, 2}, 1024 {"\x80\x80\x80\x80", not(isValidRune), 0, 3}, 1025 } 1026 1027 func TestIndexFunc(t *testing.T) { 1028 for _, tc := range indexFuncTests { 1029 first := IndexFunc(tc.in, tc.f.f) 1030 if first != tc.first { 1031 t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first) 1032 } 1033 last := LastIndexFunc(tc.in, tc.f.f) 1034 if last != tc.last { 1035 t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last) 1036 } 1037 } 1038 } 1039 1040 func equal(m string, s1, s2 string, t *testing.T) bool { 1041 if s1 == s2 { 1042 return true 1043 } 1044 e1 := Split(s1, "") 1045 e2 := Split(s2, "") 1046 for i, c1 := range e1 { 1047 if i >= len(e2) { 1048 break 1049 } 1050 r1, _ := utf8.DecodeRuneInString(c1) 1051 r2, _ := utf8.DecodeRuneInString(e2[i]) 1052 if r1 != r2 { 1053 t.Errorf("%s diff at %d: U+%04X U+%04X", m, i, r1, r2) 1054 } 1055 } 1056 return false 1057 } 1058 1059 func TestCaseConsistency(t *testing.T) { 1060 // Make a string of all the runes. 1061 numRunes := int(unicode.MaxRune + 1) 1062 if testing.Short() { 1063 numRunes = 1000 1064 } 1065 a := make([]rune, numRunes) 1066 for i := range a { 1067 a[i] = rune(i) 1068 } 1069 s := string(a) 1070 // convert the cases. 1071 upper := ToUpper(s) 1072 lower := ToLower(s) 1073 1074 // Consistency checks 1075 if n := utf8.RuneCountInString(upper); n != numRunes { 1076 t.Error("rune count wrong in upper:", n) 1077 } 1078 if n := utf8.RuneCountInString(lower); n != numRunes { 1079 t.Error("rune count wrong in lower:", n) 1080 } 1081 if !equal("ToUpper(upper)", ToUpper(upper), upper, t) { 1082 t.Error("ToUpper(upper) consistency fail") 1083 } 1084 if !equal("ToLower(lower)", ToLower(lower), lower, t) { 1085 t.Error("ToLower(lower) consistency fail") 1086 } 1087 /* 1088 These fail because of non-one-to-oneness of the data, such as multiple 1089 upper case 'I' mapping to 'i'. We comment them out but keep them for 1090 interest. 1091 For instance: CAPITAL LETTER I WITH DOT ABOVE: 1092 unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130' 1093 1094 if !equal("ToUpper(lower)", ToUpper(lower), upper, t) { 1095 t.Error("ToUpper(lower) consistency fail"); 1096 } 1097 if !equal("ToLower(upper)", ToLower(upper), lower, t) { 1098 t.Error("ToLower(upper) consistency fail"); 1099 } 1100 */ 1101 } 1102 1103 var RepeatTests = []struct { 1104 in, out string 1105 count int 1106 }{ 1107 {"", "", 0}, 1108 {"", "", 1}, 1109 {"", "", 2}, 1110 {"-", "", 0}, 1111 {"-", "-", 1}, 1112 {"-", "----------", 10}, 1113 {"abc ", "abc abc abc ", 3}, 1114 } 1115 1116 func TestRepeat(t *testing.T) { 1117 for _, tt := range RepeatTests { 1118 a := Repeat(tt.in, tt.count) 1119 if !equal("Repeat(s)", a, tt.out, t) { 1120 t.Errorf("Repeat(%v, %d) = %v; want %v", tt.in, tt.count, a, tt.out) 1121 continue 1122 } 1123 } 1124 } 1125 1126 func repeat(s string, count int) (err error) { 1127 defer func() { 1128 if r := recover(); r != nil { 1129 switch v := r.(type) { 1130 case error: 1131 err = v 1132 default: 1133 err = fmt.Errorf("%s", v) 1134 } 1135 } 1136 }() 1137 1138 Repeat(s, count) 1139 1140 return 1141 } 1142 1143 // See Issue golang.org/issue/16237 1144 func TestRepeatCatchesOverflow(t *testing.T) { 1145 tests := [...]struct { 1146 s string 1147 count int 1148 errStr string 1149 }{ 1150 0: {"--", -2147483647, "negative"}, 1151 1: {"", int(^uint(0) >> 1), ""}, 1152 2: {"-", 10, ""}, 1153 3: {"gopher", 0, ""}, 1154 4: {"-", -1, "negative"}, 1155 5: {"--", -102, "negative"}, 1156 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"}, 1157 } 1158 1159 for i, tt := range tests { 1160 err := repeat(tt.s, tt.count) 1161 if tt.errStr == "" { 1162 if err != nil { 1163 t.Errorf("#%d panicked %v", i, err) 1164 } 1165 continue 1166 } 1167 1168 if err == nil || !Contains(err.Error(), tt.errStr) { 1169 t.Errorf("#%d expected %q got %q", i, tt.errStr, err) 1170 } 1171 } 1172 } 1173 1174 func runesEqual(a, b []rune) bool { 1175 if len(a) != len(b) { 1176 return false 1177 } 1178 for i, r := range a { 1179 if r != b[i] { 1180 return false 1181 } 1182 } 1183 return true 1184 } 1185 1186 var RunesTests = []struct { 1187 in string 1188 out []rune 1189 lossy bool 1190 }{ 1191 {"", []rune{}, false}, 1192 {" ", []rune{32}, false}, 1193 {"ABC", []rune{65, 66, 67}, false}, 1194 {"abc", []rune{97, 98, 99}, false}, 1195 {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false}, 1196 {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true}, 1197 {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true}, 1198 } 1199 1200 func TestRunes(t *testing.T) { 1201 for _, tt := range RunesTests { 1202 a := []rune(tt.in) 1203 if !runesEqual(a, tt.out) { 1204 t.Errorf("[]rune(%q) = %v; want %v", tt.in, a, tt.out) 1205 continue 1206 } 1207 if !tt.lossy { 1208 // can only test reassembly if we didn't lose information 1209 s := string(a) 1210 if s != tt.in { 1211 t.Errorf("string([]rune(%q)) = %x; want %x", tt.in, s, tt.in) 1212 } 1213 } 1214 } 1215 } 1216 1217 func TestReadByte(t *testing.T) { 1218 testStrings := []string{"", abcd, faces, commas} 1219 for _, s := range testStrings { 1220 reader := NewReader(s) 1221 if e := reader.UnreadByte(); e == nil { 1222 t.Errorf("Unreading %q at beginning: expected error", s) 1223 } 1224 var res bytes.Buffer 1225 for { 1226 b, e := reader.ReadByte() 1227 if e == io.EOF { 1228 break 1229 } 1230 if e != nil { 1231 t.Errorf("Reading %q: %s", s, e) 1232 break 1233 } 1234 res.WriteByte(b) 1235 // unread and read again 1236 e = reader.UnreadByte() 1237 if e != nil { 1238 t.Errorf("Unreading %q: %s", s, e) 1239 break 1240 } 1241 b1, e := reader.ReadByte() 1242 if e != nil { 1243 t.Errorf("Reading %q after unreading: %s", s, e) 1244 break 1245 } 1246 if b1 != b { 1247 t.Errorf("Reading %q after unreading: want byte %q, got %q", s, b, b1) 1248 break 1249 } 1250 } 1251 if res.String() != s { 1252 t.Errorf("Reader(%q).ReadByte() produced %q", s, res.String()) 1253 } 1254 } 1255 } 1256 1257 func TestReadRune(t *testing.T) { 1258 testStrings := []string{"", abcd, faces, commas} 1259 for _, s := range testStrings { 1260 reader := NewReader(s) 1261 if e := reader.UnreadRune(); e == nil { 1262 t.Errorf("Unreading %q at beginning: expected error", s) 1263 } 1264 res := "" 1265 for { 1266 r, z, e := reader.ReadRune() 1267 if e == io.EOF { 1268 break 1269 } 1270 if e != nil { 1271 t.Errorf("Reading %q: %s", s, e) 1272 break 1273 } 1274 res += string(r) 1275 // unread and read again 1276 e = reader.UnreadRune() 1277 if e != nil { 1278 t.Errorf("Unreading %q: %s", s, e) 1279 break 1280 } 1281 r1, z1, e := reader.ReadRune() 1282 if e != nil { 1283 t.Errorf("Reading %q after unreading: %s", s, e) 1284 break 1285 } 1286 if r1 != r { 1287 t.Errorf("Reading %q after unreading: want rune %q, got %q", s, r, r1) 1288 break 1289 } 1290 if z1 != z { 1291 t.Errorf("Reading %q after unreading: want size %d, got %d", s, z, z1) 1292 break 1293 } 1294 } 1295 if res != s { 1296 t.Errorf("Reader(%q).ReadRune() produced %q", s, res) 1297 } 1298 } 1299 } 1300 1301 var UnreadRuneErrorTests = []struct { 1302 name string 1303 f func(*Reader) 1304 }{ 1305 {"Read", func(r *Reader) { r.Read([]byte{0}) }}, 1306 {"ReadByte", func(r *Reader) { r.ReadByte() }}, 1307 {"UnreadRune", func(r *Reader) { r.UnreadRune() }}, 1308 {"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }}, 1309 {"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }}, 1310 } 1311 1312 func TestUnreadRuneError(t *testing.T) { 1313 for _, tt := range UnreadRuneErrorTests { 1314 reader := NewReader("0123456789") 1315 if _, _, err := reader.ReadRune(); err != nil { 1316 // should not happen 1317 t.Fatal(err) 1318 } 1319 tt.f(reader) 1320 err := reader.UnreadRune() 1321 if err == nil { 1322 t.Errorf("Unreading after %s: expected error", tt.name) 1323 } 1324 } 1325 } 1326 1327 var ReplaceTests = []struct { 1328 in string 1329 old, new string 1330 n int 1331 out string 1332 }{ 1333 {"hello", "l", "L", 0, "hello"}, 1334 {"hello", "l", "L", -1, "heLLo"}, 1335 {"hello", "x", "X", -1, "hello"}, 1336 {"", "x", "X", -1, ""}, 1337 {"radar", "r", "<r>", -1, "<r>ada<r>"}, 1338 {"", "", "<>", -1, "<>"}, 1339 {"banana", "a", "<>", -1, "b<>n<>n<>"}, 1340 {"banana", "a", "<>", 1, "b<>nana"}, 1341 {"banana", "a", "<>", 1000, "b<>n<>n<>"}, 1342 {"banana", "an", "<>", -1, "b<><>a"}, 1343 {"banana", "ana", "<>", -1, "b<>na"}, 1344 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"}, 1345 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"}, 1346 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"}, 1347 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"}, 1348 {"banana", "", "<>", 1, "<>banana"}, 1349 {"banana", "a", "a", -1, "banana"}, 1350 {"banana", "a", "a", 1, "banana"}, 1351 {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"}, 1352 } 1353 1354 func TestReplace(t *testing.T) { 1355 for _, tt := range ReplaceTests { 1356 if s := Replace(tt.in, tt.old, tt.new, tt.n); s != tt.out { 1357 t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out) 1358 } 1359 if tt.n == -1 { 1360 s := ReplaceAll(tt.in, tt.old, tt.new) 1361 if s != tt.out { 1362 t.Errorf("ReplaceAll(%q, %q, %q) = %q, want %q", tt.in, tt.old, tt.new, s, tt.out) 1363 } 1364 } 1365 } 1366 } 1367 1368 var TitleTests = []struct { 1369 in, out string 1370 }{ 1371 {"", ""}, 1372 {"a", "A"}, 1373 {" aaa aaa aaa ", " Aaa Aaa Aaa "}, 1374 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "}, 1375 {"123a456", "123a456"}, 1376 {"double-blind", "Double-Blind"}, 1377 {"ÿøû", "Ÿøû"}, 1378 {"with_underscore", "With_underscore"}, 1379 {"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"}, 1380 } 1381 1382 func TestTitle(t *testing.T) { 1383 for _, tt := range TitleTests { 1384 if s := Title(tt.in); s != tt.out { 1385 t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out) 1386 } 1387 } 1388 } 1389 1390 var ContainsTests = []struct { 1391 str, substr string 1392 expected bool 1393 }{ 1394 {"abc", "bc", true}, 1395 {"abc", "bcd", false}, 1396 {"abc", "", true}, 1397 {"", "a", false}, 1398 1399 // cases to cover code in runtime/asm_amd64.s:indexShortStr 1400 // 2-byte needle 1401 {"xxxxxx", "01", false}, 1402 {"01xxxx", "01", true}, 1403 {"xx01xx", "01", true}, 1404 {"xxxx01", "01", true}, 1405 {"01xxxxx"[1:], "01", false}, 1406 {"xxxxx01"[:6], "01", false}, 1407 // 3-byte needle 1408 {"xxxxxxx", "012", false}, 1409 {"012xxxx", "012", true}, 1410 {"xx012xx", "012", true}, 1411 {"xxxx012", "012", true}, 1412 {"012xxxxx"[1:], "012", false}, 1413 {"xxxxx012"[:7], "012", false}, 1414 // 4-byte needle 1415 {"xxxxxxxx", "0123", false}, 1416 {"0123xxxx", "0123", true}, 1417 {"xx0123xx", "0123", true}, 1418 {"xxxx0123", "0123", true}, 1419 {"0123xxxxx"[1:], "0123", false}, 1420 {"xxxxx0123"[:8], "0123", false}, 1421 // 5-7-byte needle 1422 {"xxxxxxxxx", "01234", false}, 1423 {"01234xxxx", "01234", true}, 1424 {"xx01234xx", "01234", true}, 1425 {"xxxx01234", "01234", true}, 1426 {"01234xxxxx"[1:], "01234", false}, 1427 {"xxxxx01234"[:9], "01234", false}, 1428 // 8-byte needle 1429 {"xxxxxxxxxxxx", "01234567", false}, 1430 {"01234567xxxx", "01234567", true}, 1431 {"xx01234567xx", "01234567", true}, 1432 {"xxxx01234567", "01234567", true}, 1433 {"01234567xxxxx"[1:], "01234567", false}, 1434 {"xxxxx01234567"[:12], "01234567", false}, 1435 // 9-15-byte needle 1436 {"xxxxxxxxxxxxx", "012345678", false}, 1437 {"012345678xxxx", "012345678", true}, 1438 {"xx012345678xx", "012345678", true}, 1439 {"xxxx012345678", "012345678", true}, 1440 {"012345678xxxxx"[1:], "012345678", false}, 1441 {"xxxxx012345678"[:13], "012345678", false}, 1442 // 16-byte needle 1443 {"xxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEF", false}, 1444 {"0123456789ABCDEFxxxx", "0123456789ABCDEF", true}, 1445 {"xx0123456789ABCDEFxx", "0123456789ABCDEF", true}, 1446 {"xxxx0123456789ABCDEF", "0123456789ABCDEF", true}, 1447 {"0123456789ABCDEFxxxxx"[1:], "0123456789ABCDEF", false}, 1448 {"xxxxx0123456789ABCDEF"[:20], "0123456789ABCDEF", false}, 1449 // 17-31-byte needle 1450 {"xxxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEFG", false}, 1451 {"0123456789ABCDEFGxxxx", "0123456789ABCDEFG", true}, 1452 {"xx0123456789ABCDEFGxx", "0123456789ABCDEFG", true}, 1453 {"xxxx0123456789ABCDEFG", "0123456789ABCDEFG", true}, 1454 {"0123456789ABCDEFGxxxxx"[1:], "0123456789ABCDEFG", false}, 1455 {"xxxxx0123456789ABCDEFG"[:21], "0123456789ABCDEFG", false}, 1456 1457 // partial match cases 1458 {"xx01x", "012", false}, // 3 1459 {"xx0123x", "01234", false}, // 5-7 1460 {"xx01234567x", "012345678", false}, // 9-15 1461 {"xx0123456789ABCDEFx", "0123456789ABCDEFG", false}, // 17-31, issue 15679 1462 } 1463 1464 func TestContains(t *testing.T) { 1465 for _, ct := range ContainsTests { 1466 if Contains(ct.str, ct.substr) != ct.expected { 1467 t.Errorf("Contains(%s, %s) = %v, want %v", 1468 ct.str, ct.substr, !ct.expected, ct.expected) 1469 } 1470 } 1471 } 1472 1473 var ContainsAnyTests = []struct { 1474 str, substr string 1475 expected bool 1476 }{ 1477 {"", "", false}, 1478 {"", "a", false}, 1479 {"", "abc", false}, 1480 {"a", "", false}, 1481 {"a", "a", true}, 1482 {"aaa", "a", true}, 1483 {"abc", "xyz", false}, 1484 {"abc", "xcz", true}, 1485 {"a☺b☻c☹d", "uvw☻xyz", true}, 1486 {"aRegExp*", ".(|)*+?^$[]", true}, 1487 {dots + dots + dots, " ", false}, 1488 } 1489 1490 func TestContainsAny(t *testing.T) { 1491 for _, ct := range ContainsAnyTests { 1492 if ContainsAny(ct.str, ct.substr) != ct.expected { 1493 t.Errorf("ContainsAny(%s, %s) = %v, want %v", 1494 ct.str, ct.substr, !ct.expected, ct.expected) 1495 } 1496 } 1497 } 1498 1499 var ContainsRuneTests = []struct { 1500 str string 1501 r rune 1502 expected bool 1503 }{ 1504 {"", 'a', false}, 1505 {"a", 'a', true}, 1506 {"aaa", 'a', true}, 1507 {"abc", 'y', false}, 1508 {"abc", 'c', true}, 1509 {"a☺b☻c☹d", 'x', false}, 1510 {"a☺b☻c☹d", '☻', true}, 1511 {"aRegExp*", '*', true}, 1512 } 1513 1514 func TestContainsRune(t *testing.T) { 1515 for _, ct := range ContainsRuneTests { 1516 if ContainsRune(ct.str, ct.r) != ct.expected { 1517 t.Errorf("ContainsRune(%q, %q) = %v, want %v", 1518 ct.str, ct.r, !ct.expected, ct.expected) 1519 } 1520 } 1521 } 1522 1523 var EqualFoldTests = []struct { 1524 s, t string 1525 out bool 1526 }{ 1527 {"abc", "abc", true}, 1528 {"ABcd", "ABcd", true}, 1529 {"123abc", "123ABC", true}, 1530 {"αβδ", "ΑΒΔ", true}, 1531 {"abc", "xyz", false}, 1532 {"abc", "XYZ", false}, 1533 {"abcdefghijk", "abcdefghijX", false}, 1534 {"abcdefghijk", "abcdefghij\u212A", true}, 1535 {"abcdefghijK", "abcdefghij\u212A", true}, 1536 {"abcdefghijkz", "abcdefghij\u212Ay", false}, 1537 {"abcdefghijKz", "abcdefghij\u212Ay", false}, 1538 {"1", "2", false}, 1539 {"utf-8", "US-ASCII", false}, 1540 } 1541 1542 func TestEqualFold(t *testing.T) { 1543 for _, tt := range EqualFoldTests { 1544 if out := EqualFold(tt.s, tt.t); out != tt.out { 1545 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out) 1546 } 1547 if out := EqualFold(tt.t, tt.s); out != tt.out { 1548 t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out) 1549 } 1550 } 1551 } 1552 1553 func BenchmarkEqualFold(b *testing.B) { 1554 for i := 0; i < b.N; i++ { 1555 for _, tt := range EqualFoldTests { 1556 if out := EqualFold(tt.s, tt.t); out != tt.out { 1557 b.Fatal("wrong result") 1558 } 1559 } 1560 } 1561 } 1562 1563 var CountTests = []struct { 1564 s, sep string 1565 num int 1566 }{ 1567 {"", "", 1}, 1568 {"", "notempty", 0}, 1569 {"notempty", "", 9}, 1570 {"smaller", "not smaller", 0}, 1571 {"12345678987654321", "6", 2}, 1572 {"611161116", "6", 3}, 1573 {"notequal", "NotEqual", 0}, 1574 {"equal", "equal", 1}, 1575 {"abc1231231123q", "123", 3}, 1576 {"11111", "11", 2}, 1577 } 1578 1579 func TestCount(t *testing.T) { 1580 for _, tt := range CountTests { 1581 if num := Count(tt.s, tt.sep); num != tt.num { 1582 t.Errorf("Count(%q, %q) = %d, want %d", tt.s, tt.sep, num, tt.num) 1583 } 1584 } 1585 } 1586 1587 var cutTests = []struct { 1588 s, sep string 1589 before, after string 1590 found bool 1591 }{ 1592 {"abc", "b", "a", "c", true}, 1593 {"abc", "a", "", "bc", true}, 1594 {"abc", "c", "ab", "", true}, 1595 {"abc", "abc", "", "", true}, 1596 {"abc", "", "", "abc", true}, 1597 {"abc", "d", "abc", "", false}, 1598 {"", "d", "", "", false}, 1599 {"", "", "", "", true}, 1600 } 1601 1602 func TestCut(t *testing.T) { 1603 for _, tt := range cutTests { 1604 if before, after, found := Cut(tt.s, tt.sep); before != tt.before || after != tt.after || found != tt.found { 1605 t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found) 1606 } 1607 } 1608 } 1609 1610 func makeBenchInputHard() string { 1611 tokens := [...]string{ 1612 "<a>", "<p>", "<b>", "<strong>", 1613 "</a>", "</p>", "</b>", "</strong>", 1614 "hello", "world", 1615 } 1616 x := make([]byte, 0, 1<<20) 1617 for { 1618 i := rand.Intn(len(tokens)) 1619 if len(x)+len(tokens[i]) >= 1<<20 { 1620 break 1621 } 1622 x = append(x, tokens[i]...) 1623 } 1624 return string(x) 1625 } 1626 1627 var benchInputHard = makeBenchInputHard() 1628 1629 func benchmarkIndexHard(b *testing.B, sep string) { 1630 for i := 0; i < b.N; i++ { 1631 Index(benchInputHard, sep) 1632 } 1633 } 1634 1635 func benchmarkLastIndexHard(b *testing.B, sep string) { 1636 for i := 0; i < b.N; i++ { 1637 LastIndex(benchInputHard, sep) 1638 } 1639 } 1640 1641 func benchmarkCountHard(b *testing.B, sep string) { 1642 for i := 0; i < b.N; i++ { 1643 Count(benchInputHard, sep) 1644 } 1645 } 1646 1647 func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, "<>") } 1648 func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, "</pre>") } 1649 func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, "<b>hello world</b>") } 1650 func BenchmarkIndexHard4(b *testing.B) { 1651 benchmarkIndexHard(b, "<pre><b>hello</b><strong>world</strong></pre>") 1652 } 1653 1654 func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, "<>") } 1655 func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, "</pre>") } 1656 func BenchmarkLastIndexHard3(b *testing.B) { benchmarkLastIndexHard(b, "<b>hello world</b>") } 1657 1658 func BenchmarkCountHard1(b *testing.B) { benchmarkCountHard(b, "<>") } 1659 func BenchmarkCountHard2(b *testing.B) { benchmarkCountHard(b, "</pre>") } 1660 func BenchmarkCountHard3(b *testing.B) { benchmarkCountHard(b, "<b>hello world</b>") } 1661 1662 var benchInputTorture = Repeat("ABC", 1<<10) + "123" + Repeat("ABC", 1<<10) 1663 var benchNeedleTorture = Repeat("ABC", 1<<10+1) 1664 1665 func BenchmarkIndexTorture(b *testing.B) { 1666 for i := 0; i < b.N; i++ { 1667 Index(benchInputTorture, benchNeedleTorture) 1668 } 1669 } 1670 1671 func BenchmarkCountTorture(b *testing.B) { 1672 for i := 0; i < b.N; i++ { 1673 Count(benchInputTorture, benchNeedleTorture) 1674 } 1675 } 1676 1677 func BenchmarkCountTortureOverlapping(b *testing.B) { 1678 A := Repeat("ABC", 1<<20) 1679 B := Repeat("ABC", 1<<10) 1680 for i := 0; i < b.N; i++ { 1681 Count(A, B) 1682 } 1683 } 1684 1685 func BenchmarkCountByte(b *testing.B) { 1686 indexSizes := []int{10, 32, 4 << 10, 4 << 20, 64 << 20} 1687 benchStr := Repeat(benchmarkString, 1688 (indexSizes[len(indexSizes)-1]+len(benchmarkString)-1)/len(benchmarkString)) 1689 benchFunc := func(b *testing.B, benchStr string) { 1690 b.SetBytes(int64(len(benchStr))) 1691 for i := 0; i < b.N; i++ { 1692 Count(benchStr, "=") 1693 } 1694 } 1695 for _, size := range indexSizes { 1696 b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { 1697 benchFunc(b, benchStr[:size]) 1698 }) 1699 } 1700 1701 } 1702 1703 var makeFieldsInput = func() string { 1704 x := make([]byte, 1<<20) 1705 // Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space. 1706 for i := range x { 1707 switch rand.Intn(10) { 1708 case 0: 1709 x[i] = ' ' 1710 case 1: 1711 if i > 0 && x[i-1] == 'x' { 1712 copy(x[i-1:], "χ") 1713 break 1714 } 1715 fallthrough 1716 default: 1717 x[i] = 'x' 1718 } 1719 } 1720 return string(x) 1721 } 1722 1723 var makeFieldsInputASCII = func() string { 1724 x := make([]byte, 1<<20) 1725 // Input is ~10% space, rest ASCII non-space. 1726 for i := range x { 1727 if rand.Intn(10) == 0 { 1728 x[i] = ' ' 1729 } else { 1730 x[i] = 'x' 1731 } 1732 } 1733 return string(x) 1734 } 1735 1736 var stringdata = []struct{ name, data string }{ 1737 {"ASCII", makeFieldsInputASCII()}, 1738 {"Mixed", makeFieldsInput()}, 1739 } 1740 1741 func BenchmarkFields(b *testing.B) { 1742 for _, sd := range stringdata { 1743 b.Run(sd.name, func(b *testing.B) { 1744 for j := 1 << 4; j <= 1<<20; j <<= 4 { 1745 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) { 1746 b.ReportAllocs() 1747 b.SetBytes(int64(j)) 1748 data := sd.data[:j] 1749 for i := 0; i < b.N; i++ { 1750 Fields(data) 1751 } 1752 }) 1753 } 1754 }) 1755 } 1756 } 1757 1758 func BenchmarkFieldsFunc(b *testing.B) { 1759 for _, sd := range stringdata { 1760 b.Run(sd.name, func(b *testing.B) { 1761 for j := 1 << 4; j <= 1<<20; j <<= 4 { 1762 b.Run(fmt.Sprintf("%d", j), func(b *testing.B) { 1763 b.ReportAllocs() 1764 b.SetBytes(int64(j)) 1765 data := sd.data[:j] 1766 for i := 0; i < b.N; i++ { 1767 FieldsFunc(data, unicode.IsSpace) 1768 } 1769 }) 1770 } 1771 }) 1772 } 1773 } 1774 1775 func BenchmarkSplitEmptySeparator(b *testing.B) { 1776 for i := 0; i < b.N; i++ { 1777 Split(benchInputHard, "") 1778 } 1779 } 1780 1781 func BenchmarkSplitSingleByteSeparator(b *testing.B) { 1782 for i := 0; i < b.N; i++ { 1783 Split(benchInputHard, "/") 1784 } 1785 } 1786 1787 func BenchmarkSplitMultiByteSeparator(b *testing.B) { 1788 for i := 0; i < b.N; i++ { 1789 Split(benchInputHard, "hello") 1790 } 1791 } 1792 1793 func BenchmarkSplitNSingleByteSeparator(b *testing.B) { 1794 for i := 0; i < b.N; i++ { 1795 SplitN(benchInputHard, "/", 10) 1796 } 1797 } 1798 1799 func BenchmarkSplitNMultiByteSeparator(b *testing.B) { 1800 for i := 0; i < b.N; i++ { 1801 SplitN(benchInputHard, "hello", 10) 1802 } 1803 } 1804 1805 func BenchmarkRepeat(b *testing.B) { 1806 s := "0123456789" 1807 for _, n := range []int{5, 10} { 1808 for _, c := range []int{1, 2, 6} { 1809 b.Run(fmt.Sprintf("%dx%d", n, c), func(b *testing.B) { 1810 for i := 0; i < b.N; i++ { 1811 Repeat(s[:n], c) 1812 } 1813 }) 1814 } 1815 } 1816 } 1817 1818 func BenchmarkIndexAnyASCII(b *testing.B) { 1819 x := Repeat("#", 2048) // Never matches set 1820 cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz" 1821 for k := 1; k <= 2048; k <<= 4 { 1822 for j := 1; j <= 64; j <<= 1 { 1823 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1824 for i := 0; i < b.N; i++ { 1825 IndexAny(x[:k], cs[:j]) 1826 } 1827 }) 1828 } 1829 } 1830 } 1831 1832 func BenchmarkIndexAnyUTF8(b *testing.B) { 1833 x := Repeat("#", 2048) // Never matches set 1834 cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world." 1835 for k := 1; k <= 2048; k <<= 4 { 1836 for j := 1; j <= 64; j <<= 1 { 1837 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1838 for i := 0; i < b.N; i++ { 1839 IndexAny(x[:k], cs[:j]) 1840 } 1841 }) 1842 } 1843 } 1844 } 1845 1846 func BenchmarkLastIndexAnyASCII(b *testing.B) { 1847 x := Repeat("#", 2048) // Never matches set 1848 cs := "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz" 1849 for k := 1; k <= 2048; k <<= 4 { 1850 for j := 1; j <= 64; j <<= 1 { 1851 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1852 for i := 0; i < b.N; i++ { 1853 LastIndexAny(x[:k], cs[:j]) 1854 } 1855 }) 1856 } 1857 } 1858 } 1859 1860 func BenchmarkLastIndexAnyUTF8(b *testing.B) { 1861 x := Repeat("#", 2048) // Never matches set 1862 cs := "你好世界, hello world. 你好世界, hello world. 你好世界, hello world." 1863 for k := 1; k <= 2048; k <<= 4 { 1864 for j := 1; j <= 64; j <<= 1 { 1865 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1866 for i := 0; i < b.N; i++ { 1867 LastIndexAny(x[:k], cs[:j]) 1868 } 1869 }) 1870 } 1871 } 1872 } 1873 1874 func BenchmarkTrimASCII(b *testing.B) { 1875 cs := "0123456789abcdef" 1876 for k := 1; k <= 4096; k <<= 4 { 1877 for j := 1; j <= 16; j <<= 1 { 1878 b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) { 1879 x := Repeat(cs[:j], k) // Always matches set 1880 for i := 0; i < b.N; i++ { 1881 Trim(x[:k], cs[:j]) 1882 } 1883 }) 1884 } 1885 } 1886 } 1887 1888 func BenchmarkTrimByte(b *testing.B) { 1889 x := " the quick brown fox " 1890 for i := 0; i < b.N; i++ { 1891 Trim(x, " ") 1892 } 1893 } 1894 1895 func BenchmarkIndexPeriodic(b *testing.B) { 1896 key := "aa" 1897 for _, skip := range [...]int{2, 4, 8, 16, 32, 64} { 1898 b.Run(fmt.Sprintf("IndexPeriodic%d", skip), func(b *testing.B) { 1899 s := Repeat("a"+Repeat(" ", skip-1), 1<<16/skip) 1900 for i := 0; i < b.N; i++ { 1901 Index(s, key) 1902 } 1903 }) 1904 } 1905 } 1906 1907 func BenchmarkJoin(b *testing.B) { 1908 vals := []string{"red", "yellow", "pink", "green", "purple", "orange", "blue"} 1909 for l := 0; l <= len(vals); l++ { 1910 b.Run(strconv.Itoa(l), func(b *testing.B) { 1911 b.ReportAllocs() 1912 vals := vals[:l] 1913 for i := 0; i < b.N; i++ { 1914 Join(vals, " and ") 1915 } 1916 }) 1917 } 1918 } 1919 1920 func BenchmarkTrimSpace(b *testing.B) { 1921 tests := []struct{ name, input string }{ 1922 {"NoTrim", "typical"}, 1923 {"ASCII", " foo bar "}, 1924 {"SomeNonASCII", " \u2000\t\r\n x\t\t\r\r\ny\n \u3000 "}, 1925 {"JustNonASCII", "\u2000\u2000\u2000☺☺☺☺\u3000\u3000\u3000"}, 1926 } 1927 for _, test := range tests { 1928 b.Run(test.name, func(b *testing.B) { 1929 for i := 0; i < b.N; i++ { 1930 TrimSpace(test.input) 1931 } 1932 }) 1933 } 1934 } 1935 1936 var stringSink string 1937 1938 func BenchmarkReplaceAll(b *testing.B) { 1939 b.ReportAllocs() 1940 for i := 0; i < b.N; i++ { 1941 stringSink = ReplaceAll("banana", "a", "<>") 1942 } 1943 }