-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[Console] Allow to test the different streams at the same time #61494
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
base: 7.4
Are you sure you want to change the base?
Changes from all commits
ccb38e8
629c58a
24ae826
c87d6b0
6468952
78ae091
a455715
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Fidry\Console package. | ||
* | ||
* (c) Théo FIDRY <theo.fidry@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Symfony\Component\Console\Output; | ||
|
||
use DomainException; | ||
use Symfony\Component\Console\Formatter\OutputFormatterInterface; | ||
use function count; | ||
use function func_get_args; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
final class CombinedOutput implements OutputInterface | ||
{ | ||
/** | ||
* @var OutputInterface[] | ||
*/ | ||
private array $outputs; | ||
|
||
public function __construct( | ||
OutputInterface ...$outputs, | ||
) { | ||
self::assertHasAtLeastOneOutput($outputs); | ||
|
||
$this->outputs = $outputs; | ||
} | ||
|
||
public function write(iterable|string $messages, bool $newline = false, int $options = 0): void | ||
{ | ||
foreach ($this->outputs as $output) { | ||
$output->write(...func_get_args()); | ||
} | ||
} | ||
|
||
public function writeln(iterable|string $messages, int $options = 0): void | ||
{ | ||
foreach ($this->outputs as $output) { | ||
$output->writeln(...func_get_args()); | ||
} | ||
} | ||
|
||
public function setVerbosity(int $level): void | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function getVerbosity(): int | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function isSilent(): bool | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function isQuiet(): bool | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function isVerbose(): bool | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function isVeryVerbose(): bool | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function isDebug(): bool | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function setDecorated(bool $decorated): void | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function isDecorated(): bool | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function setFormatter(OutputFormatterInterface $formatter): void | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
public function getFormatter(): OutputFormatterInterface | ||
{ | ||
throw new DomainException('Should not called.'); | ||
} | ||
|
||
/** | ||
* @param OutputInterface[] $outputs | ||
*/ | ||
private static function assertHasAtLeastOneOutput(array $outputs): void | ||
{ | ||
if (count($outputs) < 1) { | ||
throw new DomainException('Expected at least one output.'); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,8 @@ | |
|
||
use Symfony\Component\Console\Exception\InvalidArgumentException; | ||
use Symfony\Component\Console\Formatter\OutputFormatterInterface; | ||
use function rewind; | ||
use function stream_get_contents; | ||
|
||
/** | ||
* StreamOutput writes the output to a given stream. | ||
|
@@ -74,6 +76,7 @@ protected function doWrite(string $message, bool $newline): void | |
fflush($this->stream); | ||
} | ||
|
||
// TODO: should be public & static? | ||
/** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this piece of code is implemented and use in several places. I wonder if it would make sense to either expose it as a static public utility or extract it and re-use that extracted utility here. But irrelevant to the MR, to clean up |
||
* Returns true if the stream supports colorization. | ||
* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Fidry\Console package. | ||
* | ||
* (c) Théo FIDRY <theo.fidry@gmail.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Symfony\Component\Console\Output; | ||
|
||
use DomainException; | ||
use RuntimeException; | ||
use Symfony\Component\Console\Formatter\OutputFormatterInterface; | ||
use function fopen; | ||
use function func_get_args; | ||
use function rewind; | ||
use function stream_get_contents; | ||
|
||
/** | ||
* @internal | ||
* | ||
* @author Théo FIDRY <theo.fidry@gmail.com> | ||
*/ | ||
final class TestOutput implements ConsoleOutputInterface | ||
{ | ||
private OutputInterface $innerOutput; | ||
private OutputInterface $innerErrorOutput; | ||
private OutputInterface $displayOutput; | ||
private CombinedOutput $output; | ||
private CombinedOutput $errorOutput; | ||
|
||
/** | ||
* @param OutputInterface::VERBOSITY_* $verbosity | ||
*/ | ||
public function __construct( | ||
private int $verbosity, | ||
private OutputFormatterInterface $formatter, | ||
) { | ||
$this->innerOutput = self::createOutput($this); | ||
$this->innerErrorOutput = self::createOutput($this); | ||
$this->displayOutput = self::createOutput($this); | ||
|
||
$this->output = new CombinedOutput( | ||
$this->innerOutput, | ||
$this->displayOutput, | ||
); | ||
$this->errorOutput = new CombinedOutput( | ||
$this->innerErrorOutput, | ||
$this->displayOutput, | ||
); | ||
} | ||
|
||
public function getOutputContents(): string | ||
{ | ||
return $this->getStreamContents($this->innerOutput); | ||
} | ||
|
||
public function getErrorOutputContents(): string | ||
{ | ||
return $this->getStreamContents($this->innerErrorOutput); | ||
} | ||
|
||
public function getDisplayContents(): string | ||
{ | ||
return $this->getStreamContents($this->displayOutput); | ||
} | ||
|
||
public function getErrorOutput(): OutputInterface | ||
{ | ||
return $this->errorOutput; | ||
} | ||
|
||
public function setErrorOutput(OutputInterface $error): void | ||
{ | ||
throw new DomainException('Should not be modified.'); | ||
} | ||
|
||
public function section(): ConsoleSectionOutput | ||
{ | ||
throw new DomainException('Not supported (yet).'); | ||
} | ||
|
||
public function write(iterable|string $messages, bool $newline = false, int $options = 0): void | ||
{ | ||
$this->output->write(...func_get_args()); | ||
} | ||
|
||
public function writeln(iterable|string $messages, int $options = 0): void | ||
{ | ||
$this->output->writeln(...func_get_args()); | ||
} | ||
|
||
public function setVerbosity(int $level): void | ||
{ | ||
throw new DomainException('Should not be modified.'); | ||
} | ||
|
||
public function getVerbosity(): int | ||
{ | ||
return $this->verbosity; | ||
} | ||
|
||
public function isSilent(): bool | ||
{ | ||
return self::VERBOSITY_SILENT <= $this->verbosity; | ||
} | ||
|
||
public function isQuiet(): bool | ||
{ | ||
return self::VERBOSITY_QUIET === $this->verbosity; | ||
} | ||
|
||
public function isVerbose(): bool | ||
{ | ||
return self::VERBOSITY_VERBOSE <= $this->verbosity; | ||
} | ||
|
||
public function isVeryVerbose(): bool | ||
{ | ||
return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; | ||
} | ||
|
||
public function isDebug(): bool | ||
{ | ||
return self::VERBOSITY_DEBUG <= $this->verbosity; | ||
} | ||
|
||
public function setDecorated(bool $decorated): void | ||
{ | ||
throw new DomainException('Should not be modified.'); | ||
} | ||
|
||
public function isDecorated(): bool | ||
{ | ||
return $this->formatter->isDecorated(); | ||
} | ||
|
||
public function setFormatter(OutputFormatterInterface $formatter): void | ||
{ | ||
throw new DomainException('Should not be modified.'); | ||
} | ||
|
||
public function getFormatter(): OutputFormatterInterface | ||
{ | ||
return $this->formatter; | ||
} | ||
|
||
private static function createOutput(OutputInterface $config): StreamOutput | ||
{ | ||
$stream = fopen('php://memory', 'wb'); | ||
|
||
if (false === $stream) { | ||
throw new RuntimeException('Failed to open stream.'); | ||
} | ||
|
||
return new StreamOutput( | ||
$stream, | ||
$config->getVerbosity(), | ||
$config->isDecorated(), | ||
$config->getFormatter(), | ||
); | ||
} | ||
|
||
private function getStreamContents(StreamOutput $output): string | ||
{ | ||
$stream = $output->getStream(); | ||
|
||
rewind($stream); | ||
|
||
return stream_get_contents($stream); | ||
Check failure on line 175 in src/Symfony/Component/Console/Output/TestOutput.php
|
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this assertion, you could have an argument and then the array with other objetcs. All merged together