TableTest.php 37KB

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