Skip to content

Commit

Permalink
Add Runner function for retrieving an application to be used with tes…
Browse files Browse the repository at this point in the history
…ts (consolidation#968)

* Robo-947: Add function for retrieving an application to be used with tests.

* Fix nits. Drupal does not dictate all code styles.

* Fix the nit.

* Don't invoke getRoboFileCommands unnecessarily.

* Nitpicks.

* Test try:exec to validate status codes.

* Nitpicks.

* Add references to usage of test app getter.

* Don't use a trait in Runner from the tests dir.

* Try disabling interactivity.

* Revert "Try disabling interactivity."

This reverts commit 46a727b.

* Use null coalescence.

* Remove incorrect commentary.

* Mark test as skipped for lowest dependency check for symfony4.
  • Loading branch information
lpeabody authored Aug 28, 2020
1 parent d2ae86d commit 26ff52f
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use League\Container\ContainerAwareInterface;
use League\Container\ContainerAwareTrait;
use Consolidation\Config\Util\EnvConfig;
use Symfony\Component\Console\Output\NullOutput;

class Runner implements ContainerAwareInterface
{
Expand Down Expand Up @@ -156,6 +157,43 @@ public function execute($argv, $appName = null, $appVersion = null, $output = nu
return $this->run($argv, $output, $app, $commandFiles, $this->classLoader);
}

/**
* Return an initialized application loaded with specified commands and configuration.
*
* This should ONLY be used for testing purposes. Works well in conjunction with Symfony's CommandTester.
*
* @see https://symfony.com/doc/current/console.html#testing-commands
* @see CommandTestertTest
* @see CommandTesterTrait
*
* @param string|null $appName
* Name of the application.
* @param string|null $appVersion
* Version of the application.
* @param string|array|null $commandFile
* Name of the specific command file, or array of commands, that should be included with the application.
* @param \Robo\Config\Config|null $config
* Robo configuration to be used with the application.
* @param \Composer\Autoload\ClassLoader|null $classLoader
* Class loader to use.
*
* @return \Robo\Application
* Initialized application based on passed configuration and command classes.
*/
public function getAppForTesting($appName = null, $appVersion = null, $commandFile = null, $config = null, $classLoader = null)
{
$app = Robo::createDefaultApplication($appName, $appVersion);
$output = new NullOutput();
$container = Robo::createDefaultContainer(null, $output, $app, $config, $classLoader);
if (!is_null($commandFile) && (is_array($commandFile) || is_string($commandFile))) {
if (is_string($commandFile)) {
$commandFile = [$commandFile];
}
$this->registerCommandClasses($app, $commandFile);
}
return $app;
}

/**
* Get a list of locations where config files may be loaded
*
Expand Down
36 changes: 36 additions & 0 deletions tests/integration/CommandTesterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
namespace Robo;

use PHPUnit\Framework\TestCase;
use Robo\Traits\CommandTesterTrait;
use RoboExample\Robo\Plugin\Commands\ExampleCommands;

class CommandTestertTest extends TestCase
{
use CommandTesterTrait;

public function setUp()
{
$this->setupCommandTester(ExampleCommands::class);
}

public function testInputApis()
{
if (getenv('SCENARIO') == 'symfony4' && getenv('DEPENDENCIES') == 'lowest') {
$this->markTestSkipped('There is a bug with a lower dependency of symfony4 in how it handles tty.');
}
list($tryInputOutput, $statusCode) = $this->executeCommand('try:input', ["I'm great!", "yes", "PHP", "1234"]);
$this->assertEquals(0, $statusCode);
$this->assertContains("I'm great!", $tryInputOutput);
$this->assertContains("PHP", $tryInputOutput);
$this->assertContains("1234", $tryInputOutput);
}

public function testTesterWithOptions()
{
list($execOutput, $statusCode) = $this->executeCommand('try:exec', []);
$this->assertEquals(0, $statusCode);
list($execOutput, $statusCode) = $this->executeCommand('try:exec', [], ['--error']);
$this->assertNotEquals(0, $statusCode);
}
}
56 changes: 56 additions & 0 deletions tests/src/Traits/CommandTesterTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Robo\Traits;

use Consolidation\AnnotatedCommand\CommandFileDiscovery;
use Robo\Robo;
use Robo\Runner;
use Symfony\Component\Console\Tester\CommandTester;

trait CommandTesterTrait
{
/** @var string */
protected $appName;

/** @var string */
protected $appVersion;

/** @var string|array|null */
protected $commandClasses = null;

/** @var Runner */
protected $runner;

/**
* Setup the tester.
*
* @param string|array|null $commandClasses
*/
public function setupCommandTester($commandClasses = null)
{
// Define our invariants for our test.
$this->runner = new Runner();
if (!is_null($commandClasses)) {
$this->commandClasses = $commandClasses;
}
}

/**
* @param $command_string
* @param array $inputs
* @param array $command_extra
* @param string|array|null $commandClasses
* @return array
*/
protected function executeCommand($command_string, $inputs = [], $command_extra = [], $commandClasses = null)
{
$commandClasses = $commandClasses ?? $this->commandClasses;
$app = $this->runner->getAppForTesting($this->appName, $this->appVersion, $commandClasses);
$command = $app->get($command_string);
$tester = new CommandTester($command);
$tester->setInputs($inputs);
$status_code = $tester->execute(array_merge(['command' => $command_string], $command_extra));
Robo::unsetContainer();
return [trim($tester->getDisplay()), $status_code];
}
}

0 comments on commit 26ff52f

Please sign in to comment.