CommandTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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.6.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\Console;
  17. use Cake\Command\Command;
  18. use Cake\Console\ConsoleIo;
  19. use Cake\Console\ConsoleOptionParser;
  20. use Cake\Console\Exception\StopException;
  21. use Cake\ORM\Locator\TableLocator;
  22. use Cake\ORM\Table;
  23. use Cake\TestSuite\Stub\ConsoleOutput;
  24. use Cake\TestSuite\TestCase;
  25. use InvalidArgumentException;
  26. use TestApp\Command\AbortCommand;
  27. use TestApp\Command\AutoLoadModelCommand;
  28. use TestApp\Command\DemoCommand;
  29. /**
  30. * Test case for Console\Command
  31. */
  32. class CommandTest extends TestCase
  33. {
  34. /**
  35. * test orm locator is setup
  36. *
  37. * @return void
  38. */
  39. public function testConstructorSetsLocator()
  40. {
  41. $command = new Command();
  42. $result = $command->getTableLocator();
  43. $this->assertInstanceOf(TableLocator::class, $result);
  44. }
  45. /**
  46. * test loadModel is configured properly
  47. *
  48. * @return void
  49. */
  50. public function testConstructorLoadModel()
  51. {
  52. $command = new Command();
  53. $command->loadModel('Comments');
  54. $this->assertInstanceOf(Table::class, $command->Comments);
  55. }
  56. /**
  57. * test loadModel is configured properly
  58. *
  59. * @return void
  60. */
  61. public function testConstructorAutoLoadModel()
  62. {
  63. $command = new AutoLoadModelCommand();
  64. $this->assertInstanceOf(Table::class, $command->Posts);
  65. }
  66. /**
  67. * Test name
  68. *
  69. * @return void
  70. */
  71. public function testSetName()
  72. {
  73. $command = new Command();
  74. $this->assertSame($command, $command->setName('routes show'));
  75. $this->assertSame('routes show', $command->getName());
  76. $this->assertSame('routes', $command->getRootName());
  77. }
  78. /**
  79. * Test invalid name
  80. *
  81. * @return void
  82. */
  83. public function testSetNameInvalid()
  84. {
  85. $this->expectException(InvalidArgumentException::class);
  86. $this->expectExceptionMessage('The name \'routes_show\' is missing a space. Names should look like `cake routes`');
  87. $command = new Command();
  88. $command->setName('routes_show');
  89. }
  90. /**
  91. * Test invalid name
  92. *
  93. * @return void
  94. */
  95. public function testSetNameInvalidLeadingSpace()
  96. {
  97. $this->expectException(InvalidArgumentException::class);
  98. $command = new Command();
  99. $command->setName(' routes_show');
  100. }
  101. /**
  102. * Test option parser fetching
  103. *
  104. * @return void
  105. */
  106. public function testGetOptionParser()
  107. {
  108. $command = new Command();
  109. $command->setName('cake routes show');
  110. $parser = $command->getOptionParser();
  111. $this->assertInstanceOf(ConsoleOptionParser::class, $parser);
  112. $this->assertSame('routes show', $parser->getCommand());
  113. }
  114. /**
  115. * Test that initialize is called.
  116. *
  117. * @return void
  118. */
  119. public function testRunCallsInitialize()
  120. {
  121. $command = $this->getMockBuilder(Command::class)
  122. ->setMethods(['initialize'])
  123. ->getMock();
  124. $command->setName('cake example');
  125. $command->expects($this->once())->method('initialize');
  126. $command->run([], $this->getMockIo(new ConsoleOutput()));
  127. }
  128. /**
  129. * Test run() outputs help
  130. *
  131. * @return void
  132. */
  133. public function testRunOutputHelp()
  134. {
  135. $command = new Command();
  136. $command->setName('cake demo');
  137. $output = new ConsoleOutput();
  138. $this->assertSame(
  139. Command::CODE_SUCCESS,
  140. $command->run(['-h'], $this->getMockIo($output))
  141. );
  142. $messages = implode("\n", $output->messages());
  143. $this->assertStringNotContainsString('Demo', $messages);
  144. $this->assertStringContainsString('cake demo [-h]', $messages);
  145. }
  146. /**
  147. * Test run() outputs help
  148. *
  149. * @return void
  150. */
  151. public function testRunOutputHelpLongOption()
  152. {
  153. $command = new Command();
  154. $command->setName('cake demo');
  155. $output = new ConsoleOutput();
  156. $this->assertSame(
  157. Command::CODE_SUCCESS,
  158. $command->run(['--help'], $this->getMockIo($output))
  159. );
  160. $messages = implode("\n", $output->messages());
  161. $this->assertStringNotContainsString('Demo', $messages);
  162. $this->assertStringContainsString('cake demo [-h]', $messages);
  163. }
  164. /**
  165. * Test run() sets output level
  166. *
  167. * @return void
  168. */
  169. public function testRunVerboseOption()
  170. {
  171. $command = new DemoCommand();
  172. $command->setName('cake demo');
  173. $output = new ConsoleOutput();
  174. $this->assertNull($command->run(['--verbose'], $this->getMockIo($output)));
  175. $messages = implode("\n", $output->messages());
  176. $this->assertStringContainsString('Verbose!', $messages);
  177. $this->assertStringContainsString('Demo Command!', $messages);
  178. $this->assertStringContainsString('Quiet!', $messages);
  179. $this->assertStringNotContainsString('cake demo [-h]', $messages);
  180. }
  181. /**
  182. * Test run() sets output level
  183. *
  184. * @return void
  185. */
  186. public function testRunQuietOption()
  187. {
  188. $command = new DemoCommand();
  189. $command->setName('cake demo');
  190. $output = new ConsoleOutput();
  191. $this->assertNull($command->run(['--quiet'], $this->getMockIo($output)));
  192. $messages = implode("\n", $output->messages());
  193. $this->assertStringContainsString('Quiet!', $messages);
  194. $this->assertStringNotContainsString('Verbose!', $messages);
  195. $this->assertStringNotContainsString('Demo Command!', $messages);
  196. }
  197. /**
  198. * Test run() sets option parser failure
  199. *
  200. * @return void
  201. */
  202. public function testRunOptionParserFailure()
  203. {
  204. $command = $this->getMockBuilder(Command::class)
  205. ->setMethods(['getOptionParser'])
  206. ->getMock();
  207. $parser = new ConsoleOptionParser('cake example');
  208. $parser->addArgument('name', ['required' => true]);
  209. $command->method('getOptionParser')->will($this->returnValue($parser));
  210. $output = new ConsoleOutput();
  211. $result = $command->run([], $this->getMockIo($output));
  212. $this->assertSame(Command::CODE_ERROR, $result);
  213. $messages = implode("\n", $output->messages());
  214. $this->assertStringContainsString(
  215. 'Error: Missing required arguments. The `name` argument is required',
  216. $messages
  217. );
  218. }
  219. /**
  220. * Test abort()
  221. *
  222. * @return void
  223. */
  224. public function testAbort()
  225. {
  226. $this->expectException(StopException::class);
  227. $this->expectExceptionCode(1);
  228. $command = new Command();
  229. $command->abort();
  230. }
  231. /**
  232. * Test abort()
  233. *
  234. * @return void
  235. */
  236. public function testAbortCustomCode()
  237. {
  238. $this->expectException(StopException::class);
  239. $this->expectExceptionCode(99);
  240. $command = new Command();
  241. $command->abort(99);
  242. }
  243. /**
  244. * test executeCommand with a string class
  245. *
  246. * @return void
  247. */
  248. public function testExecuteCommandString()
  249. {
  250. $output = new ConsoleOutput();
  251. $command = new Command();
  252. $result = $command->executeCommand(DemoCommand::class, [], $this->getMockIo($output));
  253. $this->assertNull($result);
  254. $this->assertEquals(['Quiet!', 'Demo Command!'], $output->messages());
  255. }
  256. /**
  257. * test executeCommand with an invalid string class
  258. *
  259. * @return void
  260. */
  261. public function testExecuteCommandStringInvalid()
  262. {
  263. $this->expectException(InvalidArgumentException::class);
  264. $this->expectExceptionMessage("Command class 'Nope' does not exist");
  265. $command = new Command();
  266. $command->executeCommand('Nope', [], $this->getMockIo(new ConsoleOutput()));
  267. }
  268. /**
  269. * test executeCommand with arguments
  270. *
  271. * @return void
  272. */
  273. public function testExecuteCommandArguments()
  274. {
  275. $output = new ConsoleOutput();
  276. $command = new Command();
  277. $command->executeCommand(DemoCommand::class, ['Jane'], $this->getMockIo($output));
  278. $this->assertEquals(['Quiet!', 'Demo Command!', 'Jane'], $output->messages());
  279. }
  280. /**
  281. * test executeCommand with arguments
  282. *
  283. * @return void
  284. */
  285. public function testExecuteCommandArgumentsOptions()
  286. {
  287. $output = new ConsoleOutput();
  288. $command = new Command();
  289. $command->executeCommand(DemoCommand::class, ['--quiet', 'Jane'], $this->getMockIo($output));
  290. $this->assertEquals(['Quiet!'], $output->messages());
  291. }
  292. /**
  293. * test executeCommand with an instance
  294. *
  295. * @return void
  296. */
  297. public function testExecuteCommandInstance()
  298. {
  299. $output = new ConsoleOutput();
  300. $command = new Command();
  301. $result = $command->executeCommand(new DemoCommand(), [], $this->getMockIo($output));
  302. $this->assertNull($result);
  303. $this->assertEquals(['Quiet!', 'Demo Command!'], $output->messages());
  304. }
  305. /**
  306. * test executeCommand with an abort
  307. *
  308. * @return void
  309. */
  310. public function testExecuteCommandAbort()
  311. {
  312. $output = new ConsoleOutput();
  313. $command = new Command();
  314. $result = $command->executeCommand(AbortCommand::class, [], $this->getMockIo($output));
  315. $this->assertSame(127, $result);
  316. $this->assertEquals(['<error>Command aborted</error>'], $output->messages());
  317. }
  318. /**
  319. * test executeCommand with an invalid instance
  320. *
  321. * @return void
  322. */
  323. public function testExecuteCommandInstanceInvalid()
  324. {
  325. $this->expectException(InvalidArgumentException::class);
  326. $this->expectExceptionMessage("Command 'stdClass' is not a subclass");
  327. $command = new Command();
  328. $command->executeCommand(new \stdClass(), [], $this->getMockIo(new ConsoleOutput()));
  329. }
  330. protected function getMockIo($output)
  331. {
  332. $io = $this->getMockBuilder(ConsoleIo::class)
  333. ->setConstructorArgs([$output, $output, null, null])
  334. ->setMethods(['in'])
  335. ->getMock();
  336. return $io;
  337. }
  338. }