8000 [Console] Add support for error ouput in the CommandTester by cdekok · Pull Request #27434 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Console] Add support for error ouput in the CommandTester #27434

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
merged 1 commit into from
Sep 23, 2018
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
1 change: 1 addition & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ CHANGELOG
pass it the command as an array of its arguments instead
* made the `ProcessHelper` class final
* added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`)
* added `capture_stderr_separately` option to `CommandTester::execute()`

4.1.0
-----
Expand Down
58 changes: 1 addition & 57 deletions src/Symfony/Component/Console/Tester/ApplicationTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

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

/**
* Eases the testing of console applications.
Expand All @@ -33,7 +31,6 @@ class ApplicationTester
private $application;
private $input;
private $statusCode;
private $captureStreamsIndependently = false;

public function __construct(Application $application)
{
Expand Down Expand Up @@ -69,65 +66,12 @@ public function run(array $input, $options = array())
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));
if (isset($options['decorated'])) {
$this->output->setDecorated($options['decorated']);
}
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
}
} else {
$this->output = new ConsoleOutput(
isset($options['verbosity']) ? $options['verbosity'] : ConsoleOutput::VERBOSITY_NORMAL,
isset($options['decorated']) ? $options['decorated'] : null
);

$errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
$errorOutput->setFormatter($this->output->getFormatter());
$errorOutput->setVerbosity($this->output->getVerbosity());
$errorOutput->setDecorated($this->output->isDecorated());

$reflectedOutput = new \ReflectionObject($this->output);
$strErrProperty = $reflectedOutput->getProperty('stderr');
$strErrProperty->setAccessible(true);
$strErrProperty->setValue($this->output, $errorOutput);

$reflectedParent = $reflectedOutput->getParentClass();
$streamProperty = $reflectedParent->getProperty('stream');
$streamProperty->setAccessible(true);
$streamProperty->setValue($this->output, fopen('php://memory', 'w', false));
}
$this->initOutput($options);

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

putenv($shellInteractive ? "SHELL_INTERACTIVE=$shellInteractive" : 'SHELL_INTERACTIVE');

return $this->statusCode;
}

/**
* Gets the output written to STDERR by the application.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string
*/
public function getErrorOutput($normalize = false)
{
if (!$this->captureStreamsIndependently) {
throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
}

rewind($this->output->getErrorOutput()->getStream());

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

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

return $display;
}
}
16 changes: 8 additions & 8 deletions src/Symfony/Component/Console/Tester/CommandTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;

/**
* Eases the testing of console commands.
Expand All @@ -39,9 +38,10 @@ public function __construct(Command $command)
*
* Available execution options:
*
* * interactive: Sets the input interactive flag
* * decorated: Sets the output decorated flag
* * verbosity: Sets the output verbosity flag
* * interactive: Sets the input interactive flag
* * decorated: Sets the output decorated flag
* * verbosity: Sets the output verbosity flag
* * capture_stderr_separately: Make output of stdOut and stdErr separately available
*
* @param array $input An array of command arguments and options
* @param array $options An array of execution options
Expand All @@ -68,12 +68,12 @@ public function execute(array $input, array $options = array())
$this->input->setInteractive($options['interactive']);
}

$this->output = new StreamOutput(fopen('php://memory', 'w', false));
$this->output->setDecorated(isset($options['decorated']) ? $options['decorated'] : false);
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
if (!isset($options['decorated'])) {
$options['decorated'] = false;
}

$this->initOutput($options);

return $this->statusCode = $this->command->run($this->input, $this->output);
}
}
71 changes: 69 additions & 2 deletions src/Symfony/Component/Console/Tester/TesterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
namespace Symfony\Component\Console\Tester;

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

/**
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
*
* @internal
*/
trait TesterTrait
{
/** @var StreamOutput */
private $output;
private $inputs = array();
private $captureStreamsIndependently = false;

/**
* Gets the display returned by the last execution of the command or application.
Expand All @@ -46,6 +46,30 @@ public function getDisplay($normalize = false)
return $display;
}

/**
* Gets the output written to STDERR by the application.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string
*/
public function getErrorOutput($normalize = false)
{
if (!$this->captureStreamsIndependently) {
throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
}

rewind($this->output->getErrorOutput()->getStream());

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

if ($normalize) {
$display = str_replace(PHP_EOL, "\n", $display);
}< 8000 /td>

return $display;
}

/**
* Gets the input instance used by the last execution of the command or application.
*
Expand Down Expand Up @@ -91,6 +115,49 @@ public function setInputs(array $inputs)
return $this;
}

/**
* Initializes the output property.
*
* Available options:
*
* * decorated: Sets the output decorated flag
* * verbosity: Sets the output verbosity flag
* * capture_stderr_separately: Make output of stdOut and stdErr separately available
*/
private function initOutput(array $options)
{
$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));
if (isset($options['decorated'])) {
$this->output->setDecorated($options['decorated']);
}
if (isset($options['verbosity'])) {
$this->output->setVerbosity($options['verbosity']);
}
} else {
$this->output = new ConsoleOutput(
isset($options['verbosity']) ? $options['verbosity'] : ConsoleOutput::VERBOSITY_NORMAL,
isset($options['decorated']) ? $options['decorated'] : null
);

$errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
$errorOutput->setFormatter($this->output->getFormatter());
$errorOutput->setVerbosity($this->output->getVerbosity());
$errorOutput->setDecorated($this->output->isDecorated());

$reflectedOutput = new \ReflectionObject($this->output);
$strErrProperty = $reflectedOutput->getProperty('stderr');
$strErrProperty->setAccessible(true);
$strErrProperty->setValue($this->output, $errorOutput);

$reflectedParent = $reflectedOutput->getParentClass();
$streamProperty = $reflectedParent->getProperty('stream');
$streamProperty->setAccessible(true);
$streamProperty->setValue($this->o 3262 utput, fopen('php://memory', 'w', false));
}
}

private static function createStream(array $inputs)
{
$stream = fopen('php://memory', 'r+', false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,24 @@ public function testGetStatusCode()
{
$this->assertSame(0, $this->tester->getStatusCode(), '->getStatusCode() returns the status code');
}

public function testErrorOutput()
{
$application = new Application();
$application->setAutoExit(false);
$application->register('foo')
->addArgument('foo')
->setCode(function ($input, $output) {
$output->getErrorOutput()->write('foo');
})
;

$tester = new ApplicationTester($application);
$tester->run(
array('command' => 'foo', 'foo' => 'bar'),
array('capture_stderr_separately' => true)
);

$this->assertSame('foo', $tester->getErrorOutput());
}
}
19 changes: 19 additions & 0 deletions src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,23 @@ public function testSymfonyStyleCommandWithInputs()

$this->assertEquals(0, $tester->getStatusCode());
}

public function testErrorOutput()
{
$command = new Command('foo');
$command->addArgument('command');
$command->addArgument('foo');
$command->setCode(function ($input, $output) {
$output->getErrorOutput()->write('foo');
}
);

$tester = new CommandTester($command);
$tester->execute(
array('foo' => 'bar'),
array('capture_stderr_separately' => true)
);

$this->assertSame('foo', $tester->getErrorOutput());
}
}
0