TableHelperTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP Project
  13. * @since 3.1.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\Command\Helper;
  17. use Cake\Command\Helper\TableHelper;
  18. use Cake\Console\ConsoleIo;
  19. use Cake\Console\TestSuite\StubConsoleOutput;
  20. use Cake\TestSuite\TestCase;
  21. /**
  22. * TableHelper test.
  23. */
  24. class TableHelperTest extends TestCase
  25. {
  26. /**
  27. * @var \Cake\Console\TestSuite\StubConsoleOutput
  28. */
  29. protected StubConsoleOutput $stub;
  30. /**
  31. * @var \Cake\Console\ConsoleIo
  32. */
  33. protected ConsoleIo $io;
  34. /**
  35. * @var \Cake\Shell\Helper\TableHelper
  36. */
  37. protected TableHelper $helper;
  38. /**
  39. * setUp method
  40. */
  41. public function setUp(): void
  42. {
  43. parent::setUp();
  44. $this->stub = new StubConsoleOutput();
  45. $this->io = new ConsoleIo($this->stub);
  46. $this->helper = new TableHelper($this->io);
  47. }
  48. /**
  49. * Test output
  50. */
  51. public function testOutputDefaultOutput(): void
  52. {
  53. $data = [
  54. ['Header 1', 'Header', 'Long Header'],
  55. ['short', 'Longish thing', 'short'],
  56. ['Longer thing', 'short', 'Longest Value'],
  57. ];
  58. $this->helper->output($data);
  59. $expected = [
  60. '+--------------+---------------+---------------+',
  61. '| <info>Header 1</info> | <info>Header</info> | <info>Long Header</info> |',
  62. '+--------------+---------------+---------------+',
  63. '| short | Longish thing | short |',
  64. '| Longer thing | short | Longest Value |',
  65. '+--------------+---------------+---------------+',
  66. ];
  67. $this->assertEquals($expected, $this->stub->messages());
  68. }
  69. /**
  70. * Test output with inconsistent keys.
  71. *
  72. * When outputting entities or other structured data,
  73. * headers shouldn't need to have the same keys as it is
  74. * annoying to use.
  75. */
  76. public function testOutputInconsistentKeys(): void
  77. {
  78. $data = [
  79. ['Header 1', 'Header', 'Long Header'],
  80. ['a' => 'short', 'b' => 'Longish thing', 'c' => 'short'],
  81. ['c' => 'Longer thing', 'a' => 'short', 'b' => 'Longest Value'],
  82. ];
  83. $this->helper->output($data);
  84. $expected = [
  85. '+--------------+---------------+---------------+',
  86. '| <info>Header 1</info> | <info>Header</info> | <info>Long Header</info> |',
  87. '+--------------+---------------+---------------+',
  88. '| short | Longish thing | short |',
  89. '| Longer thing | short | Longest Value |',
  90. '+--------------+---------------+---------------+',
  91. ];
  92. $this->assertEquals($expected, $this->stub->messages());
  93. }
  94. /**
  95. * Test that output works when data contains just empty strings.
  96. */
  97. public function testOutputEmptyStrings(): void
  98. {
  99. $data = [
  100. ['Header 1', 'Header', 'Empty'],
  101. ['short', 'Longish thing', ''],
  102. ['Longer thing', 'short', ''],
  103. ];
  104. $this->helper->output($data);
  105. $expected = [
  106. '+--------------+---------------+-------+',
  107. '| <info>Header 1</info> | <info>Header</info> | <info>Empty</info> |',
  108. '+--------------+---------------+-------+',
  109. '| short | Longish thing | |',
  110. '| Longer thing | short | |',
  111. '+--------------+---------------+-------+',
  112. ];
  113. $this->assertEquals($expected, $this->stub->messages());
  114. }
  115. /**
  116. * Test that output works when data contains nulls.
  117. */
  118. public function testNullValues(): void
  119. {
  120. $data = [
  121. ['Header 1', 'Header', 'Empty'],
  122. ['short', 'Longish thing', null],
  123. ['Longer thing', 'short', null],
  124. ];
  125. $this->helper->output($data);
  126. $expected = [
  127. '+--------------+---------------+-------+',
  128. '| <info>Header 1</info> | <info>Header</info> | <info>Empty</info> |',
  129. '+--------------+---------------+-------+',
  130. '| short | Longish thing | |',
  131. '| Longer thing | short | |',
  132. '+--------------+---------------+-------+',
  133. ];
  134. $this->assertEquals($expected, $this->stub->messages());
  135. }
  136. /**
  137. * Test output with multi-byte characters
  138. */
  139. public function testOutputUtf8(): void
  140. {
  141. $data = [
  142. ['Header 1', 'Head', 'Long Header'],
  143. ['short', 'ÄÄÄÜÜÜ', 'short'],
  144. ['Longer thing', 'longerish', 'Longest Value'],
  145. ];
  146. $this->helper->output($data);
  147. $expected = [
  148. '+--------------+-----------+---------------+',
  149. '| <info>Header 1</info> | <info>Head</info> | <info>Long Header</info> |',
  150. '+--------------+-----------+---------------+',
  151. '| short | ÄÄÄÜÜÜ | short |',
  152. '| Longer thing | longerish | Longest Value |',
  153. '+--------------+-----------+---------------+',
  154. ];
  155. $this->assertEquals($expected, $this->stub->messages());
  156. }
  157. /**
  158. * Test output with multi-byte characters
  159. */
  160. public function testOutputFullwidth(): void
  161. {
  162. $data = [
  163. ['Header 1', 'Head', 'Long Header'],
  164. ['short', '竜頭蛇尾', 'short'],
  165. ['Longer thing', 'longerish', 'Longest Value'],
  166. ];
  167. $this->helper->output($data);
  168. $expected = [
  169. '+--------------+-----------+---------------+',
  170. '| <info>Header 1</info> | <info>Head</info> | <info>Long Header</info> |',
  171. '+--------------+-----------+---------------+',
  172. '| short | 竜頭蛇尾 | short |',
  173. '| Longer thing | longerish | Longest Value |',
  174. '+--------------+-----------+---------------+',
  175. ];
  176. $this->assertEquals($expected, $this->stub->messages());
  177. }
  178. /**
  179. * Test output without headers
  180. */
  181. public function testOutputWithoutHeaderStyle(): void
  182. {
  183. $data = [
  184. ['Header 1', 'Header', 'Long Header'],
  185. ['short', 'Longish thing', 'short'],
  186. ['Longer thing', 'short', 'Longest Value'],
  187. ];
  188. $this->helper->setConfig(['headerStyle' => false]);
  189. $this->helper->output($data);
  190. $expected = [
  191. '+--------------+---------------+---------------+',
  192. '| Header 1 | Header | Long Header |',
  193. '+--------------+---------------+---------------+',
  194. '| short | Longish thing | short |',
  195. '| Longer thing | short | Longest Value |',
  196. '+--------------+---------------+---------------+',
  197. ];
  198. $this->assertEquals($expected, $this->stub->messages());
  199. }
  200. /**
  201. * Test output with different header style
  202. */
  203. public function testOutputWithDifferentHeaderStyle(): void
  204. {
  205. $data = [
  206. ['Header 1', 'Header', 'Long Header'],
  207. ['short', 'Longish thing', 'short'],
  208. ['Longer thing', 'short', 'Longest Value'],
  209. ];
  210. $this->helper->setConfig(['headerStyle' => 'error']);
  211. $this->helper->output($data);
  212. $expected = [
  213. '+--------------+---------------+---------------+',
  214. '| <error>Header 1</error> | <error>Header</error> | <error>Long Header</error> |',
  215. '+--------------+---------------+---------------+',
  216. '| short | Longish thing | short |',
  217. '| Longer thing | short | Longest Value |',
  218. '+--------------+---------------+---------------+',
  219. ];
  220. $this->assertEquals($expected, $this->stub->messages());
  221. }
  222. /**
  223. * Test output without table headers
  224. */
  225. public function testOutputWithoutHeaders(): void
  226. {
  227. $data = [
  228. ['short', 'Longish thing', 'short'],
  229. ['Longer thing', 'short', 'Longest Value'],
  230. ];
  231. $this->helper->setConfig(['headers' => false]);
  232. $this->helper->output($data);
  233. $expected = [
  234. '+--------------+---------------+---------------+',
  235. '| short | Longish thing | short |',
  236. '| Longer thing | short | Longest Value |',
  237. '+--------------+---------------+---------------+',
  238. ];
  239. $this->assertEquals($expected, $this->stub->messages());
  240. }
  241. /**
  242. * Test output with formatted cells
  243. */
  244. public function testOutputWithFormattedCells(): void
  245. {
  246. $data = [
  247. ['short', 'Longish thing', '<info>short</info>'],
  248. ['Longer thing', 'short', '<warning>Longest</warning> <error>Value</error>'],
  249. ];
  250. $this->helper->setConfig(['headers' => false]);
  251. $this->helper->output($data);
  252. $expected = [
  253. '+--------------+---------------+---------------+',
  254. '| short | Longish thing | <info>short</info> |',
  255. '| Longer thing | short | <warning>Longest</warning> <error>Value</error> |',
  256. '+--------------+---------------+---------------+',
  257. ];
  258. $this->assertEquals($expected, $this->stub->messages());
  259. }
  260. /**
  261. * Test output with row separator
  262. */
  263. public function testOutputWithRowSeparator(): void
  264. {
  265. $data = [
  266. ['Header 1', 'Header', 'Long Header'],
  267. ['short', 'Longish thing', 'short'],
  268. ['Longer thing', 'short', 'Longest Value'],
  269. ];
  270. $this->helper->setConfig(['rowSeparator' => true]);
  271. $this->helper->output($data);
  272. $expected = [
  273. '+--------------+---------------+---------------+',
  274. '| <info>Header 1</info> | <info>Header</info> | <info>Long Header</info> |',
  275. '+--------------+---------------+---------------+',
  276. '| short | Longish thing | short |',
  277. '+--------------+---------------+---------------+',
  278. '| Longer thing | short | Longest Value |',
  279. '+--------------+---------------+---------------+',
  280. ];
  281. $this->assertEquals($expected, $this->stub->messages());
  282. }
  283. /**
  284. * Test output with row separator and no headers
  285. */
  286. public function testOutputWithRowSeparatorAndHeaders(): void
  287. {
  288. $data = [
  289. ['Header 1', 'Header', 'Long Header'],
  290. ['short', 'Longish thing', 'short'],
  291. ['Longer thing', 'short', 'Longest Value'],
  292. ];
  293. $this->helper->setConfig(['rowSeparator' => true]);
  294. $this->helper->output($data);
  295. $expected = [
  296. '+--------------+---------------+---------------+',
  297. '| <info>Header 1</info> | <info>Header</info> | <info>Long Header</info> |',
  298. '+--------------+---------------+---------------+',
  299. '| short | Longish thing | short |',
  300. '+--------------+---------------+---------------+',
  301. '| Longer thing | short | Longest Value |',
  302. '+--------------+---------------+---------------+',
  303. ];
  304. $this->assertEquals($expected, $this->stub->messages());
  305. }
  306. /**
  307. * Test output when there is no data.
  308. */
  309. public function testOutputWithNoData(): void
  310. {
  311. $this->helper->output([]);
  312. $this->assertEquals([], $this->stub->messages());
  313. }
  314. /**
  315. * Test output with a header but no data.
  316. */
  317. public function testOutputWithHeaderAndNoData(): void
  318. {
  319. $data = [
  320. ['Header 1', 'Header', 'Long Header'],
  321. ];
  322. $this->helper->output($data);
  323. $expected = [
  324. '+----------+--------+-------------+',
  325. '| <info>Header 1</info> | <info>Header</info> | <info>Long Header</info> |',
  326. '+----------+--------+-------------+',
  327. ];
  328. $this->assertEquals($expected, $this->stub->messages());
  329. }
  330. /**
  331. * Test no data when headers are disabled.
  332. */
  333. public function testOutputHeaderDisabledNoData(): void
  334. {
  335. $this->helper->setConfig(['header' => false]);
  336. $this->helper->output([]);
  337. $this->assertEquals([], $this->stub->messages());
  338. }
  339. /**
  340. * Right-aligned text style test.
  341. */
  342. public function testTextRightStyle(): void
  343. {
  344. $data = [
  345. ['Item', 'Price per piece (yen)'],
  346. ['Apple', '<text-right><info>¥</info> 200</text-right>'],
  347. ['Orange', '100'],
  348. ];
  349. $this->helper->output($data);
  350. $expected = [
  351. '+--------+-----------------------+',
  352. '| <info>Item</info> | <info>Price per piece (yen)</info> |',
  353. '+--------+-----------------------+',
  354. '| Apple | <info>¥</info> 200 |',
  355. '| Orange | 100 |',
  356. '+--------+-----------------------+',
  357. ];
  358. $this->assertEquals($expected, $this->stub->messages());
  359. }
  360. /**
  361. * Right-aligned text style test.(If there is text rightside the text-right tag)
  362. */
  363. public function testTextRightsideTheTextRightTag(): void
  364. {
  365. $this->expectException(\UnexpectedValueException::class);
  366. $data = [
  367. ['Item', 'Price per piece (yen)'],
  368. ['Apple', '<text-right>some</text-right>text'],
  369. ];
  370. $this->helper->output($data);
  371. }
  372. /**
  373. * Right-aligned text style test.(If there is text leftside the text-right tag)
  374. */
  375. public function testTextLeftsideTheTextRightTag(): void
  376. {
  377. $this->expectException(\UnexpectedValueException::class);
  378. $data = [
  379. ['Item', 'Price per piece (yen)'],
  380. ['Apple', 'text<text-right>some</text-right>'],
  381. ];
  382. $this->helper->output($data);
  383. }
  384. /**
  385. * Table row column of type integer should be cast to string
  386. */
  387. public function testRowValueInteger(): void
  388. {
  389. $data = [
  390. ['Item', 'Quantity'],
  391. ['Cakes', 2],
  392. ];
  393. $this->helper->output($data);
  394. $expected = [
  395. '+-------+----------+',
  396. '| <info>Item</info> | <info>Quantity</info> |',
  397. '+-------+----------+',
  398. '| Cakes | 2 |',
  399. '+-------+----------+',
  400. ];
  401. $this->assertEquals($expected, $this->stub->messages());
  402. }
  403. /**
  404. * Table row column of type null should be cast to empty string
  405. */
  406. public function testRowValueNull(): void
  407. {
  408. $data = [
  409. ['Item', 'Quantity'],
  410. ['Cakes', null],
  411. ];
  412. $this->helper->output($data);
  413. $expected = [
  414. '+-------+----------+',
  415. '| <info>Item</info> | <info>Quantity</info> |',
  416. '+-------+----------+',
  417. '| Cakes | |',
  418. '+-------+----------+',
  419. ];
  420. $this->assertEquals($expected, $this->stub->messages());
  421. }
  422. }