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