Skip to content

Commit

Permalink
refactor(2.0): Add ExtraDownloadsRepository
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Apr 17, 2024
1 parent 5f3de63 commit 3933c2b
Show file tree
Hide file tree
Showing 2 changed files with 378 additions and 0 deletions.
144 changes: 144 additions & 0 deletions src/Composer/Repository/ExtraDownloadsRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace LastCall\DownloadsPlugin\Composer\Repository;

use Composer\Installer\InstallationManager;
use Composer\Json\JsonFile;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Repository\InvalidRepositoryException;
use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;

class ExtraDownloadsRepository implements InstalledRepositoryInterface
{
private array $extraDownloads;

public function __construct(private JsonFile $file)
{
$this->initialize();
}

public function addPackage(PackageInterface $package): void
{
if ($package instanceof ExtraDownloadInterface) {
$this->extraDownloads[$package->getName()] = $package->getTrackingChecksum();
}
}

public function removePackage(PackageInterface $package): void
{
if ($package instanceof ExtraDownloadInterface) {
unset($this->extraDownloads[$package->getName()]);
}
}

public function hasPackage(PackageInterface $package): bool
{
if (!$package instanceof ExtraDownloadInterface) {
return false;
}
$name = $package->getName();
if (!isset($this->extraDownloads[$name])) {
return false;
}

return $this->extraDownloads[$name] === $package->getTrackingChecksum();
}

protected function initialize(): void
{
$this->extraDownloads = [];

if (!$this->file->exists()) {
return;
}

try {
$packages = $this->file->read();

if (!\is_array($packages)) {
throw new \UnexpectedValueException('Could not parse package list from the repository');
}
} catch (\Exception $e) {
throw new InvalidRepositoryException('Invalid repository data in '.$this->file->getPath().', packages could not be loaded: ['.$e::class.'] '.$e->getMessage());
}

foreach ($packages as $name => $trackingChecksum) {
$this->extraDownloads[$name] = $trackingChecksum;
}
}

public function reload(): void
{
$this->initialize();
}

public function isFresh(): bool
{
return !$this->file->exists();
}

public function write(bool $devMode, InstallationManager $installationManager): void
{
$this->file->write($this->extraDownloads);
}

public function getCanonicalPackages(): array
{
return [];
}

public function getDevPackageNames(): array
{
return [];
}

public function setDevPackageNames(array $devPackageNames): void
{
}

public function count(): int
{
return 0;
}

public function getRepoName(): string
{
return 'installed extra downloads';
}

public function getDevMode(): ?bool
{
return null;
}

public function findPackage(string $name, $constraint): ?PackageInterface
{
return null;
}

public function findPackages(string $name, $constraint = null): array
{
return [];
}

public function getPackages(): array
{
return [];
}

public function getProviders(string $packageName): array
{
return [];
}

public function loadPackages(array $packageNameMap, array $acceptableStabilities, array $stabilityFlags, array $alreadyLoaded = []): array
{
return [];
}

public function search(string $query, int $mode = 0, ?string $type = null): array
{
return [];
}
}
234 changes: 234 additions & 0 deletions tests/Unit/Composer/Repository/ExtraDownloadsRepositoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
<?php

namespace LastCall\DownloadsPlugin\Tests\Unit\Composer\Repository;

use Composer\Installer\InstallationManager;
use Composer\Json\JsonFile;
use Composer\Package\PackageInterface;
use Composer\Repository\InvalidRepositoryException;
use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;
use LastCall\DownloadsPlugin\Composer\Repository\ExtraDownloadsRepository;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Seld\JsonLint\ParsingException;
use VirtualFileSystem\FileSystem;

