1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Console\Tests\Helper; 13 14use PHPUnit\Framework\TestCase; 15use Symfony\Component\Console\Helper\Table; 16use Symfony\Component\Console\Helper\TableCell; 17use Symfony\Component\Console\Helper\TableSeparator; 18use Symfony\Component\Console\Helper\TableStyle; 19use Symfony\Component\Console\Output\StreamOutput; 20 21class TableTest extends TestCase 22{ 23 protected $stream; 24 25 protected function setUp() 26 { 27 $this->stream = fopen('php://memory', 'r+'); 28 } 29 30 protected function tearDown() 31 { 32 fclose($this->stream); 33 $this->stream = null; 34 } 35 36 /** 37 * @dataProvider renderProvider 38 */ 39 public function testRender($headers, $rows, $style, $expected, $decorated = false) 40 { 41 $table = new Table($output = $this->getOutputStream($decorated)); 42 $table 43 ->setHeaders($headers) 44 ->setRows($rows) 45 ->setStyle($style) 46 ; 47 $table->render(); 48 49 $this->assertEquals($expected, $this->getOutputContent($output)); 50 } 51 52 /** 53 * @dataProvider renderProvider 54 */ 55 public function testRenderAddRows($headers, $rows, $style, $expected, $decorated = false) 56 { 57 $table = new Table($output = $this->getOutputStream($decorated)); 58 $table 59 ->setHeaders($headers) 60 ->addRows($rows) 61 ->setStyle($style) 62 ; 63 $table->render(); 64 65 $this->assertEquals($expected, $this->getOutputContent($output)); 66 } 67 68 /** 69 * @dataProvider renderProvider 70 */ 71 public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected, $decorated = false) 72 { 73 $table = new Table($output = $this->getOutputStream($decorated)); 74 $table 75 ->setHeaders($headers) 76 ->setStyle($style) 77 ; 78 foreach ($rows as $row) { 79 $table->addRow($row); 80 } 81 $table->render(); 82 83 $this->assertEquals($expected, $this->getOutputContent($output)); 84 } 85 86 public function renderProvider() 87 { 88 $books = [ 89 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'], 90 ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'], 91 ['960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'], 92 ['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'], 93 ]; 94 95 return [ 96 [ 97 ['ISBN', 'Title', 'Author'], 98 $books, 99 'default', 100<<<'TABLE' 101+---------------+--------------------------+------------------+ 102| ISBN | Title | Author | 103+---------------+--------------------------+------------------+ 104| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 105| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 106| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | 107| 80-902734-1-6 | And Then There Were None | Agatha Christie | 108+---------------+--------------------------+------------------+ 109 110TABLE 111 ], 112 [ 113 ['ISBN', 'Title', 'Author'], 114 $books, 115 'compact', 116<<<'TABLE' 117 ISBN Title Author 118 99921-58-10-7 Divine Comedy Dante Alighieri 119 9971-5-0210-0 A Tale of Two Cities Charles Dickens 120 960-425-059-0 The Lord of the Rings J. R. R. Tolkien 121 80-902734-1-6 And Then There Were None Agatha Christie 122 123TABLE 124 ], 125 [ 126 ['ISBN', 'Title', 'Author'], 127 $books, 128 'borderless', 129<<<'TABLE' 130 =============== ========================== ================== 131 ISBN Title Author 132 =============== ========================== ================== 133 99921-58-10-7 Divine Comedy Dante Alighieri 134 9971-5-0210-0 A Tale of Two Cities Charles Dickens 135 960-425-059-0 The Lord of the Rings J. R. R. Tolkien 136 80-902734-1-6 And Then There Were None Agatha Christie 137 =============== ========================== ================== 138 139TABLE 140 ], 141 [ 142 ['ISBN', 'Title'], 143 [ 144 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'], 145 ['9971-5-0210-0'], 146 ['960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'], 147 ['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'], 148 ], 149 'default', 150<<<'TABLE' 151+---------------+--------------------------+------------------+ 152| ISBN | Title | | 153+---------------+--------------------------+------------------+ 154| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 155| 9971-5-0210-0 | | | 156| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | 157| 80-902734-1-6 | And Then There Were None | Agatha Christie | 158+---------------+--------------------------+------------------+ 159 160TABLE 161 ], 162 [ 163 [], 164 [ 165 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'], 166 ['9971-5-0210-0'], 167 ['960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'], 168 ['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'], 169 ], 170 'default', 171<<<'TABLE' 172+---------------+--------------------------+------------------+ 173| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 174| 9971-5-0210-0 | | | 175| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | 176| 80-902734-1-6 | And Then There Were None | Agatha Christie | 177+---------------+--------------------------+------------------+ 178 179TABLE 180 ], 181 [ 182 ['ISBN', 'Title', 'Author'], 183 [ 184 ['99921-58-10-7', "Divine\nComedy", 'Dante Alighieri'], 185 ['9971-5-0210-2', "Harry Potter\nand the Chamber of Secrets", "Rowling\nJoanne K."], 186 ['9971-5-0210-2', "Harry Potter\nand the Chamber of Secrets", "Rowling\nJoanne K."], 187 ['960-425-059-0', 'The Lord of the Rings', "J. R. R.\nTolkien"], 188 ], 189 'default', 190<<<'TABLE' 191+---------------+----------------------------+-----------------+ 192| ISBN | Title | Author | 193+---------------+----------------------------+-----------------+ 194| 99921-58-10-7 | Divine | Dante Alighieri | 195| | Comedy | | 196| 9971-5-0210-2 | Harry Potter | Rowling | 197| | and the Chamber of Secrets | Joanne K. | 198| 9971-5-0210-2 | Harry Potter | Rowling | 199| | and the Chamber of Secrets | Joanne K. | 200| 960-425-059-0 | The Lord of the Rings | J. R. R. | 201| | | Tolkien | 202+---------------+----------------------------+-----------------+ 203 204TABLE 205 ], 206 [ 207 ['ISBN', 'Title'], 208 [], 209 'default', 210<<<'TABLE' 211+------+-------+ 212| ISBN | Title | 213+------+-------+ 214 215TABLE 216 ], 217 [ 218 [], 219 [], 220 'default', 221 '', 222 ], 223 'Cell text with tags used for Output styling' => [ 224 ['ISBN', 'Title', 'Author'], 225 [ 226 ['<info>99921-58-10-7</info>', '<error>Divine Comedy</error>', '<fg=blue;bg=white>Dante Alighieri</fg=blue;bg=white>'], 227 ['9971-5-0210-0', 'A Tale of Two Cities', '<info>Charles Dickens</>'], 228 ], 229 'default', 230<<<'TABLE' 231+---------------+----------------------+-----------------+ 232| ISBN | Title | Author | 233+---------------+----------------------+-----------------+ 234| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 235| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 236+---------------+----------------------+-----------------+ 237 238TABLE 239 ], 240 'Cell text with tags not used for Output styling' => [ 241 ['ISBN', 'Title', 'Author'], 242 [ 243 ['<strong>99921-58-10-700</strong>', '<f>Divine Com</f>', 'Dante Alighieri'], 244 ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'], 245 ], 246 'default', 247<<<'TABLE' 248+----------------------------------+----------------------+-----------------+ 249| ISBN | Title | Author | 250+----------------------------------+----------------------+-----------------+ 251| <strong>99921-58-10-700</strong> | <f>Divine Com</f> | Dante Alighieri | 252| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 253+----------------------------------+----------------------+-----------------+ 254 255TABLE 256 ], 257 'Cell with colspan' => [ 258 ['ISBN', 'Title', 'Author'], 259 [ 260 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'], 261 new TableSeparator(), 262 [new TableCell('Divine Comedy(Dante Alighieri)', ['colspan' => 3])], 263 new TableSeparator(), 264 [ 265 new TableCell('Arduino: A Quick-Start Guide', ['colspan' => 2]), 266 'Mark Schmidt', 267 ], 268 new TableSeparator(), 269 [ 270 '9971-5-0210-0', 271 new TableCell("A Tale of \nTwo Cities", ['colspan' => 2]), 272 ], 273 new TableSeparator(), 274 [ 275 new TableCell('Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil!', ['colspan' => 3]), 276 ], 277 ], 278 'default', 279<<<'TABLE' 280+-------------------------------+-------------------------------+-----------------------------+ 281| ISBN | Title | Author | 282+-------------------------------+-------------------------------+-----------------------------+ 283| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 284+-------------------------------+-------------------------------+-----------------------------+ 285| Divine Comedy(Dante Alighieri) | 286+-------------------------------+-------------------------------+-----------------------------+ 287| Arduino: A Quick-Start Guide | Mark Schmidt | 288+-------------------------------+-------------------------------+-----------------------------+ 289| 9971-5-0210-0 | A Tale of | 290| | Two Cities | 291+-------------------------------+-------------------------------+-----------------------------+ 292| Cupiditate dicta atque porro, tempora exercitationem modi animi nulla nemo vel nihil! | 293+-------------------------------+-------------------------------+-----------------------------+ 294 295TABLE 296 ], 297 'Cell with rowspan' => [ 298 ['ISBN', 'Title', 'Author'], 299 [ 300 [ 301 new TableCell('9971-5-0210-0', ['rowspan' => 3]), 302 new TableCell('Divine Comedy', ['rowspan' => 2]), 303 'Dante Alighieri', 304 ], 305 [], 306 ["The Lord of \nthe Rings", "J. R. \nR. Tolkien"], 307 new TableSeparator(), 308 ['80-902734-1-6', new TableCell("And Then \nThere \nWere None", ['rowspan' => 3]), 'Agatha Christie'], 309 ['80-902734-1-7', 'Test'], 310 ], 311 'default', 312<<<'TABLE' 313+---------------+---------------+-----------------+ 314| ISBN | Title | Author | 315+---------------+---------------+-----------------+ 316| 9971-5-0210-0 | Divine Comedy | Dante Alighieri | 317| | | | 318| | The Lord of | J. R. | 319| | the Rings | R. Tolkien | 320+---------------+---------------+-----------------+ 321| 80-902734-1-6 | And Then | Agatha Christie | 322| 80-902734-1-7 | There | Test | 323| | Were None | | 324+---------------+---------------+-----------------+ 325 326TABLE 327 ], 328 'Cell with rowspan and colspan' => [ 329 ['ISBN', 'Title', 'Author'], 330 [ 331 [ 332 new TableCell('9971-5-0210-0', ['rowspan' => 2, 'colspan' => 2]), 333 'Dante Alighieri', 334 ], 335 ['Charles Dickens'], 336 new TableSeparator(), 337 [ 338 'Dante Alighieri', 339 new TableCell('9971-5-0210-0', ['rowspan' => 3, 'colspan' => 2]), 340 ], 341 ['J. R. R. Tolkien'], 342 ['J. R. R'], 343 ], 344 'default', 345<<<'TABLE' 346+------------------+---------+-----------------+ 347| ISBN | Title | Author | 348+------------------+---------+-----------------+ 349| 9971-5-0210-0 | Dante Alighieri | 350| | Charles Dickens | 351+------------------+---------+-----------------+ 352| Dante Alighieri | 9971-5-0210-0 | 353| J. R. R. Tolkien | | 354| J. R. R | | 355+------------------+---------+-----------------+ 356 357TABLE 358 ], 359 'Cell with rowspan and colspan contains new line break' => [ 360 ['ISBN', 'Title', 'Author'], 361 [ 362 [ 363 new TableCell("9971\n-5-\n021\n0-0", ['rowspan' => 2, 'colspan' => 2]), 364 'Dante Alighieri', 365 ], 366 ['Charles Dickens'], 367 new TableSeparator(), 368 [ 369 'Dante Alighieri', 370 new TableCell("9971\n-5-\n021\n0-0", ['rowspan' => 2, 'colspan' => 2]), 371 ], 372 ['Charles Dickens'], 373 new TableSeparator(), 374 [ 375 new TableCell("9971\n-5-\n021\n0-0", ['rowspan' => 2, 'colspan' => 2]), 376 new TableCell("Dante \nAlighieri", ['rowspan' => 2, 'colspan' => 1]), 377 ], 378 ], 379 'default', 380<<<'TABLE' 381+-----------------+-------+-----------------+ 382| ISBN | Title | Author | 383+-----------------+-------+-----------------+ 384| 9971 | Dante Alighieri | 385| -5- | Charles Dickens | 386| 021 | | 387| 0-0 | | 388+-----------------+-------+-----------------+ 389| Dante Alighieri | 9971 | 390| Charles Dickens | -5- | 391| | 021 | 392| | 0-0 | 393+-----------------+-------+-----------------+ 394| 9971 | Dante | 395| -5- | Alighieri | 396| 021 | | 397| 0-0 | | 398+-----------------+-------+-----------------+ 399 400TABLE 401 ], 402 'Cell with rowspan and colspan without using TableSeparator' => [ 403 ['ISBN', 'Title', 'Author'], 404 [ 405 [ 406 new TableCell("9971\n-5-\n021\n0-0", ['rowspan' => 2, 'colspan' => 2]), 407 'Dante Alighieri', 408 ], 409 ['Charles Dickens'], 410 [ 411 'Dante Alighieri', 412 new TableCell("9971\n-5-\n021\n0-0", ['rowspan' => 2, 'colspan' => 2]), 413 ], 414 ['Charles Dickens'], 415 ], 416 'default', 417<<<'TABLE' 418+-----------------+-------+-----------------+ 419| ISBN | Title | Author | 420+-----------------+-------+-----------------+ 421| 9971 | Dante Alighieri | 422| -5- | Charles Dickens | 423| 021 | | 424| 0-0 | | 425| Dante Alighieri | 9971 | 426| Charles Dickens | -5- | 427| | 021 | 428| | 0-0 | 429+-----------------+-------+-----------------+ 430 431TABLE 432 ], 433 'Cell with rowspan and colspan with separator inside a rowspan' => [ 434 ['ISBN', 'Author'], 435 [ 436 [ 437 new TableCell('9971-5-0210-0', ['rowspan' => 3, 'colspan' => 1]), 438 'Dante Alighieri', 439 ], 440 [new TableSeparator()], 441 ['Charles Dickens'], 442 ], 443 'default', 444<<<'TABLE' 445+---------------+-----------------+ 446| ISBN | Author | 447+---------------+-----------------+ 448| 9971-5-0210-0 | Dante Alighieri | 449| |-----------------| 450| | Charles Dickens | 451+---------------+-----------------+ 452 453TABLE 454 ], 455 'Multiple header lines' => [ 456 [ 457 [new TableCell('Main title', ['colspan' => 3])], 458 ['ISBN', 'Title', 'Author'], 459 ], 460 [], 461 'default', 462<<<'TABLE' 463+------+-------+--------+ 464| Main title | 465+------+-------+--------+ 466| ISBN | Title | Author | 467+------+-------+--------+ 468 469TABLE 470 ], 471 'Row with multiple cells' => [ 472 [], 473 [ 474 [ 475 new TableCell('1', ['colspan' => 3]), 476 new TableCell('2', ['colspan' => 2]), 477 new TableCell('3', ['colspan' => 2]), 478 new TableCell('4', ['colspan' => 2]), 479 ], 480 ], 481 'default', 482<<<'TABLE' 483+---+--+--+---+--+---+--+---+--+ 484| 1 | 2 | 3 | 4 | 485+---+--+--+---+--+---+--+---+--+ 486 487TABLE 488 ], 489 'Coslpan and table cells with comment style' => [ 490 [ 491 new TableCell('<comment>Long Title</comment>', ['colspan' => 3]), 492 ], 493 [ 494 [ 495 new TableCell('9971-5-0210-0', ['colspan' => 3]), 496 ], 497 new TableSeparator(), 498 [ 499 'Dante Alighieri', 500 'J. R. R. Tolkien', 501 'J. R. R', 502 ], 503 ], 504 'default', 505 <<<TABLE 506+-----------------+------------------+---------+ 507|\033[32m \033[39m\033[33mLong Title\033[39m\033[32m \033[39m| 508+-----------------+------------------+---------+ 509| 9971-5-0210-0 | 510+-----------------+------------------+---------+ 511| Dante Alighieri | J. R. R. Tolkien | J. R. R | 512+-----------------+------------------+---------+ 513 514TABLE 515 , 516 true, 517 ], 518 'Row with formatted cells containing a newline' => [ 519 [], 520 [ 521 [ 522 new TableCell('<error>Dont break'."\n".'here</error>', ['colspan' => 2]), 523 ], 524 new TableSeparator(), 525 [ 526 'foo', 527 new TableCell('<error>Dont break'."\n".'here</error>', ['rowspan' => 2]), 528 ], 529 [ 530 'bar', 531 ], 532 ], 533 'default', 534 <<<'TABLE' 535+-------+------------+ 536[39;49m| [39;49m[37;41mDont break[39;49m[39;49m |[39;49m 537[39;49m| [39;49m[37;41mhere[39;49m | 538+-------+------------+ 539[39;49m| foo | [39;49m[37;41mDont break[39;49m[39;49m |[39;49m 540[39;49m| bar | [39;49m[37;41mhere[39;49m | 541+-------+------------+ 542 543TABLE 544 , 545 true, 546 ], 547 ]; 548 } 549 550 public function testRenderMultiByte() 551 { 552 $table = new Table($output = $this->getOutputStream()); 553 $table 554 ->setHeaders(['■■']) 555 ->setRows([[1234]]) 556 ->setStyle('default') 557 ; 558 $table->render(); 559 560 $expected = 561<<<'TABLE' 562+------+ 563| ■■ | 564+------+ 565| 1234 | 566+------+ 567 568TABLE; 569 570 $this->assertEquals($expected, $this->getOutputContent($output)); 571 } 572 573 public function testTableCellWithNumericIntValue() 574 { 575 $table = new Table($output = $this->getOutputStream()); 576 577 $table->setRows([[new TableCell(12345)]]); 578 $table->render(); 579 580 $expected = 581<<<'TABLE' 582+-------+ 583| 12345 | 584+-------+ 585 586TABLE; 587 588 $this->assertEquals($expected, $this->getOutputContent($output)); 589 } 590 591 public function testTableCellWithNumericFloatValue() 592 { 593 $table = new Table($output = $this->getOutputStream()); 594 595 $table->setRows([[new TableCell(12345.01)]]); 596 $table->render(); 597 598 $expected = 599<<<'TABLE' 600+----------+ 601| 12345.01 | 602+----------+ 603 604TABLE; 605 606 $this->assertEquals($expected, $this->getOutputContent($output)); 607 } 608 609 public function testStyle() 610 { 611 $style = new TableStyle(); 612 $style 613 ->setHorizontalBorderChar('.') 614 ->setVerticalBorderChar('.') 615 ->setCrossingChar('.') 616 ; 617 618 Table::setStyleDefinition('dotfull', $style); 619 $table = new Table($output = $this->getOutputStream()); 620 $table 621 ->setHeaders(['Foo']) 622 ->setRows([['Bar']]) 623 ->setStyle('dotfull'); 624 $table->render(); 625 626 $expected = 627<<<'TABLE' 628....... 629. Foo . 630....... 631. Bar . 632....... 633 634TABLE; 635 636 $this->assertEquals($expected, $this->getOutputContent($output)); 637 } 638 639 public function testRowSeparator() 640 { 641 $table = new Table($output = $this->getOutputStream()); 642 $table 643 ->setHeaders(['Foo']) 644 ->setRows([ 645 ['Bar1'], 646 new TableSeparator(), 647 ['Bar2'], 648 new TableSeparator(), 649 ['Bar3'], 650 ]); 651 $table->render(); 652 653 $expected = 654<<<'TABLE' 655+------+ 656| Foo | 657+------+ 658| Bar1 | 659+------+ 660| Bar2 | 661+------+ 662| Bar3 | 663+------+ 664 665TABLE; 666 667 $this->assertEquals($expected, $this->getOutputContent($output)); 668 669 $this->assertEquals($table, $table->addRow(new TableSeparator()), 'fluent interface on addRow() with a single TableSeparator() works'); 670 } 671 672 public function testRenderMultiCalls() 673 { 674 $table = new Table($output = $this->getOutputStream()); 675 $table->setRows([ 676 [new TableCell('foo', ['colspan' => 2])], 677 ]); 678 $table->render(); 679 $table->render(); 680 $table->render(); 681 682 $expected = 683<<<TABLE 684+----+---+ 685| foo | 686+----+---+ 687+----+---+ 688| foo | 689+----+---+ 690+----+---+ 691| foo | 692+----+---+ 693 694TABLE; 695 696 $this->assertEquals($expected, $this->getOutputContent($output)); 697 } 698 699 public function testColumnStyle() 700 { 701 $table = new Table($output = $this->getOutputStream()); 702 $table 703 ->setHeaders(['ISBN', 'Title', 'Author', 'Price']) 704 ->setRows([ 705 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'], 706 ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'], 707 ]); 708 709 $style = new TableStyle(); 710 $style->setPadType(\STR_PAD_LEFT); 711 $table->setColumnStyle(3, $style); 712 713 $table->render(); 714 715 $expected = 716 <<<TABLE 717+---------------+----------------------+-----------------+--------+ 718| ISBN | Title | Author | Price | 719+---------------+----------------------+-----------------+--------+ 720| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 | 721| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 | 722+---------------+----------------------+-----------------+--------+ 723 724TABLE; 725 726 $this->assertEquals($expected, $this->getOutputContent($output)); 727 } 728 729 public function testThrowsWhenTheCellInAnArray() 730 { 731 $this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException'); 732 $this->expectExceptionMessage('A cell must be a TableCell, a scalar or an object implementing "__toString()", "array" given.'); 733 $table = new Table($output = $this->getOutputStream()); 734 $table 735 ->setHeaders(['ISBN', 'Title', 'Author', 'Price']) 736 ->setRows([ 737 ['99921-58-10-7', [], 'Dante Alighieri', '9.95'], 738 ]); 739 740 $table->render(); 741 } 742 743 public function testColumnWidth() 744 { 745 $table = new Table($output = $this->getOutputStream()); 746 $table 747 ->setHeaders(['ISBN', 'Title', 'Author', 'Price']) 748 ->setRows([ 749 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'], 750 ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'], 751 ]) 752 ->setColumnWidth(0, 15) 753 ->setColumnWidth(3, 10); 754 755 $style = new TableStyle(); 756 $style->setPadType(\STR_PAD_LEFT); 757 $table->setColumnStyle(3, $style); 758 759 $table->render(); 760 761 $expected = 762 <<<TABLE 763+-----------------+----------------------+-----------------+------------+ 764| ISBN | Title | Author | Price | 765+-----------------+----------------------+-----------------+------------+ 766| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 | 767| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 | 768+-----------------+----------------------+-----------------+------------+ 769 770TABLE; 771 772 $this->assertEquals($expected, $this->getOutputContent($output)); 773 } 774 775 public function testColumnWidths() 776 { 777 $table = new Table($output = $this->getOutputStream()); 778 $table 779 ->setHeaders(['ISBN', 'Title', 'Author', 'Price']) 780 ->setRows([ 781 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'], 782 ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'], 783 ]) 784 ->setColumnWidths([15, 0, -1, 10]); 785 786 $style = new TableStyle(); 787 $style->setPadType(\STR_PAD_LEFT); 788 $table->setColumnStyle(3, $style); 789 790 $table->render(); 791 792 $expected = 793 <<<TABLE 794+-----------------+----------------------+-----------------+------------+ 795| ISBN | Title | Author | Price | 796+-----------------+----------------------+-----------------+------------+ 797| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 | 798| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 | 799+-----------------+----------------------+-----------------+------------+ 800 801TABLE; 802 803 $this->assertEquals($expected, $this->getOutputContent($output)); 804 } 805 806 public function testIsNotDefinedStyleException() 807 { 808 $this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException'); 809 $this->expectExceptionMessage('Style "absent" is not defined.'); 810 $table = new Table($this->getOutputStream()); 811 $table->setStyle('absent'); 812 } 813 814 public function testGetStyleDefinition() 815 { 816 $this->expectException('Symfony\Component\Console\Exception\InvalidArgumentException'); 817 $this->expectExceptionMessage('Style "absent" is not defined.'); 818 Table::getStyleDefinition('absent'); 819 } 820 821 public function testBoxedStyleWithColspan() 822 { 823 $boxed = new TableStyle(); 824 $boxed 825 ->setHorizontalBorderChar('─') 826 ->setVerticalBorderChar('│') 827 ->setCrossingChar('┼') 828 ; 829 830 $table = new Table($output = $this->getOutputStream()); 831 $table->setStyle($boxed); 832 $table 833 ->setHeaders(['ISBN', 'Title', 'Author']) 834 ->setRows([ 835 ['99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'], 836 new TableSeparator(), 837 [new TableCell('This value spans 3 columns.', ['colspan' => 3])], 838 ]) 839 ; 840 $table->render(); 841 842 $expected = 843 <<<TABLE 844┼───────────────┼───────────────┼─────────────────┼ 845│ ISBN │ Title │ Author │ 846┼───────────────┼───────────────┼─────────────────┼ 847│ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri │ 848┼───────────────┼───────────────┼─────────────────┼ 849│ This value spans 3 columns. │ 850┼───────────────┼───────────────┼─────────────────┼ 851 852TABLE; 853 854 $this->assertSame($expected, $this->getOutputContent($output)); 855 } 856 857 protected function getOutputStream($decorated = false) 858 { 859 return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, $decorated); 860 } 861 862 protected function getOutputContent(StreamOutput $output) 863 { 864 rewind($output->getStream()); 865 866 return str_replace(\PHP_EOL, "\n", stream_get_contents($output->getStream())); 867 } 868} 869