From 38feab6e9e7ddebe1bbefe37a4e85fbedcd4acc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Ondr=C3=A1=C4=8Dek?= Date: Tue, 30 Dec 2025 00:50:36 +0100 Subject: [PATCH] Replace annotations with attributes in exceptions messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roman Ondráček --- .../Schema/Serialization/ArraySerializer.php | 10 +-- .../Validation/ControllerPathValidation.php | 8 +-- .../Schema/Validation/GroupPathValidation.php | 10 +-- src/Core/Schema/Validation/IdValidation.php | 10 +-- src/Core/Schema/Validation/PathValidation.php | 10 +-- .../Validation/RequestParameterValidation.php | 2 +- .../Core/Annotation/Controller/Method.phpt | 3 + .../Controller/RequestParameter.phpt | 8 +++ .../Core/Annotation/Controller/Response.phpt | 36 ++++++++++ tests/Cases/Core/DI/ApiExtension.phpt | 6 +- .../Cases/Core/DI/Loader/AttributeLoader.phpt | 7 +- .../Core/DI/Loader/AttributeMultiLoader.phpt | 3 - .../Mapping/Parameter/EnumTypeMapperTest.phpt | 61 +++++++++++++++++ .../Serialization/ArraySerializator.phpt | 24 +++---- .../Validation/ControllerPathValidation.phpt | 21 ++++-- .../Validation/ControllerValidation.phpt | 4 +- .../Validation/GroupPathValidation.phpt | 23 +++++-- .../Core/Schema/Validation/IdValidation.phpt | 4 +- .../Schema/Validation/PathValidation.phpt | 40 +++++++++-- .../RequestParameterValidation.phpt | 2 +- .../Transformer/JsonTransformer.phpt | 14 ++++ .../Entity/EntityAdapterTest.php | 16 ----- .../AnnotationFoobarController.php | 68 ------------------- .../Controllers/AnnotationMultiController.php | 36 ---------- .../Controllers/AttributeFoobarController.php | 4 ++ 25 files changed, 244 insertions(+), 186 deletions(-) create mode 100644 tests/Cases/Core/Annotation/Controller/Response.phpt create mode 100644 tests/Cases/Core/Mapping/Parameter/EnumTypeMapperTest.phpt delete mode 100644 tests/Fixtures/Controllers/AnnotationFoobarController.php delete mode 100644 tests/Fixtures/Controllers/AnnotationMultiController.php diff --git a/src/Core/Schema/Serialization/ArraySerializer.php b/src/Core/Schema/Serialization/ArraySerializer.php index 2dd567b9..9bf1efe6 100644 --- a/src/Core/Schema/Serialization/ArraySerializer.php +++ b/src/Core/Schema/Serialization/ArraySerializer.php @@ -58,7 +58,7 @@ private function serializeEndpoint(Controller $controller, Method $method): arra */ private function serializeInit(Controller $controller, Method $method): array { - // Build full mask (Group @Path(s) + Controller @Path + Endpoint @Path) + // Build full mask (Group #[Path](s) + Controller #[Path] + Endpoint #[Path]) // without duplicated slashes (//) // and without trailing slash at the end // but with slash at the beginning @@ -71,8 +71,8 @@ private function serializeInit(Controller $controller, Method $method): array $mask = Helpers::slashless($mask); $mask = '/' . trim($mask, '/'); - // Build full id (@GroupId(s) + @ControllerId + @Id) - // If @Id is empty, then fullid is also empty + // Build full id (Group #[Id](s) + Controller #[Id] + #[Id]) + // If #[Id] is empty, then full id is also empty if ($method->getId() === null || $method->getId() === '') { $id = null; } else { @@ -142,7 +142,7 @@ private function serializePattern(array &$endpoint, Controller $controller, Meth return $pattern; }); - // Check if @RequestParameter(in=path) is also defined in mask + // Check if #[RequestParameter(in=path)] is also defined in mask foreach ($pathParameters as $parameter) { foreach ($maskParameters as $maskParameter) { if ($maskParameter['name'] === $parameter->getName()) { @@ -150,7 +150,7 @@ private function serializePattern(array &$endpoint, Controller $controller, Meth } } - throw new InvalidStateException(sprintf('@RequestParameter(name="%s", in=path) is not defined in mask (@Path annotations)', $parameter->getName())); + throw new InvalidStateException(sprintf('#[RequestParameter(name="%s", in=path)] is not defined in mask (#[Path] annotations)', $parameter->getName())); } // Fulfill endpoint parameters (in path) diff --git a/src/Core/Schema/Validation/ControllerPathValidation.php b/src/Core/Schema/Validation/ControllerPathValidation.php index 95f717f4..d3413f84 100644 --- a/src/Core/Schema/Validation/ControllerPathValidation.php +++ b/src/Core/Schema/Validation/ControllerPathValidation.php @@ -24,7 +24,7 @@ protected function validateSlashes(SchemaBuilder $builder): void if ($path === '') { throw new InvalidSchemaException( - sprintf('@Path in "%s" must be set.', $controller->getClass()) + sprintf('#[Path] in "%s" must be set.', $controller->getClass()) ); } @@ -35,14 +35,14 @@ protected function validateSlashes(SchemaBuilder $builder): void // MUST: Starts with slash (/) if (!str_starts_with($path, '/')) { throw new InvalidSchemaException( - sprintf('@Path "%s" in "%s" must starts with "/" (slash).', $path, $controller->getClass()) + sprintf('#[Path] "%s" in "%s" must starts with "/" (slash).', $path, $controller->getClass()) ); } // MUST NOT: Ends with slash (/) if (str_ends_with($path, '/')) { throw new InvalidSchemaException( - sprintf('@Path "%s" in "%s" must not ends with "/" (slash).', $path, $controller->getClass()) + sprintf('#[Path] "%s" in "%s" must not ends with "/" (slash).', $path, $controller->getClass()) ); } } @@ -65,7 +65,7 @@ protected function validateRegex(SchemaBuilder $builder): void if ($match !== null) { throw new InvalidSchemaException( sprintf( - '@Path "%s" in "%s" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9-_/].', + '#[Path] "%s" in "%s" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9-_/].', $path, $controller->getClass(), $match[1] diff --git a/src/Core/Schema/Validation/GroupPathValidation.php b/src/Core/Schema/Validation/GroupPathValidation.php index 55ca50b8..496f064a 100644 --- a/src/Core/Schema/Validation/GroupPathValidation.php +++ b/src/Core/Schema/Validation/GroupPathValidation.php @@ -24,21 +24,21 @@ protected function validateSlashes(SchemaBuilder $builder): void if ($groupPath === '/') { // INVALID: nonsense throw new InvalidSchemaException( - sprintf('@Path "%s" in "%s" cannot be only "/", it is nonsense.', $groupPath, $controller->getClass()) + sprintf('#[Path] "%s" in "%s" cannot be only "/", it is nonsense.', $groupPath, $controller->getClass()) ); } // MUST: Starts with slash (/) if (!str_starts_with($groupPath, '/')) { throw new InvalidSchemaException( - sprintf('@Path "%s" in "%s" must starts with "/" (slash).', $groupPath, $controller->getClass()) + sprintf('#[Path] "%s" in "%s" must starts with "/" (slash).', $groupPath, $controller->getClass()) ); } // MUST NOT: Ends with slash (/) if (str_ends_with($groupPath, '/')) { throw new InvalidSchemaException( - sprintf('@Path "%s" in "%s" must not ends with "/" (slash).', $groupPath, $controller->getClass()) + sprintf('#[Path] "%s" in "%s" must not ends with "/" (slash).', $groupPath, $controller->getClass()) ); } } @@ -63,7 +63,7 @@ protected function validateRegex(SchemaBuilder $builder): void if ($match !== null) { throw new InvalidSchemaException( sprintf( - '@Path "%s" in "%s" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9-_/{}].', + '#[Path] "%s" in "%s" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9-_/{}].', $path, $controller->getClass(), $match[1] @@ -86,7 +86,7 @@ protected function validateRegex(SchemaBuilder $builder): void if ($match !== null) { throw (new InvalidSchemaException( sprintf( - '@Path "%s" in "%s" contains illegal characters "%s" in parameter. Allowed characters in parameter are only {[a-z-A-Z0-9-_]+}', + '#[Path] "%s" in "%s" contains illegal characters "%s" in parameter. Allowed characters in parameter are only {[a-z-A-Z0-9-_]+}', $path, $controller->getClass(), $match[1] diff --git a/src/Core/Schema/Validation/IdValidation.php b/src/Core/Schema/Validation/IdValidation.php index 64e71869..e710414d 100644 --- a/src/Core/Schema/Validation/IdValidation.php +++ b/src/Core/Schema/Validation/IdValidation.php @@ -22,7 +22,7 @@ protected function validateDuplicities(SchemaBuilder $builder): void foreach ($controllers as $controller) { foreach ($controller->getMethods() as $method) { - // Skip if @Id is not set + // Skip if #[Id] is not set if ($method->getId() === null || $method->getId() === '') { continue; } @@ -33,11 +33,11 @@ protected function validateDuplicities(SchemaBuilder $builder): void [$method->getId()] )); - // If this @GroupId(s).@ControllerId.@Id exists, throw an exception + // If this Group #[Id](s).Controller #[Id].#[Id] exists, throw an exception if (isset($ids[$fullid])) { throw new InvalidSchemaException( sprintf( - 'Duplicate @Id "%s" in "%s::%s()" and "%s::%s()"', + 'Duplicate #[Id] "%s" in "%s::%s()" and "%s::%s()"', $fullid, $controller->getClass(), $method->getName(), @@ -58,7 +58,7 @@ protected function validateRegex(SchemaBuilder $builder): void foreach ($controllers as $controller) { foreach ($controller->getMethods() as $method) { - // Skip if @Id is not set + // Skip if #[Id] is not set if ($method->getId() === null || $method->getId() === '') { continue; } @@ -75,7 +75,7 @@ protected function validateRegex(SchemaBuilder $builder): void if ($match !== null) { throw new InvalidSchemaException( sprintf( - '@Id "%s" in "%s::%s()" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9_].', + '#[Id] "%s" in "%s::%s()" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9_].', $id, $controller->getClass(), $method->getName(), diff --git a/src/Core/Schema/Validation/PathValidation.php b/src/Core/Schema/Validation/PathValidation.php index 98789bcd..45c41afc 100644 --- a/src/Core/Schema/Validation/PathValidation.php +++ b/src/Core/Schema/Validation/PathValidation.php @@ -25,7 +25,7 @@ protected function validateRequirements(SchemaBuilder $builder): void if ($method->getPath() === '') { throw (new InvalidSchemaException( sprintf( - '"%s::%s()" has empty @Path.', + '"%s::%s()" has empty #[Path].', $controller->getClass(), $method->getName() ) @@ -49,7 +49,7 @@ protected function validateSlashes(SchemaBuilder $builder): void if (!str_starts_with($path, '/')) { throw (new InvalidSchemaException( sprintf( - '@Path "%s" in "%s::%s()" must starts with "/" (slash).', + '#[Path] "%s" in "%s::%s()" must starts with "/" (slash).', $path, $controller->getClass(), $method->getName() @@ -63,7 +63,7 @@ protected function validateSlashes(SchemaBuilder $builder): void if (str_ends_with($path, '/') && strlen($path) > 1) { throw (new InvalidSchemaException( sprintf( - '@Path "%s" in "%s::%s()" must not ends with "/" (slash).', + '#[Path] "%s" in "%s::%s()" must not ends with "/" (slash).', $path, $controller->getClass(), $method->getName() @@ -95,7 +95,7 @@ protected function validateRegex(SchemaBuilder $builder): void if ($match !== null) { throw (new InvalidSchemaException( sprintf( - '@Path "%s" in "%s::%s()" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9-_/{}].', + '#[Path] "%s" in "%s::%s()" contains illegal characters "%s". Allowed characters are only [a-zA-Z0-9-_/{}].', $path, $controller->getClass(), $method->getName(), @@ -121,7 +121,7 @@ protected function validateRegex(SchemaBuilder $builder): void if ($match !== null) { throw (new InvalidSchemaException( sprintf( - '@Path "%s" in "%s::%s()" contains illegal characters "%s" in parameter. Allowed characters in parameter are only {[a-z-A-Z0-9-_]+}', + '#[Path] "%s" in "%s::%s()" contains illegal characters "%s" in parameter. Allowed characters in parameter are only {[a-z-A-Z0-9-_]+}', $path, $controller->getClass(), $method->getName(), diff --git a/src/Core/Schema/Validation/RequestParameterValidation.php b/src/Core/Schema/Validation/RequestParameterValidation.php index 36afb49b..7d12cd97 100644 --- a/src/Core/Schema/Validation/RequestParameterValidation.php +++ b/src/Core/Schema/Validation/RequestParameterValidation.php @@ -111,7 +111,7 @@ protected function validateMaskParametersAreInPath(SchemaBuilder $builder): void } throw new InvalidSchemaException(sprintf( - 'Mask parameter "%s" is not defined as @RequestParameter(in=path) in "%s"', + 'Mask parameter "%s" is not defined as #[RequestParameter(in=path)] in "%s"', $maskParameter['name'], $controller->getClass() )); diff --git a/tests/Cases/Core/Annotation/Controller/Method.phpt b/tests/Cases/Core/Annotation/Controller/Method.phpt index 05214cdd..6e6c81a4 100644 --- a/tests/Cases/Core/Annotation/Controller/Method.phpt +++ b/tests/Cases/Core/Annotation/Controller/Method.phpt @@ -8,6 +8,9 @@ require_once __DIR__ . '/../../../../bootstrap.php'; // Ok Toolkit::test(function (): void { + $method = new Method('GET'); + Assert::equal(['GET'], $method->getMethods()); + $method = new Method(['GET']); Assert::equal(['GET'], $method->getMethods()); diff --git a/tests/Cases/Core/Annotation/Controller/RequestParameter.phpt b/tests/Cases/Core/Annotation/Controller/RequestParameter.phpt index ae852026..91de23f4 100644 --- a/tests/Cases/Core/Annotation/Controller/RequestParameter.phpt +++ b/tests/Cases/Core/Annotation/Controller/RequestParameter.phpt @@ -44,6 +44,14 @@ Toolkit::test(function (): void { Assert::null($requestParameter->getDescription()); }); +// Exception - empty name +Toolkit::test(function (): void { + Assert::exception(function (): void { + new RequestParameter('', EndpointParameter::TYPE_STRING, EndpointParameter::IN_PATH); + }, InvalidArgumentException::class, 'Empty #[RequestParameter] name given'); +}); + + // Exception - no type Toolkit::test(function (): void { Assert::exception(function (): void { diff --git a/tests/Cases/Core/Annotation/Controller/Response.phpt b/tests/Cases/Core/Annotation/Controller/Response.phpt new file mode 100644 index 00000000..aa7c61a0 --- /dev/null +++ b/tests/Cases/Core/Annotation/Controller/Response.phpt @@ -0,0 +1,36 @@ +getDescription()); + Assert::same('200', $response->getCode()); + Assert::same('EntityClass', $response->getEntity()); +}); + +// OK - default values +Toolkit::test(function (): void { + $response = new Response('name'); + + Assert::same('name', $response->getDescription()); + Assert::same('default', $response->getCode()); + Assert::null($response->getEntity()); +}); + +// Exception - empty description +Toolkit::test(function (): void { + Assert::exception(function (): void { + new Response(''); + }, InvalidArgumentException::class, 'Empty #[Response] description given'); +}); diff --git a/tests/Cases/Core/DI/ApiExtension.phpt b/tests/Cases/Core/DI/ApiExtension.phpt index 38277137..726b7cf2 100644 --- a/tests/Cases/Core/DI/ApiExtension.phpt +++ b/tests/Cases/Core/DI/ApiExtension.phpt @@ -17,7 +17,7 @@ use Nette\DI\Compiler; use Nette\DI\Container; use Nette\DI\ContainerLoader; use Tester\Assert; -use Tests\Fixtures\Controllers\AnnotationFoobarController; +use Tests\Fixtures\Controllers\AttributeFoobarController; use Tests\Fixtures\Psr\DummyLogger; require_once __DIR__ . '/../../../bootstrap.php'; @@ -52,7 +52,7 @@ Toolkit::test(function (): void { 'debugMode' => true, ], 'services' => [ - AnnotationFoobarController::class, + AttributeFoobarController::class, ], ]); }, 2); @@ -67,7 +67,7 @@ Toolkit::test(function (): void { Assert::equal('/api/v1/foobar/baz1', $schema->getEndpoints()[0]->getMask()); Assert::equal('#^/api/v1/foobar/baz1$#', $schema->getEndpoints()[0]->getPattern()); Assert::equal([], $schema->getEndpoints()[0]->getParameters()); - Assert::equal(AnnotationFoobarController::class, $schema->getEndpoints()[0]->getHandler()->getClass()); + Assert::equal(AttributeFoobarController::class, $schema->getEndpoints()[0]->getHandler()->getClass()); Assert::equal('baz1', $schema->getEndpoints()[0]->getHandler()->getMethod()); }); diff --git a/tests/Cases/Core/DI/Loader/AttributeLoader.phpt b/tests/Cases/Core/DI/Loader/AttributeLoader.phpt index 5e00e9af..f2ee3808 100644 --- a/tests/Cases/Core/DI/Loader/AttributeLoader.phpt +++ b/tests/Cases/Core/DI/Loader/AttributeLoader.phpt @@ -10,7 +10,6 @@ use Contributte\Tester\Toolkit; use Nette\DI\ContainerBuilder; use Nette\DI\Definitions\ServiceDefinition; use Tester\Assert; -use Tests\Fixtures\Controllers\AnnotationFoobarController; use Tests\Fixtures\Controllers\ApiV1Controller; use Tests\Fixtures\Controllers\AttributeFoobarController; @@ -23,7 +22,7 @@ Toolkit::test(function (): void { ->andReturnUsing(function (): array { $controllers = []; $controllers[] = $c1 = new ServiceDefinition(); - $c1->setType(AnnotationFoobarController::class); + $c1->setType(AttributeFoobarController::class); return $controllers; }); @@ -39,8 +38,6 @@ Toolkit::test(function (): void { // Parse attributes Toolkit::test(function (): void { $builder = new ContainerBuilder(); - $builder->addDefinition('annotation_controller') - ->setType(AnnotationFoobarController::class); $builder->addDefinition('attribute_controller') ->setType(AttributeFoobarController::class); @@ -62,6 +59,7 @@ function testController(Controller $controller): void { Assert::equal('/foobar', $controller->getPath()); Assert::equal('foobar', $controller->getId()); + Assert::equal(['Foobar' => null], $controller->getTags()); Assert::count(4, $controller->getMethods()); @@ -73,6 +71,7 @@ function testController(Controller $controller): void Assert::equal('baz2', $controller->getMethods()['baz2']->getName()); Assert::equal('/baz2', $controller->getMethods()['baz2']->getPath()); Assert::equal(['GET', 'POST'], $controller->getMethods()['baz2']->getHttpMethods()); + Assert::equal(['Baz' => null], $controller->getMethods()['baz2']->getTags()); Assert::equal( [ diff --git a/tests/Cases/Core/DI/Loader/AttributeMultiLoader.phpt b/tests/Cases/Core/DI/Loader/AttributeMultiLoader.phpt index 7a055c4b..6f5cdd15 100644 --- a/tests/Cases/Core/DI/Loader/AttributeMultiLoader.phpt +++ b/tests/Cases/Core/DI/Loader/AttributeMultiLoader.phpt @@ -9,14 +9,11 @@ use Apitte\Core\Schema\SchemaBuilder; use Contributte\Tester\Toolkit; use Nette\DI\ContainerBuilder; use Tester\Assert; -use Tests\Fixtures\Controllers\AnnotationMultiController; use Tests\Fixtures\Controllers\AttributeMultiController; // Parse attributes Toolkit::test(function (): void { $builder = new ContainerBuilder(); - $builder->addDefinition('annotation_multi_controller') - ->setType(AnnotationMultiController::class); $builder->addDefinition('attribute_multi_controller') ->setType(AttributeMultiController::class); diff --git a/tests/Cases/Core/Mapping/Parameter/EnumTypeMapperTest.phpt b/tests/Cases/Core/Mapping/Parameter/EnumTypeMapperTest.phpt new file mode 100644 index 00000000..463ac657 --- /dev/null +++ b/tests/Cases/Core/Mapping/Parameter/EnumTypeMapperTest.phpt @@ -0,0 +1,61 @@ +setEnum(['', 'bar', 42]); + $options = [ + 'endpoint' => $endpointParameter, + ]; + + Assert::same('', $mapper->normalize('', $options)); + Assert::same('bar', $mapper->normalize('bar', $options)); + Assert::same(42, $mapper->normalize(42, $options)); + } + + public function testFail(): void + { + $mapper = new EnumTypeMapper(); + $endpointParameter = new EndpointParameter( + name: 'foobar', + type: EndpointParameter::TYPE_STRING, + ); + $options = [ + 'endpoint' => $endpointParameter, + ]; + + Assert::exception(function () use ($mapper, $options): void { + $mapper->normalize('', $options); + }, InvalidArgumentTypeException::class); + + $options['endpoint']->setEnum(['foo', 'bar']); + + Assert::exception(function () use ($mapper, $options): void { + $mapper->normalize(null, $options); + }, InvalidArgumentTypeException::class); + + Assert::exception(function () use ($mapper, $options): void { + $mapper->normalize('string', $options); + }, InvalidArgumentTypeException::class); + } + +} + +(new EnumTypeMapperTest())->run(); diff --git a/tests/Cases/Core/Schema/Serialization/ArraySerializator.phpt b/tests/Cases/Core/Schema/Serialization/ArraySerializator.phpt index d33a1815..b726dace 100644 --- a/tests/Cases/Core/Schema/Serialization/ArraySerializator.phpt +++ b/tests/Cases/Core/Schema/Serialization/ArraySerializator.phpt @@ -13,7 +13,7 @@ use Tester\Assert; // Serialize: success Toolkit::test(function (): void { - $serializator = new ArraySerializer(); + $serializer = new ArraySerializer(); $builder = new SchemaBuilder(); @@ -148,12 +148,12 @@ Toolkit::test(function (): void { ], ]; - Assert::same($expected, $serializator->serialize($builder)); + Assert::same($expected, $serializer->serialize($builder)); }); // Serialize: Exception - duplicate mask parameter - in controller Toolkit::test(function (): void { - $serializator = new ArraySerializer(); + $serializer = new ArraySerializer(); $builder = new SchemaBuilder(); @@ -167,14 +167,14 @@ Toolkit::test(function (): void { $m1->addParameter('m1-p1', EndpointParameter::IN_PATH); - Assert::exception(function () use ($serializator, $builder): void { - $serializator->serialize($builder); + Assert::exception(function () use ($serializer, $builder): void { + $serializer->serialize($builder); }, InvalidStateException::class, 'Duplicate mask parameter "c1-p1" in path "/{c1-p1}/{c1-p1}/{m1-p1}"'); }); // Serialize: Exception - duplicate mask parameter - in method Toolkit::test(function (): void { - $serializator = new ArraySerializer(); + $serializer = new ArraySerializer(); $builder = new SchemaBuilder(); @@ -185,14 +185,14 @@ Toolkit::test(function (): void { $m1 = $c1->addMethod('m1'); $m1->setPath('{m1-p1}/{m1-p1}'); - Assert::exception(function () use ($serializator, $builder): void { - $serializator->serialize($builder); + Assert::exception(function () use ($serializer, $builder): void { + $serializer->serialize($builder); }, InvalidStateException::class, 'Duplicate mask parameter "m1-p1" in path "/{c1-p1}/{m1-p1}/{m1-p1}"'); }); // Serialize: Exception - Parameter in mask is not defined in path Toolkit::test(function (): void { - $serializator = new ArraySerializer(); + $serializer = new ArraySerializer(); $builder = new SchemaBuilder(); @@ -204,7 +204,7 @@ Toolkit::test(function (): void { $m1->addParameter('m1-p1', EndpointParameter::IN_PATH); - Assert::exception(function () use ($serializator, $builder): void { - $serializator->serialize($builder); - }, InvalidStateException::class, '@RequestParameter(name="m1-p1", in=path) is not defined in mask (@Path annotations)'); + Assert::exception(function () use ($serializer, $builder): void { + $serializer->serialize($builder); + }, InvalidStateException::class, '#[RequestParameter(name="m1-p1", in=path)] is not defined in mask (#[Path] annotations)'); }); diff --git a/tests/Cases/Core/Schema/Validation/ControllerPathValidation.phpt b/tests/Cases/Core/Schema/Validation/ControllerPathValidation.phpt index 5ea185d8..ec72c13f 100644 --- a/tests/Cases/Core/Schema/Validation/ControllerPathValidation.phpt +++ b/tests/Cases/Core/Schema/Validation/ControllerPathValidation.phpt @@ -8,6 +8,19 @@ use Apitte\Core\Schema\Validation\ControllerPathValidation; use Contributte\Tester\Toolkit; use Tester\Assert; +// Validate: success +Toolkit::test(function (): void { + $validation = new ControllerPathValidation(); + $builder = new SchemaBuilder(); + + $c1 = $builder->addController('c1'); + $c1->setPath('/'); + + Assert::noError(function () use ($validation, $builder): void { + $validation->validate($builder); + }); +}); + // Validate: success Toolkit::test(function (): void { $validation = new ControllerPathValidation(); @@ -30,7 +43,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path in "c1" must be set.'); + }, InvalidSchemaException::class, '#[Path] in "c1" must be set.'); }); // Validate: start with / @@ -43,7 +56,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "foo" in "c1" must starts with "/" (slash).'); + }, InvalidSchemaException::class, '#[Path] "foo" in "c1" must starts with "/" (slash).'); }); // Validate: end with / @@ -56,7 +69,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "/foo/" in "c1" must not ends with "/" (slash).'); + }, InvalidSchemaException::class, '#[Path] "/foo/" in "c1" must not ends with "/" (slash).'); }); // Validate: invalid characters @@ -69,5 +82,5 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "/{foo$}" in "c1" contains illegal characters "{". Allowed characters are only [a-zA-Z0-9-_/].'); + }, InvalidSchemaException::class, '#[Path] "/{foo$}" in "c1" contains illegal characters "{". Allowed characters are only [a-zA-Z0-9-_/].'); }); diff --git a/tests/Cases/Core/Schema/Validation/ControllerValidation.phpt b/tests/Cases/Core/Schema/Validation/ControllerValidation.phpt index c3586d19..44c2835f 100644 --- a/tests/Cases/Core/Schema/Validation/ControllerValidation.phpt +++ b/tests/Cases/Core/Schema/Validation/ControllerValidation.phpt @@ -7,14 +7,14 @@ use Apitte\Core\Schema\SchemaBuilder; use Apitte\Core\Schema\Validation\ControllerValidation; use Contributte\Tester\Toolkit; use Tester\Assert; -use Tests\Fixtures\Controllers\AnnotationFoobarController; +use Tests\Fixtures\Controllers\AttributeFoobarController; // Validate: success Toolkit::test(function (): void { $validation = new ControllerValidation(); $builder = new SchemaBuilder(); - $builder->addController(AnnotationFoobarController::class); + $builder->addController(AttributeFoobarController::class); Assert::noError(function () use ($validation, $builder): void { $validation->validate($builder); diff --git a/tests/Cases/Core/Schema/Validation/GroupPathValidation.phpt b/tests/Cases/Core/Schema/Validation/GroupPathValidation.phpt index 0a12f0bb..53c633f4 100644 --- a/tests/Cases/Core/Schema/Validation/GroupPathValidation.phpt +++ b/tests/Cases/Core/Schema/Validation/GroupPathValidation.phpt @@ -44,7 +44,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "/" in "c1" cannot be only "/", it is nonsense.'); + }, InvalidSchemaException::class, '#[Path] "/" in "c1" cannot be only "/", it is nonsense.'); }); // Validate: starts with / @@ -57,7 +57,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "foo" in "c1" must starts with "/" (slash).'); + }, InvalidSchemaException::class, '#[Path] "foo" in "c1" must starts with "/" (slash).'); }); // Validate: end with / @@ -70,7 +70,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "/foo/" in "c1" must not ends with "/" (slash).'); + }, InvalidSchemaException::class, '#[Path] "/foo/" in "c1" must not ends with "/" (slash).'); }); // Validate: invalid characters @@ -83,7 +83,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "/foo$" in "c1" contains illegal characters "$". Allowed characters are only [a-zA-Z0-9-_/{}].'); + }, InvalidSchemaException::class, '#[Path] "/foo$" in "c1" contains illegal characters "$". Allowed characters are only [a-zA-Z0-9-_/{}].'); }); // Validate: invalid parameter (contains) @@ -96,5 +96,18 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Path "/{foo&&&bar}" in "c1" contains illegal characters "&&&". Allowed characters are only [a-zA-Z0-9-_/{}].'); + }, InvalidSchemaException::class, '#[Path] "/{foo&&&bar}" in "c1" contains illegal characters "&&&". Allowed characters are only [a-zA-Z0-9-_/{}].'); +}); + +// Validate: parameter containing slash (allowed in path, disallowed in parameter) +Toolkit::test(function (): void { + $validation = new GroupPathValidation(); + $builder = new SchemaBuilder(); + + $c1 = $builder->addController('c1'); + $c1->addGroupPath('/{foo/bar}'); + + Assert::exception(function () use ($validation, $builder): void { + $validation->validate($builder); + }, InvalidSchemaException::class, '#[Path] "/{foo/bar}" in "c1" contains illegal characters "/" in parameter. Allowed characters in parameter are only {[a-z-A-Z0-9-_]+}'); }); diff --git a/tests/Cases/Core/Schema/Validation/IdValidation.phpt b/tests/Cases/Core/Schema/Validation/IdValidation.phpt index 2bc71b62..0c1a15bf 100644 --- a/tests/Cases/Core/Schema/Validation/IdValidation.phpt +++ b/tests/Cases/Core/Schema/Validation/IdValidation.phpt @@ -45,7 +45,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, 'Duplicate @Id "foo.bar" in "c2::method()" and "c1::method()"'); + }, InvalidSchemaException::class, 'Duplicate #[Id] "foo.bar" in "c2::method()" and "c1::method()"'); }); // Validate: invalid characters @@ -59,5 +59,5 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, '@Id "{$bar}" in "c1::method()" contains illegal characters "{$". Allowed characters are only [a-zA-Z0-9_].'); + }, InvalidSchemaException::class, '#[Id] "{$bar}" in "c1::method()" contains illegal characters "{$". Allowed characters are only [a-zA-Z0-9_].'); }); diff --git a/tests/Cases/Core/Schema/Validation/PathValidation.phpt b/tests/Cases/Core/Schema/Validation/PathValidation.phpt index 651eaf19..ffe82bd6 100644 --- a/tests/Cases/Core/Schema/Validation/PathValidation.phpt +++ b/tests/Cases/Core/Schema/Validation/PathValidation.phpt @@ -19,7 +19,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($builder): void { $validator = new PathValidation(); $validator->validate($builder); - }, InvalidSchemaException::class, '@Path "foobar" in "c1::foo()" must starts with "/" (slash).'); + }, InvalidSchemaException::class, '#[Path] "foobar" in "c1::foo()" must starts with "/" (slash).'); }); // Validate: end slash @@ -33,7 +33,22 @@ Toolkit::test(function (): void { Assert::exception(function () use ($builder): void { $validator = new PathValidation(); $validator->validate($builder); - }, InvalidSchemaException::class, '@Path "/foobar/" in "c1::foo()" must not ends with "/" (slash).'); + }, InvalidSchemaException::class, '#[Path] "/foobar/" in "c1::foo()" must not ends with "/" (slash).'); +}); + +// Validate: empty path +Toolkit::test(function (): void { + $builder = new SchemaBuilder(); + + $c1 = $builder->addController('c1'); + $c1m1 = $c1->addMethod('foo1'); + $c1m1->setPath(''); + $c1m1->addHttpMethod('GET'); + + Assert::exception(function () use ($builder): void { + $validator = new PathValidation(); + $validator->validate($builder); + }, InvalidSchemaException::class, '"c1::foo1()" has empty #[Path].'); }); // Validate: invalid parameter (ends) @@ -48,7 +63,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($builder): void { $validator = new PathValidation(); $validator->validate($builder); - }, InvalidSchemaException::class, '@Path "/{foo$}" in "c1::foo1()" contains illegal characters "$". Allowed characters are only [a-zA-Z0-9-_/{}].'); + }, InvalidSchemaException::class, '#[Path] "/{foo$}" in "c1::foo1()" contains illegal characters "$". Allowed characters are only [a-zA-Z0-9-_/{}].'); }); // Validate: invalid parameter (starts) @@ -63,7 +78,7 @@ Toolkit::test(function (): void { Assert::exception(function () use ($builder): void { $validator = new PathValidation(); $validator->validate($builder); - }, InvalidSchemaException::class, '@Path "/{%foo}" in "c1::foo1()" contains illegal characters "%". Allowed characters are only [a-zA-Z0-9-_/{}].'); + }, InvalidSchemaException::class, '#[Path] "/{%foo}" in "c1::foo1()" contains illegal characters "%". Allowed characters are only [a-zA-Z0-9-_/{}].'); }); // Validate: invalid parameter (contains) @@ -78,7 +93,22 @@ Toolkit::test(function (): void { Assert::exception(function () use ($builder): void { $validator = new PathValidation(); $validator->validate($builder); - }, InvalidSchemaException::class, '@Path "/{foo&&&bar}" in "c1::foo1()" contains illegal characters "&&&". Allowed characters are only [a-zA-Z0-9-_/{}].'); + }, InvalidSchemaException::class, '#[Path] "/{foo&&&bar}" in "c1::foo1()" contains illegal characters "&&&". Allowed characters are only [a-zA-Z0-9-_/{}].'); +}); + +// Validate: parameter containing slash (allowed in path, disallowed in parameter) +Toolkit::test(function (): void { + $builder = new SchemaBuilder(); + + $c1 = $builder->addController('c1'); + $c1m1 = $c1->addMethod('foo1'); + $c1m1->setPath('/{foo/bar}'); + $c1m1->addHttpMethod('GET'); + + Assert::exception(function () use ($builder): void { + $validator = new PathValidation(); + $validator->validate($builder); + }, InvalidSchemaException::class, '#[Path] "/{foo/bar}" in "c1::foo1()" contains illegal characters "/" in parameter. Allowed characters in parameter are only {[a-z-A-Z0-9-_]+}'); }); // Validate: multiple parameters diff --git a/tests/Cases/Core/Schema/Validation/RequestParameterValidation.phpt b/tests/Cases/Core/Schema/Validation/RequestParameterValidation.phpt index 8c7dba8b..89439207 100644 --- a/tests/Cases/Core/Schema/Validation/RequestParameterValidation.phpt +++ b/tests/Cases/Core/Schema/Validation/RequestParameterValidation.phpt @@ -143,5 +143,5 @@ Toolkit::test(function (): void { Assert::exception(function () use ($validation, $builder): void { $validation->validate($builder); - }, InvalidSchemaException::class, 'Mask parameter "m1-p1" is not defined as @RequestParameter(in=path) in "c1-class"'); + }, InvalidSchemaException::class, 'Mask parameter "m1-p1" is not defined as #[RequestParameter(in=path)] in "c1-class"'); }); diff --git a/tests/Cases/Negotiation/Transformer/JsonTransformer.phpt b/tests/Cases/Negotiation/Transformer/JsonTransformer.phpt index a3d9388e..d139a9b6 100644 --- a/tests/Cases/Negotiation/Transformer/JsonTransformer.phpt +++ b/tests/Cases/Negotiation/Transformer/JsonTransformer.phpt @@ -2,6 +2,7 @@ require_once __DIR__ . '/../../../bootstrap.php'; +use Apitte\Core\Exception\Api\ServerErrorException; use Apitte\Core\Http\ApiRequest; use Apitte\Core\Http\ApiResponse; use Apitte\Negotiation\Http\ArrayEntity; @@ -23,3 +24,16 @@ Toolkit::test(function (): void { Assert::equal('{"foo":"bar"}', $response->getContents()); }); + +// Encode exception +Toolkit::test(function (): void { + $transformer = new JsonTransformer(); + $request = new ApiRequest(Psr7ServerRequestFactory::fromSuperGlobal()); + $response = new ApiResponse(Psr7ResponseFactory::fromGlobal()); + $context = ['exception' => (new ServerErrorException('Test exception'))->withContext('foo')]; + + $response = $transformer->transform($request, $response, $context); + $response->getBody()->rewind(); + + Assert::equal('{"exception":"Test exception","context":"foo"}', $response->getContents()); +}); diff --git a/tests/Cases/OpenApi/SchemaDefinition/Entity/EntityAdapterTest.php b/tests/Cases/OpenApi/SchemaDefinition/Entity/EntityAdapterTest.php index 7871a1ad..072d43c3 100644 --- a/tests/Cases/OpenApi/SchemaDefinition/Entity/EntityAdapterTest.php +++ b/tests/Cases/OpenApi/SchemaDefinition/Entity/EntityAdapterTest.php @@ -184,10 +184,6 @@ public function testBadCase(): void */ public function testTypedEntity(): void { - if (PHP_VERSION_ID < 70400) { - $this->skip(); - } - $adapter = new EntityAdapter(); Assert::same( @@ -242,10 +238,6 @@ public function testArrayShape(): void public function testNativeUnionEntity(): void { - if (PHP_VERSION_ID < 80000) { - $this->skip(); - } - $adapter = new EntityAdapter(); Assert::same( @@ -285,10 +277,6 @@ public function testNativeUnionEntity(): void public function testNativeIntersectionEntity(): void { - if (PHP_VERSION_ID < 80100) { - $this->skip(); - } - $adapter = new EntityAdapter(); Assert::same( @@ -309,10 +297,6 @@ public function testNativeIntersectionEntity(): void public function testMixedEntity(): void { - if (PHP_VERSION_ID < 80000) { - $this->skip(); - } - $adapter = new EntityAdapter(); Assert::same( [ diff --git a/tests/Fixtures/Controllers/AnnotationFoobarController.php b/tests/Fixtures/Controllers/AnnotationFoobarController.php deleted file mode 100644 index 34fe7df2..00000000 --- a/tests/Fixtures/Controllers/AnnotationFoobarController.php +++ /dev/null @@ -1,68 +0,0 @@ -