From ce99b8b9f963b7cd4dfcf5c415908ac8f0c01cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Wed, 18 Oct 2023 01:02:21 +0200 Subject: [PATCH] fix: Correct detect the Composer version with a polluted output In the case the output is polluted by deprecation messages or other, Box could not figure out the Composer version. --- src/Composer/ComposerOrchestrator.php | 2 +- src/Composer/ComposerProcessFactory.php | 3 +- tests/Composer/ComposerOrchestratorTest.php | 116 ++++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 tests/Composer/ComposerOrchestratorTest.php diff --git a/src/Composer/ComposerOrchestrator.php b/src/Composer/ComposerOrchestrator.php index 4ef305b4c..d0eeee288 100644 --- a/src/Composer/ComposerOrchestrator.php +++ b/src/Composer/ComposerOrchestrator.php @@ -75,7 +75,7 @@ public function getVersion(): string $output = $getVersionProcess->getOutput(); - if (1 !== preg_match('/^Composer version ([^\\s]+)/', $output, $match)) { + if (1 !== preg_match('/Composer version (\S+?) /', $output, $match)) { throw UndetectableComposerVersion::forOutput( $getVersionProcess, $output, diff --git a/src/Composer/ComposerProcessFactory.php b/src/Composer/ComposerProcessFactory.php index 6afe7c495..074433a88 100644 --- a/src/Composer/ComposerProcessFactory.php +++ b/src/Composer/ComposerProcessFactory.php @@ -21,9 +21,10 @@ use const KevinGH\Box\BOX_ALLOW_XDEBUG; /** + * @final * @private */ -final class ComposerProcessFactory +class ComposerProcessFactory { public static function create( ?string $composerExecutable = null, diff --git a/tests/Composer/ComposerOrchestratorTest.php b/tests/Composer/ComposerOrchestratorTest.php new file mode 100644 index 000000000..1b5cbc082 --- /dev/null +++ b/tests/Composer/ComposerOrchestratorTest.php @@ -0,0 +1,116 @@ + + * Théo Fidry + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace KevinGH\Box\Composer; + +use Fidry\FileSystem\FileSystem; +use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; +use Prophecy\Prophecy\ObjectProphecy; +use Psr\Log\NullLogger; +use Symfony\Component\Process\Process; + +/** + * @covers \KevinGH\Box\Composer\ComposerOrchestrator + * @internal + */ +final class ComposerOrchestratorTest extends TestCase +{ + use ProphecyTrait; + + /** @var ObjectProphecy */ + private ObjectProphecy $processFactoryProphecy; + /** @var ObjectProphecy */ + private ObjectProphecy $processProphecy; + private ComposerOrchestrator $orchestrator; + + protected function setUp(): void + { + $this->processFactoryProphecy = $this->prophesize(ComposerProcessFactory::class); + $this->processProphecy = $this->prophesize(Process::class); + + $this->orchestrator = new ComposerOrchestrator( + $this->processFactoryProphecy->reveal(), + new NullLogger(), + new FileSystem(), + ); + } + + /** + * @dataProvider outputProvider + */ + public function test_it_can_detect_the_version_from_the_process_output( + string $output, + string|UndetectableComposerVersion $expected, + ): void { + $this->processFactoryProphecy + ->getVersionProcess() + ->willReturn($this->processProphecy->reveal()); + + $this->configureProcessProphecy($output); + + if ($expected instanceof UndetectableComposerVersion) { + $this->expectExceptionObject($expected); + } + + $actual = $this->orchestrator->getVersion(); + + self::assertSame($expected, $actual); + } + + public static function outputProvider(): iterable + { + yield 'nominal' => [ + 'Composer version 2.6.3 2023-09-15 09:38:21', + '2.6.3', + ]; + + yield 'with ANSI' => [ + 'Composer version 2.6.3 2023-09-15 09:38:21', + new UndetectableComposerVersion( + <<<'EOF' + Could not determine the Composer version from the following output: + Composer version 2.6.3 2023-09-15 09:38:21 + EOF, + ), + ]; + + yield 'output polluted by deprecated messages' => [ + <<<'EOF' + PHP Deprecated: ... + Composer version 2.6.3 2023-09-15 09:38:21 + EOF, + '2.6.3', + ]; + } + + public function configureProcessProphecy(string $output): void + { + $this->processProphecy + ->getCommandLine() + ->willReturn('cmd'); + + $this->processProphecy + ->run() + ->willReturn(0); + + $this->processProphecy + ->isSuccessful() + ->willReturn(true); + + $this->processProphecy + ->getOutput() + ->willReturn($output); + } +}