From bcd5d2848d7681407376046cf6aea2159df93464 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya <alejandrocelaya@gmail.com> Date: Wed, 12 Oct 2022 12:47:58 +0200 Subject: [PATCH] Used PHPUnit mocks in RoleResolverTest instead of prophezy --- module/CLI/src/ApiKey/RoleResolver.php | 5 +- .../CLI/src/ApiKey/RoleResolverInterface.php | 3 - .../src/Command/Api/GenerateKeyCommand.php | 4 +- .../CLI/src/Command/Api/ListKeysCommand.php | 4 +- module/CLI/test/ApiKey/RoleResolverTest.php | 64 +++++++++++-------- module/Rest/src/ApiKey/Role.php | 24 ++++--- module/Rest/test/ApiKey/RoleTest.php | 4 +- 7 files changed, 61 insertions(+), 47 deletions(-) diff --git a/module/CLI/src/ApiKey/RoleResolver.php b/module/CLI/src/ApiKey/RoleResolver.php index 588a2fa2..c1ae8f05 100644 --- a/module/CLI/src/ApiKey/RoleResolver.php +++ b/module/CLI/src/ApiKey/RoleResolver.php @@ -7,6 +7,7 @@ namespace Shlinkio\Shlink\CLI\ApiKey; use Shlinkio\Shlink\CLI\Exception\InvalidRoleConfigException; use Shlinkio\Shlink\Core\Domain\DomainServiceInterface; use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition; +use Shlinkio\Shlink\Rest\ApiKey\Role; use Symfony\Component\Console\Input\InputInterface; use function is_string; @@ -19,8 +20,8 @@ class RoleResolver implements RoleResolverInterface public function determineRoles(InputInterface $input): array { - $domainAuthority = $input->getOption(self::DOMAIN_ONLY_PARAM); - $author = $input->getOption(self::AUTHOR_ONLY_PARAM); + $domainAuthority = $input->getOption(Role::DOMAIN_SPECIFIC->paramName()); + $author = $input->getOption(Role::AUTHORED_SHORT_URLS->paramName()); $roleDefinitions = []; if ($author) { diff --git a/module/CLI/src/ApiKey/RoleResolverInterface.php b/module/CLI/src/ApiKey/RoleResolverInterface.php index 98d50483..92a04594 100644 --- a/module/CLI/src/ApiKey/RoleResolverInterface.php +++ b/module/CLI/src/ApiKey/RoleResolverInterface.php @@ -9,9 +9,6 @@ use Symfony\Component\Console\Input\InputInterface; interface RoleResolverInterface { - public const AUTHOR_ONLY_PARAM = 'author-only'; - public const DOMAIN_ONLY_PARAM = 'domain-only'; - /** * @return RoleDefinition[] */ diff --git a/module/CLI/src/Command/Api/GenerateKeyCommand.php b/module/CLI/src/Command/Api/GenerateKeyCommand.php index b24619ef..12adcd57 100644 --- a/module/CLI/src/Command/Api/GenerateKeyCommand.php +++ b/module/CLI/src/Command/Api/GenerateKeyCommand.php @@ -32,8 +32,8 @@ class GenerateKeyCommand extends Command protected function configure(): void { - $authorOnly = RoleResolverInterface::AUTHOR_ONLY_PARAM; - $domainOnly = RoleResolverInterface::DOMAIN_ONLY_PARAM; + $authorOnly = Role::AUTHORED_SHORT_URLS->paramName(); + $domainOnly = Role::DOMAIN_SPECIFIC->paramName(); $help = <<<HELP The <info>%command.name%</info> generates a new valid API key. diff --git a/module/CLI/src/Command/Api/ListKeysCommand.php b/module/CLI/src/Command/Api/ListKeysCommand.php index 0e98af31..59f5b534 100644 --- a/module/CLI/src/Command/Api/ListKeysCommand.php +++ b/module/CLI/src/Command/Api/ListKeysCommand.php @@ -62,8 +62,8 @@ class ListKeysCommand extends Command $rowData[] = $apiKey->isAdmin() ? 'Admin' : implode("\n", $apiKey->mapRoles( fn (Role $role, array $meta) => empty($meta) - ? Role::toFriendlyName($role) - : sprintf('%s: %s', Role::toFriendlyName($role), Role::domainAuthorityFromMeta($meta)), + ? $role->toFriendlyName() + : sprintf('%s: %s', $role->toFriendlyName(), Role::domainAuthorityFromMeta($meta)), )); return $rowData; diff --git a/module/CLI/test/ApiKey/RoleResolverTest.php b/module/CLI/test/ApiKey/RoleResolverTest.php index 21f541a2..245a7106 100644 --- a/module/CLI/test/ApiKey/RoleResolverTest.php +++ b/module/CLI/test/ApiKey/RoleResolverTest.php @@ -4,27 +4,27 @@ declare(strict_types=1); namespace ShlinkioTest\Shlink\CLI\ApiKey; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Shlinkio\Shlink\CLI\ApiKey\RoleResolver; use Shlinkio\Shlink\CLI\Exception\InvalidRoleConfigException; use Shlinkio\Shlink\Core\Domain\DomainServiceInterface; use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition; +use Shlinkio\Shlink\Rest\ApiKey\Role; use Symfony\Component\Console\Input\InputInterface; +use function Functional\map; + class RoleResolverTest extends TestCase { - use ProphecyTrait; - private RoleResolver $resolver; - private ObjectProphecy $domainService; + private MockObject $domainService; protected function setUp(): void { - $this->domainService = $this->prophesize(DomainServiceInterface::class); - $this->resolver = new RoleResolver($this->domainService->reveal(), 'default.com'); + $this->domainService = $this->createMock(DomainServiceInterface::class); + $this->resolver = new RoleResolver($this->domainService, 'default.com'); } /** @@ -36,61 +36,65 @@ class RoleResolverTest extends TestCase array $expectedRoles, int $expectedDomainCalls, ): void { - $getDomain = $this->domainService->getOrCreate('example.com')->willReturn( - Domain::withAuthority('example.com')->setId('1'), - ); + $this->domainService + ->expects($this->exactly($expectedDomainCalls)) + ->method('getOrCreate') + ->with($this->equalTo('example.com')) + ->willReturn(Domain::withAuthority('example.com')->setId('1')); $result = $this->resolver->determineRoles($input); self::assertEquals($expectedRoles, $result); - $getDomain->shouldHaveBeenCalledTimes($expectedDomainCalls); } public function provideRoles(): iterable { $domain = Domain::withAuthority('example.com')->setId('1'); $buildInput = function (array $definition): InputInterface { - $input = $this->prophesize(InputInterface::class); + $input = $this->createStub(InputInterface::class); + $input->method('getOption')->willReturnMap( + map($definition, static fn (mixed $returnValue, string $param) => [$param, $returnValue]), + ); - foreach ($definition as $name => $value) { - $input->getOption($name)->willReturn($value); - } - - return $input->reveal(); + return $input; }; yield 'no roles' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => null, RoleResolver::AUTHOR_ONLY_PARAM => false]), + $buildInput([Role::DOMAIN_SPECIFIC->paramName() => null, Role::AUTHORED_SHORT_URLS->paramName() => false]), [], 0, ]; yield 'domain role only' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => 'example.com', RoleResolver::AUTHOR_ONLY_PARAM => false]), + $buildInput( + [Role::DOMAIN_SPECIFIC->paramName() => 'example.com', Role::AUTHORED_SHORT_URLS->paramName() => false], + ), [RoleDefinition::forDomain($domain)], 1, ]; yield 'false domain role' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => false]), + $buildInput([Role::DOMAIN_SPECIFIC->paramName() => false]), [], 0, ]; yield 'true domain role' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => true]), + $buildInput([Role::DOMAIN_SPECIFIC->paramName() => true]), [], 0, ]; yield 'string array domain role' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => ['foo', 'bar']]), + $buildInput([Role::DOMAIN_SPECIFIC->paramName() => ['foo', 'bar']]), [], 0, ]; yield 'author role only' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => null, RoleResolver::AUTHOR_ONLY_PARAM => true]), + $buildInput([Role::DOMAIN_SPECIFIC->paramName() => null, Role::AUTHORED_SHORT_URLS->paramName() => true]), [RoleDefinition::forAuthoredShortUrls()], 0, ]; yield 'both roles' => [ - $buildInput([RoleResolver::DOMAIN_ONLY_PARAM => 'example.com', RoleResolver::AUTHOR_ONLY_PARAM => true]), + $buildInput( + [Role::DOMAIN_SPECIFIC->paramName() => 'example.com', Role::AUTHORED_SHORT_URLS->paramName() => true], + ), [RoleDefinition::forAuthoredShortUrls(), RoleDefinition::forDomain($domain)], 1, ]; @@ -99,12 +103,16 @@ class RoleResolverTest extends TestCase /** @test */ public function exceptionIsThrownWhenTryingToAddDomainOnlyLinkedToDefaultDomain(): void { - $input = $this->prophesize(InputInterface::class); - $input->getOption(RoleResolver::DOMAIN_ONLY_PARAM)->willReturn('default.com'); - $input->getOption(RoleResolver::AUTHOR_ONLY_PARAM)->willReturn(null); + $input = $this->createStub(InputInterface::class); + $input + ->method('getOption') + ->willReturnMap([ + [Role::DOMAIN_SPECIFIC->paramName(), 'default.com'], + [Role::AUTHORED_SHORT_URLS->paramName(), null], + ]); $this->expectException(InvalidRoleConfigException::class); - $this->resolver->determineRoles($input->reveal()); + $this->resolver->determineRoles($input); } } diff --git a/module/Rest/src/ApiKey/Role.php b/module/Rest/src/ApiKey/Role.php index f852571d..5a4edb81 100644 --- a/module/Rest/src/ApiKey/Role.php +++ b/module/Rest/src/ApiKey/Role.php @@ -17,6 +17,22 @@ enum Role: string case AUTHORED_SHORT_URLS = 'AUTHORED_SHORT_URLS'; case DOMAIN_SPECIFIC = 'DOMAIN_SPECIFIC'; + public function toFriendlyName(): string + { + return match ($this) { + self::AUTHORED_SHORT_URLS => 'Author only', + self::DOMAIN_SPECIFIC => 'Domain only', + }; + } + + public function paramName(): string + { + return match ($this) { + self::AUTHORED_SHORT_URLS => 'author-only', + self::DOMAIN_SPECIFIC => 'domain-only', + }; + } + public static function toSpec(ApiKeyRole $role, ?string $context = null): Specification { return match ($role->role()) { @@ -42,12 +58,4 @@ enum Role: string { return $meta['authority'] ?? ''; } - - public static function toFriendlyName(Role $role): string - { - return match ($role) { - self::AUTHORED_SHORT_URLS => 'Author only', - self::DOMAIN_SPECIFIC => 'Domain only', - }; - } } diff --git a/module/Rest/test/ApiKey/RoleTest.php b/module/Rest/test/ApiKey/RoleTest.php index f3cc64b2..715b89b8 100644 --- a/module/Rest/test/ApiKey/RoleTest.php +++ b/module/Rest/test/ApiKey/RoleTest.php @@ -99,9 +99,9 @@ class RoleTest extends TestCase * @test * @dataProvider provideRoleNames */ - public function getsExpectedRoleFriendlyName(Role $roleName, string $expectedFriendlyName): void + public function getsExpectedRoleFriendlyName(Role $role, string $expectedFriendlyName): void { - self::assertEquals($expectedFriendlyName, Role::toFriendlyName($roleName)); + self::assertEquals($expectedFriendlyName, $role->toFriendlyName()); } public function provideRoleNames(): iterable