diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c5573d..5f5ed61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.8.0] ### Added -- Support for `doctrine/annotations: ^2.0` - Support for PHP 8 attributes +- Support for `doctrine/annotations: ^2.0` ## [1.7.0] ### Added diff --git a/composer.json b/composer.json index 370ffb7..e02257d 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "doctrine/annotations": "^1.14 || ^2.0" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^9.5", + "phpunit/phpunit": "^9.6", "mockery/mockery": "^1.3.6", "symfony/yaml": "^3.4.34|^4.3|^5.4|^6.0", "doctrine/doctrine-bundle": "^1.12.0|^2.1", diff --git a/src/Attribute/Query.php b/src/Attribute/Query.php index e47ff38..6ace7d0 100644 --- a/src/Attribute/Query.php +++ b/src/Attribute/Query.php @@ -5,7 +5,6 @@ namespace Paysera\Bundle\ApiBundle\Attribute; use Attribute; -use Paysera\Bundle\ApiBundle\Annotation\Validation; use Paysera\Bundle\ApiBundle\Entity\QueryResolverOptions; use Paysera\Bundle\ApiBundle\Entity\RestRequestOptions; use Paysera\Bundle\ApiBundle\Exception\ConfigurationException; diff --git a/src/Service/RoutingLoader/RoutingAttributeLoader.php b/src/Service/RoutingLoader/RoutingAttributeLoader.php index 46c5c82..e925406 100644 --- a/src/Service/RoutingLoader/RoutingAttributeLoader.php +++ b/src/Service/RoutingLoader/RoutingAttributeLoader.php @@ -17,6 +17,8 @@ */ class RoutingAttributeLoader extends AttributeRouteControllerLoader { + private const ATTRIBUTE_SUPPORT_PHP_VERSION_ID = 80100; // `new` in initializers support is required + /** * @var RestRequestHelper */ @@ -57,7 +59,7 @@ protected function configureRoute( $this->loadAnnotations($route, $class, $method); - if (PHP_VERSION_ID >= 80000) { + if (PHP_VERSION_ID >= self::ATTRIBUTE_SUPPORT_PHP_VERSION_ID) { $this->loadAttributes($route, $class, $method); } } diff --git a/tests/Functional/Fixtures/FixtureTestBundle/Controller/AttributedClassRequiredPermissionsController.php b/tests/Functional/Fixtures/FixtureTestBundle/Controller/AttributedClassRequiredPermissionsController.php new file mode 100644 index 0000000..50808dd --- /dev/null +++ b/tests/Functional/Fixtures/FixtureTestBundle/Controller/AttributedClassRequiredPermissionsController.php @@ -0,0 +1,31 @@ + 'internal.field1'])] +class AttributedClassValidationController +{ + /** + * @Route(path="/attributed/class/testValidation", methods={"POST"}) + */ + #[Body(parameterName: 'resource')] + #[Validation(groups: ['field1_email'], violationPathMap: ['field1' => 'my_mapped_key'])] + public function testValidation(MyObject $resource): Response + { + // should fail validation + return new Response('FAIL'); + } + + /** + * @Route(path="/attributed/class/testValidationFromClass", methods={"POST"}) + */ + #[Body(parameterName: 'resource')] + public function testValidationFromClass(MyObject $resource): Response + { + // should fail validation + return new Response('FAIL'); + } +} diff --git a/tests/Functional/Fixtures/FixtureTestBundle/Controller/AttributedController.php b/tests/Functional/Fixtures/FixtureTestBundle/Controller/AttributedController.php new file mode 100644 index 0000000..8bf78f2 --- /dev/null +++ b/tests/Functional/Fixtures/FixtureTestBundle/Controller/AttributedController.php @@ -0,0 +1,264 @@ + 'my_mapped_key'])] + public function testBodyNormalizationWithValidation(MyObject $resource): Response + { + // should fail validation + return new Response('FAIL'); + } + + /** + * @Route(path="/attributed/testBodyNormalizationWithInnerTypeValidation", methods={"POST"}) + */ + #[Body(parameterName: 'resource')] + #[Validation(groups: ['internal_field1_email'])] + public function testBodyNormalizationWithInnerTypeValidation(MyObject $resource): Response + { + // should fail validation + return new Response('FAIL'); + } + + /** + * @Route(path="/attributed/testBodyValidationCanBeTurnedOff", methods={"POST"}) + */ + #[Body(parameterName: 'resource')] + #[Validation(enabled: false)] + public function testBodyValidationCanBeTurnedOff(MyObject $resource): Response + { + return new Response('OK'); + } + + /** + * @Route(path="/attributed/testBodyValidationCanBeTurnedOffWithEmptyGroups", methods={"POST"}) + */ + #[Body(parameterName: 'resource')] + #[Validation(groups: [])] + public function testBodyValidationCanBeTurnedOffWithEmptyGroups(MyObject $resource): Response + { + return new Response('OK'); + } + + /** + * @Route(path="/attributed/testPathAttribute/{id}", methods={"GET"}) + * @Route(path="/attributed/testPathAttribute", methods={"GET"}) + */ + #[PathAttribute(parameterName: 'parameter', pathPartName: 'id', resolverType: 'prefixed')] + public function testPathAttribute(string $parameter = 'default'): Response + { + return new Response($parameter); + } + + /** + * @Route(path="/attributed/testPathAttributeWithFindingObject/{id}", methods={"GET"}) + */ + #[PathAttribute(parameterName: 'myObject', pathPartName: 'id')] + public function testPathAttributeWithFindingObject(MyObject $myObject): Response + { + return new Response($myObject->getField1()); + } + + /** + * @Route(path="/attributed/testPathAttributeWithFailedResolution/{id}", methods={"GET"}) + */ + #[PathAttribute(parameterName: 'myObject', pathPartName: 'id', resolverType: 'always_null')] + public function testPathAttributeWithFailedResolution(MyObject $myObject): Response + { + // should fail before calling controller + return new Response('FAIL'); + } + + /** + * @Route(path="/attributed/testQueryResolver", methods={"GET"}) + */ + #[Query(parameterName: 'parameter', denormalizationType: 'extract:parameter')] + public function testQueryResolver(string $parameter): Response + { + return new Response($parameter); + } + + /** + * @Route(path="/attributed/testQueryResolverWithDenormalizationGroup", methods={"GET"}) + */ + #[Query(parameterName: 'parameter', denormalizationType: 'extract:parameter', denormalizationGroup: 'custom')] + public function testQueryResolverWithDenormalizationGroup(string $parameter): Response + { + return new Response($parameter); + } + + /** + * @Route(path="/attributed/testQueryResolverPagerLimitIs42", methods={"GET"}) + */ + #[Query(parameterName: 'pager')] + public function testQueryResolverPagerLimitIs42(Pager $pager): Response + { + return new Response($pager->getLimit() === 42 ? 'OK' : 'FAIL'); + } + + /** + * @Route(path="/attributed/testQueryResolverHasDefaultValidation", methods={"GET"}) + */ + #[Query(parameterName: 'myObject')] + public function testQueryResolverHasDefaultValidation(MyObject $myObject): Response + { + // should fail validation + return new Response('FAIL'); + } + + /** + * @Route(path="/attributed/testQueryResolverCanTurnOffValidation", methods={"GET"}) + */ + #[Query(parameterName: 'myObject', validation: new Validation(enabled: false))] + public function testQueryResolverCanTurnOffValidation(MyObject $myObject): Response + { + return new Response('OK'); + } + + /** + * @Route(path="/attributed/testQueryResolverCanTurnOffValidationWithEmptyGroups", methods={"GET"}) + */ + #[Query(parameterName: 'myObject', validation: new Validation(groups: []))] + public function testQueryResolverCanTurnOffValidationWithEmptyGroups(MyObject $myObject): Response + { + return new Response('OK'); + } + + /** + * @Route(path="/attributed/testQueryResolverValidationWithInvalidData", methods={"GET"}) + */ + #[Query(parameterName: 'myObject', validation: new Validation(groups: ['field1_email'], violationPathMap: ['field1' => 'mapped_key']))] + public function testQueryResolverValidationWithInvalidData(MyObject $myObject): Response + { + // should fail validation + return new Response('FAIL'); + } + + /** + * @Route(path="/attributed/testRequiredPermissions", methods={"GET"}) + */ + #[RequiredPermissions(permissions: ['ROLE_USER', 'ROLE_ADMIN'])] + public function testRequiredPermissions(): Response + { + return new Response('OK'); + } + + /** + * @Route(path="/attributed/testResponseNormalization", methods={"GET"}) + */ + #[ResponseNormalization(normalizationType: 'my_object_custom')] + public function testResponseNormalization(): MyObject + { + return (new MyObject()) + ->setField1('hi') + ; + } + + /** + * @Route(path="/attributed/testResponseNormalizationWithNormalizationGroup", methods={"GET"}) + */ + #[ResponseNormalization(normalizationGroup: 'custom')] + public function testResponseNormalizationWithNormalizationGroup(): MyObject + { + return (new MyObject()) + ->setField1('hi') + ; + } + + /** + * @Route(path="/attributed/testResponseNormalizationWithGuessedNormalizer", methods={"GET"}) + */ + #[ResponseNormalization] + public function testResponseNormalizationWithGuessedNormalizer(): MyObject + { + return (new MyObject()) + ->setField1('hi') + ; + } +} diff --git a/tests/Functional/Fixtures/FixtureTestBundle/Resources/config/services.xml b/tests/Functional/Fixtures/FixtureTestBundle/Resources/config/services.xml index b4ada44..46836bd 100644 --- a/tests/Functional/Fixtures/FixtureTestBundle/Resources/config/services.xml +++ b/tests/Functional/Fixtures/FixtureTestBundle/Resources/config/services.xml @@ -78,10 +78,16 @@ + + + diff --git a/tests/Functional/Fixtures/config/common.yml b/tests/Functional/Fixtures/config/common.yml index c3b2acb..ccb0059 100644 --- a/tests/Functional/Fixtures/config/common.yml +++ b/tests/Functional/Fixtures/config/common.yml @@ -37,7 +37,7 @@ doctrine: services: logger: - class: Psr\Log\NullLogger + class: Psr\Log\NullLogger # Symfony\Component\ErrorHandler\BufferingLogger public: true rest_registry: alias: paysera_api.rest_request_options_registry diff --git a/tests/Functional/FunctionalAnnotationsTest.php b/tests/Functional/FunctionalAnnotationsTest.php index eee6dd4..946146e 100644 --- a/tests/Functional/FunctionalAnnotationsTest.php +++ b/tests/Functional/FunctionalAnnotationsTest.php @@ -20,11 +20,42 @@ protected function setUp(): void * @param Request $request * @param Response|null $extraResponseVersion */ - public function testRestRequestConfiguration( + public function testAnnotatedRestRequestConfiguration( Response $expectedResponse, Request $request, Response $extraResponseVersion = null ) { + $this->makeTest('annotated', $expectedResponse, $request, $extraResponseVersion); + } + + /** + * @dataProvider restRequestsConfigurationProvider + * @param Response $expectedResponse + * @param Request $request + * @param Response|null $extraResponseVersion + */ + public function testAttributedRestRequestConfiguration( + Response $expectedResponse, + Request $request, + Response $extraResponseVersion = null + ) { + $this->makeTest('attributed', $expectedResponse, $request, $extraResponseVersion); + } + + private function makeTest( + string $pathPrefix, + Response $expectedResponse, + Request $request, + Response $extraResponseVersion = null + ): void { + if ($pathPrefix === 'attributed') { + $this->checkAttributeConfigurationSupport(); + } + + $request->server->set( + 'REQUEST_URI', + sprintf('/%s%s', $pathPrefix, $request->server->get('REQUEST_URI')) + ); $response = $this->handleRequest($request); $assertionMessage = 'expected correct content'; @@ -52,14 +83,14 @@ public function testRestRequestConfiguration( ); } - public function restRequestsConfigurationProvider() + public function restRequestsConfigurationProvider(): array { return [ 'testBodyNormalizationWithExtractedKeyValue' => [ new Response('this_should_be_extracted'), $this->createJsonRequest( 'POST', - '/annotated/testBodyNormalizationWithExtractedKeyValue', + '/testBodyNormalizationWithExtractedKeyValue', [ 'something' => 'unimportant', 'key' => 'this_should_be_extracted', @@ -70,14 +101,14 @@ public function restRequestsConfigurationProvider() new Response('default'), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithExtractedKeyValue' + '/testBodyNormalizationWithExtractedKeyValue' ), ], 'testBodyNormalizationWithDenormalizationGroup' => [ new Response('custom'), $this->createJsonRequest( 'POST', - '/annotated/testBodyNormalizationWithDenormalizationGroup', + '/testBodyNormalizationWithDenormalizationGroup', [ 'key_custom' => 'custom', 'key' => 'wrong_key', @@ -91,7 +122,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithExtractedKeyValue', + '/testBodyNormalizationWithExtractedKeyValue', 'something', ['Content-Type' => 'text/plain'] ), @@ -103,14 +134,14 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithRequiredBody' + '/testBodyNormalizationWithRequiredBody' ), ], 'testBodyAndResponseNormalization' => [ new Response('{"field1":"value1"}'), $this->createJsonRequest( 'POST', - '/annotated/testBodyAndResponseNormalization', + '/testBodyAndResponseNormalization', ['field1' => 'value1'] ), ], @@ -121,7 +152,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/testBodyAndResponseNormalization', + '/testBodyAndResponseNormalization', ['internal' => ['field1' => 1]] ), ], @@ -132,7 +163,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/testBodyNormalizationWithCustomContentType', + '/testBodyNormalizationWithCustomContentType', ['key' => 'value'] ), ], @@ -140,7 +171,7 @@ public function restRequestsConfigurationProvider() new Response('prefixed_my_text'), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithCustomContentType', + '/testBodyNormalizationWithCustomContentType', 'my_text', ['Content-Type' => 'text/plain'] ), @@ -152,7 +183,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/testBodyNormalizationWithCustomContentTypeAndJsonDecode', + '/testBodyNormalizationWithCustomContentTypeAndJsonDecode', ['key' => 'value'] ), ], @@ -160,7 +191,7 @@ public function restRequestsConfigurationProvider() new Response('value'), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithCustomContentTypeAndJsonDecode', + '/testBodyNormalizationWithCustomContentTypeAndJsonDecode', json_encode(['key' => 'value']), ['Content-Type' => 'text/plain'] ), @@ -169,7 +200,7 @@ public function restRequestsConfigurationProvider() new Response('prefixed_by_body'), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithSemiContentTypeRestriction', + '/testBodyNormalizationWithSemiContentTypeRestriction', 'by_body', ['Content-Type' => 'text/something'] ), @@ -181,7 +212,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'POST', - '/annotated/testBodyNormalizationWithSemiContentTypeRestriction', + '/testBodyNormalizationWithSemiContentTypeRestriction', 'by_body', ['Content-Type' => 'image/gif'] ), @@ -203,7 +234,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/testBodyNormalizationWithValidation', + '/testBodyNormalizationWithValidation', ['field1' => 'not an email'] ), new Response( @@ -238,7 +269,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/testBodyNormalizationWithInnerTypeValidation', + '/testBodyNormalizationWithInnerTypeValidation', ['field1' => 'blah', 'internal' => ['field1' => 'not an email']] ), new Response( @@ -260,7 +291,7 @@ public function restRequestsConfigurationProvider() new Response('OK', 200), $this->createJsonRequest( 'POST', - '/annotated/testBodyValidationCanBeTurnedOff', + '/testBodyValidationCanBeTurnedOff', ['field1' => ''] ), ], @@ -268,7 +299,7 @@ public function restRequestsConfigurationProvider() new Response('OK', 200), $this->createJsonRequest( 'POST', - '/annotated/testBodyValidationCanBeTurnedOffWithEmptyGroups', + '/testBodyValidationCanBeTurnedOffWithEmptyGroups', ['field1' => ''] ), ], @@ -276,35 +307,35 @@ public function restRequestsConfigurationProvider() new Response('prefixed_123'), $this->createRequest( 'GET', - '/annotated/testPathAttribute/123' + '/testPathAttribute/123' ), ], 'testPathAttribute with optional resolution' => [ new Response('default'), $this->createRequest( 'GET', - '/annotated/testPathAttribute' + '/testPathAttribute' ), ], 'testPathAttributeWithFindingObject' => [ new Response('123'), $this->createRequest( 'GET', - '/annotated/testPathAttributeWithFindingObject/123' + '/testPathAttributeWithFindingObject/123' ), ], 'testPathAttributeWithFailedResolution' => [ new Response('{"error":"not_found","error_description":"Resource was not found"}', 404), $this->createRequest( 'GET', - '/annotated/testPathAttributeWithFailedResolution/{id}' + '/testPathAttributeWithFailedResolution/{id}' ), ], 'testQueryResolver' => [ new Response('my_param'), $this->createRequest( 'GET', - '/annotated/testQueryResolver?parameter=my_param' + '/testQueryResolver?parameter=my_param' ), ], 'testQueryResolver is always mandatory' => [ @@ -314,21 +345,21 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testQueryResolver?other_parameter=my_param' + '/testQueryResolver?other_parameter=my_param' ), ], 'testQueryResolverWithDenormalizationGroup' => [ new Response('custom'), $this->createRequest( 'GET', - '/annotated/testQueryResolverWithDenormalizationGroup?parameter=wrong_key¶meter_custom=custom' + '/testQueryResolverWithDenormalizationGroup?parameter=wrong_key¶meter_custom=custom' ), ], 'testQueryResolverPagerLimitIs42' => [ new Response('OK'), $this->createRequest( 'GET', - '/annotated/testQueryResolverPagerLimitIs42?limit=42' + '/testQueryResolverPagerLimitIs42?limit=42' ), ], 'testQueryResolverHasDefaultValidation' => [ @@ -338,7 +369,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testQueryResolverHasDefaultValidation?field1=' + '/testQueryResolverHasDefaultValidation?field1=' ), ], 'testQueryResolverCanTurnOffValidation' => [ @@ -348,7 +379,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testQueryResolverCanTurnOffValidation?field1=' + '/testQueryResolverCanTurnOffValidation?field1=' ), ], 'testQueryResolverCanTurnOffValidationWithEmptyGroups' => [ @@ -358,7 +389,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testQueryResolverCanTurnOffValidationWithEmptyGroups?field1=' + '/testQueryResolverCanTurnOffValidationWithEmptyGroups?field1=' ), ], 'testQueryResolverValidationWithInvalidData - normalizer errors do not map fields' => [ @@ -368,7 +399,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testQueryResolverValidationWithInvalidData' + '/testQueryResolverValidationWithInvalidData' ), ], 'testQueryResolverValidationWithInvalidData' => [ @@ -388,7 +419,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testQueryResolverValidationWithInvalidData?field1=not_an_email' + '/testQueryResolverValidationWithInvalidData?field1=not_an_email' ), new Response( json_encode([ @@ -412,7 +443,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testRequiredPermissions' + '/testRequiredPermissions' ), ], 'testRequiredPermissions without not enough permissions' => [ @@ -422,7 +453,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/testRequiredPermissions', + '/testRequiredPermissions', null, [], 'user' @@ -432,7 +463,7 @@ public function restRequestsConfigurationProvider() new Response('OK'), $this->createRequest( 'GET', - '/annotated/testRequiredPermissions', + '/testRequiredPermissions', null, [], 'admin' @@ -445,7 +476,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/class/testRequiredPermissions' + '/class/testRequiredPermissions' ), ], 'testRequiredPermissions with class annotation and with not enough permissions' => [ @@ -455,7 +486,7 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/class/testRequiredPermissions', + '/class/testRequiredPermissions', null, [], 'user' @@ -465,7 +496,7 @@ public function restRequestsConfigurationProvider() new Response('OK'), $this->createRequest( 'GET', - '/annotated/class/testRequiredPermissions', + '/class/testRequiredPermissions', null, [], 'admin' @@ -478,14 +509,14 @@ public function restRequestsConfigurationProvider() ), $this->createRequest( 'GET', - '/annotated/class/simpleAction' + '/class/simpleAction' ), ], 'testRequiredPermissions with class annotation and REST-specific method annotations: OK' => [ new Response('OK'), $this->createRequest( 'GET', - '/annotated/class/simpleAction', + '/class/simpleAction', null, [], 'user' @@ -508,7 +539,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/class/testValidation', + '/class/testValidation', ['field1' => 'not an email', 'internal' => ['field1' => 'also not an email']] ), new Response( @@ -543,7 +574,7 @@ public function restRequestsConfigurationProvider() ), $this->createJsonRequest( 'POST', - '/annotated/class/testValidationFromClass', + '/class/testValidationFromClass', ['field1' => 'not an email', 'internal' => ['field1' => 'also not an email']] ), new Response( @@ -565,21 +596,21 @@ public function restRequestsConfigurationProvider() new Response('{"field1_custom":"hi"}'), $this->createRequest( 'GET', - '/annotated/testResponseNormalization' + '/testResponseNormalization' ), ], 'testResponseNormalizationWithNormalizationGroup' => [ new Response('{"field1_custom":"hi"}'), $this->createRequest( 'GET', - '/annotated/testResponseNormalizationWithNormalizationGroup' + '/testResponseNormalizationWithNormalizationGroup' ), ], 'testResponseNormalizationWithGuessedNormalizer' => [ new Response('{"field1":"hi"}'), $this->createRequest( 'GET', - '/annotated/testResponseNormalizationWithGuessedNormalizer' + '/testResponseNormalizationWithGuessedNormalizer' ), ], ]; diff --git a/tests/Functional/FunctionalTestCase.php b/tests/Functional/FunctionalTestCase.php index 199f425..703b3bc 100644 --- a/tests/Functional/FunctionalTestCase.php +++ b/tests/Functional/FunctionalTestCase.php @@ -7,6 +7,7 @@ use Doctrine\ORM\Tools\SchemaTool; use Paysera\Bundle\ApiBundle\Tests\Functional\Fixtures\TestKernel; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\Routing\AttributeRouteControllerLoader; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\HttpKernel\Kernel; @@ -108,4 +109,15 @@ protected function getEntityManager(): EntityManagerInterface { return $this->kernel->getContainer()->get('doctrine.orm.entity_manager'); } + + protected function checkAttributeConfigurationSupport(): void + { + if (!class_exists(AttributeRouteControllerLoader::class)) { + $this->markTestSkipped('Unsupported Symfony version'); + } + + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Unsupported PHP version'); + } + } } diff --git a/tests/Unit/Service/Annotation/ReflectionMethodWrapperTest.php b/tests/Unit/Service/RoutingLoader/ReflectionMethodWrapperTest.php similarity index 82% rename from tests/Unit/Service/Annotation/ReflectionMethodWrapperTest.php rename to tests/Unit/Service/RoutingLoader/ReflectionMethodWrapperTest.php index 6a746d6..030e782 100644 --- a/tests/Unit/Service/Annotation/ReflectionMethodWrapperTest.php +++ b/tests/Unit/Service/RoutingLoader/ReflectionMethodWrapperTest.php @@ -1,7 +1,7 @@ getParameterByName('param2'); $this->assertSame('param2', $reflectionParameter->getName()); } - public function testGetParameterByNameWithNoSuchParameter() + public function testGetParameterByNameWithNoSuchParameter(): void { $wrapper = new ReflectionMethodWrapper(new ReflectionMethod(self::class, 'fixtureMethod')); @@ -26,14 +26,14 @@ public function testGetParameterByNameWithNoSuchParameter() $wrapper->getParameterByName('nonExisting'); } - public function testGetNonBuiltInTypeForParameter() + public function testGetNonBuiltInTypeForParameter(): void { $wrapper = new ReflectionMethodWrapper(new ReflectionMethod(self::class, 'fixtureMethod')); $this->assertSame('DateTime', $wrapper->getNonBuiltInTypeForParameter('param2')); } - public function testGetNonBuiltInTypeForParameterWithBuiltInType() + public function testGetNonBuiltInTypeForParameterWithBuiltInType(): void { $wrapper = new ReflectionMethodWrapper(new ReflectionMethod(self::class, 'fixtureMethod')); @@ -41,7 +41,7 @@ public function testGetNonBuiltInTypeForParameterWithBuiltInType() $wrapper->getNonBuiltInTypeForParameter('param1'); } - public function testGetNonBuiltInTypeForParameterWithNoType() + public function testGetNonBuiltInTypeForParameterWithNoType(): void { $wrapper = new ReflectionMethodWrapper(new ReflectionMethod(self::class, 'fixtureMethod')); @@ -49,11 +49,11 @@ public function testGetNonBuiltInTypeForParameterWithNoType() $wrapper->getNonBuiltInTypeForParameter('param3'); } - public function testGetFriendlyName() + public function testGetFriendlyName(): void { $wrapper = new ReflectionMethodWrapper(new ReflectionMethod(self::class, 'fixtureMethod')); $this->assertSame( - 'Paysera\Bundle\ApiBundle\Tests\Unit\Service\Annotation\ReflectionMethodWrapperTest::fixtureMethod', + sprintf('%s::%s', get_class($this), 'fixtureMethod'), $wrapper->getFriendlyName() ); } diff --git a/tests/Unit/Service/Annotation/RestRequestOptionsBuilderTest.php b/tests/Unit/Service/RoutingLoader/RestRequestAnnotationOptionsBuilderTest.php similarity index 86% rename from tests/Unit/Service/Annotation/RestRequestOptionsBuilderTest.php rename to tests/Unit/Service/RoutingLoader/RestRequestAnnotationOptionsBuilderTest.php index df2a44c..a36d451 100644 --- a/tests/Unit/Service/Annotation/RestRequestOptionsBuilderTest.php +++ b/tests/Unit/Service/RoutingLoader/RestRequestAnnotationOptionsBuilderTest.php @@ -1,7 +1,7 @@ shouldReceive('validateRestRequestOptions') - ->andReturnUsing(function (RestRequestOptions $options, string $fieldlyName) use ($expectedOptions) { + ->andReturnUsing(function (RestRequestOptions $options, string $friendlyName) use ($expectedOptions) { $this->assertEquals($expectedOptions, $options); $this->assertEquals( - 'Paysera\Bundle\ApiBundle\Tests\Unit\Service\Annotation\RestRequestOptionsBuilderTest::fixtureMethod', - $fieldlyName + sprintf('%s::%s', get_class($this), 'fixtureMethod'), + $friendlyName ); }) ; @@ -61,7 +61,7 @@ public function testBuildOptions() $this->assertEquals($expectedOptions, $options); } - public function testBuildOptionsWithSeveralUnsupportedAnnotations() + public function testBuildOptionsWithSeveralUnsupportedAnnotations(): void { $optionsValidator = Mockery::mock(RestRequestOptionsValidator::class); @@ -75,7 +75,7 @@ public function testBuildOptionsWithSeveralUnsupportedAnnotations() ], new ReflectionMethod(self::class, 'fixtureMethod')); } - public function fixtureMethod() + public function fixtureMethod(): void { // do nothing } diff --git a/tests/Unit/Service/RoutingLoader/RestRequestAttributeOptionsBuilderTest.php b/tests/Unit/Service/RoutingLoader/RestRequestAttributeOptionsBuilderTest.php new file mode 100644 index 0000000..4e74811 --- /dev/null +++ b/tests/Unit/Service/RoutingLoader/RestRequestAttributeOptionsBuilderTest.php @@ -0,0 +1,68 @@ +shouldReceive('apply')->andReturnUsing(function (RestRequestOptions $options) { + $options->setRequiredPermissions(['modified1']); + }); + + $annotationMock2 = Mockery::mock(RestAttributeInterface::class); + $annotationMock2->shouldReceive('apply')->andReturnUsing(function (RestRequestOptions $options) { + $options->setResponseNormalizationType('modified2'); + }); + + $expectedOptions = (new RestRequestOptions()) + ->setRequiredPermissions(['modified1']) + ->setResponseNormalizationType('modified2') + ; + + $optionsValidator + ->shouldReceive('validateRestRequestOptions') + ->andReturnUsing(function (RestRequestOptions $options, string $friendlyName) use ($expectedOptions) { + $this->assertEquals($expectedOptions, $options); + $this->assertEquals( + sprintf('%s::%s', get_class($this), 'fixtureMethod'), + $friendlyName + ); + }) + ; + + $annotations = [ + $annotationMock1, + $annotationMock2, + ]; + + $options = $builder->buildOptions($annotations, $reflectionMethod); + + $this->assertEquals($expectedOptions, $options); + } + + public function fixtureMethod(): void + { + // do nothing + } +}