Skip to content

[Console] add setInputs to ApplicationTester and share some code #24819

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 12 additions & 55 deletions src/Symfony/Component/Console/Tester/ApplicationTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;

/**
Expand All @@ -30,13 +28,11 @@
*/
class ApplicationTester
{
use TesterTrait;

private $application;
private $input;
private $statusCode;
/**
* @var OutputInterface
*/
private $output;
private $captureStreamsIndependently = false;

public function __construct(Application $application)
Expand Down Expand Up @@ -66,6 +62,13 @@ public function run(array $input, $options = array())
$this->input->setInteractive($options['interactive']);
}

$shellInteractive = getenv('SHELL_INTERACTIVE');

if ($this->inputs) {
$this->input->setStream(self::createStream($this->inputs));
putenv('SHELL_INTERACTIVE=1');
}

$this->captureStreamsIndependently = array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
if (!$this->captureStreamsIndependently) {
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
Expand Down Expand Up @@ -97,27 +100,11 @@ public function run(array $input, $options = array())
$streamProperty->setValue($this->output, fopen('php://memory', 'w', false));
}

return $this->statusCode = $this->application->run($this->input, $this->output);
}

/**
* Gets the display returned by the last execution of the application.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string The display
*/
public function getDisplay($normalize = false)
{
rewind($this->output->getStream());

$display = stream_get_contents($this->output->getStream());
$this->statusCode = $this->application->run($this->input, $this->output);

if ($normalize) {
$display = str_replace(PHP_EOL, "\n", $display);
}
putenv($shellInteractive ? "SHELL_INTERACTIVE=$shellInteractive" : 'SHELL_INTERACTIVE');

return $display;
return $this->statusCode;
}

/**
Expand All @@ -143,34 +130,4 @@ public function getErrorOutput($normalize = false)

return $display;
}

/**
* Gets the input instance used by the last execution of the application.
*
* @return InputInterface The current input instance
*/
public function getInput()
{
return $this->input;
}

/**
* Gets the output instance used by the last execution of the application.
*
* @return OutputInterface The current output instance
*/
public function getOutput()
{
return $this->output;
}

/**
* Gets the status code returned by the last execution of the application.
*
* @return int The status code
*/
public function getStatusCode()
{
return $this->statusCode;
}
}
81 changes: 2 additions & 79 deletions src/Symfony/Component/Console/Tester/CommandTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Eases the testing of console commands.
Expand All @@ -25,10 +23,10 @@
*/
class CommandTester
{
use TesterTrait;

private $command;
private $input;
private $output;
private $inputs = array();
private $statusCode;

public function __construct(Command $command)
Expand Down Expand Up @@ -78,79 +76,4 @@ public function execute(array $input, array $options = array())

return $this->statusCode = $this->command->run($this->input, $this->output);
}

/**
* Gets the display returned by the last execution of the command.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string The display
*/
public function getDisplay($normalize = false)
{
rewind($this->output->getStream());

$display = stream_get_contents($this->output->getStream());

if ($normalize) {
$display = str_replace(PHP_EOL, "\n", $display);
}

return $display;
}

/**
* Gets the input instance used by the last execution of the command.
*
* @return InputInterface The current input instance
*/
public function getInput()
{
return $this->input;
}

/**
* Gets the output instance used by the last execution of the command.
*
* @return OutputInterface The current output instance
*/
public function getOutput()
{
return $this->output;
}

/**
* Gets the status code returned by the last execution of the application.
*
* @return int The status code
*/
public function getStatusCode()
{
return $this->statusCode;
}

/**
* Sets the user inputs.
*
* @param array $inputs An array of strings representing each input
* passed to the command input stream
*
* @return CommandTester
*/
public function setInputs(array $inputs)
{
$this->inputs = $inputs;

return $this;
}

private static function createStream(array $inputs)
{
$stream = fopen('php://memory', 'r+', false);

fwrite($stream, implode(PHP_EOL, $inputs));
rewind($stream);

return $stream;
}
}
103 changes: 103 additions & 0 deletions src/Symfony/Component/Console/Tester/TesterTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;

/**
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
*
* @internal
*/
trait TesterTrait
{
/** @var StreamOutput */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not useful and differs with getOutput() return type, I would drop it

Copy link
Contributor

@ogizanagi ogizanagi Nov 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it is useful actually (for autocompletion and SCA). This trait needs a StreamOutput instance here, not any OutputInterface. That's why I suggested this docblock in #24819 (comment) :)

screenshot 2017-11-05 a 19 27 06

private $output;
private $inputs = array();

/**
* Gets the display returned by the last execution of the command or application.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string The display
*/
public function getDisplay($normalize = false)
{
rewind($this->output->getStream());

$display = stream_get_contents($this->output->getStream());

if ($normalize) {
$display = str_replace(PHP_EOL, "\n", $display);
}

return $display;
}

/**
* Gets the input instance used by the last execution of the command or application.
*
* @return InputInterface The current input instance
*/
public function getInput()
{
return $this->input;
}

/**
* Gets the output instance used by the last execution of the command or application.
*
* @return OutputInterface The current output instance
*/
public function getOutput()
{
return $this->output;
}

/**
* Gets the status code returned by the last execution of the command or application.
*
* @return int The status code
*/
public function getStatusCode()
{
return $this->statusCode;
}

/**
* Sets the user inputs.
*
* @param $inputs array An array of strings representing each input
* passed to the command input stream
*
* @return self
*/
public function setInputs(array $inputs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this to work in ApplicationTester, the tester needs to set the input stream from this value.
So CommandTester::createInputStream() should be shared between both testers (that's my motivation for a trait) and this line should be added to ApplicationTester::run().

{
$this->inputs = $inputs;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the property does not exist in ApplicationTester, it should be created

Copy link
Contributor

@ogizanagi ogizanagi Nov 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or moved to the trait along with:

/** @var StreamOutput */
private $output;


return $this;
}

private static function createStream(array $inputs)
{
$stream = fopen('php://memory', 'r+', false);

fwrite($stream, implode(PHP_EOL, $inputs));
rewind($stream);

return $stream;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Tester\ApplicationTester;

class ApplicationTesterTest extends TestCase
Expand All @@ -27,7 +29,9 @@ protected function setUp()
$this->application->setAutoExit(false);
$this->application->register('foo')
->addArgument('foo')
->setCode(function ($input, $output) { $output->writeln('foo'); })
->setCode(function ($input, $output) {
$output->writeln('foo');
})
;

$this->tester = new ApplicationTester($this->application);
Expand Down Expand Up @@ -63,6 +67,25 @@ public function testGetDisplay()
$this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution');
}

public function testSetInputs()
{
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')->setCode(function ($input, $output) {
$helper = new QuestionHelper();
$helper->ask($input, $output, new Question('Q1'));
$helper->ask($input, $output, new Question('Q2'));
$helper->ask($input, $output, new Question('Q3'));
});
$tester = new ApplicationTester($application);

$tester->setInputs(array('I1', 'I2', 'I3'));
$tester->run(array('command' => 'foo'));

$this->assertSame(0, $tester->getStatusCode());
$this->assertEquals('Q1Q2Q3', $tester->getDisplay(true));
}

public function testGetStatusCode()
{
$this->assertSame(0, $this->tester->getStatusCode(), '->getStatusCode() returns the status code');
Expand Down