diff --git a/Enum/ParameterExtensionEnum.php b/Enum/ParameterExtensionEnum.php index 4696db9..cc62e69 100644 --- a/Enum/ParameterExtensionEnum.php +++ b/Enum/ParameterExtensionEnum.php @@ -21,4 +21,9 @@ class ParameterExtensionEnum public const X_PARAMETER_LOCATION = 'parameter_location'; public const X_OPTION_RESOLVE = 'option_resolve'; public const X_CLASS = 'class'; + + public static function getAll(): array + { + return [self::X_PARAMETER_LOCATION, self::X_OPTION_RESOLVE, self::X_CLASS]; + } } diff --git a/Tests/AnnotationXTest.php b/Tests/AnnotationXTest.php new file mode 100644 index 0000000..b8cd61d --- /dev/null +++ b/Tests/AnnotationXTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests; + +use OpenApi\Annotations\Property; +use OpenApi\Annotations\Schema; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + +class AnnotationXTest extends KernelTestCase +{ + public function testSchemaBuilder(): void + { + $key = 'option_resolve'; + $value = 'kek'; + + $schema = $this->createSchemaDefinition($key, $value); + $x = $schema->properties[0]->x; + + self::assertEquals($x, [$key => 'kek']); + } + + private function createSchemaDefinition(string $key, string $value): Schema + { + return new Schema( + [ + 'type' => 'object', + 'required' => [], + 'properties' => [ + new Property( + [ + 'property' => 'new', + 'x' => [$key => $value], + ] + ), + ], + ] + ); + } +} diff --git a/Tests/CheckRequestSchema/CheckSchemaQueryParameterTest.php b/Tests/CheckRequestSchema/CheckSchemaQueryParameterTest.php new file mode 100644 index 0000000..189eaae --- /dev/null +++ b/Tests/CheckRequestSchema/CheckSchemaQueryParameterTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\CheckRequestSchema; + +use ArrayObject; +use Exception; +use Linkin\Bundle\SwaggerResolverBundle\Builder\OpenApiResolverBuilder; +use Linkin\Bundle\SwaggerResolverBundle\Configuration\OpenApiConfiguration; +use Linkin\Bundle\SwaggerResolverBundle\Matcher\ParameterTypeMatcher; +use Linkin\Bundle\SwaggerResolverBundle\Validator\NumberMaximumValidator; +use Linkin\Bundle\SwaggerResolverBundle\Validator\NumberMinimumValidator; +use OpenApi\Annotations\Property; +use OpenApi\Annotations\Schema; +use OpenApi\Serializer; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + +class CheckSchemaQueryParameterTest extends KernelTestCase +{ + /** + * @throws Exception + */ + public function testSchemaBuilderMissingOptions(): void + { + $fieldName = 'limitField'; + $originValue = 2000; + + $builder = new OpenApiResolverBuilder( + new ArrayObject(), + new ArrayObject([new NumberMinimumValidator(), new NumberMaximumValidator()]), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaDefinitionQueryOptions(); + $optionsResolver = $builder->build($schema); + $result = $optionsResolver->resolve(['limitField' => 2000]); + + self::assertSame($result[$fieldName], $originValue); + } + + private function createSchemaDefinitionQueryOptions(): Schema + { + return new Schema([ + 'required' => + [ + 'limitField' => 'limitField', + ], + 'title' => 'query', + 'properties' => + [ + 'search' => + new Property([ + 'type' => 'string', + 'example' => 'search', + ]), + 'hah' => + new Property([ + 'type' => 'string', + 'example' => 'cap', + ]), + 'limitField' => + new Property([ + 'type' => 'integer', + 'example' => 150, + ]), + ], + 'type' => 'object', + ]); + } +} diff --git a/Tests/DeprecatedTest.php b/Tests/DeprecatedTest.php new file mode 100644 index 0000000..94ee822 --- /dev/null +++ b/Tests/DeprecatedTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests; + +use Exception; +use Linkin\Bundle\SwaggerResolverBundle\Builder\OpenApiResolverBuilder; +use Linkin\Bundle\SwaggerResolverBundle\Configuration\OpenApiConfiguration; +use Linkin\Bundle\SwaggerResolverBundle\Matcher\ParameterTypeMatcher; +use OpenApi\Annotations\Property; +use OpenApi\Annotations\Schema; +use OpenApi\Serializer; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + +class DeprecatedTest extends KernelTestCase +{ + /** + * @throws Exception + */ + public function testSchemaBuilder(): void + { + $fieldName = 'testDeprecated'; + $fieldType = 'string'; + + $builder = new OpenApiResolverBuilder( + new \ArrayObject(), + new \ArrayObject(), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaDefinition($fieldName, $fieldType); + $optionsResolver = $builder->build($schema); + + self::assertTrue($optionsResolver->isDeprecated($fieldName)); + } + + private function createSchemaDefinition(string $fieldName, string $type): Schema + { + return new Schema( + [ + 'type' => 'object', + 'required' => [], + 'properties' => [ + new Property( + [ + 'property' => $fieldName, + 'type' => $type, + 'deprecated' => true + ] + ), + ], + ] + ); + } +} diff --git a/Tests/EnumTest/EnumParameterTest.php b/Tests/EnumTest/EnumParameterTest.php new file mode 100644 index 0000000..10218f5 --- /dev/null +++ b/Tests/EnumTest/EnumParameterTest.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\EnumTest; + +use ArrayObject; +use Linkin\Bundle\SwaggerResolverBundle\Builder\OpenApiResolverBuilder; +use Linkin\Bundle\SwaggerResolverBundle\Configuration\OpenApiConfiguration; +use Linkin\Bundle\SwaggerResolverBundle\Matcher\ParameterTypeMatcher; +use OpenApi\Annotations\Property; +use OpenApi\Annotations\Schema; +use OpenApi\Serializer; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class EnumParameterTest extends KernelTestCase +{ + public function testSchemaEnumOptions(): void + { + $fieldName = 'a'; + $fieldType = 'string'; + + $builder = new OpenApiResolverBuilder( + new ArrayObject(), + new ArrayObject(), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaDefinitionOptions($fieldName, $fieldType); + $optionsResolver = $builder->build($schema); + + $optionsResolver->resolve(['a' => 'first']); + + self::assertTrue(true); + } + + public function testSchemaWrongEnumOptions(): void + { + $fieldName = 'a'; + $fieldType = 'string'; + + $builder = new OpenApiResolverBuilder( + new ArrayObject(), + new ArrayObject(), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaDefinitionOptions($fieldName, $fieldType); + $optionsResolver = $builder->build($schema); + + $this->expectException(InvalidOptionsException::class); + $optionsResolver->resolve(['a' => 'not enum value']); + } + + private function createSchemaDefinitionOptions(string $fieldName, string $type): Schema + { + return new Schema( + [ + 'type' => 'object', + 'required' => [$fieldName], + 'properties' => [ + $fieldName => new Property( + [ + 'property' => $fieldName, + 'example' => 'first', + 'type' => $type, + 'required' => true, + 'enum' => ['first', 'second'] + ] + ), + ], + ] + ); + } +} diff --git a/Tests/EnumTest/ParameterCollectionFormatEnumTest.php b/Tests/EnumTest/ParameterCollectionFormatEnumTest.php new file mode 100644 index 0000000..c974ee5 --- /dev/null +++ b/Tests/EnumTest/ParameterCollectionFormatEnumTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\EnumTest; + +use Linkin\Bundle\SwaggerResolverBundle\Enum\ParameterCollectionFormatEnum; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +class ParameterCollectionFormatEnumTest extends TestCase +{ + public function testGetAll(): void + { + self::assertSame(ParameterCollectionFormatEnum::getAll(), [ + 'csv', + 'ssv', + 'tsv', + 'pipes', + 'multi', + ]); + } + + public function testGetDelimiter(): void + { + self::assertSame(',', ParameterCollectionFormatEnum::getDelimiter('csv')); + self::assertSame(' ', ParameterCollectionFormatEnum::getDelimiter('ssv')); + self::assertSame("\t", ParameterCollectionFormatEnum::getDelimiter('tsv')); + self::assertSame('|', ParameterCollectionFormatEnum::getDelimiter('pipes')); + self::assertSame('&', ParameterCollectionFormatEnum::getDelimiter('multi')); + } + + public function testFailGetDelimiterByUnexpectedFormat(): void + { + $this->expectException(RuntimeException::class); + ParameterCollectionFormatEnum::getDelimiter('_undefined_'); + } +} diff --git a/Tests/EnumTest/ParameterExtensionEnumTest.php b/Tests/EnumTest/ParameterExtensionEnumTest.php new file mode 100644 index 0000000..21fe689 --- /dev/null +++ b/Tests/EnumTest/ParameterExtensionEnumTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\EnumTest; + +use Linkin\Bundle\SwaggerResolverBundle\Enum\ParameterExtensionEnum; +use PHPUnit\Framework\TestCase; + +class ParameterExtensionEnumTest extends TestCase +{ + public function testGetAll(): void + { + self::assertSame(ParameterExtensionEnum::getAll(), [ + 'parameter_location', + 'option_resolve', + 'class', + ]); + } +} diff --git a/Tests/EnumTest/ParameterLocationEnumTest.php b/Tests/EnumTest/ParameterLocationEnumTest.php new file mode 100644 index 0000000..1db5f97 --- /dev/null +++ b/Tests/EnumTest/ParameterLocationEnumTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\EnumTest; + +use Linkin\Bundle\SwaggerResolverBundle\Enum\ParameterLocationEnum; +use PHPUnit\Framework\TestCase; + +class ParameterLocationEnumTest extends TestCase +{ + public function testGetAll(): void + { + self::assertSame(ParameterLocationEnum::getAll(), [ + 'body', + 'formData', + 'header', + 'path', + 'query', + ]); + } +} \ No newline at end of file diff --git a/Tests/EnumTest/ParameterTypeEnumTest.php b/Tests/EnumTest/ParameterTypeEnumTest.php new file mode 100644 index 0000000..c6ae03c --- /dev/null +++ b/Tests/EnumTest/ParameterTypeEnumTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\EnumTest; + +use Linkin\Bundle\SwaggerResolverBundle\Enum\ParameterTypeEnum; +use PHPUnit\Framework\TestCase; + +class ParameterTypeEnumTest extends TestCase +{ + public function testGetAll(): void + { + self::assertSame(ParameterTypeEnum::getAll(), [ + 'array', + 'boolean', + 'file', + 'integer', + 'number', + 'string', + ]); + } +} diff --git a/Tests/MockDto/DockBlockTestDto.php b/Tests/MockDto/DockBlockTestDto.php new file mode 100644 index 0000000..58b6ba4 --- /dev/null +++ b/Tests/MockDto/DockBlockTestDto.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests; + +use Exception; +use Linkin\Bundle\SwaggerResolverBundle\Builder\OpenApiResolverBuilder; +use Linkin\Bundle\SwaggerResolverBundle\Configuration\OpenApiConfiguration; +use Linkin\Bundle\SwaggerResolverBundle\Matcher\ParameterTypeMatcher; +use OpenApi\Annotations\Property; +use OpenApi\Annotations\Schema; +use OpenApi\Serializer; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; + +class OptionResolverExceptionTest extends KernelTestCase +{ + public function testSchemaBuilderMissingOptions(): void + { + $fieldName = 'testString'; + $fieldType = 'string'; + $originValue = 'test'; + + $builder = new OpenApiResolverBuilder( + new \ArrayObject(), + new \ArrayObject(), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaDefinitionOptions($fieldName, $fieldType); + $optionsResolver = $builder->build($schema); + + $this->expectException(MissingOptionsException::class); + $result = $optionsResolver->resolve([]); + + self::assertSame($result[$fieldName], $originValue); + } + + /** + * @throws Exception + */ + public function testSchemaBuilderUndefinedOption(): void + { + $fieldName = 'a'; + $fieldType = 'string'; + + $builder = new OpenApiResolverBuilder( + new \ArrayObject(), + new \ArrayObject(), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaInvalidOption($fieldName, $fieldType); + $optionsResolver = $builder->build($schema); + + $this->expectException(InvalidOptionsException::class); + $optionsResolver->resolve(['a' => 123]); + } + + private function createSchemaDefinitionOptions(string $fieldName, string $type): Schema + { + return new Schema( + [ + 'type' => 'object', + 'required' => [$fieldName], + 'properties' => [ + new Property( + [ + 'property' => $fieldName, + 'type' => $type, + 'required' => true + ] + ), + ], + ] + ); + } + + private function createSchemaInvalidOption(string $fieldName, string $type): Schema + { + return new Schema( + [ + 'type' => 'object', + 'required' => [$fieldName], + 'properties' => [ + $fieldName => new Property( + [ + 'example' => 'primer', + 'property' => $fieldName, + 'type' => $type, + 'required' => true + ] + ), + ], + ] + ); + } +} diff --git a/Tests/RequiredTest.php b/Tests/RequiredTest.php new file mode 100644 index 0000000..06dcc71 --- /dev/null +++ b/Tests/RequiredTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests; + +use Linkin\Bundle\SwaggerResolverBundle\Builder\OpenApiResolverBuilder; +use Linkin\Bundle\SwaggerResolverBundle\Configuration\OpenApiConfiguration; +use Linkin\Bundle\SwaggerResolverBundle\Matcher\ParameterTypeMatcher; +use OpenApi\Annotations\Property; +use OpenApi\Annotations\Schema; +use OpenApi\Serializer; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class RequiredTest extends KernelTestCase +{ + public function testSchemaBuilder(): void + { + $fieldName = 'testString'; + $fieldType = 'string'; + + $builder = new OpenApiResolverBuilder( + new \ArrayObject(), + new \ArrayObject(), + [], + $this->createMock(OpenApiConfiguration::class), + new ParameterTypeMatcher(), + new Serializer() + ); + + $schema = $this->createSchemaDefinition($fieldName, $fieldType); + $optionsResolver = $builder->build($schema); + + $this->expectException(InvalidOptionsException::class); + $optionsResolver->resolve([$fieldName => null]); + + self::assertTrue($optionsResolver->isDeprecated($fieldName)); + } + + private function createSchemaDefinition(string $fieldName, string $type): Schema + { + return new Schema( + [ + 'type' => 'object', + 'required' => [$fieldName], + 'properties' => [ + new Property( + [ + 'property' => $fieldName, + 'type' => $type, + 'required' => true + ] + ), + ], + ] + ); + } +} diff --git a/Tests/ValidatorTest/ArrayMaxItemsValidatorTest.php b/Tests/ValidatorTest/ArrayMaxItemsValidatorTest.php new file mode 100644 index 0000000..0c16d69 --- /dev/null +++ b/Tests/ValidatorTest/ArrayMaxItemsValidatorTest.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\ArrayMaxItemsValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class ArrayMaxItemsValidatorTest extends KernelTestCase +{ + private const TYPE_ARRAY = 'array'; + private const COLLECTION_FORMAT_CSV = 'csv'; + private const COLLECTION_FORMAT_MULTI = 'multi'; + + private ArrayMaxItemsValidator $validator; + + protected function setUp(): void + { + $this->validator = new ArrayMaxItemsValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $format, ?int $maxItems, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format, $maxItems); + $isSupported = $this->validator->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'type' => '_invalid_format_', + 'maxItems' => 3, + 'expectedResult' => false, + ], + 'Success when maxItems was not set' => [ + 'type' => self::TYPE_ARRAY, + 'maxItems' => null, + 'expectedResult' => true, + ], + 'Success with right format' => [ + 'type' => self::TYPE_ARRAY, + 'maxItems' => 3, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(?string $collectionFormat, int $maxItems, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($collectionFormat, $maxItems); + + $this->expectException(InvalidOptionsException::class); + + $this->validator->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when null collectionFormat and received array as string' => [ + 'collectionFormat' => null, + 'maxItems' => 3, + 'value' => 'monday,tuesday,wednesday', + ], + 'Fail when set collectionFormat and received plain array' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'maxItems' => 3, + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Fail when unexpected delimiter' => [ + 'collectionFormat' => '__delimiter__', + 'maxItems' => 3, + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Fail when items greater than maximal count' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_MULTI, + 'maxItems' => 3, + 'value' => 'days=monday&days=tuesday&days=wednesday&days=thursday', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(?string $collectionFormat, int $maxItems, mixed $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($collectionFormat, $maxItems); + + $this->validator->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when CSV collectionFormat' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'maxItems' => 3, + 'value' => 'monday,tuesday,wednesday', + ], + 'Pass when valid multi format and equal to maximal count' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_MULTI, + 'maxItems' => 3, + 'value' => 'days=monday&days=tuesday&days=wednesday', + ], + ]; + } + + private function createSchemaDefinition(string $format, ?int $maxItems): Property + { + return new Property( + [ + 'type' => $format, + 'maxItems' => $maxItems, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(?string $collectionFormat, int $maxItems): Property + { + return new Property( + [ + 'type' => self::TYPE_ARRAY, + 'maxItems' => $maxItems, + 'collectionFormat' => $collectionFormat, + ] + ); + } +} diff --git a/Tests/ValidatorTest/ArrayMinItemsValidatorTest.php b/Tests/ValidatorTest/ArrayMinItemsValidatorTest.php new file mode 100644 index 0000000..f2cc3bc --- /dev/null +++ b/Tests/ValidatorTest/ArrayMinItemsValidatorTest.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\ArrayMinItemsValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class ArrayMinItemsValidatorTest extends KernelTestCase +{ + private const TYPE_ARRAY = 'array'; + private const COLLECTION_FORMAT_CSV = 'csv'; + private const COLLECTION_FORMAT_MULTI = 'multi'; + + private ArrayMinItemsValidator $validator; + + protected function setUp(): void + { + $this->validator = new ArrayMinItemsValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSupport(string $format, ?int $minItems, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format, $minItems); + $isSupported = $this->validator->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'type' => '_invalid_format_', + 'minItems' => 3, + 'expectedResult' => false, + ], + 'Success when maxItems was not set' => [ + 'type' => self::TYPE_ARRAY, + 'minItems' => null, + 'expectedResult' => true, + ], + 'Success with right format' => [ + 'type' => self::TYPE_ARRAY, + 'minItems' => 3, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(?string $collectionFormat, int $minItems, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($collectionFormat, $minItems); + + $this->expectException(InvalidOptionsException::class); + + $this->validator->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when null collectionFormat and received array as string' => [ + 'collectionFormat' => null, + 'minItems' => 3, + 'value' => 'monday,tuesday,wednesday', + ], + 'Fail when set collectionFormat and received plain array' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'minItems' => 3, + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Fail when unexpected delimiter' => [ + 'collectionFormat' => '__delimiter__', + 'minItems' => 3, + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Fail when items lower than maximal count' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_MULTI, + 'minItems' => 3, + 'value' => 'days=monday', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(?string $collectionFormat, int $minItems, mixed $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($collectionFormat, $minItems); + + $this->validator->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when CSV collectionFormat' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'minItems' => 3, + 'value' => 'monday,tuesday,wednesday', + ], + 'Pass when valid multi format and equal to maximal count' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_MULTI, + 'minItems' => 3, + 'value' => 'days=monday&days=tuesday&days=wednesday', + ], + ]; + } + + private function createSchemaDefinition(string $format, ?int $minItems): Property + { + return new Property( + [ + 'type' => $format, + 'minItems' => $minItems, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(?string $collectionFormat, int $minItems): Property + { + return new Property( + [ + 'property' => 'example', + 'type' => self::TYPE_ARRAY, + 'minItems' => $minItems, + 'collectionFormat' => $collectionFormat, + ] + ); + } +} diff --git a/Tests/ValidatorTest/ArrayUniqueItemsValidatorTest.php b/Tests/ValidatorTest/ArrayUniqueItemsValidatorTest.php new file mode 100644 index 0000000..75a573b --- /dev/null +++ b/Tests/ValidatorTest/ArrayUniqueItemsValidatorTest.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\ArrayUniqueItemsValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class ArrayUniqueItemsValidatorTest extends KernelTestCase +{ + private const TYPE_ARRAY = 'array'; + private const COLLECTION_FORMAT_CSV = 'csv'; + private const COLLECTION_FORMAT_MULTI = 'multi'; + + + /** + * @var ArrayUniqueItemsValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new ArrayUniqueItemsValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $format, ?bool $hasUniqueItems, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format, $hasUniqueItems); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'type' => '_invalid_format_', + 'hasUniqueItems' => true, + 'expectedResult' => false, + ], + 'Fail when unique items was not set' => [ + 'type' => self::TYPE_ARRAY, + 'hasUniqueItems' => false, + 'expectedResult' => false, + ], + 'Success with right format' => [ + 'type' => self::TYPE_ARRAY, + 'hasUniqueItems' => true, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(?string $collectionFormat, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($collectionFormat); + + $this->expectException(InvalidOptionsException::class); + + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when null collectionFormat and received array as string' => [ + 'collectionFormat' => null, + 'value' => 'monday,tuesday,wednesday', + ], + 'Fail when set collectionFormat and received plain array' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Fail when unexpected delimiter' => [ + 'collectionFormat' => '__delimiter__', + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Fail when not unique values in array' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_MULTI, + 'value' => 'days=monday&days=tuesday&days=wednesday&days=monday', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(?string $collectionFormat, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($collectionFormat); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when null value' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'value' => null, + ], + 'Pass when null collectionFormat and received plain array' => [ + 'collectionFormat' => null, + 'value' => ['monday', 'tuesday', 'wednesday'], + ], + 'Pass when CSV collectionFormat' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_CSV, + 'value' => 'monday,tuesday,wednesday', + ], + 'Pass when valid multi format with unique items' => [ + 'collectionFormat' => self::COLLECTION_FORMAT_MULTI, + 'value' => 'days=monday&days=tuesday&days=wednesday', + ], + ]; + } + + private function createSchemaDefinition(string $format, ?bool $hasUniqueItems): Property + { + return new Property( + [ + 'type' => $format, + 'uniqueItems' => $hasUniqueItems, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(?string $collectionFormat): Property + { + return new Property( + [ + 'type' => self::TYPE_ARRAY, + 'uniqueItems' => true, + 'collectionFormat' => $collectionFormat, + ] + ); + } +} diff --git a/Tests/ValidatorTest/FormatDateTimeValidatorTest.php b/Tests/ValidatorTest/FormatDateTimeValidatorTest.php new file mode 100644 index 0000000..d8f4aec --- /dev/null +++ b/Tests/ValidatorTest/FormatDateTimeValidatorTest.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\FormatDateTimeValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class FormatDateTimeValidatorTest extends KernelTestCase +{ + private const FORMAT_DATETIME = 'datetime'; + + /** + * @var FormatDateTimeValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new FormatDateTimeValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $format, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'format' => '_invalid_format_', + 'expectedResult' => false, + ], + 'Success with right format' => [ + 'type' => self::FORMAT_DATETIME, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when true value' => [true], + 'Fail when incorrect month pattern - number' => ['2022-571-01 10:00:01'], + 'Fail when incorrect day pattern - number' => ['2022-07-011 10:00:01'], + 'Fail when incorrect year pattern - number' => ['20220-07-011 10:00:01'], + 'Fail when incorrect hour pattern - number' => ['2022-07-01 1011:00:01'], + 'Fail when incorrect minutes pattern - number' => ['2022-07-01 10:0012:01'], + 'Fail when incorrect second pattern - number' => ['2022-07-01 10:00:90'], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when null value' => [null], + 'Pass when empty string value' => [''], + 'Pass when value with UTC' => ['1985-06-04T23:20:50Z'], + 'Pass when value with offset' => ['1955-06-04T16:39:57-08:00'], + 'Pass when value with UTC and leap second' => ['1990-06-04T23:59:60Z'], + 'Pass when value with offset and leap second' => ['1990-06-04T15:59:60-08:00'], + 'Pass when value with Netherlands time' => ['1930-06-04T12:00:27+03:00'], + ]; + } + + private function createSchemaDefinition(string $format): Property + { + return new Property( + [ + 'format' => $format, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(): Property + { + return new Property( + [ + 'format' => self::FORMAT_DATETIME, + ] + ); + } +} diff --git a/Tests/ValidatorTest/FormatDateValidatorTest.php b/Tests/ValidatorTest/FormatDateValidatorTest.php new file mode 100644 index 0000000..f9b1c1d --- /dev/null +++ b/Tests/ValidatorTest/FormatDateValidatorTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\FormatDateValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class FormatDateValidatorTest extends KernelTestCase +{ + private const FORMAT_DATE = 'date'; + + /** + * @var FormatDateValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new FormatDateValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $format, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'format' => '_invalid_format_', + 'expectedResult' => false, + ], + 'Success with right format' => [ + 'type' => self::FORMAT_DATE, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when true value' => [true], + 'Fail when value with incorrect datetime' => ['100'], + 'Fail when value with incorrect datetime - year' => ['01-01'], + 'Fail when value with incorrect datetime - month' => ['2019-13-01'], + 'Fail when value with incorrect datetime - day' => ['2019-01-32'], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when null value' => [null], + 'Pass when empty string value' => [''], + 'Pass when value with correct date pattern' => ['2022-01-01'], + 'Pass when value with correct date pattern - february' => ['2029-02-28'], + 'Pass when value with correct date pattern - february+' => ['2020-02-29'], + ]; + } + + private function createSchemaDefinition(string $format): Property + { + return new Property( + [ + 'format' => $format, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(): Property + { + return new Property( + [ + 'format' => self::FORMAT_DATE, + ] + ); + } +} diff --git a/Tests/ValidatorTest/FormatTimeValidatorTest.php b/Tests/ValidatorTest/FormatTimeValidatorTest.php new file mode 100644 index 0000000..b1f76b7 --- /dev/null +++ b/Tests/ValidatorTest/FormatTimeValidatorTest.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\FormatTimeValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class FormatTimeValidatorTest extends KernelTestCase +{ + private const FORMAT_TIME = 'time'; + + /** + * @var FormatTimeValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new FormatTimeValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $format, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'format' => '_invalid_format_', + 'expectedResult' => false, + ], + 'Success with right format' => [ + 'type' => self::FORMAT_TIME, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when true value' => [true], + 'Fail when value with incorrect format - number' => ['100'], + 'Fail when value with incorrect format - more than 2 digit' => ['100:05:55'], + 'Fail when value with incorrect hours' => ['30:00:00'], + 'Fail when value with incorrect minutes' => ['23:60:00'], + 'Fail when value with incorrect seconds' => ['23:59:61'], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when null value' => [null], + 'Pass when empty string value' => [''], + 'Pass when value with correct time' => ['01:02:03'], + 'Pass when value with correct time min' => ['00:00:00'], + 'Pass when value with correct time max' => ['23:59:59'], + ]; + } + + private function createSchemaDefinition(string $format): Property + { + return new Property( + [ + 'format' => $format, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(): Property + { + return new Property( + [ + 'format' => self::FORMAT_TIME, + ] + ); + } +} diff --git a/Tests/ValidatorTest/FormatTimestampValidatorTest.php b/Tests/ValidatorTest/FormatTimestampValidatorTest.php new file mode 100644 index 0000000..347e81f --- /dev/null +++ b/Tests/ValidatorTest/FormatTimestampValidatorTest.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\FormatTimestampValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class FormatTimestampValidatorTest extends KernelTestCase +{ + private const FORMAT_TIMESTAMP = 'timestamp'; + + /** + * @var FormatTimestampValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new FormatTimestampValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $format, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($format); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported format' => [ + 'format' => '_invalid_format_', + 'expectedResult' => false, + ], + 'Success with right format' => [ + 'type' => self::FORMAT_TIMESTAMP, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail when timestamp is not numeric' => ['2020-10-10 10:00:00'], + 'Fail when true value' => [true], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation($value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation(); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass when null value' => [null], + 'Pass when true value' => [false], + 'Pass when empty string value' => [''], + 'Pass when empty zero value' => ['0'], + 'Pass when value with correct timestamp' => ['1629620000'], + ]; + } + + private function createSchemaDefinition(string $format): Property + { + return new Property( + [ + 'format' => $format, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(): Property + { + return new Property( + [ + 'format' => self::FORMAT_TIMESTAMP, + ] + ); + } +} diff --git a/Tests/ValidatorTest/NumberMaximumValidatorTest.php b/Tests/ValidatorTest/NumberMaximumValidatorTest.php new file mode 100644 index 0000000..df752b8 --- /dev/null +++ b/Tests/ValidatorTest/NumberMaximumValidatorTest.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\NumberMaximumValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class NumberMaximumValidatorTest extends KernelTestCase +{ + private const TYPE_NUMBER = 'number'; + private const TYPE_INT = 'integer'; + + /** + * @var NumberMaximumValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new NumberMaximumValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $type, $maximum, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($type, $maximum); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported type' => [ + 'type' => '_invalid_type_', + 'maximum' => 100, + 'expectedResult' => false, + ], + 'Success with int' => [ + 'type' => self::TYPE_INT, + 'maximum' => 100, + 'expectedResult' => true, + ], + 'Success with float' => [ + 'type' => self::TYPE_NUMBER, + 'maximum' => 10.99, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(bool $isExclusiveMaximum, $maximum, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($isExclusiveMaximum, $maximum); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail with maximal int value and exclusive mode' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 10, + 'value' => 10, + ], + 'Fail with int more than maximal value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => 10, + 'value' => 11, + ], + 'Fail with negative maximal int value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => -10, + 'value' => -9, + ], + 'Fail with int value as string' => [ + 'isExclusiveMaximum' => false, + 'maximum' => -10, + 'value' => '-9', + ], + 'Fail with maximal float value and exclusive mode' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 10.01, + 'value' => 10.01, + ], + 'Fail with float more than maximal value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => 10.1, + 'value' => 10.1001, + ], + 'Fail with negative maximal float value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => -10.1, + 'value' => -10.09, + ], + 'Fail with float value as string' => [ + 'isExclusiveMaximum' => false, + 'maximum' => -10.1, + 'value' => '-10.09', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(bool $isExclusiveMaximum, $maximum, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($isExclusiveMaximum, $maximum); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass validation null value' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 10, + 'value' => null, + ], + 'Pass validation with lower than maximal int value and exclusive mode' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 10, + 'value' => 9, + ], + 'Pass validation with equal to maximal int value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => 10, + 'value' => 10, + ], + 'Pass validation with negative maximal int value and exclusive mode' => [ + 'isExclusiveMaximum' => true, + 'maximum' => -10, + 'value' => -11, + ], + 'Pass validation with negative maximal int value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => -10, + 'value' => -10, + ], + 'Pass validation with int value as string' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 0, + 'value' => '-10', + ], + 'Pass validation with lower than maximal float value and exclusive mode' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 10.002, + 'value' => 10.001, + ], + 'Pass validation with equal to maximal float value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => 10.002, + 'value' => 10.002, + ], + 'Pass validation with negative maximal float value and exclusive mode' => [ + 'isExclusiveMaximum' => true, + 'maximum' => -1.0001, + 'value' => -1.0002, + ], + 'Pass validation with negative maximal float value' => [ + 'isExclusiveMaximum' => false, + 'maximum' => -1.0002, + 'value' => -1.0002, + ], + 'Pass validation with float value as string' => [ + 'isExclusiveMaximum' => true, + 'maximum' => 0, + 'value' => '-0.001', + ], + ]; + } + + private function createSchemaDefinition(string $type, $maximum): Property + { + return new Property( + [ + 'type' => $type, + 'maximum' => $maximum, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(bool $isExclusiveMaximum, $maximum): Property + { + return new Property( + [ + 'type' => self::TYPE_INT, + 'maximum' => $maximum, + 'exclusiveMaximum' => $isExclusiveMaximum, + ] + ); + } +} diff --git a/Tests/ValidatorTest/NumberMinimumValidatorTest.php b/Tests/ValidatorTest/NumberMinimumValidatorTest.php new file mode 100644 index 0000000..b870e0b --- /dev/null +++ b/Tests/ValidatorTest/NumberMinimumValidatorTest.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\NumberMinimumValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class NumberMinimumValidatorTest extends KernelTestCase +{ + private const TYPE_NUMBER = 'number'; + private const TYPE_INT = 'integer'; + + /** + * @var NumberMinimumValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new NumberMinimumValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $type, $minimum, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($type, $minimum); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported type' => [ + 'type' => '_invalid_type_', + 'minimum' => 100, + 'expectedResult' => false, + ], + 'Success with int' => [ + 'type' => self::TYPE_INT, + 'minimum' => 90, + 'expectedResult' => true, + ], + 'Success with float' => [ + 'type' => self::TYPE_NUMBER, + 'minimum' => 10.08, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(bool $isExclusiveMinimum, $minimum, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($isExclusiveMinimum, $minimum); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail with minimal int value and exclusive mode' => [ + 'isExclusiveMinimum' => true, + 'minimum' => 10, + 'value' => 10, + ], + 'Fail with int lower than minimal value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => 10, + 'value' => 9, + ], + 'Fail with negative minimal int value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => -10, + 'value' => -11, + ], + 'Fail with int value as string' => [ + 'isExclusiveMinimum' => false, + 'minimum' => -10, + 'value' => '-11', + ], + 'Fail with minimal float value and exclusive mode' => [ + 'isExclusiveMinimum' => true, + 'minimum' => 10.01, + 'value' => 10.01, + ], + 'Fail with float lower than minimal value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => 10.1, + 'value' => 10.0009, + ], + 'Fail with negative minimal float value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => -10.1, + 'value' => -10.11, + ], + 'Fail with float value as string' => [ + 'isExclusiveMinimum' => false, + 'minimum' => -10.1, + 'value' => '-10.11', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(bool $isExclusiveMinimum, $minimum, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($isExclusiveMinimum, $minimum); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass validation null value' => [ + 'isExclusiveMinimum' => true, + 'minimum' => 10, + 'value' => null, + ], + 'Pass validation with not numeric value' => [ + 'isExclusiveMinimum' => true, + 'minimum' => 10, + 'value' => 'some-string', + ], + 'Pass validation with greater than minimal int value and exclusive mode' => [ + 'isExclusiveMinimum' => true, + 'minimum' => 10, + 'value' => 11, + ], + 'Pass validation with equal to minimal int value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => 10, + 'value' => 10, + ], + 'Pass validation with negative minimal int value and exclusive mode' => [ + 'isExclusiveMinimum' => true, + 'minimum' => -10, + 'value' => -9, + ], + 'Pass validation with negative minimal int value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => -10, + 'value' => -10, + ], + 'Pass validation with int value as string' => [ + 'isExclusiveMinimum' => true, + 'minimum' => -10, + 'value' => '-9', + ], + 'Pass validation with greater than minimal float value and exclusive mode' => [ + 'isExclusiveMinimum' => true, + 'minimum' => 10.002, + 'value' => 10.0021, + ], + 'Pass validation with equal to minimal float value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => 10.002, + 'value' => 10.002, + ], + 'Pass validation with negative minimal float value and exclusive mode' => [ + 'isExclusiveMinimum' => true, + 'minimum' => -1.1, + 'value' => -1.0, + ], + 'Pass validation with negative minimal float value' => [ + 'isExclusiveMinimum' => false, + 'minimum' => -1.0002, + 'value' => -1.0002, + ], + 'Pass validation with float value as string' => [ + 'isExclusiveMinimum' => true, + 'minimum' => -1, + 'value' => '-0.999', + ], + ]; + } + + private function createSchemaDefinition(string $type, $minimum): Property + { + return new Property( + [ + 'type' => $type, + 'minimum' => $minimum, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation(bool $isExclusiveMinimum, $minimum): Property + { + return new Property( + [ + 'type' => self::TYPE_INT, + 'minimum' => $minimum, + 'exclusiveMinimum' => $isExclusiveMinimum, + ] + ); + } +} diff --git a/Tests/ValidatorTest/NumberMultipleOfValidatorTest.php b/Tests/ValidatorTest/NumberMultipleOfValidatorTest.php new file mode 100644 index 0000000..2c2cca1 --- /dev/null +++ b/Tests/ValidatorTest/NumberMultipleOfValidatorTest.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\NumberMultipleOfValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class NumberMultipleOfValidatorTest extends KernelTestCase +{ + private const TYPE_NUMBER = 'number'; + private const TYPE_INT = 'integer'; + + /** + * @var NumberMultipleOfValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new NumberMultipleOfValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $type, $multipleOf, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($type, $multipleOf); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported type' => [ + 'type' => '_invalid_type_', + 'multipleOf' => 3, + 'expectedResult' => false, + ], + 'Success with int' => [ + 'type' => self::TYPE_INT, + 'multipleOf' => 3, + 'expectedResult' => true, + ], + 'Success with float' => [ + 'type' => self::TYPE_NUMBER, + 'multipleOf' => 3.7, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation($multipleOf, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($multipleOf); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail with not multiple of int value' => [ + 'multipleOf' => 13, + 'value' => 9, + ], + 'Fail with not multiple of int negative value' => [ + 'multipleOf' => 13, + 'value' => -9, + ], + 'Fail with int value as string' => [ + 'multipleOf' => 13, + 'value' => '-9', + ], + 'Fail with not multiple of float value' => [ + 'multipleOf' => 13.3, + 'value' => 9.3, + ], + 'Fail with not multiple of float negative value' => [ + 'multipleOf' => 13.3, + 'value' => -9.3, + ], + 'Fail with float value as string' => [ + 'multipleOf' => 13.3, + 'value' => '-9.3', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation($multipleOf, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($multipleOf); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass validation null value' => [ + 'multipleOf' => 13, + 'value' => null, + ], + 'Pass validation with multiple of int value' => [ + 'multipleOf' => 13, + 'value' => 26, + ], + 'Pass validation with multiple of int negative value' => [ + 'multipleOf' => 13, + 'value' => -26, + ], + 'Pass validation with int value as string' => [ + 'multipleOf' => 13, + 'value' => '-26', + ], + ]; + } + + private function createSchemaDefinition(string $type, $multipleOf): Property + { + return new Property( + [ + 'type' => $type, + 'multipleOf' => $multipleOf, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation($multipleOf): Property + { + return new Property( + [ + 'type' => self::TYPE_INT, + 'multipleOf' => $multipleOf, + ] + ); + } +} diff --git a/Tests/ValidatorTest/StringMaxLengthValidatorTest.php b/Tests/ValidatorTest/StringMaxLengthValidatorTest.php new file mode 100644 index 0000000..09baeaa --- /dev/null +++ b/Tests/ValidatorTest/StringMaxLengthValidatorTest.php @@ -0,0 +1,153 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\StringMaxLengthValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +use function str_repeat; + +class StringMaxLengthValidatorTest extends KernelTestCase +{ + private const TYPE = 'string'; + + /** + * @var StringMaxLengthValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new StringMaxLengthValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $type, ?int $maxLength, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($type, $maxLength); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported type' => [ + 'type' => '_invalid_type_', + 'maxLength' => 100, + 'expectedResult' => false, + ], + 'Success' => [ + 'type' => self::TYPE, + 'maxLength' => 100, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(int $maxLength, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($maxLength); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail with string equal to allowed' => [ + 'maxLength' => 3, + 'value' => '13678', + ], + 'Fail with latin string greater than allowed' => [ + 'maxLength' => 10, + 'value' => str_repeat('w', 11), + ], + 'Fail with cyrillic string greater than allowed' => [ + 'maxLength' => 10, + 'value' => str_repeat('я', 11), + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(int $maxLength, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($maxLength); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass with null value' => [ + 'maxLength' => 1, + 'value' => null, + ], + 'Pass with float equal to allowed' => [ + 'maxLength' => 4, + 'value' => '1.11', + ], + 'Pass validation with latin string equal to allowed' => [ + 'maxLength' => 10, + 'value' => str_repeat('w', 10), + ], + 'Pass validation with cyrillic string equal to allowed' => [ + 'maxLength' => 10, + 'value' => str_repeat('я', 10), + ], + 'Pass validation with latin string' => [ + 'maxLength' => 10, + 'value' => str_repeat('w', 9), + ], + 'Pass validation with cyrillic string' => [ + 'maxLength' => 10, + 'value' => str_repeat('я', 9), + ], + ]; + } + + private function createSchemaDefinition(string $type, ?int $maxLength): Property + { + return new Property( + [ + 'type' => $type, + 'maxLength' => $maxLength, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation($maxLength): Property + { + return new Property( + [ + 'type' => self::TYPE, + 'maxLength' => $maxLength, + ] + ); + } +} diff --git a/Tests/ValidatorTest/StringMinLengthValidatorTest.php b/Tests/ValidatorTest/StringMinLengthValidatorTest.php new file mode 100644 index 0000000..d4ddeca --- /dev/null +++ b/Tests/ValidatorTest/StringMinLengthValidatorTest.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\StringMinLengthValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +use function str_repeat; + +class StringMinLengthValidatorTest extends KernelTestCase +{ + private const TYPE = 'string'; + + /** + * @var StringMinLengthValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new StringMinLengthValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $type, ?int $minLength, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($type, $minLength); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported type' => [ + 'type' => '_invalid_type_', + 'minLength' => 90, + 'expectedResult' => false, + ], + 'Success' => [ + 'type' => self::TYPE, + 'minLength' => 90, + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(int $minLength, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($minLength); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'F ail with latin string lower than allowed' => [ + 'minLength' => 5, + 'value' => str_repeat('w', 4), + ], + 'Fail with cyrillic string lower than allowed' => [ + 'minLength' => 5, + 'value' => str_repeat('я', 4), + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(int $maxLength, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailToPassValidation($maxLength); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass validation with null' => [ + 'maxLength' => 1, + 'value' => null, + ], + 'Pass with string equal to allowed' => [ + 'maxLength' => 3, + 'value' => '110', + ], + 'Pass validation with latin string equal to allowed' => [ + 'minLength' => 10, + 'value' => str_repeat('w', 10), + ], + 'Pass validation with cyrillic string equal to allowed' => [ + 'minLength' => 10, + 'value' => str_repeat('я', 10), + ], + 'Pass validation with latin string' => [ + 'minLength' => 10, + 'value' => str_repeat('w', 11), + ], + 'Pass validation with cyrillic string' => [ + 'minLength' => 10, + 'value' => str_repeat('я', 11), + ], + ]; + } + + private function createSchemaDefinition(string $type, ?int $minLength): Property + { + return new Property( + [ + 'type' => $type, + 'minLength' => $minLength, + ] + ); + } + + private function createSchemaDefinitionFailToPassValidation($minLength): Property + { + return new Property( + [ + 'type' => self::TYPE, + 'minLength' => $minLength, + ] + ); + } +} diff --git a/Tests/ValidatorTest/StringPatternValidatorTest.php b/Tests/ValidatorTest/StringPatternValidatorTest.php new file mode 100644 index 0000000..1d22e7d --- /dev/null +++ b/Tests/ValidatorTest/StringPatternValidatorTest.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Linkin\Bundle\SwaggerResolverBundle\Tests\ValidatorTest; + +use Linkin\Bundle\SwaggerResolverBundle\Validator\StringPatternValidator; +use OpenApi\Annotations\Property; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; + +class StringPatternValidatorTest extends KernelTestCase +{ + private const TYPE = 'string'; + + /** + * @var StringPatternValidator + */ + private $sut; + + protected function setUp(): void + { + $this->sut = new StringPatternValidator(); + } + + /** + * @dataProvider supportsDataProvider + */ + public function testSchemaBuilder(string $type, ?string $pattern, bool $expectedResult): void + { + $schema = $this->createSchemaDefinition($type, $pattern); + $isSupported = $this->sut->supports($schema); + + self::assertSame($isSupported, $expectedResult); + } + + public function supportsDataProvider(): array + { + return [ + 'Fail with unsupported type' => [ + 'type' => '_invalid_type_', + 'pattern' => '\d', + 'expectedResult' => false, + ], + 'Success' => [ + 'type' => self::TYPE, + 'pattern' => '\d', + 'expectedResult' => true, + ], + ]; + } + + /** + * @dataProvider failToPassValidationDataProvider + */ + public function testFailToPassValidation(string $pattern, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailAndPassValidation($pattern); + + $this->expectException(InvalidOptionsException::class); + $this->sut->validate($schemaProperty, $value); + } + + public function failToPassValidationDataProvider(): array + { + return [ + 'Fail with string not match pattern' => [ + 'pattern' => '^[\d]+\.[\d]+\.[\d]+$', + 'value' => '1-2-3', + ], + ]; + } + + /** + * @dataProvider canPassValidationDataProvider + */ + public function testCanPassValidation(string $pattern, $value): void + { + $schemaProperty = $this->createSchemaDefinitionFailAndPassValidation($pattern); + + $this->sut->validate($schemaProperty, $value); + self::assertTrue(true); + } + + public function canPassValidationDataProvider(): array + { + return [ + 'Pass validation with null' => [ + 'pattern' => '^[\d]+$', + 'value' => null, + ], + 'Pass validation with string' => [ + 'pattern' => '^[\d]+\.[\d]+\.[\d]+$', + 'value' => '1.2.3', + ], + 'Pass validation with string wrapped in backslashes' => [ + 'pattern' => '/^[\d]+\.[\d]+\.[\d]+$/', + 'value' => '1.2.3', + ], + 'Pass validation with specific symbols' => [ + 'pattern' => '/.*\:\/\/.*/', + 'value' => 'https://some string', + ], + ]; + } + + private function createSchemaDefinition(string $type, ?string $pattern): Property + { + return new Property( + [ + 'type' => $type, + 'pattern' => $pattern, + ] + ); + } + + private function createSchemaDefinitionFailAndPassValidation($pattern): Property + { + return new Property( + [ + 'type' => self::TYPE, + 'pattern' => $pattern, + ] + ); + } +}