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