From 55d8833b06af35bd880d8c855af734b454548fa3 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sat, 5 Nov 2022 17:49:12 -0500 Subject: [PATCH] feat: support version 8, custom UUIDs --- docs/reference.rst | 1 + docs/reference/rfc4122-uuidv8.rst | 13 +++++++ docs/rfc4122.rst | 7 +++- docs/rfc4122/version6.rst | 2 +- docs/rfc4122/version7.rst | 2 +- docs/rfc4122/version8.rst | 51 ++++++++++++++++++++++++ psalm-baseline.xml | 19 ++------- src/Rfc4122/MaxTrait.php | 2 +- src/Rfc4122/UuidBuilder.php | 2 + src/Rfc4122/UuidV6.php | 2 +- src/Rfc4122/UuidV7.php | 6 ++- src/Rfc4122/UuidV8.php | 65 +++++++++++++++++++++++++++++++ src/Rfc4122/Validator.php | 2 +- src/Rfc4122/VersionTrait.php | 2 +- src/Uuid.php | 41 +++++++++++++++++-- src/UuidFactory.php | 21 ++++++++++ src/functions.php | 20 ++++++++++ tests/FunctionsTest.php | 16 ++++++++ tests/Rfc4122/UuidBuilderTest.php | 7 ++++ tests/Rfc4122/UuidV8Test.php | 57 +++++++++++++++++++++++++++ tests/Rfc4122/ValidatorTest.php | 4 +- tests/UuidTest.php | 20 ++++++++++ 22 files changed, 332 insertions(+), 30 deletions(-) create mode 100644 docs/reference/rfc4122-uuidv8.rst create mode 100644 docs/rfc4122/version8.rst create mode 100644 src/Rfc4122/UuidV8.php create mode 100644 tests/Rfc4122/UuidV8Test.php diff --git a/docs/reference.rst b/docs/reference.rst index 55d5c9e..d78bae5 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -19,6 +19,7 @@ Reference reference/rfc4122-uuidv5 reference/rfc4122-uuidv6 reference/rfc4122-uuidv7 + reference/rfc4122-uuidv8 reference/guid-fields reference/guid-guid reference/nonstandard-fields diff --git a/docs/reference/rfc4122-uuidv8.rst b/docs/reference/rfc4122-uuidv8.rst new file mode 100644 index 0000000..f2465bd --- /dev/null +++ b/docs/reference/rfc4122-uuidv8.rst @@ -0,0 +1,13 @@ +.. _reference.rfc4122.uuidv8: + +=============== +Rfc4122\\UuidV8 +=============== + +.. php:namespace:: Ramsey\Uuid\Rfc4122 + +.. php:class:: UuidV8 + + Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`. + + UuidV8 represents a :ref:`version 8, custom UUID `. diff --git a/docs/rfc4122.rst b/docs/rfc4122.rst index 2520f97..4ef53fa 100644 --- a/docs/rfc4122.rst +++ b/docs/rfc4122.rst @@ -15,6 +15,7 @@ RFC 4122 UUIDs rfc4122/version5 rfc4122/version6 rfc4122/version7 + rfc4122/version8 `RFC 4122`_ defines five versions of UUID, while a `new Internet-Draft under review`_ defines three new versions. Each version has different generation @@ -57,6 +58,10 @@ Version 7: Unix Epoch Time sortable UUID without the privacy and entropy concerns associated with version 1 and version 6 UUIDs. For more details, see :ref:`rfc4122.version7`. +Version 8: Custom + This version of UUID allows applications to generate custom identifiers in + an RFC-compatible format. For more details, see :doc:`rfc4122/version8`. + .. _RFC 4122: https://tools.ietf.org/html/rfc4122 -.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04 +.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00 diff --git a/docs/rfc4122/version6.rst b/docs/rfc4122/version6.rst index e4b79bb..07b610e 100644 --- a/docs/rfc4122/version6.rst +++ b/docs/rfc4122/version6.rst @@ -208,6 +208,6 @@ need the benefit of a monotonically increasing unique identifier, see :ref:`rfc4122.version7`. -.. _Internet-Draft under review: https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/ +.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 .. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ .. _RFC 4122: https://tools.ietf.org/html/rfc4122 diff --git a/docs/rfc4122/version7.rst b/docs/rfc4122/version7.rst index 1143c7c..d708467 100644 --- a/docs/rfc4122/version7.rst +++ b/docs/rfc4122/version7.rst @@ -167,7 +167,7 @@ This will print something like this: ULID, unless it was converted from a version 7 UUID. .. _ULIDs: https://github.com/ulid/spec -.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2 +.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 .. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ .. _Crockford's Base 32 algorithm: https://www.crockford.com/base32.html .. _tuupola/base32: https://packagist.org/packages/tuupola/base32 diff --git a/docs/rfc4122/version8.rst b/docs/rfc4122/version8.rst new file mode 100644 index 0000000..96f2b6f --- /dev/null +++ b/docs/rfc4122/version8.rst @@ -0,0 +1,51 @@ +.. _rfc4122.version8: + +================= +Version 8: Custom +================= + +.. note:: + + Version 8, custom UUIDs are a new format of UUID, proposed in an + `Internet-Draft under review`_ at the IETF. While the draft is still going + through the IETF process, the version 7 format is not expected to change + in any way that breaks compatibility. + +Version 8 UUIDs allow applications to create custom UUIDs in an RFC-compatible +way. The only requirement is the version and variant bits must be set according +to the UUID specification. The bytes provided may contain any value according to +your application's needs. Be aware, however, that other applications may not +understand the semantics of the value. + +.. warning:: + + The bytes should be a 16-byte octet string, an open blob of data that you + may fill with 128 bits of information. However, bits 48 through 51 will be + replaced with the UUID version field, and bits 64 and 65 will be replaced + with the UUID variant. You must not rely on these bits for your application + needs. + +.. code-block:: php + :caption: Generate a version 8, custom UUID + :name: rfc4122.version8.example + + use Ramsey\Uuid\Uuid; + + $uuid = Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"); + + printf( + "UUID: %s\nVersion: %d\n", + $uuid->toString(), + $uuid->getFields()->getVersion() + ); + +This will generate a version 8 UUID and print out its string representation. +It will look something like this: + +.. code-block:: text + + UUID: 00112233-4455-8677-8899-aabbccddeeff + Version: 8 + + +.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 85843cc..a571c8e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -47,11 +47,6 @@ $timeGenerator - - - unserialize - - uuid_generate_md5 @@ -66,11 +61,6 @@ $this - - - unserialize - - $this @@ -96,7 +86,9 @@ - + + $this + $this $this $this $this @@ -123,11 +115,6 @@ NonstandardUuidV6 - - - unserialize - - unserialize diff --git a/src/Rfc4122/MaxTrait.php b/src/Rfc4122/MaxTrait.php index 2ec3047..dedb727 100644 --- a/src/Rfc4122/MaxTrait.php +++ b/src/Rfc4122/MaxTrait.php @@ -20,7 +20,7 @@ namespace Ramsey\Uuid\Rfc4122; * The max UUID is special form of UUID that is specified to have all 128 bits * set to one. It is the inverse of the nil UUID. * - * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID * * @psalm-immutable */ diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php index 859649f..2c2677d 100644 --- a/src/Rfc4122/UuidBuilder.php +++ b/src/Rfc4122/UuidBuilder.php @@ -95,6 +95,8 @@ class UuidBuilder implements UuidBuilderInterface return new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter); case Uuid::UUID_TYPE_UNIX_TIME: return new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter); + case Uuid::UUID_TYPE_CUSTOM: + return new UuidV8($fields, $this->numberConverter, $codec, $this->timeConverter); } throw new UnsupportedOperationException( diff --git a/src/Rfc4122/UuidV6.php b/src/Rfc4122/UuidV6.php index 9b2ddee..7e37433 100644 --- a/src/Rfc4122/UuidV6.php +++ b/src/Rfc4122/UuidV6.php @@ -20,7 +20,7 @@ use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6; * Reordered time, or version 6, UUIDs include timestamp, clock sequence, and * node values that are combined into a 128-bit unsigned integer * - * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6 + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6 * * @psalm-immutable */ diff --git a/src/Rfc4122/UuidV7.php b/src/Rfc4122/UuidV7.php index 90c2471..5b524c4 100644 --- a/src/Rfc4122/UuidV7.php +++ b/src/Rfc4122/UuidV7.php @@ -22,8 +22,10 @@ use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; use Ramsey\Uuid\Uuid; /** - * Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node - * values that are combined into a 128-bit unsigned integer + * Unix Epoch time, or version 7, UUIDs include a timestamp in milliseconds + * since the Unix Epoch, along with random bytes + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7 * * @psalm-immutable */ diff --git a/src/Rfc4122/UuidV8.php b/src/Rfc4122/UuidV8.php new file mode 100644 index 0000000..78b0290 --- /dev/null +++ b/src/Rfc4122/UuidV8.php @@ -0,0 +1,65 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Version 8, Custom UUIDs provide an RFC 4122 compatible format for + * experimental or vendor-specific uses + * + * The only requirement for version 8 UUIDs is that the version and variant bits + * must be set. Otherwise, implementations are free to set the other bits + * according to their needs. As a result, the uniqueness of version 8 UUIDs is + * implementation-specific and should not be assumed. + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8 + * + * @psalm-immutable + */ +final class UuidV8 extends Uuid implements UuidInterface +{ + /** + * Creates a version 8 (custom) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_CUSTOM) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV8 must represent a ' + . 'version 8 (custom) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/src/Rfc4122/Validator.php b/src/Rfc4122/Validator.php index 6b1f0de..e82a11e 100644 --- a/src/Rfc4122/Validator.php +++ b/src/Rfc4122/Validator.php @@ -28,7 +28,7 @@ use function str_replace; final class Validator implements ValidatorInterface { private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-' - . '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z'; + . '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z'; /** * @psalm-return non-empty-string diff --git a/src/Rfc4122/VersionTrait.php b/src/Rfc4122/VersionTrait.php index 316f780..0195e46 100644 --- a/src/Rfc4122/VersionTrait.php +++ b/src/Rfc4122/VersionTrait.php @@ -53,7 +53,7 @@ trait VersionTrait Uuid::UUID_TYPE_TIME, Uuid::UUID_TYPE_DCE_SECURITY, Uuid::UUID_TYPE_HASH_MD5, Uuid::UUID_TYPE_RANDOM, Uuid::UUID_TYPE_HASH_SHA1, Uuid::UUID_TYPE_REORDERED_TIME, - Uuid::UUID_TYPE_UNIX_TIME => true, + Uuid::UUID_TYPE_UNIX_TIME, Uuid::UUID_TYPE_CUSTOM => true, default => false, }; } diff --git a/src/Uuid.php b/src/Uuid.php index 6656aba..144a7a0 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -88,7 +88,7 @@ class Uuid implements UuidInterface * The max UUID is a special form of UUID that is specified to have all 128 * bits set to one * - * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID */ public const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff'; @@ -173,17 +173,22 @@ class Uuid implements UuidInterface /** * Version 6 (reordered time) UUID * - * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6 + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6 */ public const UUID_TYPE_REORDERED_TIME = 6; /** * Version 7 (Unix Epoch time) UUID * - * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2 UUID Version 7 + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7 */ public const UUID_TYPE_UNIX_TIME = 7; + /** + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8 + */ + public const UUID_TYPE_CUSTOM = 8; + /** * DCE Security principal domain * @@ -690,4 +695,34 @@ class Uuid implements UuidInterface 'The provided factory does not support the uuid7() method', ); } + + /** + * Returns a version 8 (custom) UUID + * + * The bytes provided may contain any value according to your application's + * needs. Be aware, however, that other applications may not understand the + * semantics of the value. + * + * @param string $bytes A 16-byte octet string. This is an open blob + * of data that you may fill with 128 bits of information. Be aware, + * however, bits 48 through 51 will be replaced with the UUID version + * field, and bits 64 and 65 will be replaced with the UUID variant. You + * MUST NOT rely on these bits for your application needs. + * + * @return UuidInterface A UuidInterface instance that represents a + * version 8 UUID + */ + public static function uuid8(string $bytes): UuidInterface + { + $factory = self::getFactory(); + + if (method_exists($factory, 'uuid8')) { + /** @var UuidInterface */ + return $factory->uuid8($bytes); + } + + throw new UnsupportedOperationException( + 'The provided factory does not support the uuid8() method', + ); + } } diff --git a/src/UuidFactory.php b/src/UuidFactory.php index d340ca5..fae8fbb 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -400,6 +400,27 @@ class UuidFactory implements UuidFactoryInterface return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME); } + /** + * Returns a version 8 (Custom) UUID + * + * The bytes provided may contain any value according to your application's + * needs. Be aware, however, that other applications may not understand the + * semantics of the value. + * + * @param string $bytes A 16-byte octet string. This is an open blob + * of data that you may fill with 128 bits of information. Be aware, + * however, bits 48 through 51 will be replaced with the UUID version + * field, and bits 64 and 65 will be replaced with the UUID variant. You + * MUST NOT rely on these bits for your application needs. + * + * @return UuidInterface A UuidInterface instance that represents a + * version 8 UUID + */ + public function uuid8(string $bytes): UuidInterface + { + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM); + } + /** * Returns a Uuid created from the provided byte string * diff --git a/src/functions.php b/src/functions.php index fa80f4e..2adf214 100644 --- a/src/functions.php +++ b/src/functions.php @@ -136,3 +136,23 @@ function v7(?DateTimeInterface $dateTime = null): string { return Uuid::uuid7($dateTime)->toString(); } + +/** + * Returns a version 8 (custom) UUID + * + * The bytes provided may contain any value according to your application's + * needs. Be aware, however, that other applications may not understand the + * semantics of the value. + * + * @param string $bytes A 16-byte octet string. This is an open blob + * of data that you may fill with 128 bits of information. Be aware, + * however, bits 48 through 51 will be replaced with the UUID version + * field, and bits 64 and 65 will be replaced with the UUID variant. You + * MUST NOT rely on these bits for your application needs. + * + * @return non-empty-string Version 7 UUID as a string + */ +function v8(string $bytes): string +{ + return Uuid::uuid8($bytes)->toString(); +} diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index bd368ee..dfa981c 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -8,6 +8,7 @@ use DateTimeImmutable; use DateTimeInterface; use Ramsey\Uuid\Rfc4122\FieldsInterface; use Ramsey\Uuid\Rfc4122\UuidV7; +use Ramsey\Uuid\Rfc4122\UuidV8; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Integer as IntegerObject; use Ramsey\Uuid\Uuid; @@ -19,6 +20,7 @@ use function Ramsey\Uuid\v4; use function Ramsey\Uuid\v5; use function Ramsey\Uuid\v6; use function Ramsey\Uuid\v7; +use function Ramsey\Uuid\v8; class FunctionsTest extends TestCase { @@ -118,4 +120,18 @@ class FunctionsTest extends TestCase $this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime()); $this->assertSame(1663195473, $uuid->getDateTime()->getTimestamp()); } + + public function testV8ReturnsVersion8UuidString(): void + { + $v8 = v8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"); + + /** @var UuidV8 $uuid */ + $uuid = Uuid::fromString($v8); + + /** @var FieldsInterface $fields */ + $fields = $uuid->getFields(); + + $this->assertIsString($v8); + $this->assertSame(Uuid::UUID_TYPE_CUSTOM, $fields->getVersion()); + } } diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php index 07f2d07..710ab73 100644 --- a/tests/Rfc4122/UuidBuilderTest.php +++ b/tests/Rfc4122/UuidBuilderTest.php @@ -23,6 +23,7 @@ use Ramsey\Uuid\Rfc4122\UuidV4; use Ramsey\Uuid\Rfc4122\UuidV5; use Ramsey\Uuid\Rfc4122\UuidV6; use Ramsey\Uuid\Rfc4122\UuidV7; +use Ramsey\Uuid\Rfc4122\UuidV8; use Ramsey\Uuid\Test\TestCase; use function hex2bin; @@ -114,6 +115,12 @@ class UuidBuilderTest extends TestCase 'expectedClass' => UuidV7::class, 'expectedVersion' => 7, ], + + [ + 'uuid' => 'ff6f8cb0-c57d-81e1-9b21-0800200c9a66', + 'expectedClass' => UuidV8::class, + 'expectedVersion' => 8, + ], ]; } diff --git a/tests/Rfc4122/UuidV8Test.php b/tests/Rfc4122/UuidV8Test.php new file mode 100644 index 0000000..4f9af75 --- /dev/null +++ b/tests/Rfc4122/UuidV8Test.php @@ -0,0 +1,57 @@ + $version, + ]); + + $numberConverter = Mockery::mock(NumberConverterInterface::class); + $codec = Mockery::mock(CodecInterface::class); + $timeConverter = Mockery::mock(TimeConverterInterface::class); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'Fields used to create a UuidV8 must represent a ' + . 'version 8 (custom) UUID' + ); + + new UuidV8($fields, $numberConverter, $codec, $timeConverter); + } + + /** + * @return array + */ + public function provideTestVersions(): array + { + return [ + ['version' => 0], + ['version' => 1], + ['version' => 2], + ['version' => 3], + ['version' => 4], + ['version' => 5], + ['version' => 6], + ['version' => 7], + ['version' => 9], + ]; + } +} diff --git a/tests/Rfc4122/ValidatorTest.php b/tests/Rfc4122/ValidatorTest.php index 779de50..b3b2e8a 100644 --- a/tests/Rfc4122/ValidatorTest.php +++ b/tests/Rfc4122/ValidatorTest.php @@ -48,7 +48,7 @@ class ValidatorTest extends TestCase 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, 6, 7]; + $trueVersions = [1, 2, 3, 4, 5, 6, 7, 8]; $trueVariants = [8, 9, 'a', 'b']; $testValues = []; @@ -113,7 +113,7 @@ class ValidatorTest extends TestCase public function testGetPattern(): void { $expectedPattern = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-' - . '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z'; + . '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z'; $validator = new Validator(); diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 849b0f3..4c1bd5c 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -827,6 +827,26 @@ class UuidTest extends TestCase } } + public function testUuid8(): void + { + $uuid = Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"); + $this->assertSame(2, $uuid->getVariant()); + $this->assertSame(8, $uuid->getVersion()); + } + + public function testUuid8ThrowsExceptionForUnsupportedFactory(): void + { + /** @var UuidFactoryInterface&MockInterface $factory */ + $factory = Mockery::mock(UuidFactoryInterface::class); + + Uuid::setFactory($factory); + + $this->expectException(UnsupportedOperationException::class); + $this->expectExceptionMessage('The provided factory does not support the uuid8() method'); + + Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"); + } + /** * Tests known version-3 UUIDs *