CommandCollectionTest.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.5.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\Console;
  16. use Cake\Console\CommandCollection;
  17. use Cake\Core\Configure;
  18. use Cake\Core\Plugin;
  19. use Cake\Shell\I18nShell;
  20. use Cake\Shell\RoutesShell;
  21. use Cake\TestSuite\TestCase;
  22. use stdClass;
  23. use TestApp\Command\DemoCommand;
  24. /**
  25. * Test case for the CommandCollection
  26. */
  27. class CommandCollectionTest extends TestCase
  28. {
  29. public function setUp()
  30. {
  31. parent::setUp();
  32. Configure::write('App.namespace', 'TestApp');
  33. }
  34. /**
  35. * Test constructor with valid classnames
  36. *
  37. * @return void
  38. */
  39. public function testConstructor()
  40. {
  41. $collection = new CommandCollection([
  42. 'i18n' => I18nShell::class,
  43. 'routes' => RoutesShell::class
  44. ]);
  45. $this->assertTrue($collection->has('routes'));
  46. $this->assertTrue($collection->has('i18n'));
  47. $this->assertCount(2, $collection);
  48. }
  49. /**
  50. * Constructor with invalid class names should blow up
  51. *
  52. * @return void
  53. */
  54. public function testConstructorInvalidClass()
  55. {
  56. $this->expectException(\InvalidArgumentException::class);
  57. $this->expectExceptionMessage('Cannot use \'stdClass\' for command \'nope\' it is not a subclass of Cake\Console\Shell');
  58. new CommandCollection([
  59. 'i18n' => I18nShell::class,
  60. 'nope' => stdClass::class
  61. ]);
  62. }
  63. /**
  64. * Test basic add/get
  65. *
  66. * @return void
  67. */
  68. public function testAdd()
  69. {
  70. $collection = new CommandCollection();
  71. $this->assertSame($collection, $collection->add('routes', RoutesShell::class));
  72. $this->assertTrue($collection->has('routes'));
  73. $this->assertSame(RoutesShell::class, $collection->get('routes'));
  74. }
  75. /**
  76. * test adding a command instance.
  77. *
  78. * @return void
  79. */
  80. public function testAddCommand()
  81. {
  82. $collection = new CommandCollection();
  83. $this->assertSame($collection, $collection->add('ex', DemoCommand::class));
  84. $this->assertTrue($collection->has('ex'));
  85. $this->assertSame(DemoCommand::class, $collection->get('ex'));
  86. }
  87. /**
  88. * Test that add() replaces.
  89. *
  90. * @return void
  91. */
  92. public function testAddReplace()
  93. {
  94. $collection = new CommandCollection();
  95. $this->assertSame($collection, $collection->add('routes', RoutesShell::class));
  96. $this->assertSame($collection, $collection->add('routes', I18nShell::class));
  97. $this->assertTrue($collection->has('routes'));
  98. $this->assertSame(I18nShell::class, $collection->get('routes'));
  99. }
  100. /**
  101. * Test adding with instances
  102. *
  103. * @return void
  104. */
  105. public function testAddInstance()
  106. {
  107. $collection = new CommandCollection();
  108. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')
  109. ->disableOriginalConstructor()
  110. ->getMock();
  111. $shell = new RoutesShell($io);
  112. $collection->add('routes', $shell);
  113. $this->assertTrue($collection->has('routes'));
  114. $this->assertSame($shell, $collection->get('routes'));
  115. }
  116. /**
  117. * Instances that are not shells should fail.
  118. *
  119. */
  120. public function testAddInvalidInstance()
  121. {
  122. $this->expectException(\InvalidArgumentException::class);
  123. $this->expectExceptionMessage('Cannot use \'stdClass\' for command \'routes\' it is not a subclass of Cake\Console\Shell');
  124. $collection = new CommandCollection();
  125. $shell = new stdClass();
  126. $collection->add('routes', $shell);
  127. }
  128. /**
  129. * Class names that are not shells should fail
  130. *
  131. */
  132. public function testInvalidShellClassName()
  133. {
  134. $this->expectException(\InvalidArgumentException::class);
  135. $this->expectExceptionMessage('Cannot use \'stdClass\' for command \'routes\' it is not a subclass of Cake\Console\Shell');
  136. $collection = new CommandCollection();
  137. $collection->add('routes', stdClass::class);
  138. }
  139. /**
  140. * Test removing a command
  141. *
  142. * @return void
  143. */
  144. public function testRemove()
  145. {
  146. $collection = new CommandCollection();
  147. $collection->add('routes', RoutesShell::class);
  148. $this->assertSame($collection, $collection->remove('routes'));
  149. $this->assertFalse($collection->has('routes'));
  150. }
  151. /**
  152. * Removing an unknown command does not fail
  153. *
  154. * @return void
  155. */
  156. public function testRemoveUnknown()
  157. {
  158. $collection = new CommandCollection();
  159. $this->assertSame($collection, $collection->remove('nope'));
  160. $this->assertFalse($collection->has('nope'));
  161. }
  162. /**
  163. * test getIterator
  164. *
  165. * @return void
  166. */
  167. public function testGetIterator()
  168. {
  169. $in = [
  170. 'i18n' => I18nShell::class,
  171. 'routes' => RoutesShell::class
  172. ];
  173. $collection = new CommandCollection($in);
  174. $out = [];
  175. foreach ($collection as $key => $value) {
  176. $out[$key] = $value;
  177. }
  178. $this->assertEquals($in, $out);
  179. }
  180. /**
  181. * test autodiscovering app shells
  182. *
  183. * @return void
  184. */
  185. public function testAutoDiscoverApp()
  186. {
  187. $collection = new CommandCollection();
  188. $collection->addMany($collection->autoDiscover());
  189. $this->assertTrue($collection->has('app'));
  190. $this->assertTrue($collection->has('demo'));
  191. $this->assertTrue($collection->has('i18m'));
  192. $this->assertTrue($collection->has('sample'));
  193. $this->assertTrue($collection->has('testing_dispatch'));
  194. $this->assertSame('TestApp\Shell\AppShell', $collection->get('app'));
  195. $this->assertSame('TestApp\Command\DemoCommand', $collection->get('demo'));
  196. $this->assertSame('TestApp\Shell\I18mShell', $collection->get('i18m'));
  197. $this->assertSame('TestApp\Shell\SampleShell', $collection->get('sample'));
  198. }
  199. /**
  200. * test autodiscovering core shells
  201. *
  202. * @return void
  203. */
  204. public function testAutoDiscoverCore()
  205. {
  206. $collection = new CommandCollection();
  207. $collection->addMany($collection->autoDiscover());
  208. $this->assertTrue($collection->has('version'));
  209. $this->assertTrue($collection->has('routes'));
  210. $this->assertTrue($collection->has('i18n'));
  211. $this->assertTrue($collection->has('orm_cache'));
  212. $this->assertTrue($collection->has('server'));
  213. $this->assertTrue($collection->has('cache'));
  214. $this->assertFalse($collection->has('command_list'), 'Hidden commands should stay hidden');
  215. // These have to be strings as ::class uses the local namespace.
  216. $this->assertSame('Cake\Shell\RoutesShell', $collection->get('routes'));
  217. $this->assertSame('Cake\Shell\I18nShell', $collection->get('i18n'));
  218. $this->assertSame('Cake\Command\VersionCommand', $collection->get('version'));
  219. }
  220. /**
  221. * test missing plugin discovery
  222. *
  223. * @return void
  224. */
  225. public function testDiscoverPluginUnknown()
  226. {
  227. $collection = new CommandCollection();
  228. $this->assertSame([], $collection->discoverPlugin('Nope'));
  229. }
  230. /**
  231. * test autodiscovering plugin shells
  232. *
  233. * @return void
  234. */
  235. public function testDiscoverPlugin()
  236. {
  237. Plugin::load('TestPlugin');
  238. Plugin::load('Company/TestPluginThree');
  239. $collection = new CommandCollection();
  240. // Add a dupe to test de-duping
  241. $collection->add('sample', DemoCommand::class);
  242. $result = $collection->discoverPlugin('TestPlugin');
  243. $this->assertArrayHasKey(
  244. 'example',
  245. $result,
  246. 'Used short name for unique plugin shell'
  247. );
  248. $this->assertArrayHasKey(
  249. 'test_plugin.example',
  250. $result,
  251. 'Long names are stored for unique shells'
  252. );
  253. $this->assertArrayNotHasKey('sample', $result, 'Existing command not output');
  254. $this->assertArrayHasKey(
  255. 'test_plugin.sample',
  256. $result,
  257. 'Duplicate shell was given a full alias'
  258. );
  259. $this->assertEquals('TestPlugin\Shell\ExampleShell', $result['example']);
  260. $this->assertEquals($result['example'], $result['test_plugin.example']);
  261. $this->assertEquals('TestPlugin\Shell\SampleShell', $result['test_plugin.sample']);
  262. $result = $collection->discoverPlugin('Company/TestPluginThree');
  263. $this->assertArrayHasKey(
  264. 'company',
  265. $result,
  266. 'Used short name for unique plugin shell'
  267. );
  268. $this->assertArrayHasKey(
  269. 'company/test_plugin_three.company',
  270. $result,
  271. 'Long names are stored as well'
  272. );
  273. $this->assertSame($result['company'], $result['company/test_plugin_three.company']);
  274. }
  275. }