Skip to content

Commit

Permalink
Add more test coverage for CommandRunner.
Browse files Browse the repository at this point in the history
Cover failure/working paths for shell invocation.
  • Loading branch information
markstory committed Jun 20, 2017
1 parent 73a85be commit a7f9372
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 4 deletions.
37 changes: 33 additions & 4 deletions src/Console/CommandRunner.php
Expand Up @@ -15,6 +15,9 @@
namespace Cake\Console;

use Cake\Console\CommandCollection;
use Cake\Console\ConsoleIo;
use Cake\Console\Exception\StopException;
use Cake\Console\Shell;
use Cake\Http\BaseApplication;
use RuntimeException;

Expand All @@ -41,10 +44,11 @@ public function __construct(BaseApplication $app, $root = 'cake')
* Run the command contained in $argv.
*
* @param array $argv The arguments from the CLI environment.
* @param \Cake\Console\ConsoleIo $io The ConsoleIo instance. Used primarily for testing.
* @return int The exit code of the command.
* @throws \RuntimeException
*/
public function run(array $argv)
public function run(array $argv, ConsoleIo $io = null)
{
$this->app->bootstrap();

Expand All @@ -62,18 +66,38 @@ public function run(array $argv)
"Unknown root command{$command}. Was expecting `{$this->root}`."
);
}
// Remove the root command
$io = $io ?: new ConsoleIo();

// Remove the root executable segment
array_shift($argv);

$shell = $this->getShell($commands, $argv);
$shell = $this->getShell($io, $commands, $argv);

// Remove the command name segment
array_shift($argv);
try {
$shell->initialize();
$result = $shell->runCommand($argv, true);
} catch (StopException $e) {
return $e->getCode();
}

if ($result === null || $result === true) {
return Shell::CODE_SUCCESS;
}
if (is_int($result)) {
return $result;
}

return Shell::CODE_ERROR;
}

/**
* Get the shell instance for the argv list.
*
* @return \Cake\Console\Shell
*/
protected function getShell(CommandCollection $commands, array $argv)
protected function getShell(ConsoleIo $io, CommandCollection $commands, array $argv)
{
$command = array_shift($argv);
if (!$commands->has($command)) {
Expand All @@ -82,5 +106,10 @@ protected function getShell(CommandCollection $commands, array $argv)
" Run `{$this->root} --help` to get the list of valid commands."
);
}
$classOrInstance = $commands->get($command);
if (is_string($classOrInstance)) {
return new $classOrInstance($io);
}
return $classOrInstance;
}
}
80 changes: 80 additions & 0 deletions tests/TestCase/Console/CommandRunnerTest.php
Expand Up @@ -16,9 +16,12 @@

use Cake\Console\CommandCollection;
use Cake\Console\CommandRunner;
use Cake\Console\ConsoleIo;
use Cake\Console\Shell;
use Cake\Core\Configure;
use Cake\Http\BaseApplication;
use Cake\TestSuite\TestCase;
use Cake\TestSuite\Stub\ConsoleOutput;

/**
* Test case for the CommandCollection
Expand Down Expand Up @@ -143,4 +146,81 @@ public function testRunVersionShortOption()
{
$this->markTestIncomplete();
}

/**
* Test running a valid command
*
* @return void
*/
public function testRunValidCommand()
{
$app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap'])
->setConstructorArgs([$this->config])
->getMock();

$output = new ConsoleOutput();

$runner = new CommandRunner($app, 'cake');
$result = $runner->run(['cake', 'routes'], $this->getMockIo($output));
$this->assertSame(Shell::CODE_SUCCESS, $result);

$contents = implode("\n", $output->messages());
$this->assertContains('URI template', $contents);
$this->assertContains('Welcome to CakePHP', $contents);
}

/**
* Test running a valid raising an error
*
* @return void
*/
public function testRunValidCommandWithAbort()
{
$app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap', 'console'])
->setConstructorArgs([$this->config])
->getMock();

$commands = new CommandCollection(['failure' => 'TestApp\Shell\SampleShell']);
$app->method('console')->will($this->returnValue($commands));

$output = new ConsoleOutput();

$runner = new CommandRunner($app, 'cake');
$result = $runner->run(['cake', 'failure', 'with_abort'], $this->getMockIo($output));
$this->assertSame(Shell::CODE_ERROR, $result);
}

/**
* Test returning a non-zero value
*
* @return void
*/
public function testRunValidCommandReturnInteger()
{
$app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap', 'console'])
->setConstructorArgs([$this->config])
->getMock();

$commands = new CommandCollection(['failure' => 'TestApp\Shell\SampleShell']);
$app->method('console')->will($this->returnValue($commands));

$output = new ConsoleOutput();

$runner = new CommandRunner($app, 'cake');
$result = $runner->run(['cake', 'failure', 'returnValue'], $this->getMockIo($output));
$this->assertSame(99, $result);
}

protected function getMockIo($output)
{
$io = $this->getMockBuilder(ConsoleIo::class)
->setConstructorArgs([$output, $output, null, null])
->setMethods(['in'])
->getMock();

return $io;
}
}
10 changes: 10 additions & 0 deletions tests/test_app/TestApp/Shell/SampleShell.php
Expand Up @@ -46,4 +46,14 @@ public function derp()
{
$this->out('This is the example method called from TestPlugin.SampleShell');
}

public function withAbort()
{
$this->abort('Bad things');
}

public function returnValue()
{
return 99;
}
}

0 comments on commit a7f9372

Please sign in to comment.