github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/text/runes/runes_test.go (about) 1 // Copyright 2015 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 runes 6 7 import ( 8 "strings" 9 "testing" 10 "unicode/utf8" 11 12 "golang.org/x/text/transform" 13 ) 14 15 type transformTest struct { 16 desc string 17 szDst int 18 atEOF bool 19 repl string 20 in string 21 out string // result string of first call to Transform 22 outFull string // transform of entire input string 23 err error 24 25 t transform.Transformer 26 } 27 28 const large = 10240 29 30 func (tt *transformTest) check(t *testing.T, i int) { 31 if tt.t == nil { 32 return 33 } 34 dst := make([]byte, tt.szDst) 35 src := []byte(tt.in) 36 nDst, nSrc, err := tt.t.Transform(dst, src, tt.atEOF) 37 if err != tt.err { 38 t.Errorf("%d:%s:error: got %v; want %v", i, tt.desc, err, tt.err) 39 } 40 if got := string(dst[:nDst]); got != tt.out { 41 t.Errorf("%d:%s:out: got %q; want %q", i, tt.desc, got, tt.out) 42 } 43 44 // Calls tt.t.Transform for the remainder of the input. We use this to test 45 // the nSrc return value. 46 out := make([]byte, large) 47 n := copy(out, dst[:nDst]) 48 nDst, _, _ = tt.t.Transform(out[n:], src[nSrc:], true) 49 if got, want := string(out[:n+nDst]), tt.outFull; got != want { 50 t.Errorf("%d:%s:outFull: got %q; want %q", i, tt.desc, got, want) 51 } 52 } 53 54 func idem(r rune) rune { return r } 55 56 func TestMap(t *testing.T) { 57 runes := []rune{'a', 'ç', '中', '\U00012345', 'a'} 58 // Default mapper used for this test. 59 rotate := Map(func(r rune) rune { 60 for i, m := range runes { 61 if m == r { 62 return runes[i+1] 63 } 64 } 65 return r 66 }) 67 68 for i, tt := range []transformTest{{ 69 desc: "empty", 70 szDst: large, 71 atEOF: true, 72 in: "", 73 out: "", 74 outFull: "", 75 t: rotate, 76 }, { 77 desc: "no change", 78 szDst: 1, 79 atEOF: true, 80 in: "b", 81 out: "b", 82 outFull: "b", 83 t: rotate, 84 }, { 85 desc: "short dst", 86 szDst: 2, 87 atEOF: true, 88 in: "aaaa", 89 out: "ç", 90 outFull: "çççç", 91 err: transform.ErrShortDst, 92 t: rotate, 93 }, { 94 desc: "short dst ascii, no change", 95 szDst: 2, 96 atEOF: true, 97 in: "bbb", 98 out: "bb", 99 outFull: "bbb", 100 err: transform.ErrShortDst, 101 t: rotate, 102 }, { 103 desc: "short dst writing error", 104 szDst: 2, 105 atEOF: false, 106 in: "a\x80", 107 out: "ç", 108 outFull: "ç\ufffd", 109 err: transform.ErrShortDst, 110 t: rotate, 111 }, { 112 desc: "short dst writing incomplete rune", 113 szDst: 2, 114 atEOF: true, 115 in: "a\xc0", 116 out: "ç", 117 outFull: "ç\ufffd", 118 err: transform.ErrShortDst, 119 t: rotate, 120 }, { 121 desc: "short dst, longer", 122 szDst: 5, 123 atEOF: true, 124 in: "Hellø", 125 out: "Hell", 126 outFull: "Hellø", 127 err: transform.ErrShortDst, 128 t: rotate, 129 }, { 130 desc: "short dst, single", 131 szDst: 1, 132 atEOF: false, 133 in: "ø", 134 out: "", 135 outFull: "ø", 136 err: transform.ErrShortDst, 137 t: Map(idem), 138 }, { 139 desc: "short dst, longer, writing error", 140 szDst: 8, 141 atEOF: false, 142 in: "\x80Hello\x80", 143 out: "\ufffdHello", 144 outFull: "\ufffdHello\ufffd", 145 err: transform.ErrShortDst, 146 t: rotate, 147 }, { 148 desc: "short src", 149 szDst: 2, 150 atEOF: false, 151 in: "a\xc2", 152 out: "ç", 153 outFull: "ç\ufffd", 154 err: transform.ErrShortSrc, 155 t: rotate, 156 }, { 157 desc: "invalid input, atEOF", 158 szDst: large, 159 atEOF: true, 160 in: "\x80", 161 out: "\ufffd", 162 outFull: "\ufffd", 163 t: rotate, 164 }, { 165 desc: "invalid input, !atEOF", 166 szDst: large, 167 atEOF: false, 168 in: "\x80", 169 out: "\ufffd", 170 outFull: "\ufffd", 171 t: rotate, 172 }, { 173 desc: "invalid input, incomplete rune atEOF", 174 szDst: large, 175 atEOF: true, 176 in: "\xc0", 177 out: "\ufffd", 178 outFull: "\ufffd", 179 t: rotate, 180 }, { 181 desc: "misc correct", 182 szDst: large, 183 atEOF: true, 184 in: "a\U00012345 ç!", 185 out: "ça 中!", 186 outFull: "ça 中!", 187 t: rotate, 188 }, { 189 desc: "misc correct and invalid", 190 szDst: large, 191 atEOF: true, 192 in: "Hello\x80 w\x80orl\xc0d!\xc0", 193 out: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", 194 outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", 195 t: rotate, 196 }, { 197 desc: "misc correct and invalid, short src", 198 szDst: large, 199 atEOF: false, 200 in: "Hello\x80 w\x80orl\xc0d!\xc2", 201 out: "Hello\ufffd w\ufffdorl\ufffdd!", 202 outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", 203 err: transform.ErrShortSrc, 204 t: rotate, 205 }, { 206 desc: "misc correct and invalid, short src, replacing RuneError", 207 szDst: large, 208 atEOF: false, 209 in: "Hel\ufffdlo\x80 w\x80orl\xc0d!\xc2", 210 out: "Hel?lo? w?orl?d!", 211 outFull: "Hel?lo? w?orl?d!?", 212 err: transform.ErrShortSrc, 213 t: Map(func(r rune) rune { 214 if r == utf8.RuneError { 215 return '?' 216 } 217 return r 218 }), 219 }} { 220 tt.check(t, i) 221 } 222 } 223 224 func TestRemove(t *testing.T) { 225 remove := Remove(Predicate(func(r rune) bool { 226 return strings.ContainsRune("aeiou\u0300\uFF24\U00012345", r) 227 })) 228 229 for i, tt := range []transformTest{ 230 0: { 231 szDst: large, 232 atEOF: true, 233 in: "", 234 out: "", 235 outFull: "", 236 t: remove, 237 }, 238 1: { 239 szDst: 0, 240 atEOF: true, 241 in: "aaaa", 242 out: "", 243 outFull: "", 244 t: remove, 245 }, 246 2: { 247 szDst: 1, 248 atEOF: true, 249 in: "aaaa", 250 out: "", 251 outFull: "", 252 t: remove, 253 }, 254 3: { 255 szDst: 1, 256 atEOF: true, 257 in: "baaaa", 258 out: "b", 259 outFull: "b", 260 t: remove, 261 }, 262 4: { 263 szDst: 2, 264 atEOF: true, 265 in: "açaaa", 266 out: "ç", 267 outFull: "ç", 268 t: remove, 269 }, 270 5: { 271 szDst: 2, 272 atEOF: true, 273 in: "aaaç", 274 out: "ç", 275 outFull: "ç", 276 t: remove, 277 }, 278 6: { 279 szDst: 2, 280 atEOF: false, 281 in: "a\x80", 282 out: "", 283 outFull: "\ufffd", 284 err: transform.ErrShortDst, 285 t: remove, 286 }, 287 7: { 288 szDst: 1, 289 atEOF: true, 290 in: "a\xc0", 291 out: "", 292 outFull: "\ufffd", 293 err: transform.ErrShortDst, 294 t: remove, 295 }, 296 8: { 297 szDst: 1, 298 atEOF: false, 299 in: "a\xc2", 300 out: "", 301 outFull: "\ufffd", 302 err: transform.ErrShortSrc, 303 t: remove, 304 }, 305 9: { 306 szDst: large, 307 atEOF: true, 308 in: "\x80", 309 out: "\ufffd", 310 outFull: "\ufffd", 311 t: remove, 312 }, 313 10: { 314 szDst: large, 315 atEOF: false, 316 in: "\x80", 317 out: "\ufffd", 318 outFull: "\ufffd", 319 t: remove, 320 }, 321 11: { 322 szDst: large, 323 atEOF: true, 324 in: "\xc0", 325 out: "\ufffd", 326 outFull: "\ufffd", 327 t: remove, 328 }, 329 12: { 330 szDst: large, 331 atEOF: true, 332 in: "Hello \U00012345world!", 333 out: "Hll wrld!", 334 outFull: "Hll wrld!", 335 t: remove, 336 }, 337 13: { 338 szDst: large, 339 atEOF: true, 340 in: "Hello\x80 w\x80orl\xc0d!\xc0", 341 out: "Hll\ufffd w\ufffdrl\ufffdd!\ufffd", 342 outFull: "Hll\ufffd w\ufffdrl\ufffdd!\ufffd", 343 t: remove, 344 }, 345 14: { 346 szDst: large, 347 atEOF: false, 348 in: "Hello\x80 w\x80orl\xc0d!\xc2", 349 out: "Hll\ufffd w\ufffdrl\ufffdd!", 350 outFull: "Hll\ufffd w\ufffdrl\ufffdd!\ufffd", 351 err: transform.ErrShortSrc, 352 t: remove, 353 }, 354 15: { 355 szDst: large, 356 atEOF: false, 357 in: "Hel\ufffdlo\x80 w\x80orl\xc0d!\xc2", 358 out: "Hello world!", 359 outFull: "Hello world!", 360 err: transform.ErrShortSrc, 361 t: Remove(Predicate(func(r rune) bool { return r == utf8.RuneError })), 362 }, 363 16: { 364 szDst: 4, 365 atEOF: true, 366 in: "Hellø", 367 out: "Hll", 368 outFull: "Hllø", 369 err: transform.ErrShortDst, 370 t: remove, 371 }, 372 17: { 373 szDst: 4, 374 atEOF: false, 375 in: "Hellø", 376 out: "Hll", 377 outFull: "Hllø", 378 err: transform.ErrShortDst, 379 t: remove, 380 }, 381 18: { 382 szDst: 8, 383 atEOF: false, 384 in: "\x80Hello\uFF24\x80", 385 out: "\ufffdHll", 386 outFull: "\ufffdHll\ufffd", 387 err: transform.ErrShortDst, 388 t: remove, 389 }, 390 } { 391 tt.check(t, i) 392 } 393 } 394 395 func TestReplaceIllFormed(t *testing.T) { 396 replace := ReplaceIllFormed() 397 398 for i, tt := range []transformTest{ 399 0: { 400 szDst: large, 401 atEOF: true, 402 in: "", 403 out: "", 404 outFull: "", 405 t: replace, 406 }, 407 1: { 408 szDst: 1, 409 atEOF: true, 410 in: "aa", 411 out: "a", 412 outFull: "aa", 413 err: transform.ErrShortDst, 414 t: replace, 415 }, 416 2: { 417 szDst: 1, 418 atEOF: true, 419 in: "a\x80", 420 out: "a", 421 outFull: "a\ufffd", 422 err: transform.ErrShortDst, 423 t: replace, 424 }, 425 3: { 426 szDst: 1, 427 atEOF: true, 428 in: "a\xc0", 429 out: "a", 430 outFull: "a\ufffd", 431 err: transform.ErrShortDst, 432 t: replace, 433 }, 434 4: { 435 szDst: large, 436 atEOF: true, 437 in: "\x80", 438 out: "\ufffd", 439 outFull: "\ufffd", 440 t: replace, 441 }, 442 5: { 443 szDst: large, 444 atEOF: false, 445 in: "\x80", 446 out: "\ufffd", 447 outFull: "\ufffd", 448 t: replace, 449 }, 450 6: { 451 szDst: large, 452 atEOF: true, 453 in: "\xc2", 454 out: "\ufffd", 455 outFull: "\ufffd", 456 t: replace, 457 }, 458 7: { 459 szDst: large, 460 atEOF: false, 461 in: "\xc2", 462 out: "", 463 outFull: "\ufffd", 464 err: transform.ErrShortSrc, 465 t: replace, 466 }, 467 8: { 468 szDst: large, 469 atEOF: true, 470 in: "Hello world!", 471 out: "Hello world!", 472 outFull: "Hello world!", 473 t: replace, 474 }, 475 9: { 476 szDst: large, 477 atEOF: true, 478 in: "Hello\x80 w\x80orl\xc2d!\xc2", 479 out: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", 480 outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", 481 t: replace, 482 }, 483 10: { 484 szDst: large, 485 atEOF: false, 486 in: "Hello\x80 w\x80orl\xc2d!\xc2", 487 out: "Hello\ufffd w\ufffdorl\ufffdd!", 488 outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", 489 err: transform.ErrShortSrc, 490 t: replace, 491 }, 492 16: { 493 szDst: 10, 494 atEOF: false, 495 in: "\x80Hello\x80", 496 out: "\ufffdHello", 497 outFull: "\ufffdHello\ufffd", 498 err: transform.ErrShortDst, 499 t: replace, 500 }, 501 } { 502 tt.check(t, i) 503 } 504 } 505 506 func TestMapAlloc(t *testing.T) { 507 if n := testing.AllocsPerRun(3, func() { 508 Map(idem).Transform(nil, nil, false) 509 }); n > 0 { 510 t.Errorf("got %f; want 0", n) 511 } 512 } 513 514 func rmNop(r rune) bool { return false } 515 516 func TestRemoveAlloc(t *testing.T) { 517 if n := testing.AllocsPerRun(3, func() { 518 Remove(Predicate(rmNop)).Transform(nil, nil, false) 519 }); n > 0 { 520 t.Errorf("got %f; want 0", n) 521 } 522 } 523 524 func TestReplaceIllFormedAlloc(t *testing.T) { 525 if n := testing.AllocsPerRun(3, func() { 526 ReplaceIllFormed().Transform(nil, nil, false) 527 }); n > 0 { 528 t.Errorf("got %f; want 0", n) 529 } 530 } 531 532 func BenchmarkRemove(b *testing.B) { 533 dst := make([]byte, len(input)) 534 src := []byte(input) 535 536 r := Remove(Predicate(func(r rune) bool { return r == 'e' })) 537 b.ResetTimer() 538 539 for i := 0; i < b.N; i++ { 540 r.Transform(dst, src, true) 541 } 542 } 543 544 func BenchmarkMapAll(b *testing.B) { 545 dst := make([]byte, 2*len(input)) 546 src := []byte(input) 547 548 r := Map(func(r rune) rune { return 'a' }) 549 b.ResetTimer() 550 551 for i := 0; i < b.N; i++ { 552 r.Transform(dst, src, true) 553 } 554 } 555 556 func BenchmarkMapNone(b *testing.B) { 557 dst := make([]byte, 2*len(input)) 558 src := []byte(input) 559 560 r := Map(func(r rune) rune { return r }) 561 b.ResetTimer() 562 563 for i := 0; i < b.N; i++ { 564 r.Transform(dst, src, true) 565 } 566 } 567 568 func BenchmarkReplaceIllFormed(b *testing.B) { 569 dst := make([]byte, 2*len(input)) 570 src := []byte(input) 571 572 t := ReplaceIllFormed() 573 b.ResetTimer() 574 575 for i := 0; i < b.N; i++ { 576 t.Transform(dst, src, true) 577 } 578 } 579 580 var ( 581 input = strings.Repeat("Thé qüick brøwn føx jumps øver the lazy døg. ", 100) 582 )