class ExtraDownloadsRepositoryTest extends TestCase
{
private ?FileSystem $fs = null;
private PackageInterface|MockObject $package;
private ExtraDownloadInterface|MockObject $extraDownload;
private ExtraDownloadsRepository $repository;
private string $path = '/path/to/vendor/composer/installed-extra-downloads.json';
private string $name = 'vendor/package-name:extra-file';
private string $trackingChecksum = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08';

protected function setUp(): void
{
$this->fs = new FileSystem();
$this->package = $this->createMock(PackageInterface::class);
$this->extraDownload = $this->createMock(ExtraDownloadInterface::class);
$this->repository = new ExtraDownloadsRepository(new JsonFile($this->fs->path($this->path)));
}

protected function tearDown(): void
{
$this->fs = null;
}

public function testAddPackage(): void
{
$this->repository->addPackage($this->package);
$this->assertExtraDownloads([]);
}

public function testAddExtraDownload(): void
{
$this->extraDownload
->expects($this->once())
->method('getName')
->willReturn($this->name);
$this->extraDownload
->expects($this->once())
->method('getTrackingChecksum')
->willReturn($this->trackingChecksum);
$this->repository->addPackage($this->extraDownload);
$this->assertExtraDownloads([
$this->name => $this->trackingChecksum,
]);
}

public function testRemovePackage(): void
{
$this->repository->removePackage($this->package);
$this->assertExtraDownloads([]);
}

public function testRemoveExtraDownload(): void
{
$this->extraDownload
->expects($this->exactly(2))
->method('getName')
->willReturn($this->name);
$this->extraDownload
->expects($this->once())
->method('getTrackingChecksum')
->willReturn($this->trackingChecksum);
$this->repository->addPackage($this->extraDownload);
$this->assertExtraDownloads([
$this->name => $this->trackingChecksum,
]);
$this->repository->removePackage($this->extraDownload);
$this->assertExtraDownloads([]);
}

public function testHasPackage(): void
{
$this->assertFalse($this->repository->hasPackage($this->package));
}

public function getHasExtraDownloadTests(): array
{
return [
[false],
[true],
];
}

/**
* @dataProvider getHasExtraDownloadTests
*/
public function testHasExtraDownload(bool $sameTrackingChecksum): void
{
$this->extraDownload
->expects($this->exactly(3))
->method('getName')
->willReturn($this->name);
$trackingChecksum = $sameTrackingChecksum ? $this->trackingChecksum : '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824';
$this->extraDownload
->expects($this->exactly(2))
->method('getTrackingChecksum')
->willReturnOnConsecutiveCalls($this->trackingChecksum, $trackingChecksum);
$this->assertFalse($this->repository->hasPackage($this->extraDownload));
$this->repository->addPackage($this->extraDownload);
$this->assertSame($sameTrackingChecksum, $this->repository->hasPackage($this->extraDownload));
}

public function testReloadFromInvalidFile(): void
{
$this->fs->createDirectory(\dirname($this->path), true);
$this->fs->createFile($this->path, 'not json data');
$this->expectException(InvalidRepositoryException::class);
$this->expectExceptionMessage('Invalid repository data in '.$this->fs->path($this->path).', packages could not be loaded: ['.ParsingException::class.'] "'.$this->fs->path($this->path).'" does not contain valid JSON');
$this->repository->reload();
}

public function testReloadFromJsonString(): void
{
$this->fs->createDirectory(\dirname($this->path), true);
$this->fs->createFile($this->path, json_encode('some text'));
$this->expectException(InvalidRepositoryException::class);
$this->expectExceptionMessage('Invalid repository data in '.$this->fs->path($this->path).', packages could not be loaded: ['.\UnexpectedValueException::class.'] Could not parse package list from the repository');
$this->repository->reload();
}

public function testReload(): void
{
$this->fs->createDirectory(\dirname($this->path), true);
$this->fs->createFile($this->path, json_encode([
$this->name => $this->trackingChecksum,
]));
$this->repository->reload();
$this->assertExtraDownloads([
$this->name => $this->trackingChecksum,
]);
}

public function testIsFresh(): void
{
$this->assertTrue($this->repository->isFresh());
$this->fs->createDirectory(\dirname($this->path), true);
$this->fs->createFile($this->path, 'data');
$this->assertFalse($this->repository->isFresh());
}

public function testWrite(): void
{
$this->extraDownload
->expects($this->once())
->method('getName')
->willReturn($this->name);
$this->extraDownload
->expects($this->once())
->method('getTrackingChecksum')
->willReturn($this->trackingChecksum);
$this->repository->addPackage($this->extraDownload);
$this->assertFileDoesNotExist($this->fs->path($this->path));
$this->repository->write(true, $this->createMock(InstallationManager::class));
$this->assertFileExists($this->fs->path($this->path));
$this->assertJsonStringEqualsJsonString(json_encode([
$this->name => $this->trackingChecksum,
]), file_get_contents($this->fs->path($this->path)));
}

private function assertExtraDownloads(array $extraDownloads): void
{
$reflection = new \ReflectionProperty($this->repository, 'extraDownloads');
$this->assertSame($extraDownloads, $reflection->getValue($this->repository));
}

public function testGetCanonicalPackages(): void
{
$this->assertSame([], $this->repository->getCanonicalPackages());
}

public function testGetDevPackageNames(): void
{
$this->assertSame([], $this->repository->getDevPackageNames());
}

public function testCount(): void
{
$this->assertSame(0, $this->repository->count());
}

public function testGetRepoName(): void
{
$this->assertSame('installed extra downloads', $this->repository->getRepoName());
}

public function testGetDevMode(): void
{
$this->assertNull($this->repository->getDevMode());
}

public function testFindPackage(): void
{
$this->assertNull($this->repository->findPackage('any package name', 'any constraint'));
}

public function testFindPackages(): void
{
$this->assertSame([], $this->repository->findPackages('any package name', 'any constraint'));
}

public function testGetPackages(): void
{
$this->assertSame([], $this->repository->getPackages());
}

public function testGetProviders(): void
{
$this->assertSame([], $this->repository->getProviders('any package name'));
}

public function testLoadPackages(): void
{
$this->assertSame([], $this->repository->loadPackages([], [], [], []));
}

public function testSearch(): void
{
$this->assertSame([], $this->repository->search('package query'));
}
}

0 comments on commit 3933c2b

Please sign in to comment.