From 05a66047c07654836502cd9e34dd88f936102692 Mon Sep 17 00:00:00 2001 From: Daniel Kreuer Date: Mon, 6 Dec 2021 10:02:15 +0100 Subject: [PATCH 1/4] Introduce results writer for existing cli text --- .../Cli/CheckCommand.php | 32 ++++++------ .../Cli/ResultsWriter/CliText.php | 42 ++++++++++++++++ .../Cli/ResultsWriter/ResultsWriter.php | 13 +++++ .../Cli/ResultsWriter/CliTextTest.php | 50 +++++++++++++++++++ 4 files changed, 123 insertions(+), 14 deletions(-) create mode 100644 src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php create mode 100644 src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php create mode 100644 test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php diff --git a/src/ComposerRequireChecker/Cli/CheckCommand.php b/src/ComposerRequireChecker/Cli/CheckCommand.php index be14c207..f5b6aeb5 100644 --- a/src/ComposerRequireChecker/Cli/CheckCommand.php +++ b/src/ComposerRequireChecker/Cli/CheckCommand.php @@ -5,6 +5,7 @@ namespace ComposerRequireChecker\Cli; use ComposerRequireChecker\ASTLocator\LocateASTFromFiles; +use ComposerRequireChecker\Cli\ResultsWriter\CliText; use ComposerRequireChecker\DefinedExtensionsResolver\DefinedExtensionsResolver; use ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots; use ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromComposerRuntimeApi; @@ -24,19 +25,19 @@ use PhpParser\Lexer; use PhpParser\ParserFactory; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Webmozart\Assert\Assert; +use function array_combine; use function array_diff; +use function array_map; use function array_merge; use function count; use function dirname; use function gettype; -use function implode; use function is_string; use function realpath; use function sprintf; @@ -153,20 +154,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } + $resultsWriter = new CliText($output); + $output->writeln('The following ' . count($unknownSymbols) . ' unknown symbols were found:'); - $table = new Table($output); - $table->setHeaders(['Unknown Symbol', 'Guessed Dependency']); $guesser = new DependencyGuesser($options); - foreach ($unknownSymbols as $unknownSymbol) { - $guessedDependencies = []; - foreach ($guesser($unknownSymbol) as $guessedDependency) { - $guessedDependencies[] = $guessedDependency; - } - - $table->addRow([$unknownSymbol, implode("\n", $guessedDependencies)]); - } - - $table->render(); + $resultsWriter->write( + array_map( + static function (string $unknownSymbol) use ($guesser): array { + $guessedDependencies = []; + foreach ($guesser($unknownSymbol) as $guessedDependency) { + $guessedDependencies[] = $guessedDependency; + } + + return $guessedDependencies; + }, + array_combine($unknownSymbols, $unknownSymbols) + ), + ); return (int) (bool) $unknownSymbols; } diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php b/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php new file mode 100644 index 00000000..27e1dc57 --- /dev/null +++ b/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php @@ -0,0 +1,42 @@ +output = $output; + } + + /** + * {@inheritdoc} + */ + public function write(array $unknownSymbols): void + { + if (! $unknownSymbols) { + $this->output->writeln('There were no unknown symbols found.'); + + return; + } + + $this->output->writeln('The following ' . count($unknownSymbols) . ' unknown symbols were found:'); + $table = new Table($this->output); + $table->setHeaders(['Unknown Symbol', 'Guessed Dependency']); + foreach ($unknownSymbols as $unknownSymbol => $guessedDependencies) { + $table->addRow([$unknownSymbol, implode("\n", $guessedDependencies)]); + } + + $table->render(); + } +} diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php b/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php new file mode 100644 index 00000000..612f12be --- /dev/null +++ b/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php @@ -0,0 +1,13 @@ + $unknownSymbols the unknown symbols found + */ + public function write(array $unknownSymbols): void; +} diff --git a/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php new file mode 100644 index 00000000..e564e62f --- /dev/null +++ b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php @@ -0,0 +1,50 @@ +output = new BufferedOutput(); + $this->writer = new CliText($this->output); + } + + public function testWriteReportNoUnknownSymbolsFound(): void + { + $this->writer->write([]); + + self::assertSame('There were no unknown symbols found.' . PHP_EOL, $this->output->fetch()); + } + + public function testWriteReportWithUnknownSymbols(): void + { + $this->writer->write([ + 'Foo' => [], + 'opcache_get_status' => ['ext-opcache'], + 'dummy' => ['ext-dummy', 'ext-other'], + ]); + + $buffer = $this->output->fetch(); + self::assertStringContainsString('The following 3 unknown symbols were found:', $buffer); + self::assertStringContainsString('Foo', $buffer); + self::assertStringContainsString('| opcache_get_status', $buffer); + self::assertStringContainsString('| ext-opcache', $buffer); + self::assertStringContainsString('| dummy', $buffer); + self::assertStringContainsString('| ext-dummy', $buffer); + self::assertStringContainsString('| ext-other', $buffer); + } +} From ccb234a2131b3dbfcdff38e743f7b16e160f6e8e Mon Sep 17 00:00:00 2001 From: Daniel Kreuer Date: Mon, 6 Dec 2021 12:28:14 +0100 Subject: [PATCH 2/4] Introduce results writer for json format --- .../Cli/ResultsWriter/JsonFile.php | 58 +++++++++++++++++++ .../Cli/ResultsWriter/JsonFileTest.php | 56 ++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php create mode 100644 test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php b/src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php new file mode 100644 index 00000000..4a6ce0ec --- /dev/null +++ b/src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php @@ -0,0 +1,58 @@ +filePathname = $filePathname; + $this->applicationVersion = $applicationVersion; + } + + /** + * {@inheritdoc} + */ + public function write(array $unknownSymbols): void + { + $filePath = dirname($this->filePathname); + if (! mkdir($filePath, 0777, true) && ! is_dir($filePath)) { + throw new RuntimeException(sprintf('Directory "%s" was not created', $filePath)); + } + + file_put_contents( + $this->filePathname, + json_encode( + [ + '_meta' => [ + 'composer-require-checker' => [ + 'version' => $this->applicationVersion, + ], + 'date' => (new DateTimeImmutable())->format(DateTimeImmutable::ATOM), + ], + 'unknown-symbols' => $unknownSymbols, + ], + ) + ); + } +} diff --git a/test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php new file mode 100644 index 00000000..6e66c40f --- /dev/null +++ b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php @@ -0,0 +1,56 @@ +root = vfsStream::setup(); + $this->writer = new JsonFile('vfs://root/path/name.json', '0.0.1'); + } + + public function testWriteReport(): void + { + $this->writer->write([ + 'Foo' => [], + 'opcache_get_status' => ['ext-opcache'], + 'dummy' => ['ext-dummy', 'ext-other'], + ]); + + self::assertFileExists('vfs://root/path/name.json'); + + $actual = json_decode(file_get_contents('vfs://root/path/name.json'), true); + $actual['_meta']['date'] = 'ATOM_DATE'; + + self::assertSame( + [ + '_meta' => [ + 'composer-require-checker' => ['version' => '0.0.1'], + 'date' => 'ATOM_DATE', + ], + 'unknown-symbols' => [ + 'Foo' => [], + 'opcache_get_status' => ['ext-opcache'], + 'dummy' => ['ext-dummy', 'ext-other'], + ], + ], + $actual + ); + } +} From 7230567187957380973baf5d7a189a8e0f21fb88 Mon Sep 17 00:00:00 2001 From: Daniel Kreuer Date: Mon, 6 Dec 2021 12:41:29 +0100 Subject: [PATCH 3/4] Utilize JsonFile report writer adding output option to check command --- .../Cli/CheckCommand.php | 29 +++++++++- .../Cli/ResultsWriter/CliJson.php | 55 ++++++++++++++++++ .../Cli/ResultsWriter/JsonFile.php | 58 ------------------- .../Cli/ResultsWriter/ResultsWriter.php | 2 +- .../Cli/CheckCommandTest.php | 32 ++++++++++ .../{JsonFileTest.php => CliJsonTest.php} | 30 +++++----- 6 files changed, 132 insertions(+), 74 deletions(-) create mode 100644 src/ComposerRequireChecker/Cli/ResultsWriter/CliJson.php delete mode 100644 src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php rename test/ComposerRequireCheckerTest/Cli/ResultsWriter/{JsonFileTest.php => CliJsonTest.php} (57%) diff --git a/src/ComposerRequireChecker/Cli/CheckCommand.php b/src/ComposerRequireChecker/Cli/CheckCommand.php index f5b6aeb5..4c47aa32 100644 --- a/src/ComposerRequireChecker/Cli/CheckCommand.php +++ b/src/ComposerRequireChecker/Cli/CheckCommand.php @@ -5,6 +5,7 @@ namespace ComposerRequireChecker\Cli; use ComposerRequireChecker\ASTLocator\LocateASTFromFiles; +use ComposerRequireChecker\Cli\ResultsWriter\CliJson; use ComposerRequireChecker\Cli\ResultsWriter\CliText; use ComposerRequireChecker\DefinedExtensionsResolver\DefinedExtensionsResolver; use ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots; @@ -19,6 +20,7 @@ use ComposerRequireChecker\GeneratorUtil\ComposeGenerators; use ComposerRequireChecker\JsonLoader; use ComposerRequireChecker\UsedSymbolsLocator\LocateUsedSymbolsFromASTRoots; +use DateTimeImmutable; use InvalidArgumentException; use LogicException; use PhpParser\ErrorHandler\Collecting as CollectingErrorHandler; @@ -37,6 +39,7 @@ use function array_merge; use function count; use function dirname; +use function file_put_contents; use function gettype; use function is_string; use function realpath; @@ -69,11 +72,21 @@ protected function configure(): void InputOption::VALUE_NONE, 'this will cause ComposerRequireChecker to ignore errors when files cannot be parsed, otherwise' . ' errors will be thrown' + ) + ->addOption( + 'output', + null, + InputOption::VALUE_REQUIRED, + 'generate output either as "text" or as "json", if specified, "quiet mode" is implied' ); } protected function execute(InputInterface $input, OutputInterface $output): int { + if ($input->getOption('output') !== null) { + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + } + if (! $output->isQuiet()) { $application = $this->getApplication(); $output->writeln($application !== null ? $application->getLongVersion() : 'Unknown version'); @@ -154,7 +167,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - $resultsWriter = new CliText($output); + switch ($input->getOption('output')) { + case 'json': + $application = $this->getApplication(); + $resultsWriter = new CliJson( + static function (string $string): void { + file_put_contents('php://stdout', $string); + }, + $application !== null ? $application->getVersion() : 'Unknown version', + static fn () => new DateTimeImmutable() + ); + break; + case 'text': + default: + $resultsWriter = new CliText($output); + } $output->writeln('The following ' . count($unknownSymbols) . ' unknown symbols were found:'); $guesser = new DependencyGuesser($options); diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/CliJson.php b/src/ComposerRequireChecker/Cli/ResultsWriter/CliJson.php new file mode 100644 index 00000000..dc28dd80 --- /dev/null +++ b/src/ComposerRequireChecker/Cli/ResultsWriter/CliJson.php @@ -0,0 +1,55 @@ +writeCallable = $write; + $this->applicationVersion = $applicationVersion; + $this->nowCallable = $now; + } + + /** + * {@inheritdoc} + */ + public function write(array $unknownSymbols): void + { + $write = $this->writeCallable; + $now = $this->nowCallable; + + $write( + json_encode( + [ + '_meta' => [ + 'composer-require-checker' => [ + 'version' => $this->applicationVersion, + ], + 'date' => $now()->format(DateTimeImmutable::ATOM), + ], + 'unknown-symbols' => $unknownSymbols, + ], + JSON_THROW_ON_ERROR + ) + ); + } +} diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php b/src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php deleted file mode 100644 index 4a6ce0ec..00000000 --- a/src/ComposerRequireChecker/Cli/ResultsWriter/JsonFile.php +++ /dev/null @@ -1,58 +0,0 @@ -filePathname = $filePathname; - $this->applicationVersion = $applicationVersion; - } - - /** - * {@inheritdoc} - */ - public function write(array $unknownSymbols): void - { - $filePath = dirname($this->filePathname); - if (! mkdir($filePath, 0777, true) && ! is_dir($filePath)) { - throw new RuntimeException(sprintf('Directory "%s" was not created', $filePath)); - } - - file_put_contents( - $this->filePathname, - json_encode( - [ - '_meta' => [ - 'composer-require-checker' => [ - 'version' => $this->applicationVersion, - ], - 'date' => (new DateTimeImmutable())->format(DateTimeImmutable::ATOM), - ], - 'unknown-symbols' => $unknownSymbols, - ], - ) - ); - } -} diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php b/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php index 612f12be..e45d7e78 100644 --- a/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php +++ b/src/ComposerRequireChecker/Cli/ResultsWriter/ResultsWriter.php @@ -7,7 +7,7 @@ interface ResultsWriter { /** - * @param array $unknownSymbols the unknown symbols found + * @param array> $unknownSymbols the unknown symbols found */ public function write(array $unknownSymbols): void; } diff --git a/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php b/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php index ec9a4249..b4ae7443 100644 --- a/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php +++ b/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php @@ -14,7 +14,9 @@ use Symfony\Component\Console\Tester\CommandTester; use function dirname; +use function file_get_contents; use function file_put_contents; +use function json_decode; use function unlink; use function version_compare; @@ -75,6 +77,36 @@ public function testUnknownSymbolsFound(): void $this->assertStringContainsString('libxml_clear_errors', $display); } + public function testUnknownSymbolsFoundJsonReport(): void + { + $vfsRoot = vfsStream::setup(); + + $this->commandTester->execute([ + 'composer-json' => dirname(__DIR__, 2) . '/fixtures/unknownSymbols/composer.json', + '--report-json' => 'vfs://root/path/report.json', + ]); + + $this->assertSame(Command::FAILURE, $this->commandTester->getStatusCode()); + $display = $this->commandTester->getDisplay(); + + $this->assertStringContainsString('Doctrine\Common\Collections\ArrayCollection', $display); + + /** @var array{'unknown-symbols': array} $actual */ + $actual = json_decode(file_get_contents('vfs://root/path/report.json'), true); + + $this->assertSame( + [ + 'Doctrine\Common\Collections\ArrayCollection' => [], + 'Example\Library\Dependency' => [], + 'FILTER_VALIDATE_URL' => ['ext-filter'], + 'filter_var' => ['ext-filter'], + 'Foo\Bar\Baz' => [], + 'libxml_clear_errors' => ['ext-libxml'], + ], + $actual['unknown-symbols'] + ); + } + public function testSelfCheckShowsNoErrors(): void { $this->commandTester->execute([ diff --git a/test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliJsonTest.php similarity index 57% rename from test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php rename to test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliJsonTest.php index 6e66c40f..107a27fa 100644 --- a/test/ComposerRequireCheckerTest/Cli/ResultsWriter/JsonFileTest.php +++ b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliJsonTest.php @@ -4,25 +4,30 @@ namespace ComposerRequireCheckerTest\Cli\ResultsWriter; -use ComposerRequireChecker\Cli\ResultsWriter\JsonFile; -use org\bovigo\vfs\vfsStream; -use org\bovigo\vfs\vfsStreamDirectory; +use ComposerRequireChecker\Cli\ResultsWriter\CliJson; +use DateTimeImmutable; use PHPUnit\Framework\TestCase; -use function file_get_contents; use function json_decode; -final class JsonFileTest extends TestCase +use const JSON_THROW_ON_ERROR; + +final class CliJsonTest extends TestCase { - private JsonFile $writer; - private vfsStreamDirectory $root; + private CliJson $writer; + private string $output = ''; protected function setUp(): void { parent::setUp(); - $this->root = vfsStream::setup(); - $this->writer = new JsonFile('vfs://root/path/name.json', '0.0.1'); + $this->writer = new CliJson( + function (string $string): void { + $this->output .= $string; + }, + '0.0.1', + static fn () => new DateTimeImmutable('@0') + ); } public function testWriteReport(): void @@ -33,16 +38,13 @@ public function testWriteReport(): void 'dummy' => ['ext-dummy', 'ext-other'], ]); - self::assertFileExists('vfs://root/path/name.json'); - - $actual = json_decode(file_get_contents('vfs://root/path/name.json'), true); - $actual['_meta']['date'] = 'ATOM_DATE'; + $actual = json_decode($this->output, true, JSON_THROW_ON_ERROR); self::assertSame( [ '_meta' => [ 'composer-require-checker' => ['version' => '0.0.1'], - 'date' => 'ATOM_DATE', + 'date' => '1970-01-01T00:00:00+00:00', ], 'unknown-symbols' => [ 'Foo' => [], From 3d4cd6f039804d74a2f6b86db5780db90e45446a Mon Sep 17 00:00:00 2001 From: Daniel Kreuer Date: Tue, 7 Dec 2021 12:27:31 +0100 Subject: [PATCH 4/4] Adjust CliText results writer to be able to specify option output=text --- .../Cli/CheckCommand.php | 37 +++++++++++----- .../Cli/ResultsWriter/CliText.php | 19 ++++++++- .../Cli/CheckCommandTest.php | 42 +++++++++++++++---- .../Cli/ResultsWriter/CliTextTest.php | 40 ++++++++++++++++++ 4 files changed, 118 insertions(+), 20 deletions(-) diff --git a/src/ComposerRequireChecker/Cli/CheckCommand.php b/src/ComposerRequireChecker/Cli/CheckCommand.php index 4c47aa32..7eee6d27 100644 --- a/src/ComposerRequireChecker/Cli/CheckCommand.php +++ b/src/ComposerRequireChecker/Cli/CheckCommand.php @@ -37,10 +37,11 @@ use function array_diff; use function array_map; use function array_merge; +use function assert; use function count; use function dirname; -use function file_put_contents; use function gettype; +use function in_array; use function is_string; use function realpath; use function sprintf; @@ -81,6 +82,22 @@ protected function configure(): void ); } + protected function initialize(InputInterface $input, OutputInterface $output): void + { + if ($input->getOption('output') === null) { + return; + } + + $optionValue = $input->getOption('output'); + assert(is_string($optionValue)); + + if (! in_array($optionValue, ['text', 'json'])) { + throw new InvalidArgumentException( + 'Option "output" must be either of value "json", "text" or omitted altogether' + ); + } + } + protected function execute(InputInterface $input, OutputInterface $output): int { if ($input->getOption('output') !== null) { @@ -161,29 +178,29 @@ protected function execute(InputInterface $input, OutputInterface $output): int $options->getSymbolWhitelist() ); - if (! $unknownSymbols) { - $output->writeln('There were no unknown symbols found.'); - - return 0; - } - switch ($input->getOption('output')) { case 'json': $application = $this->getApplication(); $resultsWriter = new CliJson( - static function (string $string): void { - file_put_contents('php://stdout', $string); + static function (string $string) use ($output): void { + $output->write($string, false, OutputInterface::VERBOSITY_QUIET | OutputInterface::OUTPUT_RAW); }, $application !== null ? $application->getVersion() : 'Unknown version', static fn () => new DateTimeImmutable() ); break; case 'text': + $resultsWriter = new CliText( + $output, + static function (string $string) use ($output): void { + $output->write($string, false, OutputInterface::VERBOSITY_QUIET | OutputInterface::OUTPUT_RAW); + } + ); + break; default: $resultsWriter = new CliText($output); } - $output->writeln('The following ' . count($unknownSymbols) . ' unknown symbols were found:'); $guesser = new DependencyGuesser($options); $resultsWriter->write( array_map( diff --git a/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php b/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php index 27e1dc57..ede7c791 100644 --- a/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php +++ b/src/ComposerRequireChecker/Cli/ResultsWriter/CliText.php @@ -5,6 +5,7 @@ namespace ComposerRequireChecker\Cli\ResultsWriter; use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; use function count; @@ -13,10 +14,19 @@ final class CliText implements ResultsWriter { private OutputInterface $output; + /** @var callable */ + private $writeCallable; - public function __construct(OutputInterface $output) + public function __construct(OutputInterface $output, ?callable $write = null) { $this->output = $output; + if ($write === null) { + $write = static function (string $string) use ($output): void { + $output->write($string); + }; + } + + $this->writeCallable = $write; } /** @@ -31,12 +41,17 @@ public function write(array $unknownSymbols): void } $this->output->writeln('The following ' . count($unknownSymbols) . ' unknown symbols were found:'); - $table = new Table($this->output); + + $tableOutput = new BufferedOutput(); + $table = new Table($tableOutput); $table->setHeaders(['Unknown Symbol', 'Guessed Dependency']); foreach ($unknownSymbols as $unknownSymbol => $guessedDependencies) { $table->addRow([$unknownSymbol, implode("\n", $guessedDependencies)]); } $table->render(); + + $write = $this->writeCallable; + $write($tableOutput->fetch()); } } diff --git a/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php b/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php index b4ae7443..15be1368 100644 --- a/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php +++ b/test/ComposerRequireCheckerTest/Cli/CheckCommandTest.php @@ -14,12 +14,12 @@ use Symfony\Component\Console\Tester\CommandTester; use function dirname; -use function file_get_contents; use function file_put_contents; use function json_decode; use function unlink; use function version_compare; +use const JSON_THROW_ON_ERROR; use const PHP_VERSION; final class CheckCommandTest extends TestCase @@ -77,22 +77,29 @@ public function testUnknownSymbolsFound(): void $this->assertStringContainsString('libxml_clear_errors', $display); } - public function testUnknownSymbolsFoundJsonReport(): void + public function testInvalidOutputOptionValue(): void { - $vfsRoot = vfsStream::setup(); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Option "output" must be either of value "json", "text" or omitted altogether'); $this->commandTester->execute([ 'composer-json' => dirname(__DIR__, 2) . '/fixtures/unknownSymbols/composer.json', - '--report-json' => 'vfs://root/path/report.json', + '--output' => '__invalid__', + ]); + } + + public function testUnknownSymbolsFoundJsonReport(): void + { + $this->commandTester->execute([ + 'composer-json' => dirname(__DIR__, 2) . '/fixtures/unknownSymbols/composer.json', + '--output' => 'json', ]); $this->assertSame(Command::FAILURE, $this->commandTester->getStatusCode()); $display = $this->commandTester->getDisplay(); - $this->assertStringContainsString('Doctrine\Common\Collections\ArrayCollection', $display); - - /** @var array{'unknown-symbols': array} $actual */ - $actual = json_decode(file_get_contents('vfs://root/path/report.json'), true); + /** @var array{'unknown-symbols': array>} $actual */ + $actual = json_decode($display, true, JSON_THROW_ON_ERROR); $this->assertSame( [ @@ -107,6 +114,25 @@ public function testUnknownSymbolsFoundJsonReport(): void ); } + public function testUnknownSymbolsFoundTextReport(): void + { + $this->commandTester->execute([ + 'composer-json' => dirname(__DIR__, 2) . '/fixtures/unknownSymbols/composer.json', + '--output' => 'text', + ]); + + $this->assertSame(Command::FAILURE, $this->commandTester->getStatusCode()); + $display = $this->commandTester->getDisplay(); + + $this->assertStringNotContainsString('The following 6 unknown symbols were found:', $display); + $this->assertStringContainsString('Doctrine\Common\Collections\ArrayCollection', $display); + $this->assertStringContainsString('Example\Library\Dependency', $display); + $this->assertStringContainsString('FILTER_VALIDATE_URL', $display); + $this->assertStringContainsString('filter_var', $display); + $this->assertStringContainsString('Foo\Bar\Baz', $display); + $this->assertStringContainsString('libxml_clear_errors', $display); + } + public function testSelfCheckShowsNoErrors(): void { $this->commandTester->execute([ diff --git a/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php index e564e62f..1399c480 100644 --- a/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php +++ b/test/ComposerRequireCheckerTest/Cli/ResultsWriter/CliTextTest.php @@ -7,6 +7,7 @@ use ComposerRequireChecker\Cli\ResultsWriter\CliText; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Console\Output\OutputInterface; use const PHP_EOL; @@ -47,4 +48,43 @@ public function testWriteReportWithUnknownSymbols(): void self::assertStringContainsString('| ext-dummy', $buffer); self::assertStringContainsString('| ext-other', $buffer); } + + public function testWriteReportQuiet(): void + { + $this->output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + + $this->writer->write([ + 'Foo' => [], + 'opcache_get_status' => ['ext-opcache'], + 'dummy' => ['ext-dummy', 'ext-other'], + ]); + + $buffer = $this->output->fetch(); + self::assertSame('', $buffer); + } + + public function testWriteReportQuietWithWriteCallable(): void + { + $output = ''; + $write = static function (string $string) use (&$output): void { + $output .= $string; + }; + + $writer = new CliText($this->output, $write); + $writer->write([ + 'Foo' => [], + 'opcache_get_status' => ['ext-opcache'], + 'dummy' => ['ext-dummy', 'ext-other'], + ]); + + $buffer = $this->output->fetch(); + self::assertStringContainsString('The following 3 unknown symbols were found:', $buffer); + self::assertStringNotContainsString('Foo', $buffer); + self::assertStringContainsString('Foo', $output); + self::assertStringContainsString('| opcache_get_status', $output); + self::assertStringContainsString('| ext-opcache', $output); + self::assertStringContainsString('| dummy', $output); + self::assertStringContainsString('| ext-dummy', $output); + self::assertStringContainsString('| ext-other', $output); + } }