From 62af8748561feb340353b581b681b82b5fdadc5f Mon Sep 17 00:00:00 2001 From: Xavier Laviron Date: Mon, 14 Nov 2022 17:13:06 +0100 Subject: [PATCH] feat: use openapi array to validate filter parameters (#5114) * feat: use openapi array to validate filter parameters The filter validators were only using the 'swagger' entry from the filter description. It should also use the 'openapi' entry, as swagger is deprecated. * test(filters): test using openapi for query parameters validation --- .../Validator/ArrayItems.php | 12 +- .../Validator/Bounds.php | 12 +- .../CheckFilterDeprecationsTrait.php | 31 ++++ .../Validator/Enum.php | 6 +- .../Validator/Length.php | 8 +- .../Validator/MultipleOf.php | 6 +- .../Validator/Pattern.php | 6 +- .../Validator/Required.php | 6 +- .../Validator/ArrayItemsTest.php | 173 ++++++++++++++++++ .../Validator/BoundsTest.php | 148 +++++++++++++++ .../Validator/EnumTest.php | 37 ++++ .../Validator/LengthTest.php | 110 +++++++++++ .../Validator/MultipleOfTest.php | 39 ++++ .../Validator/PatternTest.php | 80 ++++++++ .../Validator/RequiredTest.php | 50 +++++ 15 files changed, 710 insertions(+), 14 deletions(-) create mode 100644 src/Api/QueryParameterValidator/Validator/CheckFilterDeprecationsTrait.php diff --git a/src/Api/QueryParameterValidator/Validator/ArrayItems.php b/src/Api/QueryParameterValidator/Validator/ArrayItems.php index d9e15e1c217..8cc5b50c92c 100644 --- a/src/Api/QueryParameterValidator/Validator/ArrayItems.php +++ b/src/Api/QueryParameterValidator/Validator/ArrayItems.php @@ -15,6 +15,8 @@ final class ArrayItems implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -24,9 +26,11 @@ public function validate(string $name, array $filterDescription, array $queryPar return []; } - $maxItems = $filterDescription['swagger']['maxItems'] ?? null; - $minItems = $filterDescription['swagger']['minItems'] ?? null; - $uniqueItems = $filterDescription['swagger']['uniqueItems'] ?? false; + $this->checkFilterDeprecations($filterDescription); + + $maxItems = $filterDescription['openapi']['maxItems'] ?? $filterDescription['swagger']['maxItems'] ?? null; + $minItems = $filterDescription['openapi']['minItems'] ?? $filterDescription['swagger']['minItems'] ?? null; + $uniqueItems = $filterDescription['openapi']['uniqueItems'] ?? $filterDescription['swagger']['uniqueItems'] ?? false; $errorList = []; @@ -60,7 +64,7 @@ private function getValue(string $name, array $filterDescription, array $queryPa return $value; } - $collectionFormat = $filterDescription['swagger']['collectionFormat'] ?? 'csv'; + $collectionFormat = $filterDescription['openapi']['collectionFormat'] ?? $filterDescription['swagger']['collectionFormat'] ?? 'csv'; return explode(self::getSeparator($collectionFormat), (string) $value) ?: []; // @phpstan-ignore-line } diff --git a/src/Api/QueryParameterValidator/Validator/Bounds.php b/src/Api/QueryParameterValidator/Validator/Bounds.php index eebc40b3eca..9ebf3285380 100644 --- a/src/Api/QueryParameterValidator/Validator/Bounds.php +++ b/src/Api/QueryParameterValidator/Validator/Bounds.php @@ -15,6 +15,8 @@ final class Bounds implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -25,13 +27,15 @@ public function validate(string $name, array $filterDescription, array $queryPar return []; } - $maximum = $filterDescription['swagger']['maximum'] ?? null; - $minimum = $filterDescription['swagger']['minimum'] ?? null; + $this->checkFilterDeprecations($filterDescription); + + $maximum = $filterDescription['openapi']['maximum'] ?? $filterDescription['swagger']['maximum'] ?? null; + $minimum = $filterDescription['openapi']['minimum'] ?? $filterDescription['swagger']['minimum'] ?? null; $errorList = []; if (null !== $maximum) { - if (($filterDescription['swagger']['exclusiveMaximum'] ?? false) && $value >= $maximum) { + if (($filterDescription['openapi']['exclusiveMaximum'] ?? $filterDescription['swagger']['exclusiveMaximum'] ?? false) && $value >= $maximum) { $errorList[] = sprintf('Query parameter "%s" must be less than %s', $name, $maximum); } elseif ($value > $maximum) { $errorList[] = sprintf('Query parameter "%s" must be less than or equal to %s', $name, $maximum); @@ -39,7 +43,7 @@ public function validate(string $name, array $filterDescription, array $queryPar } if (null !== $minimum) { - if (($filterDescription['swagger']['exclusiveMinimum'] ?? false) && $value <= $minimum) { + if (($filterDescription['openapi']['exclusiveMinimum'] ?? $filterDescription['swagger']['exclusiveMinimum'] ?? false) && $value <= $minimum) { $errorList[] = sprintf('Query parameter "%s" must be greater than %s', $name, $minimum); } elseif ($value < $minimum) { $errorList[] = sprintf('Query parameter "%s" must be greater than or equal to %s', $name, $minimum); diff --git a/src/Api/QueryParameterValidator/Validator/CheckFilterDeprecationsTrait.php b/src/Api/QueryParameterValidator/Validator/CheckFilterDeprecationsTrait.php new file mode 100644 index 00000000000..a72f79ed102 --- /dev/null +++ b/src/Api/QueryParameterValidator/Validator/CheckFilterDeprecationsTrait.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Api\QueryParameterValidator\Validator; + +/** + * @internal + */ +trait CheckFilterDeprecationsTrait +{ + protected function checkFilterDeprecations(array $filterDescription): void + { + if (\array_key_exists('swagger', $filterDescription)) { + trigger_deprecation( + 'api-platform/core', + '3.0', + 'Using the "swagger" key in filters description is deprecated, use "openapi" instead.' + ); + } + } +} diff --git a/src/Api/QueryParameterValidator/Validator/Enum.php b/src/Api/QueryParameterValidator/Validator/Enum.php index 2e0bf5c277b..d8f44634039 100644 --- a/src/Api/QueryParameterValidator/Validator/Enum.php +++ b/src/Api/QueryParameterValidator/Validator/Enum.php @@ -15,6 +15,8 @@ final class Enum implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -25,7 +27,9 @@ public function validate(string $name, array $filterDescription, array $queryPar return []; } - $enum = $filterDescription['swagger']['enum'] ?? null; + $this->checkFilterDeprecations($filterDescription); + + $enum = $filterDescription['openapi']['enum'] ?? $filterDescription['swagger']['enum'] ?? null; if (null !== $enum && !\in_array($value, $enum, true)) { return [ diff --git a/src/Api/QueryParameterValidator/Validator/Length.php b/src/Api/QueryParameterValidator/Validator/Length.php index 0b0c67e5595..c96f86511c2 100644 --- a/src/Api/QueryParameterValidator/Validator/Length.php +++ b/src/Api/QueryParameterValidator/Validator/Length.php @@ -15,6 +15,8 @@ final class Length implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -25,8 +27,10 @@ public function validate(string $name, array $filterDescription, array $queryPar return []; } - $maxLength = $filterDescription['swagger']['maxLength'] ?? null; - $minLength = $filterDescription['swagger']['minLength'] ?? null; + $this->checkFilterDeprecations($filterDescription); + + $maxLength = $filterDescription['openapi']['maxLength'] ?? $filterDescription['swagger']['maxLength'] ?? null; + $minLength = $filterDescription['openapi']['minLength'] ?? $filterDescription['swagger']['minLength'] ?? null; $errorList = []; diff --git a/src/Api/QueryParameterValidator/Validator/MultipleOf.php b/src/Api/QueryParameterValidator/Validator/MultipleOf.php index 6da33972688..5d792a3ba50 100644 --- a/src/Api/QueryParameterValidator/Validator/MultipleOf.php +++ b/src/Api/QueryParameterValidator/Validator/MultipleOf.php @@ -15,6 +15,8 @@ final class MultipleOf implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -25,7 +27,9 @@ public function validate(string $name, array $filterDescription, array $queryPar return []; } - $multipleOf = $filterDescription['swagger']['multipleOf'] ?? null; + $this->checkFilterDeprecations($filterDescription); + + $multipleOf = $filterDescription['openapi']['multipleOf'] ?? $filterDescription['swagger']['multipleOf'] ?? null; if (null !== $multipleOf && 0 !== ($value % $multipleOf)) { return [ diff --git a/src/Api/QueryParameterValidator/Validator/Pattern.php b/src/Api/QueryParameterValidator/Validator/Pattern.php index a585fd8b321..8ad2fadbc30 100644 --- a/src/Api/QueryParameterValidator/Validator/Pattern.php +++ b/src/Api/QueryParameterValidator/Validator/Pattern.php @@ -15,6 +15,8 @@ final class Pattern implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -25,7 +27,9 @@ public function validate(string $name, array $filterDescription, array $queryPar return []; } - $pattern = $filterDescription['swagger']['pattern'] ?? null; + $this->checkFilterDeprecations($filterDescription); + + $pattern = $filterDescription['openapi']['pattern'] ?? $filterDescription['swagger']['pattern'] ?? null; if (null !== $pattern && !preg_match($pattern, $value)) { return [ diff --git a/src/Api/QueryParameterValidator/Validator/Required.php b/src/Api/QueryParameterValidator/Validator/Required.php index 0045b0513b4..9b230876f04 100644 --- a/src/Api/QueryParameterValidator/Validator/Required.php +++ b/src/Api/QueryParameterValidator/Validator/Required.php @@ -17,6 +17,8 @@ final class Required implements ValidatorInterface { + use CheckFilterDeprecationsTrait; + /** * {@inheritdoc} */ @@ -34,8 +36,10 @@ public function validate(string $name, array $filterDescription, array $queryPar ]; } + $this->checkFilterDeprecations($filterDescription); + // if query param is empty and the configuration does not allow it - if (!($filterDescription['swagger']['allowEmptyValue'] ?? false) && empty($this->requestGetQueryParameter($queryParameters, $name))) { + if (!($filterDescription['openapi']['allowEmptyValue'] ?? $filterDescription['swagger']['allowEmptyValue'] ?? false) && empty($this->requestGetQueryParameter($queryParameters, $name))) { return [ sprintf('Query parameter "%s" does not allow empty value', $name), ]; diff --git a/tests/Api/QueryParameterValidator/Validator/ArrayItemsTest.php b/tests/Api/QueryParameterValidator/Validator/ArrayItemsTest.php index b3ce00c8b23..e5a97b3daba 100644 --- a/tests/Api/QueryParameterValidator/Validator/ArrayItemsTest.php +++ b/tests/Api/QueryParameterValidator/Validator/ArrayItemsTest.php @@ -41,6 +41,9 @@ public function testEmptyQueryParameter(): void ); } + /** + * @group legacy + */ public function testNonMatchingParameter(): void { $filter = new ArrayItems(); @@ -65,6 +68,33 @@ public function testNonMatchingParameter(): void ); } + public function testNonMatchingParameterOpenApi(): void + { + $filter = new ArrayItems(); + + $filterDefinition = [ + 'openapi' => [ + 'maxItems' => 3, + 'minItems' => 2, + ], + ]; + + $request = ['some_filter' => ['foo', 'bar', 'bar', 'foo']]; + $this->assertEquals( + ['Query parameter "some_filter" must contain less than 3 values'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $request = ['some_filter' => ['foo']]; + $this->assertEquals( + ['Query parameter "some_filter" must contain more than 2 values'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testMatchingParameter(): void { $filter = new ArrayItems(); @@ -87,6 +117,31 @@ public function testMatchingParameter(): void ); } + public function testMatchingParameterOpenApi(): void + { + $filter = new ArrayItems(); + + $filterDefinition = [ + 'openapi' => [ + 'maxItems' => 3, + 'minItems' => 2, + ], + ]; + + $request = ['some_filter' => ['foo', 'bar']]; + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $request = ['some_filter' => ['foo', 'bar', 'baz']]; + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testNonMatchingUniqueItems(): void { $filter = new ArrayItems(); @@ -104,6 +159,26 @@ public function testNonMatchingUniqueItems(): void ); } + public function testNonMatchingUniqueItemsOpenApi(): void + { + $filter = new ArrayItems(); + + $filterDefinition = [ + 'openapi' => [ + 'uniqueItems' => true, + ], + ]; + + $request = ['some_filter' => ['foo', 'bar', 'bar', 'foo']]; + $this->assertEquals( + ['Query parameter "some_filter" must contain unique values'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testMatchingUniqueItems(): void { $filter = new ArrayItems(); @@ -120,6 +195,25 @@ public function testMatchingUniqueItems(): void ); } + public function testMatchingUniqueItemsOpenApi(): void + { + $filter = new ArrayItems(); + + $filterDefinition = [ + 'openapi' => [ + 'uniqueItems' => true, + ], + ]; + + $request = ['some_filter' => ['foo', 'bar', 'baz']]; + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testSeparators(): void { $filter = new ArrayItems(); @@ -177,6 +271,66 @@ public function testSeparators(): void ); } + public function testSeparatorsOpenApi(): void + { + $filter = new ArrayItems(); + + $filterDefinition = [ + 'openapi' => [ + 'maxItems' => 2, + 'uniqueItems' => true, + 'collectionFormat' => 'csv', + ], + ]; + + $request = ['some_filter' => 'foo,bar,bar']; + $this->assertEquals( + [ + 'Query parameter "some_filter" must contain less than 2 values', + 'Query parameter "some_filter" must contain unique values', + ], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition['openapi']['collectionFormat'] = 'ssv'; + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition['openapi']['collectionFormat'] = 'ssv'; + $request = ['some_filter' => 'foo bar bar']; + $this->assertEquals( + [ + 'Query parameter "some_filter" must contain less than 2 values', + 'Query parameter "some_filter" must contain unique values', + ], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition['openapi']['collectionFormat'] = 'tsv'; + $request = ['some_filter' => 'foo\tbar\tbar']; + $this->assertEquals( + [ + 'Query parameter "some_filter" must contain less than 2 values', + 'Query parameter "some_filter" must contain unique values', + ], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition['openapi']['collectionFormat'] = 'pipes'; + $request = ['some_filter' => 'foo|bar|bar']; + $this->assertEquals( + [ + 'Query parameter "some_filter" must contain less than 2 values', + 'Query parameter "some_filter" must contain unique values', + ], + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testSeparatorsUnknownSeparator(): void { $filter = new ArrayItems(); @@ -195,4 +349,23 @@ public function testSeparatorsUnknownSeparator(): void $filter->validate('some_filter', $filterDefinition, $request); } + + public function testSeparatorsUnknownSeparatorOpenApi(): void + { + $filter = new ArrayItems(); + + $filterDefinition = [ + 'openapi' => [ + 'maxItems' => 2, + 'uniqueItems' => true, + 'collectionFormat' => 'unknownFormat', + ], + ]; + $request = ['some_filter' => 'foo,bar,bar']; + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Unknown collection format unknownFormat'); + + $filter->validate('some_filter', $filterDefinition, $request); + } } diff --git a/tests/Api/QueryParameterValidator/Validator/BoundsTest.php b/tests/Api/QueryParameterValidator/Validator/BoundsTest.php index 5157374d9dc..3bc91ca9926 100644 --- a/tests/Api/QueryParameterValidator/Validator/BoundsTest.php +++ b/tests/Api/QueryParameterValidator/Validator/BoundsTest.php @@ -39,6 +39,9 @@ public function testEmptyQueryParameter(): void ); } + /** + * @group legacy + */ public function testNonMatchingMinimum(): void { $request = ['some_filter' => '9']; @@ -80,6 +83,50 @@ public function testNonMatchingMinimum(): void ); } + public function testNonMatchingMinimumOpenApi(): void + { + $request = ['some_filter' => '9']; + $filter = new Bounds(); + + $filterDefinition = [ + 'openapi' => [ + 'minimum' => 10, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be greater than or equal to 10'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition = [ + 'openapi' => [ + 'minimum' => 10, + 'exclusiveMinimum' => false, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be greater than or equal to 10'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition = [ + 'openapi' => [ + 'minimum' => 9, + 'exclusiveMinimum' => true, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be greater than 9'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testMatchingMinimum(): void { $request = ['some_filter' => '10']; @@ -107,6 +154,36 @@ public function testMatchingMinimum(): void ); } + public function testMatchingMinimumOpenApi(): void + { + $request = ['some_filter' => '10']; + $filter = new Bounds(); + + $filterDefinition = [ + 'openapi' => [ + 'minimum' => 10, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition = [ + 'openapi' => [ + 'minimum' => 9, + 'exclusiveMinimum' => false, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testNonMatchingMaximum(): void { $request = ['some_filter' => '11']; @@ -148,6 +225,50 @@ public function testNonMatchingMaximum(): void ); } + public function testNonMatchingMaximumOpenApi(): void + { + $request = ['some_filter' => '11']; + $filter = new Bounds(); + + $filterDefinition = [ + 'openapi' => [ + 'maximum' => 10, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be less than or equal to 10'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition = [ + 'openapi' => [ + 'maximum' => 10, + 'exclusiveMaximum' => false, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be less than or equal to 10'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition = [ + 'openapi' => [ + 'maximum' => 9, + 'exclusiveMaximum' => true, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be less than 9'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testMatchingMaximum(): void { $request = ['some_filter' => '10']; @@ -174,4 +295,31 @@ public function testMatchingMaximum(): void $filter->validate('some_filter', $filterDefinition, $request) ); } + + public function testMatchingMaximumOpenApi(): void + { + $request = ['some_filter' => '10']; + $filter = new Bounds(); + + $filterDefinition = [ + 'openapi' => [ + 'maximum' => 10, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + + $filterDefinition = [ + 'openapi' => [ + 'maximum' => 10, + 'exclusiveMaximum' => false, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + } } diff --git a/tests/Api/QueryParameterValidator/Validator/EnumTest.php b/tests/Api/QueryParameterValidator/Validator/EnumTest.php index acee9b5dfcf..e2389cfb763 100644 --- a/tests/Api/QueryParameterValidator/Validator/EnumTest.php +++ b/tests/Api/QueryParameterValidator/Validator/EnumTest.php @@ -39,6 +39,9 @@ public function testEmptyQueryParameter(): void ); } + /** + * @group legacy + */ public function testNonMatchingParameter(): void { $filter = new Enum(); @@ -55,6 +58,25 @@ public function testNonMatchingParameter(): void ); } + public function testNonMatchingParameterOpenApi(): void + { + $filter = new Enum(); + + $filterDefinition = [ + 'openapi' => [ + 'enum' => ['foo', 'bar'], + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must be one of "foo, bar"'], + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'foobar']) + ); + } + + /** + * @group legacy + */ public function testMatchingParameter(): void { $filter = new Enum(); @@ -69,4 +91,19 @@ public function testMatchingParameter(): void $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'foo']) ); } + + public function testMatchingParameterOpenApi(): void + { + $filter = new Enum(); + + $filterDefinition = [ + 'openapi' => [ + 'enum' => ['foo', 'bar'], + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'foo']) + ); + } } diff --git a/tests/Api/QueryParameterValidator/Validator/LengthTest.php b/tests/Api/QueryParameterValidator/Validator/LengthTest.php index 097f0de0cac..09ab8557214 100644 --- a/tests/Api/QueryParameterValidator/Validator/LengthTest.php +++ b/tests/Api/QueryParameterValidator/Validator/LengthTest.php @@ -39,6 +39,9 @@ public function testEmptyQueryParameter(): void ); } + /** + * @group legacy + */ public function testNonMatchingParameter(): void { $filter = new Length(); @@ -61,6 +64,31 @@ public function testNonMatchingParameter(): void ); } + public function testNonMatchingParameterOpenApi(): void + { + $filter = new Length(); + + $filterDefinition = [ + 'openapi' => [ + 'minLength' => 3, + 'maxLength' => 5, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" length must be greater than or equal to 3'], + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'ab']) + ); + + $this->assertEquals( + ['Query parameter "some_filter" length must be lower than or equal to 5'], + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abcdef']) + ); + } + + /** + * @group legacy + */ public function testNonMatchingParameterWithOnlyOneDefinition(): void { $filter = new Length(); @@ -88,6 +116,36 @@ public function testNonMatchingParameterWithOnlyOneDefinition(): void ); } + public function testNonMatchingParameterWithOnlyOneDefinitionOpenApi(): void + { + $filter = new Length(); + + $filterDefinition = [ + 'openapi' => [ + 'minLength' => 3, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" length must be greater than or equal to 3'], + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'ab']) + ); + + $filterDefinition = [ + 'openapi' => [ + 'maxLength' => 5, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" length must be lower than or equal to 5'], + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abcdef']) + ); + } + + /** + * @group legacy + */ public function testMatchingParameter(): void { $filter = new Length(); @@ -112,6 +170,33 @@ public function testMatchingParameter(): void ); } + public function testMatchingParameterOpenApi(): void + { + $filter = new Length(); + + $filterDefinition = [ + 'openapi' => [ + 'minLength' => 3, + 'maxLength' => 5, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abc']) + ); + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abcd']) + ); + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abcde']) + ); + } + + /** + * @group legacy + */ public function testMatchingParameterWithOneDefinition(): void { $filter = new Length(); @@ -136,4 +221,29 @@ public function testMatchingParameterWithOneDefinition(): void $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abcde']) ); } + + public function testMatchingParameterWithOneDefinitionOpenApi(): void + { + $filter = new Length(); + + $filterDefinition = [ + 'openapi' => [ + 'minLength' => 3, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abc']) + ); + + $filterDefinition = [ + 'openapi' => [ + 'maxLength' => 5, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, ['some_filter' => 'abcde']) + ); + } } diff --git a/tests/Api/QueryParameterValidator/Validator/MultipleOfTest.php b/tests/Api/QueryParameterValidator/Validator/MultipleOfTest.php index b5d8f11e344..783e73f338d 100644 --- a/tests/Api/QueryParameterValidator/Validator/MultipleOfTest.php +++ b/tests/Api/QueryParameterValidator/Validator/MultipleOfTest.php @@ -40,6 +40,9 @@ public function testEmptyQueryParameter(): void ); } + /** + * @group legacy + */ public function testNonMatchingParameter(): void { $request = ['some_filter' => '8']; @@ -57,6 +60,26 @@ public function testNonMatchingParameter(): void ); } + public function testNonMatchingParameterOpenApi(): void + { + $request = ['some_filter' => '8']; + $filter = new MultipleOf(); + + $filterDefinition = [ + 'openapi' => [ + 'multipleOf' => 3, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must multiple of 3'], + $filter->validate('some_filter', $filterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testMatchingParameter(): void { $request = ['some_filter' => '8']; @@ -72,4 +95,20 @@ public function testMatchingParameter(): void $filter->validate('some_filter', $filterDefinition, $request) ); } + + public function testMatchingParameterOpenApi(): void + { + $request = ['some_filter' => '8']; + $filter = new MultipleOf(); + + $filterDefinition = [ + 'openapi' => [ + 'multipleOf' => 4, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $filterDefinition, $request) + ); + } } diff --git a/tests/Api/QueryParameterValidator/Validator/PatternTest.php b/tests/Api/QueryParameterValidator/Validator/PatternTest.php index c97ae786c8e..9c9dcd9ac3a 100644 --- a/tests/Api/QueryParameterValidator/Validator/PatternTest.php +++ b/tests/Api/QueryParameterValidator/Validator/PatternTest.php @@ -30,6 +30,9 @@ public function testNonDefinedFilter(): void ); } + /** + * @group legacy + */ public function testFilterWithEmptyValue(): void { $filter = new Pattern(); @@ -51,6 +54,30 @@ public function testFilterWithEmptyValue(): void ); } + public function testFilterWithEmptyValueOpenApi(): void + { + $filter = new Pattern(); + + $explicitFilterDefinition = [ + 'openapi' => [ + 'pattern' => '/foo/', + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $explicitFilterDefinition, ['some_filter' => '']) + ); + + $weirdParameter = new \stdClass(); + $weirdParameter->foo = 'non string value should not exists'; + $this->assertEmpty( + $filter->validate('some_filter', $explicitFilterDefinition, ['some_filter' => $weirdParameter]) + ); + } + + /** + * @group legacy + */ public function testFilterWithZeroAsParameter(): void { $filter = new Pattern(); @@ -67,6 +94,25 @@ public function testFilterWithZeroAsParameter(): void ); } + public function testFilterWithZeroAsParameterOpenApi(): void + { + $filter = new Pattern(); + + $explicitFilterDefinition = [ + 'openapi' => [ + 'pattern' => '/foo/', + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must match pattern /foo/'], + $filter->validate('some_filter', $explicitFilterDefinition, ['some_filter' => '0']) + ); + } + + /** + * @group legacy + */ public function testFilterWithNonMatchingValue(): void { $filter = new Pattern(); @@ -83,6 +129,25 @@ public function testFilterWithNonMatchingValue(): void ); } + public function testFilterWithNonMatchingValueOpenApi(): void + { + $filter = new Pattern(); + + $explicitFilterDefinition = [ + 'openapi' => [ + 'pattern' => '/foo/', + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" must match pattern /foo/'], + $filter->validate('some_filter', $explicitFilterDefinition, ['some_filter' => 'bar']) + ); + } + + /** + * @group legacy + */ public function testFilterWithNonchingValue(): void { $filter = new Pattern(); @@ -97,4 +162,19 @@ public function testFilterWithNonchingValue(): void $filter->validate('some_filter', $explicitFilterDefinition, ['some_filter' => 'this is a foo '.random_int(0, 10).' and it should match']) ); } + + public function testFilterWithNonchingValueOpenApi(): void + { + $filter = new Pattern(); + + $explicitFilterDefinition = [ + 'openapi' => [ + 'pattern' => '/foo \d+/', + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $explicitFilterDefinition, ['some_filter' => 'this is a foo '.random_int(0, 10).' and it should match']) + ); + } } diff --git a/tests/Api/QueryParameterValidator/Validator/RequiredTest.php b/tests/Api/QueryParameterValidator/Validator/RequiredTest.php index 753e6cc075a..bca7b404ab1 100644 --- a/tests/Api/QueryParameterValidator/Validator/RequiredTest.php +++ b/tests/Api/QueryParameterValidator/Validator/RequiredTest.php @@ -58,6 +58,9 @@ public function testRequiredFilterIsPresent(): void ); } + /** + * @group legacy + */ public function testEmptyValueNotAllowed(): void { $request = ['some_filter' => '']; @@ -85,6 +88,36 @@ public function testEmptyValueNotAllowed(): void ); } + public function testEmptyValueNotAllowedOpenApi(): void + { + $request = ['some_filter' => '']; + $filter = new Required(); + + $explicitFilterDefinition = [ + 'required' => true, + 'openapi' => [ + 'allowEmptyValue' => false, + ], + ]; + + $this->assertEquals( + ['Query parameter "some_filter" does not allow empty value'], + $filter->validate('some_filter', $explicitFilterDefinition, $request) + ); + + $implicitFilterDefinition = [ + 'required' => true, + ]; + + $this->assertEquals( + ['Query parameter "some_filter" does not allow empty value'], + $filter->validate('some_filter', $implicitFilterDefinition, $request) + ); + } + + /** + * @group legacy + */ public function testEmptyValueAllowed(): void { $request = ['some_filter' => '']; @@ -102,6 +135,23 @@ public function testEmptyValueAllowed(): void ); } + public function testEmptyValueAllowedOpenApi(): void + { + $request = ['some_filter' => '']; + $filter = new Required(); + + $explicitFilterDefinition = [ + 'required' => true, + 'openapi' => [ + 'allowEmptyValue' => true, + ], + ]; + + $this->assertEmpty( + $filter->validate('some_filter', $explicitFilterDefinition, $request) + ); + } + public function testBracketNotation(): void { $filter = new Required();