diff --git a/CHANGELOG.md b/CHANGELOG.md index f128fdb..7391f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Hexadecimal is never an empty string; fixed in [#593](https://github.com/ramsey/uuid/pull/593). * Update call to `str_getcsv()` to avoid deprecation notice in PHP 8.4; fixed in [#590](https://github.com/ramsey/uuid/pull/590). * Update docblocks for `Uuid::fromBytes()`, `Uuid::fromString()`, `Uuid::fromDateTime()`, `Uuid::fromHexadecimal()`, and `Uuid::fromInteger()` to note that each can throw `InvalidArgumentException`, addressing PHPStan errors occurring at call sites; fixed in [#552](https://github.com/ramsey/uuid/pull/552). +* `getVariant()` for `MaxUuid` now correctly returns `Uuid::RESERVED_FUTURE`, as specified in [RFC 9562, section 5.10](https://www.rfc-editor.org/rfc/rfc9562#section-5.10). +* `getVariant()` for `NilUuid` now correctly returns `Uuid::RESERVED_NCS`, as specified in [RFC 9562, section 5.9](https://www.rfc-editor.org/rfc/rfc9562#section-5.9). ### Deprecated diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php index 8e5eed5..e477528 100644 --- a/src/Rfc4122/UuidBuilder.php +++ b/src/Rfc4122/UuidBuilder.php @@ -42,13 +42,13 @@ class UuidBuilder implements UuidBuilderInterface * @param NumberConverterInterface $numberConverter The number converter to use when constructing the Uuid * @param TimeConverterInterface $timeConverter The time converter to use for converting Gregorian time extracted * from version 1, 2, and 6 UUIDs to Unix timestamps - * @param TimeConverterInterface|null $unixTimeConverter The time converter to use for converter Unix Epoch time + * @param TimeConverterInterface | null $unixTimeConverter The time converter to use for converter Unix Epoch time * extracted from version 7 UUIDs to Unix timestamps */ public function __construct( private NumberConverterInterface $numberConverter, private TimeConverterInterface $timeConverter, - ?TimeConverterInterface $unixTimeConverter = null + ?TimeConverterInterface $unixTimeConverter = null, ) { $this->unixTimeConverter = $unixTimeConverter ?? new UnixTimeConverter(new BrickMathCalculator()); } diff --git a/src/Rfc4122/VariantTrait.php b/src/Rfc4122/VariantTrait.php index 64e5279..3d39369 100644 --- a/src/Rfc4122/VariantTrait.php +++ b/src/Rfc4122/VariantTrait.php @@ -58,8 +58,18 @@ trait VariantTrait throw new InvalidBytesException('Invalid number of bytes'); } - if ($this->isMax() || $this->isNil()) { - return Uuid::RFC_4122; + // According to RFC 9562, sections {@link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 4.1} and + // {@link https://www.rfc-editor.org/rfc/rfc9562#section-5.10 5.10}, the Max UUID falls within the range + // of the future variant. + if ($this->isMax()) { + return Uuid::RESERVED_FUTURE; + } + + // According to RFC 9562, sections {@link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 4.1} and + // {@link https://www.rfc-editor.org/rfc/rfc9562#section-5.9 5.9}, the Nil UUID falls within the range + // of the Apollo NCS variant. + if ($this->isNil()) { + return Uuid::RESERVED_NCS; } /** @var int[] $parts */ diff --git a/tests/ExpectedBehaviorTest.php b/tests/ExpectedBehaviorTest.php index 804239c..d38599d 100644 --- a/tests/ExpectedBehaviorTest.php +++ b/tests/ExpectedBehaviorTest.php @@ -380,7 +380,7 @@ class ExpectedBehaviorTest extends TestCase public function provideFromStringInteger() { return [ - ['00000000-0000-0000-0000-000000000000', null, 2, '0'], + ['00000000-0000-0000-0000-000000000000', null, 0, '0'], ['ff6f8cb0-c57d-11e1-8b21-0800200c9a66', 1, 2, '339532337419071774304650190139318639206'], ['ff6f8cb0-c57d-11e1-9b21-0800200c9a66', 1, 2, '339532337419071774305803111643925486182'], ['ff6f8cb0-c57d-11e1-ab21-0800200c9a66', 1, 2, '339532337419071774306956033148532333158'], @@ -413,7 +413,7 @@ class ExpectedBehaviorTest extends TestCase ['ff6f8cb0-c57d-01e1-db21-0800200c9a66', null, 6, '339532337419071698752551071748029454950'], ['ff6f8cb0-c57d-01e1-eb21-0800200c9a66', null, 7, '339532337419071698753703993252636301926'], ['ff6f8cb0-c57d-01e1-fb21-0800200c9a66', null, 7, '339532337419071698754856914757243148902'], - ['ffffffff-ffff-ffff-ffff-ffffffffffff', null, 2, '340282366920938463463374607431768211455'], + ['ffffffff-ffff-ffff-ffff-ffffffffffff', null, 7, '340282366920938463463374607431768211455'], ]; } diff --git a/tests/Guid/FieldsTest.php b/tests/Guid/FieldsTest.php index b511974..97f5dd1 100644 --- a/tests/Guid/FieldsTest.php +++ b/tests/Guid/FieldsTest.php @@ -201,7 +201,7 @@ class FieldsTest extends TestCase ['00000000000000000000000000000000', 'getTimeLow', '00000000'], ['00000000000000000000000000000000', 'getTimeMid', '0000'], ['00000000000000000000000000000000', 'getTimestamp', '000000000000000'], - ['00000000000000000000000000000000', 'getVariant', 2], + ['00000000000000000000000000000000', 'getVariant', 0], ['00000000000000000000000000000000', 'getVersion', null], ['00000000000000000000000000000000', 'isNil', true], ['00000000000000000000000000000000', 'isMax', false], @@ -215,7 +215,7 @@ class FieldsTest extends TestCase ['ffffffffffffffffffffffffffffffff', 'getTimeLow', 'ffffffff'], ['ffffffffffffffffffffffffffffffff', 'getTimeMid', 'ffff'], ['ffffffffffffffffffffffffffffffff', 'getTimestamp', 'fffffffffffffff'], - ['ffffffffffffffffffffffffffffffff', 'getVariant', 2], + ['ffffffffffffffffffffffffffffffff', 'getVariant', 7], ['ffffffffffffffffffffffffffffffff', 'getVersion', null], ['ffffffffffffffffffffffffffffffff', 'isNil', false], ['ffffffffffffffffffffffffffffffff', 'isMax', true], diff --git a/tests/Rfc4122/FieldsTest.php b/tests/Rfc4122/FieldsTest.php index ffb9f97..e1ef87f 100644 --- a/tests/Rfc4122/FieldsTest.php +++ b/tests/Rfc4122/FieldsTest.php @@ -201,7 +201,7 @@ class FieldsTest extends TestCase ['00000000-0000-0000-0000-000000000000', 'getTimeLow', '00000000'], ['00000000-0000-0000-0000-000000000000', 'getTimeMid', '0000'], ['00000000-0000-0000-0000-000000000000', 'getTimestamp', '000000000000000'], - ['00000000-0000-0000-0000-000000000000', 'getVariant', 2], + ['00000000-0000-0000-0000-000000000000', 'getVariant', 0], ['00000000-0000-0000-0000-000000000000', 'getVersion', null], ['00000000-0000-0000-0000-000000000000', 'isNil', true], ['00000000-0000-0000-0000-000000000000', 'isMax', false], @@ -214,7 +214,7 @@ class FieldsTest extends TestCase ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimeLow', 'ffffffff'], ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimeMid', 'ffff'], ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimestamp', 'fffffffffffffff'], - ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getVariant', 2], + ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getVariant', 7], ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getVersion', null], ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'isNil', false], ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'isMax', true], diff --git a/tests/UuidTest.php b/tests/UuidTest.php index cf17384..153cffd 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -1436,13 +1436,7 @@ class UuidTest extends TestCase 'urn' => 'urn:uuid:00000000-0000-0000-0000-000000000000', 'time' => '0', 'clock_seq' => '0000', - // This is a departure from the Python tests. The Python tests - // are technically "correct" because all bits are set to zero, - // so it stands to reason that the variant is also zero, but - // that leads to this being considered a "Reserved NCS" variant, - // and that is not the case. RFC 4122 defines this special UUID, - // so it is an RFC 4122 variant. - 'variant' => Uuid::RFC_4122, + 'variant' => Uuid::RESERVED_NCS, 'version' => null, ], [ @@ -1701,20 +1695,13 @@ class UuidTest extends TestCase ], 'urn' => 'urn:uuid:ffffffff-ffff-ffff-ffff-ffffffffffff', 'time' => 'fffffffffffffff', - // This is a departure from the Python tests. The Python tests - // are technically "correct" because all bits are set to one, - // which ends up calculating the variant as 7, or "Reserved - // Future," but that is not the case, and now that max UUIDs - // are defined as a special type, within the RFC 4122 variant - // rules, we also consider it an RFC 4122 variant. - // - // Similarly, Python's tests think the clock sequence should be + // Python's tests think the clock sequence should be // 0x3fff because of the bit shifting performed on this field. // However, since all the bits in this UUID are defined as being // set to one, we will consider the clock sequence as 0xffff, // which all bits set to one. 'clock_seq' => 'ffff', - 'variant' => Uuid::RFC_4122, + 'variant' => Uuid::RESERVED_FUTURE, 'version' => null, ], ];