Skip to content

Commit

Permalink
Merge pull request #38 from pact-foundation/package-handler
Browse files Browse the repository at this point in the history
refactor(2.0): Add PackageHandler
  • Loading branch information
tienvx authored Apr 17, 2024
2 parents f785067 + 011fc92 commit cd434eb
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/Handler/PackageHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace LastCall\DownloadsPlugin\Handler;

use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use LastCall\DownloadsPlugin\Composer\Repository\ExtraDownloadsRepository;
use LastCall\DownloadsPlugin\Parser\Parser;
use LastCall\DownloadsPlugin\Parser\ParserInterface;

class PackageHandler implements PackageHandlerInterface
{
private ParserInterface $parser;
private InstalledRepositoryInterface $repository;

public function __construct(
private Composer $composer,
private IOInterface $io,
?ParserInterface $parser = null,
?InstalledRepositoryInterface $repository = null,
) {
$this->parser = $parser ?? new Parser($this->io);
$vendorDir = $this->composer->getConfig()->get('vendor-dir');
$this->repository = $repository ?? new ExtraDownloadsRepository(new JsonFile($vendorDir.'/composer/installed-extra-downloads.json', null, $this->io));
}

public function handle(PackageInterface $package): void
{
$installationManager = $this->composer->getInstallationManager();
$extraDownloads = array_filter(
$this->parser->parse($package),
fn (PackageInterface $extraDownload) => !$installationManager->isPackageInstalled($this->repository, $extraDownload)
);
if (empty($extraDownloads)) {
return;
}
$operations = array_map(
fn (PackageInterface $extraDownload) => new InstallOperation($extraDownload),
array_values($extraDownloads)
);
$installationManager->execute($this->repository, $operations, false, false);
if (!$package instanceof RootPackageInterface) {
$installationManager->ensureBinariesPresence($package);
}
}
}
10 changes: 10 additions & 0 deletions src/Handler/PackageHandlerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace LastCall\DownloadsPlugin\Handler;

use Composer\Package\PackageInterface;

interface PackageHandlerInterface
{
public function handle(PackageInterface $package): void;
}
160 changes: 160 additions & 0 deletions tests/Unit/Handler/PackageHandlerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<?php

namespace LastCall\DownloadsPlugin\Tests\Unit\Handler;

use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\Installer\InstallationManager;
use Composer\IO\IOInterface;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackage;
use Composer\Repository\InstalledRepositoryInterface;
use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;
use LastCall\DownloadsPlugin\Handler\PackageHandler;
use LastCall\DownloadsPlugin\Handler\PackageHandlerInterface;
use LastCall\DownloadsPlugin\Parser\ParserInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class PackageHandlerTest extends TestCase
{
private Composer|MockObject $composer;
private IOInterface|MockObject $io;
protected ParserInterface|MockObject $parser;
protected InstalledRepositoryInterface|MockObject $repository;
private InstallationManager|MockObject $installationManager;
private PackageHandlerInterface $handler;

protected function setUp(): void
{
$this->composer = $this->createMock(Composer::class);
$this->io = $this->createMock(IOInterface::class);
$this->parser = $this->createMock(ParserInterface::class);
$this->repository = $this->createMock(InstalledRepositoryInterface::class);
$this->installationManager = $this->createMock(InstallationManager::class);
$this->handler = new PackageHandler(
$this->composer,
$this->io,
$this->parser,
$this->repository
);
}

public function testHandleEmptyExtraDownloads(): void
{
$package = $this->createMock(PackageInterface::class);
$this->composer
->expects($this->once())
->method('getInstallationManager')
->willReturn($this->installationManager);
$this->parser
->expects($this->once())
->method('parse')
->with($package)
->willReturn([]);
$this->installationManager
->expects($this->never())
->method('isPackageInstalled');
$this->installationManager
->expects($this->never())
->method('execute');
$this->installationManager
->expects($this->never())
->method('ensureBinariesPresence');
$this->handler->handle($package);
}

public function testHandleAllExtraDownloadsInstalled(): void
{
$package = $this->createMock(PackageInterface::class);
$this->composer
->expects($this->once())
->method('getInstallationManager')
->willReturn($this->installationManager);
$this->parser
->expects($this->once())
->method('parse')
->with($package)
->willReturn([
$extraDownload1 = $this->createMock(ExtraDownloadInterface::class),
$extraDownload2 = $this->createMock(ExtraDownloadInterface::class),
$extraDownload3 = $this->createMock(ExtraDownloadInterface::class),
]);
$this->installationManager
->expects($this->exactly(3))
->method('isPackageInstalled')
->withConsecutive(
[$this->repository, $extraDownload1],
[$this->repository, $extraDownload2],
[$this->repository, $extraDownload3]
)
->willReturn(true);
$this->installationManager
->expects($this->never())
->method('execute');
$this->installationManager
->expects($this->never())
->method('ensureBinariesPresence');
$this->handler->handle($package);
}

public function getHandleTests(): array
{
return [
[new Package('vendor/library-name', '1.0.0', 'v1.0.0'), true],
[new RootPackage('my-organization/my-project', '1.2.3', 'v1.2.3'), false],
];
}

/**
* @dataProvider getHandleTests
*/
public function testHandle(PackageInterface $package, bool $ensureBinariesPresence): void
{
$this->composer
->expects($this->once())
->method('getInstallationManager')
->willReturn($this->installationManager);
$this->parser
->expects($this->once())
->method('parse')
->with($package)
->willReturn([
$extraDownload1 = $this->createMock(ExtraDownloadInterface::class),
$extraDownload2 = $this->createMock(ExtraDownloadInterface::class),
$extraDownload3 = $this->createMock(ExtraDownloadInterface::class),
]);
$this->installationManager
->expects($this->exactly(3))
->method('isPackageInstalled')
->withConsecutive(
[$this->repository, $extraDownload1],
[$this->repository, $extraDownload2],
[$this->repository, $extraDownload3]
)
->willReturnOnConsecutiveCalls(false, true, false);
$this->installationManager
->expects($this->once())
->method('execute')
->with(
$this->repository,
$this->callback(function (array $operations) use ($extraDownload1, $extraDownload3) {
$this->assertCount(2, $operations);
$this->assertInstanceOf(InstallOperation::class, $operations[0]);
$this->assertSame($extraDownload1, $operations[0]->getPackage());
$this->assertInstanceOf(InstallOperation::class, $operations[1]);
$this->assertSame($extraDownload3, $operations[1]->getPackage());

return true;
}),
false,
false,
);
$this->installationManager
->expects($this->exactly($ensureBinariesPresence))
->method('ensureBinariesPresence')
->with($package);
$this->handler->handle($package);
}
}

0 comments on commit cd434eb

Please sign in to comment.