mirror of
https://github.com/php/pie.git
synced 2026-03-24 07:22:17 +01:00
217 lines
9.4 KiB
PHP
217 lines
9.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Php\PieIntegrationTest\Command;
|
|
|
|
use Composer\Composer;
|
|
use Composer\IO\IOInterface;
|
|
use Composer\Package\Link;
|
|
use Composer\Package\RootPackage;
|
|
use Composer\Repository\InstalledArrayRepository;
|
|
use Composer\Repository\RepositoryManager;
|
|
use Composer\Semver\Constraint\Constraint;
|
|
use Composer\Semver\Constraint\MultiConstraint;
|
|
use Php\Pie\Command\InstallExtensionsForProjectCommand;
|
|
use Php\Pie\ComposerIntegration\MinimalHelperSet;
|
|
use Php\Pie\ComposerIntegration\PieJsonEditor;
|
|
use Php\Pie\ComposerIntegration\QuieterConsoleIO;
|
|
use Php\Pie\Container;
|
|
use Php\Pie\ExtensionType;
|
|
use Php\Pie\Installing\InstallForPhpProject\ComposerFactoryForProject;
|
|
use Php\Pie\Installing\InstallForPhpProject\DetermineExtensionsRequired;
|
|
use Php\Pie\Installing\InstallForPhpProject\FindMatchingPackages;
|
|
use Php\Pie\Installing\InstallForPhpProject\InstallPiePackageFromPath;
|
|
use Php\Pie\Installing\InstallForPhpProject\InstallSelectedPackage;
|
|
use Php\Pie\Platform\InstalledPiePackages;
|
|
use PHPUnit\Framework\Attributes\CoversClass;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Container\ContainerInterface;
|
|
use Symfony\Component\Console\Command\Command;
|
|
use Symfony\Component\Console\Helper\HelperSet;
|
|
use Symfony\Component\Console\Helper\QuestionHelper;
|
|
use Symfony\Component\Console\Input\ArrayInput;
|
|
use Symfony\Component\Console\Input\InputInterface;
|
|
use Symfony\Component\Console\Output\BufferedOutput;
|
|
|
|
use function getcwd;
|
|
|
|
#[CoversClass(InstallExtensionsForProjectCommand::class)]
|
|
final class InstallExtensionsForProjectCommandTest extends TestCase
|
|
{
|
|
private CommandTester $commandTester;
|
|
private ComposerFactoryForProject&MockObject $composerFactoryForProject;
|
|
private FindMatchingPackages&MockObject $findMatchingPackages;
|
|
private InstalledPiePackages&MockObject $installedPiePackages;
|
|
private InstallSelectedPackage&MockObject $installSelectedPackage;
|
|
private QuestionHelper&MockObject $questionHelper;
|
|
private InstallPiePackageFromPath&MockObject $installPiePackage;
|
|
|
|
public function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$container = $this->createMock(ContainerInterface::class);
|
|
$container->method('get')->willReturnCallback(
|
|
/** @param class-string $service */
|
|
function (string $service): mixed {
|
|
switch ($service) {
|
|
case QuieterConsoleIO::class:
|
|
return new QuieterConsoleIO(
|
|
new ArrayInput([]),
|
|
new BufferedOutput(),
|
|
new MinimalHelperSet(['question' => new QuestionHelper()]),
|
|
);
|
|
|
|
default:
|
|
return $this->createMock($service);
|
|
}
|
|
},
|
|
);
|
|
|
|
$this->composerFactoryForProject = $this->createMock(ComposerFactoryForProject::class);
|
|
$this->findMatchingPackages = $this->createMock(FindMatchingPackages::class);
|
|
$this->installedPiePackages = $this->createMock(InstalledPiePackages::class);
|
|
$this->installSelectedPackage = $this->createMock(InstallSelectedPackage::class);
|
|
$this->installPiePackage = $this->createMock(InstallPiePackageFromPath::class);
|
|
$this->questionHelper = $this->createMock(QuestionHelper::class);
|
|
|
|
Container::testFactory();
|
|
$cmd = new InstallExtensionsForProjectCommand(
|
|
$this->composerFactoryForProject,
|
|
new DetermineExtensionsRequired(),
|
|
$this->installedPiePackages,
|
|
$this->findMatchingPackages,
|
|
$this->installSelectedPackage,
|
|
$this->installPiePackage,
|
|
$container,
|
|
Container::testBuffer(),
|
|
);
|
|
$cmd->setHelperSet(new HelperSet([
|
|
'question' => $this->questionHelper,
|
|
]));
|
|
$this->commandTester = new CommandTester($cmd);
|
|
}
|
|
|
|
public function testInstallingExtensionsForPhpProject(): void
|
|
{
|
|
$rootPackage = new RootPackage('my/project', '1.2.3.0', '1.2.3');
|
|
$rootPackage->setRequires([
|
|
'ext-standard' => new Link('my/project', 'ext-standard', new Constraint('=', '*'), Link::TYPE_REQUIRE, '*'),
|
|
'ext-foobar' => new Link('my/project', 'ext-foobar', new MultiConstraint([
|
|
new Constraint('>=', '1.2.0.0-dev'),
|
|
new Constraint('<', '2.0.0.0-dev'),
|
|
]), Link::TYPE_REQUIRE, '^1.2'),
|
|
]);
|
|
$this->composerFactoryForProject->method('rootPackage')->willReturn($rootPackage);
|
|
|
|
$installedRepository = new InstalledArrayRepository([$rootPackage]);
|
|
|
|
$repositoryManager = $this->createMock(RepositoryManager::class);
|
|
$repositoryManager->method('getLocalRepository')->willReturn($installedRepository);
|
|
|
|
$composer = $this->createMock(Composer::class);
|
|
$composer->method('getPackage')->willReturn($rootPackage);
|
|
$composer->method('getRepositoryManager')->willReturn($repositoryManager);
|
|
|
|
$this->composerFactoryForProject->method('composer')->willReturn($composer);
|
|
|
|
$this->findMatchingPackages->method('for')->willReturn([
|
|
['name' => 'vendor1/foobar', 'description' => 'The official foobar implementation'],
|
|
]);
|
|
|
|
$this->questionHelper->method('ask')->willReturn('vendor1/foobar: The official foobar implementation');
|
|
|
|
$this->installSelectedPackage->expects(self::once())
|
|
->method('withPieCli')
|
|
->with('vendor1/foobar:^1.2');
|
|
|
|
$this->commandTester->execute(
|
|
['--allow-non-interactive-project-install' => true],
|
|
['verbosity' => BufferedOutput::VERBOSITY_VERY_VERBOSE],
|
|
);
|
|
|
|
$outputString = $this->commandTester->getDisplay();
|
|
|
|
$this->commandTester->assertCommandIsSuccessful($outputString);
|
|
self::assertStringContainsString('Checking extensions for your project my/project', $outputString);
|
|
self::assertStringContainsString('requires: ext-standard:* ✅ Already installed', $outputString);
|
|
self::assertStringContainsString('requires: ext-foobar:^1.2 🚫 Missing', $outputString);
|
|
}
|
|
|
|
public function testInstallingExtensionsForPhpProjectWithMultipleMatches(): void
|
|
{
|
|
$rootPackage = new RootPackage('my/project', '1.2.3.0', '1.2.3');
|
|
$rootPackage->setRequires([
|
|
'ext-standard' => new Link('my/project', 'ext-standard', new Constraint('=', '*'), Link::TYPE_REQUIRE, '*'),
|
|
'ext-foobar' => new Link('my/project', 'ext-foobar', new MultiConstraint([
|
|
new Constraint('>=', '1.2.0.0-dev'),
|
|
new Constraint('<', '2.0.0.0-dev'),
|
|
]), Link::TYPE_REQUIRE, '^1.2'),
|
|
]);
|
|
$this->composerFactoryForProject->method('rootPackage')->willReturn($rootPackage);
|
|
|
|
$installedRepository = new InstalledArrayRepository([$rootPackage]);
|
|
|
|
$repositoryManager = $this->createMock(RepositoryManager::class);
|
|
$repositoryManager->method('getLocalRepository')->willReturn($installedRepository);
|
|
|
|
$composer = $this->createMock(Composer::class);
|
|
$composer->method('getPackage')->willReturn($rootPackage);
|
|
$composer->method('getRepositoryManager')->willReturn($repositoryManager);
|
|
|
|
$this->composerFactoryForProject->method('composer')->willReturn($composer);
|
|
|
|
$this->findMatchingPackages->method('for')->willReturn([
|
|
['name' => 'vendor1/foobar', 'description' => 'The official foobar implementation'],
|
|
['name' => 'vendor2/afoobar', 'description' => 'An improved async foobar extension'],
|
|
]);
|
|
|
|
$this->questionHelper->method('ask')->willReturn('vendor1/foobar: The official foobar implementation');
|
|
|
|
$this->installSelectedPackage->expects(self::never())
|
|
->method('withPieCli');
|
|
|
|
$this->commandTester->execute(
|
|
['--allow-non-interactive-project-install' => true],
|
|
['verbosity' => BufferedOutput::VERBOSITY_VERY_VERBOSE],
|
|
);
|
|
|
|
$outputString = $this->commandTester->getDisplay();
|
|
|
|
self::assertSame(Command::FAILURE, $this->commandTester->getStatusCode());
|
|
self::assertStringContainsString('Checking extensions for your project my/project', $outputString);
|
|
self::assertStringContainsString('requires: ext-standard:* ✅ Already installed', $outputString);
|
|
self::assertStringContainsString('requires: ext-foobar:^1.2 🚫 Missing', $outputString);
|
|
self::assertStringContainsString('Multiple packages were found for ext-foobar', $outputString);
|
|
}
|
|
|
|
public function testInstallingExtensionsForPieProject(): void
|
|
{
|
|
$rootPackage = new RootPackage('my/project', '1.2.3.0', '1.2.3');
|
|
$rootPackage->setType(ExtensionType::PhpModule->value);
|
|
$this->composerFactoryForProject->method('rootPackage')->willReturn($rootPackage);
|
|
|
|
$this->installPiePackage
|
|
->expects(self::once())
|
|
->method('__invoke')
|
|
->with(
|
|
self::isInstanceOf(InstallExtensionsForProjectCommand::class),
|
|
getcwd(),
|
|
$rootPackage,
|
|
self::isInstanceOf(PieJsonEditor::class),
|
|
self::isInstanceOf(InputInterface::class),
|
|
self::isInstanceOf(IOInterface::class),
|
|
)
|
|
->willReturn(Command::SUCCESS);
|
|
|
|
$this->commandTester->execute(
|
|
[],
|
|
['verbosity' => BufferedOutput::VERBOSITY_VERY_VERBOSE],
|
|
);
|
|
|
|
$this->commandTester->assertCommandIsSuccessful();
|
|
}
|
|
}
|