TableHelperTest.php 15 KB

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