ShellTest.php 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469
  1. <?php
  2. /**
  3. * CakePHP : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://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. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP Project
  12. * @since 1.2.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Console;
  16. use Cake\Console\ConsoleIo;
  17. use Cake\Console\ConsoleOptionParser;
  18. use Cake\Console\Shell;
  19. use Cake\Core\Plugin;
  20. use Cake\Filesystem\Folder;
  21. use Cake\TestSuite\TestCase;
  22. use TestApp\Shell\TestingDispatchShell;
  23. /**
  24. * for testing merging vars
  25. */
  26. class MergeShell extends Shell
  27. {
  28. public $tasks = ['Command', 'Extract'];
  29. public $modelClass = 'Articles';
  30. }
  31. /**
  32. * ShellTestShell class
  33. */
  34. class ShellTestShell extends Shell
  35. {
  36. /**
  37. * name property
  38. *
  39. * @var string
  40. */
  41. public $name = 'ShellTestShell';
  42. /**
  43. * stopped property
  44. *
  45. * @var int
  46. */
  47. public $stopped;
  48. /**
  49. * testMessage property
  50. *
  51. * @var string
  52. */
  53. public $testMessage = 'all your base are belong to us';
  54. /**
  55. * stop method
  56. *
  57. * @param int $status
  58. * @return void
  59. */
  60. protected function _stop($status = Shell::CODE_SUCCESS)
  61. {
  62. $this->stopped = $status;
  63. }
  64. protected function _secret()
  65. {
  66. }
  67. //@codingStandardsIgnoreStart
  68. public function doSomething()
  69. {
  70. }
  71. protected function noAccess()
  72. {
  73. }
  74. public function logSomething()
  75. {
  76. $this->log($this->testMessage);
  77. }
  78. //@codingStandardsIgnoreEnd
  79. }
  80. /**
  81. * TestAppleTask class
  82. */
  83. class TestAppleTask extends Shell
  84. {
  85. }
  86. /**
  87. * TestBananaTask class
  88. */
  89. class TestBananaTask extends Shell
  90. {
  91. }
  92. class_alias(__NAMESPACE__ . '\TestAppleTask', 'Cake\Shell\Task\TestAppleTask');
  93. class_alias(__NAMESPACE__ . '\TestBananaTask', 'Cake\Shell\Task\TestBananaTask');
  94. /**
  95. * ShellTest class
  96. */
  97. class ShellTest extends TestCase
  98. {
  99. /**
  100. * Fixtures used in this test case
  101. *
  102. * @var array
  103. */
  104. public $fixtures = [
  105. 'core.articles',
  106. 'core.articles_tags',
  107. 'core.attachments',
  108. 'core.comments',
  109. 'core.posts',
  110. 'core.tags',
  111. 'core.users'
  112. ];
  113. /**
  114. * setUp method
  115. *
  116. * @return void
  117. */
  118. public function setUp()
  119. {
  120. parent::setUp();
  121. $this->io = $this->getMockBuilder('Cake\Console\ConsoleIo')
  122. ->disableOriginalConstructor()
  123. ->getMock();
  124. $this->Shell = new ShellTestShell($this->io);
  125. if (is_dir(TMP . 'shell_test')) {
  126. $Folder = new Folder(TMP . 'shell_test');
  127. $Folder->delete();
  128. }
  129. }
  130. /**
  131. * testConstruct method
  132. *
  133. * @return void
  134. */
  135. public function testConstruct()
  136. {
  137. $this->assertEquals('ShellTestShell', $this->Shell->name);
  138. $this->assertInstanceOf(ConsoleIo::class, $this->Shell->getIo());
  139. }
  140. /**
  141. * test io method
  142. *
  143. * @group deprecated
  144. * @return void
  145. */
  146. public function testIo()
  147. {
  148. $this->deprecated(function () {
  149. $this->assertInstanceOf(ConsoleIo::class, $this->Shell->io());
  150. $io = $this->getMockBuilder(ConsoleIo::class)
  151. ->disableOriginalConstructor()
  152. ->getMock();
  153. $this->assertSame($io, $this->Shell->io($io));
  154. $this->assertSame($io, $this->Shell->io());
  155. });
  156. }
  157. /**
  158. * testInitialize method
  159. *
  160. * @return void
  161. */
  162. public function testInitialize()
  163. {
  164. static::setAppNamespace();
  165. Plugin::load('TestPlugin');
  166. $this->Shell->tasks = ['Extract' => ['one', 'two']];
  167. $this->Shell->plugin = 'TestPlugin';
  168. $this->Shell->modelClass = 'TestPlugin.TestPluginComments';
  169. $this->Shell->initialize();
  170. $this->Shell->loadModel();
  171. $this->assertTrue(isset($this->Shell->TestPluginComments));
  172. $this->assertInstanceOf(
  173. 'TestPlugin\Model\Table\TestPluginCommentsTable',
  174. $this->Shell->TestPluginComments
  175. );
  176. }
  177. /**
  178. * test LoadModel method
  179. *
  180. * @return void
  181. */
  182. public function testLoadModel()
  183. {
  184. static::setAppNamespace();
  185. $Shell = new MergeShell();
  186. $this->assertInstanceOf(
  187. 'TestApp\Model\Table\ArticlesTable',
  188. $Shell->Articles
  189. );
  190. $this->assertEquals('Articles', $Shell->modelClass);
  191. Plugin::load('TestPlugin');
  192. $result = $this->Shell->loadModel('TestPlugin.TestPluginComments');
  193. $this->assertInstanceOf(
  194. 'TestPlugin\Model\Table\TestPluginCommentsTable',
  195. $result
  196. );
  197. $this->assertInstanceOf(
  198. 'TestPlugin\Model\Table\TestPluginCommentsTable',
  199. $this->Shell->TestPluginComments
  200. );
  201. }
  202. /**
  203. * testIn method
  204. *
  205. * @return void
  206. */
  207. public function testIn()
  208. {
  209. $this->io->expects($this->at(0))
  210. ->method('askChoice')
  211. ->with('Just a test?', ['y', 'n'], 'n')
  212. ->will($this->returnValue('n'));
  213. $this->io->expects($this->at(1))
  214. ->method('ask')
  215. ->with('Just a test?', 'n')
  216. ->will($this->returnValue('n'));
  217. $result = $this->Shell->in('Just a test?', ['y', 'n'], 'n');
  218. $this->assertEquals('n', $result);
  219. $result = $this->Shell->in('Just a test?', null, 'n');
  220. $this->assertEquals('n', $result);
  221. }
  222. /**
  223. * Test in() when not interactive.
  224. *
  225. * @return void
  226. */
  227. public function testInNonInteractive()
  228. {
  229. $this->io->expects($this->never())
  230. ->method('askChoice');
  231. $this->io->expects($this->never())
  232. ->method('ask');
  233. $this->Shell->interactive = false;
  234. $result = $this->Shell->in('Just a test?', 'y/n', 'n');
  235. $this->assertEquals('n', $result);
  236. }
  237. /**
  238. * testVerbose method
  239. *
  240. * @return void
  241. */
  242. public function testVerbose()
  243. {
  244. $this->io->expects($this->once())
  245. ->method('verbose')
  246. ->with('Just a test', 1);
  247. $this->Shell->verbose('Just a test');
  248. }
  249. /**
  250. * testQuiet method
  251. *
  252. * @return void
  253. */
  254. public function testQuiet()
  255. {
  256. $this->io->expects($this->once())
  257. ->method('quiet')
  258. ->with('Just a test', 1);
  259. $this->Shell->quiet('Just a test');
  260. }
  261. /**
  262. * testOut method
  263. *
  264. * @return void
  265. */
  266. public function testOut()
  267. {
  268. $this->io->expects($this->once())
  269. ->method('out')
  270. ->with('Just a test', 1);
  271. $this->Shell->out('Just a test');
  272. }
  273. /**
  274. * testErr method
  275. *
  276. * @return void
  277. */
  278. public function testErr()
  279. {
  280. $this->io->expects($this->once())
  281. ->method('error')
  282. ->with('Just a test', 1);
  283. $this->Shell->err('Just a test');
  284. }
  285. /**
  286. * testErr method with array
  287. *
  288. * @return void
  289. */
  290. public function testErrArray()
  291. {
  292. $this->io->expects($this->once())
  293. ->method('error')
  294. ->with(['Just', 'a', 'test'], 1);
  295. $this->Shell->err(['Just', 'a', 'test']);
  296. }
  297. /**
  298. * testInfo method
  299. *
  300. * @return void
  301. */
  302. public function testInfo()
  303. {
  304. $this->io->expects($this->once())
  305. ->method('info')
  306. ->with('Just a test', 1);
  307. $this->Shell->info('Just a test');
  308. }
  309. /**
  310. * testInfo method with array
  311. *
  312. * @return void
  313. */
  314. public function testInfoArray()
  315. {
  316. $this->io->expects($this->once())
  317. ->method('info')
  318. ->with(['Just', 'a', 'test'], 1);
  319. $this->Shell->info(['Just', 'a', 'test']);
  320. }
  321. /**
  322. * testWarn method
  323. *
  324. * @return void
  325. */
  326. public function testWarn()
  327. {
  328. $this->io->expects($this->once())
  329. ->method('warning')
  330. ->with('Just a test', 1);
  331. $this->Shell->warn('Just a test');
  332. }
  333. /**
  334. * testWarn method with array
  335. *
  336. * @return void
  337. */
  338. public function testWarnArray()
  339. {
  340. $this->io->expects($this->once())
  341. ->method('warning')
  342. ->with(['Just', 'a', 'test'], 1);
  343. $this->Shell->warn(['Just', 'a', 'test']);
  344. }
  345. /**
  346. * testSuccess method
  347. *
  348. * @return void
  349. */
  350. public function testSuccess()
  351. {
  352. $this->io->expects($this->once())
  353. ->method('success')
  354. ->with('Just a test', 1);
  355. $this->Shell->success('Just a test');
  356. }
  357. /**
  358. * testSuccess method with array
  359. *
  360. * @return void
  361. */
  362. public function testSuccessArray()
  363. {
  364. $this->io->expects($this->once())
  365. ->method('success')
  366. ->with(['Just', 'a', 'test'], 1);
  367. $this->Shell->success(['Just', 'a', 'test']);
  368. }
  369. /**
  370. * testNl
  371. *
  372. * @return void
  373. */
  374. public function testNl()
  375. {
  376. $this->io->expects($this->once())
  377. ->method('nl')
  378. ->with(2);
  379. $this->Shell->nl(2);
  380. }
  381. /**
  382. * testHr
  383. *
  384. * @return void
  385. */
  386. public function testHr()
  387. {
  388. $this->io->expects($this->once())
  389. ->method('hr')
  390. ->with(2);
  391. $this->Shell->hr(2);
  392. }
  393. /**
  394. * testError
  395. *
  396. * @group deprecated
  397. * @return void
  398. */
  399. public function testError()
  400. {
  401. $this->io->expects($this->at(0))
  402. ->method('err')
  403. ->with('<error>Error:</error> Foo Not Found');
  404. $this->io->expects($this->at(1))
  405. ->method('err')
  406. ->with('Searched all...');
  407. $this->deprecated(function () {
  408. $this->Shell->error('Foo Not Found', 'Searched all...');
  409. $this->assertSame($this->Shell->stopped, 1);
  410. });
  411. }
  412. /**
  413. * testLoadTasks method
  414. *
  415. * @return void
  416. */
  417. public function testLoadTasks()
  418. {
  419. $this->assertTrue($this->Shell->loadTasks());
  420. $this->Shell->tasks = null;
  421. $this->assertTrue($this->Shell->loadTasks());
  422. $this->Shell->tasks = false;
  423. $this->assertTrue($this->Shell->loadTasks());
  424. $this->Shell->tasks = true;
  425. $this->assertTrue($this->Shell->loadTasks());
  426. $this->Shell->tasks = [];
  427. $this->assertTrue($this->Shell->loadTasks());
  428. $this->Shell->tasks = ['TestApple'];
  429. $this->assertTrue($this->Shell->loadTasks());
  430. $this->assertInstanceOf('Cake\Shell\Task\TestAppleTask', $this->Shell->TestApple);
  431. $this->Shell->tasks = 'TestBanana';
  432. $this->assertTrue($this->Shell->loadTasks());
  433. $this->assertInstanceOf('Cake\Shell\Task\TestAppleTask', $this->Shell->TestApple);
  434. $this->assertInstanceOf('Cake\Shell\Task\TestBananaTask', $this->Shell->TestBanana);
  435. unset($this->Shell->ShellTestApple, $this->Shell->TestBanana);
  436. $this->Shell->tasks = ['TestApple', 'TestBanana'];
  437. $this->assertTrue($this->Shell->loadTasks());
  438. $this->assertInstanceOf('Cake\Shell\Task\TestAppleTask', $this->Shell->TestApple);
  439. $this->assertInstanceOf('Cake\Shell\Task\TestBananaTask', $this->Shell->TestBanana);
  440. }
  441. /**
  442. * test that __get() makes args and params references
  443. *
  444. * @return void
  445. */
  446. public function testMagicGetArgAndParamReferences()
  447. {
  448. $this->Shell->tasks = ['TestApple'];
  449. $this->Shell->args = ['one'];
  450. $this->Shell->params = ['help' => false];
  451. $this->Shell->loadTasks();
  452. $result = $this->Shell->TestApple;
  453. $this->Shell->args = ['one', 'two'];
  454. $this->assertSame($this->Shell->args, $result->args);
  455. $this->assertSame($this->Shell->params, $result->params);
  456. }
  457. /**
  458. * testShortPath method
  459. *
  460. * @return void
  461. */
  462. public function testShortPath()
  463. {
  464. $path = $expected = DS . 'tmp/ab/cd';
  465. $this->assertPathEquals($expected, $this->Shell->shortPath($path));
  466. $path = $expected = DS . 'tmp/ab/cd/';
  467. $this->assertPathEquals($expected, $this->Shell->shortPath($path));
  468. $path = $expected = DS . 'tmp/ab/index.php';
  469. $this->assertPathEquals($expected, $this->Shell->shortPath($path));
  470. $path = DS . 'tmp/ab/' . DS . 'cd';
  471. $expected = DS . 'tmp/ab/cd';
  472. $this->assertPathEquals($expected, $this->Shell->shortPath($path));
  473. $path = 'tmp/ab';
  474. $expected = 'tmp/ab';
  475. $this->assertPathEquals($expected, $this->Shell->shortPath($path));
  476. $path = 'tmp/ab';
  477. $expected = 'tmp/ab';
  478. $this->assertPathEquals($expected, $this->Shell->shortPath($path));
  479. $path = APP;
  480. $result = $this->Shell->shortPath($path);
  481. $this->assertNotContains(ROOT, $result, 'Short paths should not contain ROOT');
  482. }
  483. /**
  484. * testCreateFile method
  485. *
  486. * @return void
  487. */
  488. public function testCreateFileNonInteractive()
  489. {
  490. $eol = PHP_EOL;
  491. $path = TMP . 'shell_test';
  492. $file = $path . DS . 'file1.php';
  493. new Folder($path, true);
  494. $contents = "<?php{$eol}echo 'test';${eol}\$te = 'st';{$eol}";
  495. $result = $this->Shell->createFile($file, $contents);
  496. $this->assertTrue($result);
  497. $this->assertFileExists($file);
  498. $this->assertEquals(file_get_contents($file), $contents);
  499. }
  500. /**
  501. * Test that files are not changed with a 'n' reply.
  502. *
  503. * @return void
  504. */
  505. public function testCreateFileNoReply()
  506. {
  507. $eol = PHP_EOL;
  508. $path = TMP . 'shell_test';
  509. $file = $path . DS . 'file1.php';
  510. new Folder($path, true);
  511. $this->io->expects($this->once())
  512. ->method('askChoice')
  513. ->will($this->returnValue('n'));
  514. touch($file);
  515. $this->assertFileExists($file);
  516. $contents = 'My content';
  517. $result = $this->Shell->createFile($file, $contents);
  518. $this->assertFileExists($file);
  519. $this->assertTextEquals('', file_get_contents($file));
  520. $this->assertFalse($result, 'Did not create file.');
  521. }
  522. /**
  523. * Test that files are changed with a 'y' reply.
  524. *
  525. * @return void
  526. */
  527. public function testCreateFileOverwrite()
  528. {
  529. $eol = PHP_EOL;
  530. $path = TMP . 'shell_test';
  531. $file = $path . DS . 'file1.php';
  532. new Folder($path, true);
  533. $this->io->expects($this->once())
  534. ->method('askChoice')
  535. ->will($this->returnValue('y'));
  536. touch($file);
  537. $this->assertFileExists($file);
  538. $contents = 'My content';
  539. $result = $this->Shell->createFile($file, $contents);
  540. $this->assertFileExists($file);
  541. $this->assertTextEquals($contents, file_get_contents($file));
  542. $this->assertTrue($result, 'Did create file.');
  543. }
  544. /**
  545. * Test that there is no user prompt in non-interactive mode while file already exists.
  546. *
  547. * @return void
  548. */
  549. public function testCreateFileOverwriteNonInteractive()
  550. {
  551. $path = TMP . 'shell_test';
  552. $file = $path . DS . 'file1.php';
  553. new Folder($path, true);
  554. touch($file);
  555. $this->assertFileExists($file);
  556. $this->io->expects($this->never())->method('askChoice');
  557. $this->Shell->interactive = false;
  558. $result = $this->Shell->createFile($file, 'My content');
  559. $this->assertTrue($result);
  560. $this->assertEquals(file_get_contents($file), 'My content');
  561. }
  562. /**
  563. * Test that all files are changed with a 'a' reply.
  564. *
  565. * @return void
  566. */
  567. public function testCreateFileOverwriteAll()
  568. {
  569. $eol = PHP_EOL;
  570. $path = TMP . 'shell_test';
  571. $files = [
  572. $path . DS . 'file1.php' => 'My first content',
  573. $path . DS . 'file2.php' => 'My second content',
  574. $path . DS . 'file3.php' => 'My third content'
  575. ];
  576. new Folder($path, true);
  577. $this->io->expects($this->once())
  578. ->method('askChoice')
  579. ->will($this->returnValue('a'));
  580. foreach ($files as $file => $contents) {
  581. touch($file);
  582. $this->assertFileExists($file);
  583. $result = $this->Shell->createFile($file, $contents);
  584. $this->assertFileExists($file);
  585. $this->assertTextEquals($contents, file_get_contents($file));
  586. $this->assertTrue($result, 'Did create file.');
  587. }
  588. }
  589. /**
  590. * Test that you can't create files that aren't writable.
  591. *
  592. * @return void
  593. */
  594. public function testCreateFileNoPermissions()
  595. {
  596. $this->skipIf(DS === '\\', 'Cant perform operations using permissions on windows.');
  597. $path = TMP . 'shell_test';
  598. $file = $path . DS . 'no_perms';
  599. if (!is_dir($path)) {
  600. mkdir($path);
  601. }
  602. chmod($path, 0444);
  603. $this->Shell->createFile($file, 'testing');
  604. $this->assertFileNotExists($file);
  605. chmod($path, 0744);
  606. rmdir($path);
  607. }
  608. /**
  609. * test hasTask method
  610. *
  611. * @return void
  612. */
  613. public function testHasTask()
  614. {
  615. $this->Shell->tasks = ['Extract', 'Assets'];
  616. $this->Shell->loadTasks();
  617. $this->assertTrue($this->Shell->hasTask('extract'));
  618. $this->assertTrue($this->Shell->hasTask('Extract'));
  619. $this->assertFalse($this->Shell->hasTask('random'));
  620. $this->assertTrue($this->Shell->hasTask('assets'));
  621. $this->assertTrue($this->Shell->hasTask('Assets'));
  622. }
  623. /**
  624. * test task loading exception
  625. *
  626. * @expectedException \RuntimeException
  627. * @expectedExceptionMessage Task `DoesNotExist` not found. Maybe you made a typo or a plugin is missing or not loaded?
  628. * @return void
  629. */
  630. public function testMissingTaskException()
  631. {
  632. $this->Shell->tasks = ['DoesNotExist'];
  633. $this->Shell->loadTasks();
  634. }
  635. /**
  636. * test the hasMethod
  637. *
  638. * @return void
  639. */
  640. public function testHasMethod()
  641. {
  642. $this->assertTrue($this->Shell->hasMethod('doSomething'));
  643. $this->assertFalse($this->Shell->hasMethod('hr'), 'hr is callable');
  644. $this->assertFalse($this->Shell->hasMethod('_secret'), '_secret is callable');
  645. $this->assertFalse($this->Shell->hasMethod('no_access'), 'no_access is callable');
  646. }
  647. /**
  648. * test run command calling main.
  649. *
  650. * @return void
  651. */
  652. public function testRunCommandMain()
  653. {
  654. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  655. $shell = $this->getMockBuilder('Cake\Console\Shell')
  656. ->setMethods(['main', 'startup'])
  657. ->setConstructorArgs([$io])
  658. ->getMock();
  659. $shell->expects($this->once())->method('startup');
  660. $shell->expects($this->once())->method('main')
  661. ->with('cakes')
  662. ->will($this->returnValue(true));
  663. $result = $shell->runCommand(['cakes', '--verbose']);
  664. $this->assertTrue($result);
  665. $this->assertEquals('main', $shell->command);
  666. }
  667. /**
  668. * test run command calling a real method with no subcommands defined.
  669. *
  670. * @return void
  671. */
  672. public function testRunCommandWithMethod()
  673. {
  674. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  675. $shell = $this->getMockBuilder('Cake\Console\Shell')
  676. ->setMethods(['hitMe', 'startup'])
  677. ->setConstructorArgs([$io])
  678. ->getMock();
  679. $shell->expects($this->once())->method('startup');
  680. $shell->expects($this->once())->method('hitMe')
  681. ->with('cakes')
  682. ->will($this->returnValue(true));
  683. $result = $shell->runCommand(['hit_me', 'cakes', '--verbose'], true);
  684. $this->assertTrue($result);
  685. $this->assertEquals('hit_me', $shell->command);
  686. }
  687. /**
  688. * test that a command called with an extra parameter passed merges the extra parameters
  689. * to the shell's one
  690. * Also tests that if an extra `requested` parameter prevents the welcome message from
  691. * being displayed
  692. *
  693. * @return void
  694. */
  695. public function testRunCommandWithExtra()
  696. {
  697. $Parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  698. ->setMethods(['help'])
  699. ->setConstructorArgs(['knife'])
  700. ->getMock();
  701. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  702. $Shell = $this->getMockBuilder('Cake\Console\Shell')
  703. ->setMethods(['getOptionParser', 'slice', '_welcome', 'param'])
  704. ->setConstructorArgs([$io])
  705. ->getMock();
  706. $Parser->addSubCommand('slice');
  707. $Shell->expects($this->once())
  708. ->method('getOptionParser')
  709. ->will($this->returnValue($Parser));
  710. $Shell->expects($this->once())
  711. ->method('slice')
  712. ->with('cakes');
  713. $Shell->expects($this->never())->method('_welcome');
  714. $Shell->expects($this->once())->method('param')
  715. ->with('requested')
  716. ->will($this->returnValue(true));
  717. $Shell->runCommand(['slice', 'cakes'], false, ['requested' => true]);
  718. }
  719. /**
  720. * Test the dispatchShell() arguments parser
  721. *
  722. * @return void
  723. */
  724. public function testDispatchShellArgsParser()
  725. {
  726. $Shell = new Shell();
  727. $expected = [['schema', 'create', 'DbAcl'], []];
  728. // Shell::dispatchShell('schema create DbAcl');
  729. $result = $Shell->parseDispatchArguments(['schema create DbAcl']);
  730. $this->assertEquals($expected, $result);
  731. // Shell::dispatchShell('schema', 'create', 'DbAcl');
  732. $result = $Shell->parseDispatchArguments(['schema', 'create', 'DbAcl']);
  733. $this->assertEquals($expected, $result);
  734. // Shell::dispatchShell(['command' => 'schema create DbAcl']);
  735. $result = $Shell->parseDispatchArguments([[
  736. 'command' => 'schema create DbAcl'
  737. ]]);
  738. $this->assertEquals($expected, $result);
  739. // Shell::dispatchShell(['command' => ['schema', 'create', 'DbAcl']]);
  740. $result = $Shell->parseDispatchArguments([[
  741. 'command' => ['schema', 'create', 'DbAcl']
  742. ]]);
  743. $this->assertEquals($expected, $result);
  744. $expected[1] = ['param' => 'value'];
  745. // Shell::dispatchShell(['command' => 'schema create DbAcl', 'extra' => ['param' => 'value']]);
  746. $result = $Shell->parseDispatchArguments([[
  747. 'command' => 'schema create DbAcl',
  748. 'extra' => ['param' => 'value']
  749. ]]);
  750. $this->assertEquals($expected, $result);
  751. // Shell::dispatchShell(['command' => ['schema', 'create', 'DbAcl'], 'extra' => ['param' => 'value']]);
  752. $result = $Shell->parseDispatchArguments([[
  753. 'command' => ['schema', 'create', 'DbAcl'],
  754. 'extra' => ['param' => 'value']
  755. ]]);
  756. $this->assertEquals($expected, $result);
  757. }
  758. /**
  759. * test calling a shell that dispatch another one
  760. *
  761. * @return void
  762. */
  763. public function testDispatchShell()
  764. {
  765. $Shell = new TestingDispatchShell();
  766. ob_start();
  767. $Shell->runCommand(['test_task'], true);
  768. $result = ob_get_clean();
  769. $expected = <<<TEXT
  770. <info>Welcome to CakePHP Console</info>
  771. I am a test task, I dispatch another Shell
  772. I am a dispatched Shell
  773. TEXT;
  774. $this->assertEquals($expected, $result);
  775. ob_start();
  776. $Shell->runCommand(['test_task_dispatch_array'], true);
  777. $result = ob_get_clean();
  778. $this->assertEquals($expected, $result);
  779. ob_start();
  780. $Shell->runCommand(['test_task_dispatch_command_string'], true);
  781. $result = ob_get_clean();
  782. $this->assertEquals($expected, $result);
  783. ob_start();
  784. $Shell->runCommand(['test_task_dispatch_command_array'], true);
  785. $result = ob_get_clean();
  786. $this->assertEquals($expected, $result);
  787. $expected = <<<TEXT
  788. <info>Welcome to CakePHP Console</info>
  789. I am a test task, I dispatch another Shell
  790. I am a dispatched Shell. My param `foo` has the value `bar`
  791. TEXT;
  792. ob_start();
  793. $Shell->runCommand(['test_task_dispatch_with_param'], true);
  794. $result = ob_get_clean();
  795. $this->assertEquals($expected, $result);
  796. $expected = <<<TEXT
  797. <info>Welcome to CakePHP Console</info>
  798. I am a test task, I dispatch another Shell
  799. I am a dispatched Shell. My param `foo` has the value `bar`
  800. My param `fooz` has the value `baz`
  801. TEXT;
  802. ob_start();
  803. $Shell->runCommand(['test_task_dispatch_with_multiple_params'], true);
  804. $result = ob_get_clean();
  805. $this->assertEquals($expected, $result);
  806. $expected = <<<TEXT
  807. <info>Welcome to CakePHP Console</info>
  808. I am a test task, I dispatch another Shell
  809. <info>Welcome to CakePHP Console</info>
  810. I am a dispatched Shell
  811. TEXT;
  812. ob_start();
  813. $Shell->runCommand(['test_task_dispatch_with_requested_off'], true);
  814. $result = ob_get_clean();
  815. $this->assertEquals($expected, $result);
  816. }
  817. /**
  818. * Test that runCommand() doesn't call public methods when the second arg is false.
  819. *
  820. * @return void
  821. */
  822. public function testRunCommandAutoMethodOff()
  823. {
  824. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  825. $shell = $this->getMockBuilder('Cake\Console\Shell')
  826. ->setMethods(['hit_me', 'startup'])
  827. ->setConstructorArgs([$io])
  828. ->getMock();
  829. $shell->expects($this->never())->method('startup');
  830. $shell->expects($this->never())->method('hit_me');
  831. $result = $shell->runCommand(['hit_me', 'baseball'], false);
  832. $this->assertFalse($result);
  833. $result = $shell->runCommand(['hit_me', 'baseball']);
  834. $this->assertFalse($result, 'Default value of runCommand() should be false');
  835. }
  836. /**
  837. * test run command calling a real method with mismatching subcommands defined.
  838. *
  839. * @return void
  840. */
  841. public function testRunCommandWithMethodNotInSubcommands()
  842. {
  843. $parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  844. ->setMethods(['help'])
  845. ->setConstructorArgs(['knife'])
  846. ->getMock();
  847. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  848. $shell = $this->getMockBuilder('Cake\Console\Shell')
  849. ->setMethods(['getOptionParser', 'roll', 'startup'])
  850. ->setConstructorArgs([$io])
  851. ->getMock();
  852. $parser->addSubCommand('slice');
  853. $shell->expects($this->any())
  854. ->method('getOptionParser')
  855. ->will($this->returnValue($parser));
  856. $parser->expects($this->once())
  857. ->method('help');
  858. $shell->expects($this->never())->method('startup');
  859. $shell->expects($this->never())->method('roll');
  860. $result = $shell->runCommand(['roll', 'cakes', '--verbose']);
  861. $this->assertFalse($result);
  862. }
  863. /**
  864. * test run command calling a real method with subcommands defined.
  865. *
  866. * @return void
  867. */
  868. public function testRunCommandWithMethodInSubcommands()
  869. {
  870. $parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  871. ->setMethods(['help'])
  872. ->setConstructorArgs(['knife'])
  873. ->getMock();
  874. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  875. $shell = $this->getMockBuilder('Cake\Console\Shell')
  876. ->setMethods(['getOptionParser', 'slice', 'startup'])
  877. ->setConstructorArgs([$io])
  878. ->getMock();
  879. $parser->addSubCommand('slice');
  880. $shell->expects($this->any())
  881. ->method('getOptionParser')
  882. ->will($this->returnValue($parser));
  883. $shell->expects($this->once())->method('startup');
  884. $shell->expects($this->once())
  885. ->method('slice')
  886. ->with('cakes');
  887. $shell->runCommand(['slice', 'cakes', '--verbose']);
  888. }
  889. /**
  890. * test run command calling a missing method with subcommands defined.
  891. *
  892. * @return void
  893. */
  894. public function testRunCommandWithMissingMethodInSubcommands()
  895. {
  896. $parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  897. ->setMethods(['help'])
  898. ->setConstructorArgs(['knife'])
  899. ->getMock();
  900. $parser->addSubCommand('slice');
  901. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  902. $shell = $this->getMockBuilder('Cake\Console\Shell')
  903. ->setMethods(['getOptionParser', 'startup'])
  904. ->setConstructorArgs([$io])
  905. ->getMock();
  906. $shell->expects($this->any())
  907. ->method('getOptionParser')
  908. ->will($this->returnValue($parser));
  909. $shell->expects($this->never())
  910. ->method('startup');
  911. $parser->expects($this->once())
  912. ->method('help');
  913. $shell->runCommand(['slice', 'cakes', '--verbose']);
  914. }
  915. /**
  916. * test run command causing exception on Shell method.
  917. *
  918. * @return void
  919. */
  920. public function testRunCommandBaseClassMethod()
  921. {
  922. $shell = $this->getMockBuilder('Cake\Console\Shell')
  923. ->setMethods(['startup', 'getOptionParser', 'hr'])
  924. ->disableOriginalConstructor()
  925. ->getMock();
  926. $shell->setIo(
  927. $this->getMockBuilder('Cake\Console\ConsoleIo')
  928. ->setMethods(['err'])
  929. ->getMock()
  930. );
  931. $parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  932. ->disableOriginalConstructor()
  933. ->getMock();
  934. $parser->expects($this->once())->method('help');
  935. $shell->expects($this->once())->method('getOptionParser')
  936. ->will($this->returnValue($parser));
  937. $shell->expects($this->never())->method('hr');
  938. $shell->_io->expects($this->exactly(2))->method('err');
  939. $shell->runCommand(['hr']);
  940. }
  941. /**
  942. * test run command causing exception on Shell method.
  943. *
  944. * @return void
  945. */
  946. public function testRunCommandMissingMethod()
  947. {
  948. $shell = $this->getMockBuilder('Cake\Console\Shell')
  949. ->setMethods(['startup', 'getOptionParser', 'hr'])
  950. ->disableOriginalConstructor()
  951. ->getMock();
  952. $shell->setIo(
  953. $this->getMockBuilder('Cake\Console\ConsoleIo')
  954. ->setMethods(['err'])
  955. ->getMock()
  956. );
  957. $parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  958. ->disableOriginalConstructor()
  959. ->getMock();
  960. $parser->expects($this->once())->method('help');
  961. $shell->expects($this->once())->method('getOptionParser')
  962. ->will($this->returnValue($parser));
  963. $shell->_io->expects($this->exactly(2))->method('err');
  964. $result = $shell->runCommand(['idontexist']);
  965. $this->assertFalse($result);
  966. }
  967. /**
  968. * test that a --help causes help to show.
  969. *
  970. * @return void
  971. */
  972. public function testRunCommandTriggeringHelp()
  973. {
  974. $parser = $this->getMockBuilder('Cake\Console\ConsoleOptionParser')
  975. ->disableOriginalConstructor()
  976. ->getMock();
  977. $parser->expects($this->once())->method('parse')
  978. ->with(['--help'])
  979. ->will($this->returnValue([['help' => true], []]));
  980. $parser->expects($this->once())->method('help');
  981. $shell = $this->getMockBuilder('Cake\Console\Shell')
  982. ->setMethods(['getOptionParser', 'out', 'startup', '_welcome'])
  983. ->disableOriginalConstructor()
  984. ->getMock();
  985. $shell->setIo($this->getMockBuilder('Cake\Console\ConsoleIo')->getMock());
  986. $shell->expects($this->once())->method('getOptionParser')
  987. ->will($this->returnValue($parser));
  988. $shell->expects($this->once())->method('out');
  989. $shell->runCommand(['--help']);
  990. }
  991. /**
  992. * test that runCommand will not call runCommand on tasks that are not subcommands.
  993. *
  994. * @return void
  995. */
  996. public function testRunCommandNotCallUnexposedTask()
  997. {
  998. $shell = $this->getMockBuilder('Cake\Console\Shell')
  999. ->setMethods(['startup', 'hasTask'])
  1000. ->disableOriginalConstructor()
  1001. ->getMock();
  1002. $shell->setIo(
  1003. $this->getMockBuilder('Cake\Console\ConsoleIo')
  1004. ->setMethods(['err'])
  1005. ->getMock()
  1006. );
  1007. $task = $this->getMockBuilder('Cake\Console\Shell')
  1008. ->setMethods(['runCommand'])
  1009. ->disableOriginalConstructor()
  1010. ->getMock();
  1011. $task->expects($this->never())
  1012. ->method('runCommand');
  1013. $shell->expects($this->any())
  1014. ->method('hasTask')
  1015. ->will($this->returnValue(true));
  1016. $shell->expects($this->never())->method('startup');
  1017. $shell->_io->expects($this->exactly(2))->method('err');
  1018. $shell->RunCommand = $task;
  1019. $result = $shell->runCommand(['run_command', 'one']);
  1020. $this->assertFalse($result);
  1021. }
  1022. /**
  1023. * test that runCommand will call runCommand on the task.
  1024. *
  1025. * @return void
  1026. */
  1027. public function testRunCommandHittingTaskInSubcommand()
  1028. {
  1029. $parser = new ConsoleOptionParser('knife');
  1030. $parser->addSubcommand('slice');
  1031. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  1032. $shell = $this->getMockBuilder('Cake\Console\Shell')
  1033. ->setMethods(['hasTask', 'startup', 'getOptionParser'])
  1034. ->disableOriginalConstructor()
  1035. ->getMock();
  1036. $shell->setIo($io);
  1037. $task = $this->getMockBuilder('Cake\Console\Shell')
  1038. ->setMethods(['main', 'runCommand'])
  1039. ->disableOriginalConstructor()
  1040. ->getMock();
  1041. $task->setIo($io);
  1042. $task->expects($this->once())
  1043. ->method('runCommand')
  1044. ->with(['one'], false, ['requested' => true]);
  1045. $shell->expects($this->once())->method('getOptionParser')
  1046. ->will($this->returnValue($parser));
  1047. $shell->expects($this->once())->method('startup');
  1048. $shell->expects($this->any())
  1049. ->method('hasTask')
  1050. ->will($this->returnValue(true));
  1051. $shell->Slice = $task;
  1052. $shell->runCommand(['slice', 'one']);
  1053. }
  1054. /**
  1055. * test that runCommand will invoke a task
  1056. *
  1057. * @return void
  1058. */
  1059. public function testRunCommandInvokeTask()
  1060. {
  1061. $parser = new ConsoleOptionParser('knife');
  1062. $parser->addSubcommand('slice');
  1063. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  1064. $shell = $this->getMockBuilder('Cake\Console\Shell')
  1065. ->setMethods(['hasTask', 'getOptionParser'])
  1066. ->setConstructorArgs([$io])
  1067. ->getMock();
  1068. $task = $this->getMockBuilder('Cake\Console\Shell')
  1069. ->setMethods(['main', '_welcome'])
  1070. ->setConstructorArgs([$io])
  1071. ->getMock();
  1072. $shell->expects($this->once())
  1073. ->method('getOptionParser')
  1074. ->will($this->returnValue($parser));
  1075. $shell->expects($this->any())
  1076. ->method('hasTask')
  1077. ->will($this->returnValue(true));
  1078. $task->expects($this->never())
  1079. ->method('_welcome');
  1080. $shell->Slice = $task;
  1081. $shell->runCommand(['slice', 'one']);
  1082. $this->assertTrue($task->params['requested'], 'Task is requested, no welcome.');
  1083. }
  1084. /**
  1085. * test run command missing parameters
  1086. *
  1087. * @return void
  1088. */
  1089. public function testRunCommandMainMissingArgument()
  1090. {
  1091. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock();
  1092. $shell = $this->getMockBuilder('Cake\Console\Shell')
  1093. ->setMethods(['main', 'startup', 'getOptionParser'])
  1094. ->setConstructorArgs([$io])
  1095. ->getMock();
  1096. $parser = new ConsoleOptionParser('test');
  1097. $parser->addArgument('filename', [
  1098. 'required' => true,
  1099. 'help' => 'a file',
  1100. ]);
  1101. $shell->expects($this->once())
  1102. ->method('getOptionParser')
  1103. ->will($this->returnValue($parser));
  1104. $shell->expects($this->never())->method('main');
  1105. $io->expects($this->once())
  1106. ->method('error')
  1107. ->with('Error: Missing required arguments. filename is required.');
  1108. $result = $shell->runCommand([]);
  1109. $this->assertFalse($result, 'Shell should fail');
  1110. }
  1111. /**
  1112. * test wrapBlock wrapping text.
  1113. *
  1114. * @return void
  1115. */
  1116. public function testWrapText()
  1117. {
  1118. $text = 'This is the song that never ends. This is the song that never ends. This is the song that never ends.';
  1119. $result = $this->Shell->wrapText($text, ['width' => 33]);
  1120. $expected = <<<TEXT
  1121. This is the song that never ends.
  1122. This is the song that never ends.
  1123. This is the song that never ends.
  1124. TEXT;
  1125. $this->assertTextEquals($expected, $result, 'Text not wrapped.');
  1126. $result = $this->Shell->wrapText($text, ['indent' => ' ', 'width' => 33]);
  1127. $expected = <<<TEXT
  1128. This is the song that never ends.
  1129. This is the song that never ends.
  1130. This is the song that never ends.
  1131. TEXT;
  1132. $this->assertTextEquals($expected, $result, 'Text not wrapped.');
  1133. }
  1134. /**
  1135. * Testing camel cased naming of tasks
  1136. *
  1137. * @return void
  1138. */
  1139. public function testShellNaming()
  1140. {
  1141. $this->Shell->tasks = ['TestApple'];
  1142. $this->Shell->loadTasks();
  1143. $expected = 'TestApple';
  1144. $this->assertEquals($expected, $this->Shell->TestApple->name);
  1145. }
  1146. /**
  1147. * Test reading params
  1148. *
  1149. * @dataProvider paramReadingDataProvider
  1150. */
  1151. public function testParamReading($toRead, $expected)
  1152. {
  1153. $this->Shell->params = [
  1154. 'key' => 'value',
  1155. 'help' => false,
  1156. 'emptykey' => '',
  1157. 'truthy' => true
  1158. ];
  1159. $this->assertSame($expected, $this->Shell->param($toRead));
  1160. }
  1161. /**
  1162. * Data provider for testing reading values with Shell::param()
  1163. *
  1164. * @return array
  1165. */
  1166. public function paramReadingDataProvider()
  1167. {
  1168. return [
  1169. [
  1170. 'key',
  1171. 'value',
  1172. ],
  1173. [
  1174. 'help',
  1175. false,
  1176. ],
  1177. [
  1178. 'emptykey',
  1179. '',
  1180. ],
  1181. [
  1182. 'truthy',
  1183. true,
  1184. ],
  1185. [
  1186. 'does_not_exist',
  1187. null,
  1188. ]
  1189. ];
  1190. }
  1191. /**
  1192. * Test that option parsers are created with the correct name/command.
  1193. *
  1194. * @return void
  1195. */
  1196. public function testGetOptionParser()
  1197. {
  1198. $this->Shell->name = 'test';
  1199. $this->Shell->plugin = 'plugin';
  1200. $parser = $this->Shell->getOptionParser();
  1201. $this->assertEquals('plugin.test', $parser->getCommand());
  1202. }
  1203. /**
  1204. * Test file and console and logging quiet output
  1205. *
  1206. * @return void
  1207. */
  1208. public function testQuietLog()
  1209. {
  1210. $io = $this->getMockBuilder('Cake\Console\ConsoleIo')
  1211. ->disableOriginalConstructor()
  1212. ->getMock();
  1213. $io->expects($this->once())
  1214. ->method('level')
  1215. ->with(Shell::QUIET);
  1216. $io->expects($this->at(0))
  1217. ->method('setLoggers')
  1218. ->with(true);
  1219. $io->expects($this->at(2))
  1220. ->method('setLoggers')
  1221. ->with(ConsoleIo::QUIET);
  1222. $this->Shell = $this->getMockBuilder(__NAMESPACE__ . '\ShellTestShell')
  1223. ->setMethods(['welcome'])
  1224. ->setConstructorArgs([$io])
  1225. ->getMock();
  1226. $this->Shell->runCommand(['foo', '--quiet']);
  1227. }
  1228. /**
  1229. * Test getIo() and setIo() methods
  1230. *
  1231. * @return void
  1232. */
  1233. public function testGetSetIo()
  1234. {
  1235. $this->Shell->setIo($this->io);
  1236. $this->assertSame($this->Shell->getIo(), $this->io);
  1237. }
  1238. /**
  1239. * Test setRootName filters into the option parser help text.
  1240. *
  1241. * @return void
  1242. */
  1243. public function testSetRootNamePropagatesToHelpText()
  1244. {
  1245. $this->assertSame($this->Shell, $this->Shell->setRootName('tool'), 'is chainable');
  1246. $this->assertContains('tool shell_test_shell [-h]', $this->Shell->getOptionParser()->help());
  1247. }
  1248. /**
  1249. * Tests __debugInfo
  1250. *
  1251. * @return void
  1252. */
  1253. public function testDebugInfo()
  1254. {
  1255. $expected = [
  1256. 'name' => 'ShellTestShell',
  1257. 'plugin' => null,
  1258. 'command' => null,
  1259. 'tasks' => [],
  1260. 'params' => [],
  1261. 'args' => [],
  1262. 'interactive' => true
  1263. ];
  1264. $result = $this->Shell->__debugInfo();
  1265. $this->assertEquals($expected, $result);
  1266. }
  1267. }