From 2c19b2693a0502f09717f93b35e68e7d6df4db64 Mon Sep 17 00:00:00 2001 From: Claudio Zizza Date: Sat, 16 Sep 2023 01:45:56 +0200 Subject: [PATCH] Increase code coverage for Projects namespace --- lib/Projects/GetProjectPackagistData.php | 8 +++- .../Projects/GetProjectPackagistDataTest.php | 40 +++++++++++++++++ tests/Projects/GetTotalDownloadsTest.php | 40 +++++++++++++++++ tests/Projects/ProjectDataReaderTest.php | 44 +++++++++++++++++++ tests/Projects/ProjectDataRepositoryTest.php | 21 +++++++++ tests/Projects/ProjectGitSyncerTest.php | 32 +++++++++++++- tests/test-projects/empty-json/composer.json | 1 + 7 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 tests/Projects/GetProjectPackagistDataTest.php create mode 100644 tests/Projects/GetTotalDownloadsTest.php create mode 100644 tests/Projects/ProjectDataRepositoryTest.php create mode 100644 tests/test-projects/empty-json/composer.json diff --git a/lib/Projects/GetProjectPackagistData.php b/lib/Projects/GetProjectPackagistData.php index 3c818b0..52f8ba1 100644 --- a/lib/Projects/GetProjectPackagistData.php +++ b/lib/Projects/GetProjectPackagistData.php @@ -12,15 +12,19 @@ class GetProjectPackagistData { private const PACKAGIST_URL_FORMAT = 'https://packagist.org/packages/%s.json'; + public function __construct(private string $packagistUrlFormat = self::PACKAGIST_URL_FORMAT) + { + } + /** @return mixed[] */ public function __invoke(string $composerPackageName): array { - $packagistUrl = sprintf(self::PACKAGIST_URL_FORMAT, $composerPackageName); + $packagistUrl = sprintf($this->packagistUrlFormat, $composerPackageName); $response = file_get_contents($packagistUrl); $projectPackagistData = $response !== false ? json_decode($response, true) : []; - return $projectPackagistData !== false ? $projectPackagistData : []; + return $projectPackagistData ?? []; } } diff --git a/tests/Projects/GetProjectPackagistDataTest.php b/tests/Projects/GetProjectPackagistDataTest.php new file mode 100644 index 0000000..210a5eb --- /dev/null +++ b/tests/Projects/GetProjectPackagistDataTest.php @@ -0,0 +1,40 @@ + [ + 'orm.json' => '{}', + 'broken.json' => '{', + ], + ]); + + $this->packagistUrl = vfsStream::url('url') . '/packages/%s.json'; + } + + public function testFetchingPackagistData(): void + { + $projectPackagistData = new GetProjectPackagistData($this->packagistUrl); + + self::assertSame([], $projectPackagistData('orm')); + } + + public function testInvalidJson(): void + { + $projectPackagistData = new GetProjectPackagistData($this->packagistUrl); + + self::assertSame([], $projectPackagistData('broken')); + } +} diff --git a/tests/Projects/GetTotalDownloadsTest.php b/tests/Projects/GetTotalDownloadsTest.php new file mode 100644 index 0000000..2a3a7b7 --- /dev/null +++ b/tests/Projects/GetTotalDownloadsTest.php @@ -0,0 +1,40 @@ +createProject($this->createProjectData(21)); + $project2 = $this->createProject($this->createProjectData(13)); + $project3 = $this->createProject($this->createProjectData(8)); + + $projectRepository = self::createStub(ProjectRepository::class); + $projectRepository->method('findAll') + ->willReturn([$project1, $project2, $project3]); + + $getTotalDownloads = new GetTotalDownloads($projectRepository); + + self::assertSame(42, $getTotalDownloads()); + } + + /** @return array */ + private function createProjectData(int $totalDownloads): array + { + return [ + 'packagistData' => [ + 'package' => [ + 'downloads' => ['total' => $totalDownloads], + ], + ], + 'versions' => [], + ]; + } +} diff --git a/tests/Projects/ProjectDataReaderTest.php b/tests/Projects/ProjectDataReaderTest.php index db5e175..d2b450a 100644 --- a/tests/Projects/ProjectDataReaderTest.php +++ b/tests/Projects/ProjectDataReaderTest.php @@ -79,6 +79,50 @@ class ProjectDataReaderTest extends TestCase self::assertSame($this->projectIntegrationTypes['symfony'], $projectData['integrationType']); } + public function testReadNoIntegrationType(): void + { + $projectDataReader = new ProjectDataReader( + __DIR__ . '/../test-projects', + [ + [ + 'repositoryName' => 'test-integration-project', + 'integration' => true, + ], + ], + [], + ); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Project integration test-integration-project requires a type.'); + $projectDataReader->read('test-integration-project'); + } + + public function testReadIntegrationTypeDoesNotExist(): void + { + $projectDataReader = new ProjectDataReader( + __DIR__ . '/../test-projects', + [ + [ + 'repositoryName' => 'test-integration-project', + 'integration' => true, + 'integrationType' => 'symfony', + ], + ], + [], + ); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Project integration test-integration-project has a type of symfony which does not exist.'); + $projectDataReader->read('test-integration-project'); + } + + public function testReadEmptyJson(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('composer.json file exists in repository empty-json but does not contain any valid data.'); + $this->projectDataReader->read('empty-json'); + } + protected function setUp(): void { $this->projectIntegrationTypes = [ diff --git a/tests/Projects/ProjectDataRepositoryTest.php b/tests/Projects/ProjectDataRepositoryTest.php new file mode 100644 index 0000000..d8d65c5 --- /dev/null +++ b/tests/Projects/ProjectDataRepositoryTest.php @@ -0,0 +1,21 @@ + 'orm'], + ['repositoryName' => 'dbal'], + ]); + + self::assertSame(['orm', 'dbal'], $projectDataRepository->getProjectRepositoryNames()); + } +} diff --git a/tests/Projects/ProjectGitSyncerTest.php b/tests/Projects/ProjectGitSyncerTest.php index d8df9ae..06f9c75 100644 --- a/tests/Projects/ProjectGitSyncerTest.php +++ b/tests/Projects/ProjectGitSyncerTest.php @@ -10,6 +10,7 @@ use Doctrine\Website\Projects\ProjectGitSyncer; use Doctrine\Website\Tests\TestCase; use Github\Api\Repo; use Github\Client; +use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\MockObject\MockObject; use function sprintf; @@ -26,8 +27,12 @@ class ProjectGitSyncerTest extends TestCase protected function setUp(): void { + vfsStream::setup('projects', null, [ + 'orm' => ['.git' => []], + ]); + $this->processFactory = $this->createMock(ProcessFactory::class); - $this->projectsDir = __DIR__; + $this->projectsDir = vfsStream::url('projects'); $this->githubRepo = $this->createMock(Repo::class); $githubClientProvider = $this->createMock(GithubClientProvider::class); $githubClient = $this->getMockBuilder(Client::class) @@ -64,6 +69,16 @@ class ProjectGitSyncerTest extends TestCase $this->projectGitSyncer->initRepository($repositoryName); } + public function testInitRepositoryAlreadyInitialized(): void + { + $repositoryName = 'orm'; + + $this->processFactory->expects(self::never()) + ->method('run'); + + $this->projectGitSyncer->initRepository($repositoryName); + } + public function testSyncRepository(): void { $repositoryName = 'example-project'; @@ -111,4 +126,19 @@ class ProjectGitSyncerTest extends TestCase $this->projectGitSyncer->checkoutBranch($repositoryName, $branchName); } + + public function testIsRepositoryInitialized(): void + { + self::assertTrue($this->projectGitSyncer->isRepositoryInitialized('orm')); + self::assertFalse($this->projectGitSyncer->isRepositoryInitialized('foo')); + } + + public function testCheckoutTag(): void + { + $this->processFactory->expects(self::once()) + ->method('run') + ->with('cd \'vfs://projects/example-project\' && git clean -xdf && git checkout tags/\'1.0.0\''); + + $this->projectGitSyncer->checkoutTag('example-project', '1.0.0'); + } } diff --git a/tests/test-projects/empty-json/composer.json b/tests/test-projects/empty-json/composer.json new file mode 100644 index 0000000..d81cc07 --- /dev/null +++ b/tests/test-projects/empty-json/composer.json @@ -0,0 +1 @@ +42