github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/text/tabwriter/tabwriter_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 tabwriter_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "testing" 13 . "text/tabwriter" 14 ) 15 16 type buffer struct { 17 a []byte 18 } 19 20 func (b *buffer) init(n int) { b.a = make([]byte, 0, n) } 21 22 func (b *buffer) clear() { b.a = b.a[0:0] } 23 24 func (b *buffer) Write(buf []byte) (written int, err error) { 25 n := len(b.a) 26 m := len(buf) 27 if n+m <= cap(b.a) { 28 b.a = b.a[0 : n+m] 29 for i := 0; i < m; i++ { 30 b.a[n+i] = buf[i] 31 } 32 } else { 33 panic("buffer.Write: buffer too small") 34 } 35 return len(buf), nil 36 } 37 38 func (b *buffer) String() string { return string(b.a) } 39 40 func write(t *testing.T, testname string, w *Writer, src string) { 41 written, err := io.WriteString(w, src) 42 if err != nil { 43 t.Errorf("--- test: %s\n--- src:\n%q\n--- write error: %v\n", testname, src, err) 44 } 45 if written != len(src) { 46 t.Errorf("--- test: %s\n--- src:\n%q\n--- written = %d, len(src) = %d\n", testname, src, written, len(src)) 47 } 48 } 49 50 func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) { 51 err := w.Flush() 52 if err != nil { 53 t.Errorf("--- test: %s\n--- src:\n%q\n--- flush error: %v\n", testname, src, err) 54 } 55 56 res := b.String() 57 if res != expected { 58 t.Errorf("--- test: %s\n--- src:\n%q\n--- found:\n%q\n--- expected:\n%q\n", testname, src, res, expected) 59 } 60 } 61 62 func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) { 63 var b buffer 64 b.init(1000) 65 66 var w Writer 67 w.Init(&b, minwidth, tabwidth, padding, padchar, flags) 68 69 // write all at once 70 title := testname + " (written all at once)" 71 b.clear() 72 write(t, title, &w, src) 73 verify(t, title, &w, &b, src, expected) 74 75 // write byte-by-byte 76 title = testname + " (written byte-by-byte)" 77 b.clear() 78 for i := 0; i < len(src); i++ { 79 write(t, title, &w, src[i:i+1]) 80 } 81 verify(t, title, &w, &b, src, expected) 82 83 // write using Fibonacci slice sizes 84 title = testname + " (written in fibonacci slices)" 85 b.clear() 86 for i, d := 0, 0; i < len(src); { 87 write(t, title, &w, src[i:i+d]) 88 i, d = i+d, d+1 89 if i+d > len(src) { 90 d = len(src) - i 91 } 92 } 93 verify(t, title, &w, &b, src, expected) 94 } 95 96 var tests = []struct { 97 testname string 98 minwidth, tabwidth, padding int 99 padchar byte 100 flags uint 101 src, expected string 102 }{ 103 { 104 "1a", 105 8, 0, 1, '.', 0, 106 "", 107 "", 108 }, 109 110 { 111 "1a debug", 112 8, 0, 1, '.', Debug, 113 "", 114 "", 115 }, 116 117 { 118 "1b esc stripped", 119 8, 0, 1, '.', StripEscape, 120 "\xff\xff", 121 "", 122 }, 123 124 { 125 "1b esc", 126 8, 0, 1, '.', 0, 127 "\xff\xff", 128 "\xff\xff", 129 }, 130 131 { 132 "1c esc stripped", 133 8, 0, 1, '.', StripEscape, 134 "\xff\t\xff", 135 "\t", 136 }, 137 138 { 139 "1c esc", 140 8, 0, 1, '.', 0, 141 "\xff\t\xff", 142 "\xff\t\xff", 143 }, 144 145 { 146 "1d esc stripped", 147 8, 0, 1, '.', StripEscape, 148 "\xff\"foo\t\n\tbar\"\xff", 149 "\"foo\t\n\tbar\"", 150 }, 151 152 { 153 "1d esc", 154 8, 0, 1, '.', 0, 155 "\xff\"foo\t\n\tbar\"\xff", 156 "\xff\"foo\t\n\tbar\"\xff", 157 }, 158 159 { 160 "1e esc stripped", 161 8, 0, 1, '.', StripEscape, 162 "abc\xff\tdef", // unterminated escape 163 "abc\tdef", 164 }, 165 166 { 167 "1e esc", 168 8, 0, 1, '.', 0, 169 "abc\xff\tdef", // unterminated escape 170 "abc\xff\tdef", 171 }, 172 173 { 174 "2", 175 8, 0, 1, '.', 0, 176 "\n\n\n", 177 "\n\n\n", 178 }, 179 180 { 181 "3", 182 8, 0, 1, '.', 0, 183 "a\nb\nc", 184 "a\nb\nc", 185 }, 186 187 { 188 "4a", 189 8, 0, 1, '.', 0, 190 "\t", // '\t' terminates an empty cell on last line - nothing to print 191 "", 192 }, 193 194 { 195 "4b", 196 8, 0, 1, '.', AlignRight, 197 "\t", // '\t' terminates an empty cell on last line - nothing to print 198 "", 199 }, 200 201 { 202 "5", 203 8, 0, 1, '.', 0, 204 "*\t*", 205 "*.......*", 206 }, 207 208 { 209 "5b", 210 8, 0, 1, '.', 0, 211 "*\t*\n", 212 "*.......*\n", 213 }, 214 215 { 216 "5c", 217 8, 0, 1, '.', 0, 218 "*\t*\t", 219 "*.......*", 220 }, 221 222 { 223 "5c debug", 224 8, 0, 1, '.', Debug, 225 "*\t*\t", 226 "*.......|*", 227 }, 228 229 { 230 "5d", 231 8, 0, 1, '.', AlignRight, 232 "*\t*\t", 233 ".......**", 234 }, 235 236 { 237 "6", 238 8, 0, 1, '.', 0, 239 "\t\n", 240 "........\n", 241 }, 242 243 { 244 "7a", 245 8, 0, 1, '.', 0, 246 "a) foo", 247 "a) foo", 248 }, 249 250 { 251 "7b", 252 8, 0, 1, ' ', 0, 253 "b) foo\tbar", 254 "b) foo bar", 255 }, 256 257 { 258 "7c", 259 8, 0, 1, '.', 0, 260 "c) foo\tbar\t", 261 "c) foo..bar", 262 }, 263 264 { 265 "7d", 266 8, 0, 1, '.', 0, 267 "d) foo\tbar\n", 268 "d) foo..bar\n", 269 }, 270 271 { 272 "7e", 273 8, 0, 1, '.', 0, 274 "e) foo\tbar\t\n", 275 "e) foo..bar.....\n", 276 }, 277 278 { 279 "7f", 280 8, 0, 1, '.', FilterHTML, 281 "f) f<o\t<b>bar</b>\t\n", 282 "f) f<o..<b>bar</b>.....\n", 283 }, 284 285 { 286 "7g", 287 8, 0, 1, '.', FilterHTML, 288 "g) f<o\t<b>bar</b>\t non-terminated entity &", 289 "g) f<o..<b>bar</b>..... non-terminated entity &", 290 }, 291 292 { 293 "7g debug", 294 8, 0, 1, '.', FilterHTML | Debug, 295 "g) f<o\t<b>bar</b>\t non-terminated entity &", 296 "g) f<o..|<b>bar</b>.....| non-terminated entity &", 297 }, 298 299 { 300 "8", 301 8, 0, 1, '*', 0, 302 "Hello, world!\n", 303 "Hello, world!\n", 304 }, 305 306 { 307 "9a", 308 1, 0, 0, '.', 0, 309 "1\t2\t3\t4\n" + 310 "11\t222\t3333\t44444\n", 311 312 "1.2..3...4\n" + 313 "11222333344444\n", 314 }, 315 316 { 317 "9b", 318 1, 0, 0, '.', FilterHTML, 319 "1\t2<!---\f--->\t3\t4\n" + // \f inside HTML is ignored 320 "11\t222\t3333\t44444\n", 321 322 "1.2<!---\f--->..3...4\n" + 323 "11222333344444\n", 324 }, 325 326 { 327 "9c", 328 1, 0, 0, '.', 0, 329 "1\t2\t3\t4\f" + // \f causes a newline and flush 330 "11\t222\t3333\t44444\n", 331 332 "1234\n" + 333 "11222333344444\n", 334 }, 335 336 { 337 "9c debug", 338 1, 0, 0, '.', Debug, 339 "1\t2\t3\t4\f" + // \f causes a newline and flush 340 "11\t222\t3333\t44444\n", 341 342 "1|2|3|4\n" + 343 "---\n" + 344 "11|222|3333|44444\n", 345 }, 346 347 { 348 "10a", 349 5, 0, 0, '.', 0, 350 "1\t2\t3\t4\n", 351 "1....2....3....4\n", 352 }, 353 354 { 355 "10b", 356 5, 0, 0, '.', 0, 357 "1\t2\t3\t4\t\n", 358 "1....2....3....4....\n", 359 }, 360 361 { 362 "11", 363 8, 0, 1, '.', 0, 364 "本\tb\tc\n" + 365 "aa\t\u672c\u672c\u672c\tcccc\tddddd\n" + 366 "aaa\tbbbb\n", 367 368 "本.......b.......c\n" + 369 "aa......本本本.....cccc....ddddd\n" + 370 "aaa.....bbbb\n", 371 }, 372 373 { 374 "12a", 375 8, 0, 1, ' ', AlignRight, 376 "a\tè\tc\t\n" + 377 "aa\tèèè\tcccc\tddddd\t\n" + 378 "aaa\tèèèè\t\n", 379 380 " a è c\n" + 381 " aa èèè cccc ddddd\n" + 382 " aaa èèèè\n", 383 }, 384 385 { 386 "12b", 387 2, 0, 0, ' ', 0, 388 "a\tb\tc\n" + 389 "aa\tbbb\tcccc\n" + 390 "aaa\tbbbb\n", 391 392 "a b c\n" + 393 "aa bbbcccc\n" + 394 "aaabbbb\n", 395 }, 396 397 { 398 "12c", 399 8, 0, 1, '_', 0, 400 "a\tb\tc\n" + 401 "aa\tbbb\tcccc\n" + 402 "aaa\tbbbb\n", 403 404 "a_______b_______c\n" + 405 "aa______bbb_____cccc\n" + 406 "aaa_____bbbb\n", 407 }, 408 409 { 410 "13a", 411 4, 0, 1, '-', 0, 412 "4444\t日本語\t22\t1\t333\n" + 413 "999999999\t22\n" + 414 "7\t22\n" + 415 "\t\t\t88888888\n" + 416 "\n" + 417 "666666\t666666\t666666\t4444\n" + 418 "1\t1\t999999999\t0000000000\n", 419 420 "4444------日本語-22--1---333\n" + 421 "999999999-22\n" + 422 "7---------22\n" + 423 "------------------88888888\n" + 424 "\n" + 425 "666666-666666-666666----4444\n" + 426 "1------1------999999999-0000000000\n", 427 }, 428 429 { 430 "13b", 431 4, 0, 3, '.', 0, 432 "4444\t333\t22\t1\t333\n" + 433 "999999999\t22\n" + 434 "7\t22\n" + 435 "\t\t\t88888888\n" + 436 "\n" + 437 "666666\t666666\t666666\t4444\n" + 438 "1\t1\t999999999\t0000000000\n", 439 440 "4444........333...22...1...333\n" + 441 "999999999...22\n" + 442 "7...........22\n" + 443 "....................88888888\n" + 444 "\n" + 445 "666666...666666...666666......4444\n" + 446 "1........1........999999999...0000000000\n", 447 }, 448 449 { 450 "13c", 451 8, 8, 1, '\t', FilterHTML, 452 "4444\t333\t22\t1\t333\n" + 453 "999999999\t22\n" + 454 "7\t22\n" + 455 "\t\t\t88888888\n" + 456 "\n" + 457 "666666\t666666\t666666\t4444\n" + 458 "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n", 459 460 "4444\t\t333\t22\t1\t333\n" + 461 "999999999\t22\n" + 462 "7\t\t22\n" + 463 "\t\t\t\t88888888\n" + 464 "\n" + 465 "666666\t666666\t666666\t\t4444\n" + 466 "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n", 467 }, 468 469 { 470 "14", 471 1, 0, 2, ' ', AlignRight, 472 ".0\t.3\t2.4\t-5.1\t\n" + 473 "23.0\t12345678.9\t2.4\t-989.4\t\n" + 474 "5.1\t12.0\t2.4\t-7.0\t\n" + 475 ".0\t0.0\t332.0\t8908.0\t\n" + 476 ".0\t-.3\t456.4\t22.1\t\n" + 477 ".0\t1.2\t44.4\t-13.3\t\t", 478 479 " .0 .3 2.4 -5.1\n" + 480 " 23.0 12345678.9 2.4 -989.4\n" + 481 " 5.1 12.0 2.4 -7.0\n" + 482 " .0 0.0 332.0 8908.0\n" + 483 " .0 -.3 456.4 22.1\n" + 484 " .0 1.2 44.4 -13.3", 485 }, 486 487 { 488 "14 debug", 489 1, 0, 2, ' ', AlignRight | Debug, 490 ".0\t.3\t2.4\t-5.1\t\n" + 491 "23.0\t12345678.9\t2.4\t-989.4\t\n" + 492 "5.1\t12.0\t2.4\t-7.0\t\n" + 493 ".0\t0.0\t332.0\t8908.0\t\n" + 494 ".0\t-.3\t456.4\t22.1\t\n" + 495 ".0\t1.2\t44.4\t-13.3\t\t", 496 497 " .0| .3| 2.4| -5.1|\n" + 498 " 23.0| 12345678.9| 2.4| -989.4|\n" + 499 " 5.1| 12.0| 2.4| -7.0|\n" + 500 " .0| 0.0| 332.0| 8908.0|\n" + 501 " .0| -.3| 456.4| 22.1|\n" + 502 " .0| 1.2| 44.4| -13.3|", 503 }, 504 505 { 506 "15a", 507 4, 0, 0, '.', 0, 508 "a\t\tb", 509 "a.......b", 510 }, 511 512 { 513 "15b", 514 4, 0, 0, '.', DiscardEmptyColumns, 515 "a\t\tb", // htabs - do not discard column 516 "a.......b", 517 }, 518 519 { 520 "15c", 521 4, 0, 0, '.', DiscardEmptyColumns, 522 "a\v\vb", 523 "a...b", 524 }, 525 526 { 527 "15d", 528 4, 0, 0, '.', AlignRight | DiscardEmptyColumns, 529 "a\v\vb", 530 "...ab", 531 }, 532 533 { 534 "16a", 535 100, 100, 0, '\t', 0, 536 "a\tb\t\td\n" + 537 "a\tb\t\td\te\n" + 538 "a\n" + 539 "a\tb\tc\td\n" + 540 "a\tb\tc\td\te\n", 541 542 "a\tb\t\td\n" + 543 "a\tb\t\td\te\n" + 544 "a\n" + 545 "a\tb\tc\td\n" + 546 "a\tb\tc\td\te\n", 547 }, 548 549 { 550 "16b", 551 100, 100, 0, '\t', DiscardEmptyColumns, 552 "a\vb\v\vd\n" + 553 "a\vb\v\vd\ve\n" + 554 "a\n" + 555 "a\vb\vc\vd\n" + 556 "a\vb\vc\vd\ve\n", 557 558 "a\tb\td\n" + 559 "a\tb\td\te\n" + 560 "a\n" + 561 "a\tb\tc\td\n" + 562 "a\tb\tc\td\te\n", 563 }, 564 565 { 566 "16b debug", 567 100, 100, 0, '\t', DiscardEmptyColumns | Debug, 568 "a\vb\v\vd\n" + 569 "a\vb\v\vd\ve\n" + 570 "a\n" + 571 "a\vb\vc\vd\n" + 572 "a\vb\vc\vd\ve\n", 573 574 "a\t|b\t||d\n" + 575 "a\t|b\t||d\t|e\n" + 576 "a\n" + 577 "a\t|b\t|c\t|d\n" + 578 "a\t|b\t|c\t|d\t|e\n", 579 }, 580 581 { 582 "16c", 583 100, 100, 0, '\t', DiscardEmptyColumns, 584 "a\tb\t\td\n" + // hard tabs - do not discard column 585 "a\tb\t\td\te\n" + 586 "a\n" + 587 "a\tb\tc\td\n" + 588 "a\tb\tc\td\te\n", 589 590 "a\tb\t\td\n" + 591 "a\tb\t\td\te\n" + 592 "a\n" + 593 "a\tb\tc\td\n" + 594 "a\tb\tc\td\te\n", 595 }, 596 597 { 598 "16c debug", 599 100, 100, 0, '\t', DiscardEmptyColumns | Debug, 600 "a\tb\t\td\n" + // hard tabs - do not discard column 601 "a\tb\t\td\te\n" + 602 "a\n" + 603 "a\tb\tc\td\n" + 604 "a\tb\tc\td\te\n", 605 606 "a\t|b\t|\t|d\n" + 607 "a\t|b\t|\t|d\t|e\n" + 608 "a\n" + 609 "a\t|b\t|c\t|d\n" + 610 "a\t|b\t|c\t|d\t|e\n", 611 }, 612 } 613 614 func Test(t *testing.T) { 615 for _, e := range tests { 616 check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected) 617 } 618 } 619 620 type panicWriter struct{} 621 622 func (panicWriter) Write([]byte) (int, error) { 623 panic("cannot write") 624 } 625 626 func wantPanicString(t *testing.T, want string) { 627 if e := recover(); e != nil { 628 got, ok := e.(string) 629 switch { 630 case !ok: 631 t.Errorf("got %v (%T), want panic string", e, e) 632 case got != want: 633 t.Errorf("wrong panic message: got %q, want %q", got, want) 634 } 635 } 636 } 637 638 func TestPanicDuringFlush(t *testing.T) { 639 defer wantPanicString(t, "tabwriter: panic during Flush") 640 var p panicWriter 641 w := new(Writer) 642 w.Init(p, 0, 0, 5, ' ', 0) 643 io.WriteString(w, "a") 644 w.Flush() 645 t.Errorf("failed to panic during Flush") 646 } 647 648 func TestPanicDuringWrite(t *testing.T) { 649 defer wantPanicString(t, "tabwriter: panic during Write") 650 var p panicWriter 651 w := new(Writer) 652 w.Init(p, 0, 0, 5, ' ', 0) 653 io.WriteString(w, "a\n\n") // the second \n triggers a call to w.Write and thus a panic 654 t.Errorf("failed to panic during Write") 655 } 656 657 func BenchmarkTable(b *testing.B) { 658 for _, w := range [...]int{1, 10, 100} { 659 // Build a line with w cells. 660 line := bytes.Repeat([]byte("a\t"), w) 661 line = append(line, '\n') 662 for _, h := range [...]int{10, 1000, 100000} { 663 b.Run(fmt.Sprintf("%dx%d", w, h), func(b *testing.B) { 664 b.Run("new", func(b *testing.B) { 665 b.ReportAllocs() 666 for i := 0; i < b.N; i++ { 667 w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings 668 // Write the line h times. 669 for j := 0; j < h; j++ { 670 w.Write(line) 671 } 672 w.Flush() 673 } 674 }) 675 676 b.Run("reuse", func(b *testing.B) { 677 b.ReportAllocs() 678 w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings 679 for i := 0; i < b.N; i++ { 680 // Write the line h times. 681 for j := 0; j < h; j++ { 682 w.Write(line) 683 } 684 w.Flush() 685 } 686 }) 687 }) 688 } 689 } 690 } 691 692 func BenchmarkPyramid(b *testing.B) { 693 for _, x := range [...]int{10, 100, 1000} { 694 // Build a line with x cells. 695 line := bytes.Repeat([]byte("a\t"), x) 696 b.Run(fmt.Sprintf("%d", x), func(b *testing.B) { 697 b.ReportAllocs() 698 for i := 0; i < b.N; i++ { 699 w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings 700 // Write increasing prefixes of that line. 701 for j := 0; j < x; j++ { 702 w.Write(line[:j*2]) 703 w.Write([]byte{'\n'}) 704 } 705 w.Flush() 706 } 707 }) 708 } 709 } 710 711 func BenchmarkRagged(b *testing.B) { 712 var lines [8][]byte 713 for i, w := range [8]int{6, 2, 9, 5, 5, 7, 3, 8} { 714 // Build a line with w cells. 715 lines[i] = bytes.Repeat([]byte("a\t"), w) 716 } 717 for _, h := range [...]int{10, 100, 1000} { 718 b.Run(fmt.Sprintf("%d", h), func(b *testing.B) { 719 b.ReportAllocs() 720 for i := 0; i < b.N; i++ { 721 w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings 722 // Write the lines in turn h times. 723 for j := 0; j < h; j++ { 724 w.Write(lines[j%len(lines)]) 725 w.Write([]byte{'\n'}) 726 } 727 w.Flush() 728 } 729 }) 730 } 731 }