diff --git a/src/Rfc4122/Validator.php b/src/Rfc4122/Validator.php new file mode 100644 index 00000000..2df2c68b --- /dev/null +++ b/src/Rfc4122/Validator.php @@ -0,0 +1,40 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\Validator\ValidatorInterface; + +/** + * Rfc4122\Validator validates strings as UUIDs of the RFC 4122 variant + */ +class Validator implements ValidatorInterface +{ + /** + * Regular expression pattern for matching an RFC 4122 UUID + */ + public const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-' + . '[1-5]{1}[0-9A-Fa-f]{3}-[ABab89]{1}[0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$'; + + /** + * @psalm-pure + */ + public function validate(string $uuid): bool + { + $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); + + return $uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/D', $uuid); + } +} diff --git a/tests/Rfc4122/ValidatorTest.php b/tests/Rfc4122/ValidatorTest.php new file mode 100644 index 00000000..54c943e7 --- /dev/null +++ b/tests/Rfc4122/ValidatorTest.php @@ -0,0 +1,76 @@ +assertSame($expected, $validator->validate($variation)); + } + } + + /** + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification + */ + public function provideValuesForValidation(): array + { + $hexMutations = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f']; + $trueVersions = [1, 2, 3, 4, 5]; + $trueVariants = [8, 9, 'a', 'b']; + + $testValues = []; + + foreach ($hexMutations as $version) { + foreach ($hexMutations as $variant) { + $testValues[] = [ + 'value' => "ff6f8cb0-c57d-{$version}1e1-{$variant}b21-0800200c9a66", + 'expected' => in_array($variant, $trueVariants, true) && in_array($version, $trueVersions, true), + ]; + } + } + + return array_merge($testValues, [ + [ + 'value' => 'zf6f8cb0-c57d-11e1-9b21-0800200c9a66', + 'expected' => false, + ], + [ + 'value' => '3f6f8cb0-c57d-11e1-9b21-0800200c9a6', + 'expected' => false, + ], + [ + 'value' => 'af6f8cb-c57d-11e1-9b21-0800200c9a66', + 'expected' => false, + ], + [ + 'value' => 'af6f8cb0c57d11e19b210800200c9a66', + 'expected' => false, + ], + [ + 'value' => 'ff6f8cb0-c57da-51e1-9b21-0800200c9a66', + 'expected' => false, + ], + ]); + } +} diff --git a/tests/Validator/GenericValidatorTest.php b/tests/Validator/GenericValidatorTest.php index 38e7b8f4..8e18860b 100644 --- a/tests/Validator/GenericValidatorTest.php +++ b/tests/Validator/GenericValidatorTest.php @@ -14,9 +14,20 @@ class GenericValidatorTest extends TestCase */ public function testValidate(string $value, bool $expected): void { + $variations = []; + $variations[] = $value; + $variations[] = 'urn:uuid:' . $value; + $variations[] = '{' . $value . '}'; + + foreach ($variations as $variation) { + $variations[] = strtoupper($variation); + } + $validator = new GenericValidator(); - $this->assertSame($expected, $validator->validate($value)); + foreach ($variations as $variation) { + $this->assertSame($expected, $validator->validate($variation)); + } } /** @@ -24,51 +35,40 @@ public function testValidate(string $value, bool $expected): void */ public function provideValuesForValidation(): array { - return [ - 'good version 1' => [ - 'value' => 'ff6f8cb0-c57d-11e1-9b21-0800200c9a66', - 'expected' => true, - ], - 'good version 2' => [ - 'value' => 'ff6f8cb0-c57d-21e1-9b21-0800200c9a66', - 'expected' => true, - ], - 'good version 3' => [ - 'value' => 'ff6f8cb0-c57d-31e1-9b21-0800200c9a66', - 'expected' => true, - ], - 'good version 4' => [ - 'value' => 'ff6f8cb0-c57d-41e1-9b21-0800200c9a66', - 'expected' => true, - ], - 'good version 5' => [ - 'value' => 'ff6f8cb0-c57d-51e1-9b21-0800200c9a66', - 'expected' => true, - ], - 'good upper case' => [ - 'value' => 'FF6F8CB0-C57D-11E1-9B21-0800200C9A66', - 'expected' => true, - ], - 'bad hex' => [ + $hexMutations = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f']; + + $testValues = []; + + foreach ($hexMutations as $version) { + foreach ($hexMutations as $variant) { + $testValues[] = [ + 'value' => "ff6f8cb0-c57d-{$version}1e1-{$variant}b21-0800200c9a66", + 'expected' => true, + ]; + } + } + + return array_merge($testValues, [ + [ 'value' => 'zf6f8cb0-c57d-11e1-9b21-0800200c9a66', 'expected' => false, ], - 'too short 1' => [ + [ 'value' => '3f6f8cb0-c57d-11e1-9b21-0800200c9a6', 'expected' => false, ], - 'too short 2' => [ + [ 'value' => 'af6f8cb-c57d-11e1-9b21-0800200c9a66', 'expected' => false, ], - 'no dashes' => [ + [ 'value' => 'af6f8cb0c57d11e19b210800200c9a66', 'expected' => false, ], - 'too long' => [ + [ 'value' => 'ff6f8cb0-c57da-51e1-9b21-0800200c9a66', 'expected' => false, ], - ]; + ]); } }