From 217199221532766a305df952bb18881d5fc22702 Mon Sep 17 00:00:00 2001 From: honhimW Date: Wed, 26 Aug 2026 14:59:59 +0800 Subject: [PATCH] feat: Bytes add partial shift tests add rfc9562 example test vectors and UUIDv8 Examples --- .../java/io/github/honhimw/uuid/Bytes.java | 80 +++++++++++++++ .../io/github/honhimw/uuid/UuidBuilder.java | 24 ----- .../java/io/github/honhimw/uuid/gen/V3.java | 9 +- .../java/io/github/honhimw/uuid/gen/V5.java | 10 +- .../io/github/honhimw/uuid/BytesTests.java | 31 ++++++ .../java/io/github/honhimw/uuid/V1Tests.java | 30 ++++++ .../java/io/github/honhimw/uuid/V3Tests.java | 33 +++++++ .../java/io/github/honhimw/uuid/V4Tests.java | 32 ++++++ .../java/io/github/honhimw/uuid/V5Tests.java | 35 ++++++- .../java/io/github/honhimw/uuid/V6Tests.java | 30 ++++++ .../java/io/github/honhimw/uuid/V7Tests.java | 24 +++++ .../java/io/github/honhimw/uuid/V8Tests.java | 98 +++++++++++++++++++ 12 files changed, 402 insertions(+), 34 deletions(-) create mode 100644 src/test/java/io/github/honhimw/uuid/V8Tests.java diff --git a/src/main/java/io/github/honhimw/uuid/Bytes.java b/src/main/java/io/github/honhimw/uuid/Bytes.java index af4040c..4bbf6f0 100644 --- a/src/main/java/io/github/honhimw/uuid/Bytes.java +++ b/src/main/java/io/github/honhimw/uuid/Bytes.java @@ -178,6 +178,86 @@ public Bytes position(int index) { return this; } + /// Shift-right bits by n bits starting at bit offset. + /// The n-bit gap is part of the moved range, i.e. the bits at + /// [offset, offset + length + n) are shifted right by n bits, + /// directly overwriting the target positions, + /// and the vacated positions [offset, offset + n) are filled with 0. + /// All parameters are bit-indexed rather than byte-indexed. + /// + /// @param offset bit offset of the first moved bit + /// @param length bit length of the shifted range without the gap + /// @param n shift distance in bits + /// @return self + public Bytes partialShiftRight(int offset, int length, int n) { + if (n <= 0 || length <= 0) { + return this; + } + final byte[] bytes = this.bytes; + final int total = bytes.length << 3; + final int count = length + n; + // Move from the highest bit down so already-written positions + // are never re-read as sources. + for (int i = count - 1; i >= 0; i--) { + int src = offset + i; + int dst = src + n; + if (dst >= total || src >= total) { + continue; + } + int bit = (bytes[src >>> 3] >> (7 - (src & 7))) & 1; + int dstIndex = dst >>> 3; + int dstShift = 7 - (dst & 7); + bytes[dstIndex] = (byte) ((bytes[dstIndex] & ~(1 << dstShift)) | (bit << dstShift)); + } + for (int i = 0; i < n && offset + i < total; i++) { + int index = (offset + i) >>> 3; + int shift = 7 - ((offset + i) & 7); + bytes[index] &= (byte) ~(1 << shift); + } + return this; + } + + /// Shift-left bits at range [offset, offset + length) by n bits. + /// The moved bits directly overwrite the target positions + /// [offset - n, offset + length - n), + /// bits shifted below index 0 are discarded, + /// and the vacated source positions which are not covered + /// by the target range are filled with 0. + /// Bits outside the moved range remain untouched. + /// All parameters are bit-indexed rather than byte-indexed. + /// + /// @param offset bit offset of the first moved bit + /// @param length bit length of the moved range + /// @param n shift distance in bits + /// @return self + public Bytes partialShiftLeft(int offset, int length, int n) { + if (n <= 0 || length <= 0) { + return this; + } + final byte[] bytes = this.bytes; + final int total = bytes.length << 3; + // Move from the lowest bit up so already-written positions + // are never re-read as sources. + for (int i = 0; i < length; i++) { + int src = offset + i; + int dst = src - n; + if (dst < 0 || src >= total) { + continue; + } + int bit = (bytes[src >>> 3] >> (7 - (src & 7))) & 1; + int dstIndex = dst >>> 3; + int dstShift = 7 - (dst & 7); + bytes[dstIndex] = (byte) ((bytes[dstIndex] & ~(1 << dstShift)) | (bit << dstShift)); + } + // Clear the vacated source positions which are not overwritten by targets. + int from = Math.max(offset, offset + length - n); + int to = Math.min(offset + length, total); + for (int i = from; i < to; i++) { + bytes[i >>> 3] &= (byte) ~(1 << (7 - (i & 7))); + } + return this; + } + @Override public int compareTo(Bytes o) { int cmp = Integer.compare(this.bytes.length, o.bytes.length); diff --git a/src/main/java/io/github/honhimw/uuid/UuidBuilder.java b/src/main/java/io/github/honhimw/uuid/UuidBuilder.java index 74d22ad..b290aab 100644 --- a/src/main/java/io/github/honhimw/uuid/UuidBuilder.java +++ b/src/main/java/io/github/honhimw/uuid/UuidBuilder.java @@ -93,30 +93,6 @@ public static UuidBuilder fromGregorian(Timestamp ts, NodeId nodeId) { return builder; } - public static UuidBuilder fromMd5Bytes(byte[] bytes) { - if (bytes.length != 16) { - throw new IllegalArgumentException("The length of the md5-bytes array must be 16."); - } - UuidBuilder builder = empty(); - builder.bytes.put(bytes); - builder - .variant(Variant.RFC4122) - .version(Version.MD5); - return builder; - } - - public static UuidBuilder fromSha1Bytes(byte[] bytes) { - if (bytes.length != 16) { - throw new IllegalArgumentException("The length of the sha1-bytes array must be 16."); - } - UuidBuilder builder = empty(); - builder.bytes.put(bytes); - builder - .variant(Variant.RFC4122) - .version(Version.SHA1); - return builder; - } - public static UuidBuilder fromSortedGregorian(Timestamp ts, NodeId nodeId) { long ticks = ts.asGregorian(); int timeLow = (int) ((ticks >>> 28) & (-1L >>> 32)); diff --git a/src/main/java/io/github/honhimw/uuid/gen/V3.java b/src/main/java/io/github/honhimw/uuid/gen/V3.java index f91755e..9a4877a 100644 --- a/src/main/java/io/github/honhimw/uuid/gen/V3.java +++ b/src/main/java/io/github/honhimw/uuid/gen/V3.java @@ -1,8 +1,6 @@ package io.github.honhimw.uuid.gen; -import io.github.honhimw.uuid.Context; -import io.github.honhimw.uuid.UUIDs; -import io.github.honhimw.uuid.UuidBuilder; +import io.github.honhimw.uuid.*; import org.jspecify.annotations.Nullable; import java.security.MessageDigest; @@ -67,7 +65,10 @@ protected String algorithm() { public UUID of(byte[] name) { MessageDigest md = getDigester(); byte[] digest = md.digest(name); - return UuidBuilder.fromMd5Bytes(digest).build(); + return UuidBuilder.fromBytes(digest) + .variant(Variant.RFC4122) + .version(Version.MD5) + .build(); } } diff --git a/src/main/java/io/github/honhimw/uuid/gen/V5.java b/src/main/java/io/github/honhimw/uuid/gen/V5.java index 2fdb2cb..3843f3e 100644 --- a/src/main/java/io/github/honhimw/uuid/gen/V5.java +++ b/src/main/java/io/github/honhimw/uuid/gen/V5.java @@ -1,9 +1,6 @@ package io.github.honhimw.uuid.gen; -import io.github.honhimw.uuid.Bytes; -import io.github.honhimw.uuid.Context; -import io.github.honhimw.uuid.UUIDs; -import io.github.honhimw.uuid.UuidBuilder; +import io.github.honhimw.uuid.*; import org.jspecify.annotations.Nullable; import java.security.MessageDigest; @@ -80,7 +77,10 @@ public UUID of(byte[] name) { MessageDigest md = getDigester(); byte[] digest = md.digest(name); digest = Bytes.copyOf(digest, 16); - return UuidBuilder.fromSha1Bytes(digest).build(); + return UuidBuilder.fromBytes(digest) + .variant(Variant.RFC4122) + .version(Version.SHA1) + .build(); } } diff --git a/src/test/java/io/github/honhimw/uuid/BytesTests.java b/src/test/java/io/github/honhimw/uuid/BytesTests.java index 1f78f6d..a92d9cf 100644 --- a/src/test/java/io/github/honhimw/uuid/BytesTests.java +++ b/src/test/java/io/github/honhimw/uuid/BytesTests.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import java.nio.ByteBuffer; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; /// @author honhimW @@ -41,4 +42,34 @@ void _long() { Assertions.assertEquals(bytes.getLong(4), byteBuffer.getLong(4)); } + @Test + @SneakyThrows + void shiftRight() { + Bytes bytes = new Bytes(16); + bytes.putLong(-1); + + bytes + .partialShiftRight(48, 12, 4) + .partialShiftRight(64, 4, 2); + + Assertions.assertEquals("ffffffff-ffff-0fff-3c00-000000000000", new UUID(bytes.getLong(0), bytes.getLong(Long.BYTES)).toString()); + } + + @Test + @SneakyThrows + void shiftLeft() { + Bytes bytes = new Bytes(16); + bytes.putLong(0).putLong(-1); + + bytes + .partialShiftLeft(72, 40, 32); + + Assertions.assertEquals("00000000-00ff-ffff-ffff-00000000ffff", Uuid.fromBytes(bytes.unwrap()).toString()); + + bytes + .partialShiftRight(48, 12, 4); + + Assertions.assertEquals("00000000-00ff-0fff-ffff-00000000ffff", new UUID(bytes.getLong(0), bytes.getLong(Long.BYTES)).toString()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V1Tests.java b/src/test/java/io/github/honhimw/uuid/V1Tests.java index 774df1e..5cb2d4d 100644 --- a/src/test/java/io/github/honhimw/uuid/V1Tests.java +++ b/src/test/java/io/github/honhimw/uuid/V1Tests.java @@ -47,4 +47,34 @@ void context() { } } + /// [Example of a UUIDv1 Value](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv1-value) + /// ```text + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// time_low 32 0xC232AB00 + /// time_mid 16 0x9414 + /// ver 4 0x1 + /// time_high 12 0x1EC + /// var 2 0b10 + /// clock_seq 14 0b11, 0x3C8 + /// node 48 0x9F6BDECED846 + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: C232AB00-9414-11EC-B3C8-9F6BDECED846 + /// ``` + @Test + @SneakyThrows + void example() { + long ticks = 0x1EC9414C232AB00L; + long counter = 0x33C8; + Timestamp timestamp = Timestamp.fromGregorian(ticks, counter); + NodeId nodeId = NodeId.of(new byte[]{(byte) 0x9F, 0x6B, (byte) 0xDE, (byte) 0xCE, (byte) 0xD8, 0x46}); + UUID uuid = V1.of(timestamp, nodeId); + Assertions.assertEquals("c232ab00-9414-11ec-b3c8-9f6bdeced846", uuid.toString()); + Assertions.assertEquals(1, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V3Tests.java b/src/test/java/io/github/honhimw/uuid/V3Tests.java index 4dd90f6..30be9d9 100644 --- a/src/test/java/io/github/honhimw/uuid/V3Tests.java +++ b/src/test/java/io/github/honhimw/uuid/V3Tests.java @@ -55,4 +55,37 @@ void noNamespace() { Assertions.assertEquals(md5UUID, uuid); } + /// [Example of a UUIDv3 Value](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv3-value) + /// ```text + /// Namespace (DNS): 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + /// Name: www.example.com + /// ------------------------------------------------------ + /// MD5: 5df418813aed051548a72f4a814cf09e + /// + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// md5_high 48 0x5df418813aed + /// ver 4 0x3 + /// md5_mid 12 0x515 + /// var 2 0b10 + /// md5_low 62 0b00, 0x8a72f4a814cf09e + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 5df41881-3aed-3515-88a7-2f4a814cf09e + /// + /// MD5 hex and dash: 5df41881-3aed-0515-48a7-2f4a814cf09e + /// Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx + /// Final: 5df41881-3aed-3515-88a7-2f4a814cf09e + /// ``` + @Test + @SneakyThrows + void example() { + UUID uuid = V3.dns().of("www.example.com"); + Assertions.assertEquals("5df41881-3aed-3515-88a7-2f4a814cf09e", uuid.toString()); + Assertions.assertEquals(3, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V4Tests.java b/src/test/java/io/github/honhimw/uuid/V4Tests.java index 4432dd3..4a6a5e3 100644 --- a/src/test/java/io/github/honhimw/uuid/V4Tests.java +++ b/src/test/java/io/github/honhimw/uuid/V4Tests.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.math.BigInteger; import java.util.UUID; /// @author honhimW @@ -18,4 +19,35 @@ void random() { Assertions.assertEquals(2, uuid.variant()); } + /// [Example of a UUIDv4 Value](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv4-value) + /// ```text + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// random_a 48 0x919108f752d1 + /// ver 4 0x4 + /// random_b 12 0x320 + /// var 2 0b10 + /// random_c 62 0b01, 0xbacf847db4148a8 + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 919108f7-52d1-4320-9bac-f847db4148a8 + /// + /// Random hex: 919108f752d133205bacf847db4148a8 + /// Random hex and dash: 919108f7-52d1-3320-5bac-f847db4148a8 + /// Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx + /// Final: 919108f7-52d1-4320-9bac-f847db4148a8 + /// ``` + @Test + @SneakyThrows + void example() { + long h = 0x919108f752d13320L; + long l = 0x5bacf847db4148a8L; + UUID uuid = UuidBuilder.fromPair(h, l).version(Version.RANDOM).variant(Variant.RFC4122).build(); + Assertions.assertEquals("919108f7-52d1-4320-9bac-f847db4148a8", uuid.toString()); + Assertions.assertEquals(4, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V5Tests.java b/src/test/java/io/github/honhimw/uuid/V5Tests.java index afece19..f132341 100644 --- a/src/test/java/io/github/honhimw/uuid/V5Tests.java +++ b/src/test/java/io/github/honhimw/uuid/V5Tests.java @@ -1,6 +1,5 @@ package io.github.honhimw.uuid; -import io.github.honhimw.uuid.gen.V3; import io.github.honhimw.uuid.gen.V5; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; @@ -55,4 +54,38 @@ void noNamespace() { Assertions.assertEquals(md5UUID, uuid); } + /// [Example of a UUIDv5 Value](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv5-value) + /// ```text + /// Namespace (DNS): 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + /// Name: www.example.com + /// ---------------------------------------------------------- + /// SHA-1: 2ed6657de927468b55e12665a8aea6a22dee3e35 + /// + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// sha1_high 48 0x2ed6657de927 + /// ver 4 0x5 + /// sha1_mid 12 0x68b + /// var 2 0b10 + /// sha1_low 62 0b01, 0x5e12665a8aea6a2 + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 2ed6657d-e927-568b-95e1-2665a8aea6a2 + /// + /// SHA-1 hex and dash: 2ed6657d-e927-468b-55e1-2665a8aea6a2-2dee3e35 + /// Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx + /// Final: 2ed6657d-e927-568b-95e1-2665a8aea6a2 + /// Discarded: -2dee3e35 + /// ``` + @Test + @SneakyThrows + void example() { + UUID uuid = V5.dns().of("www.example.com"); + Assertions.assertEquals("2ed6657d-e927-568b-95e1-2665a8aea6a2", uuid.toString()); + Assertions.assertEquals(5, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V6Tests.java b/src/test/java/io/github/honhimw/uuid/V6Tests.java index b8d476b..532631a 100644 --- a/src/test/java/io/github/honhimw/uuid/V6Tests.java +++ b/src/test/java/io/github/honhimw/uuid/V6Tests.java @@ -53,4 +53,34 @@ void context() { } } + /// [Example of a UUIDv6 Value](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv6-value) + /// ```text + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// time_high 32 0x1EC9414C + /// time_mid 16 0x232A + /// ver 4 0x6 + /// time_high 12 0xB00 + /// var 2 0b10 + /// clock_seq 14 0b11, 0x3C8 + /// node 48 0x9F6BDECED846 + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 1EC9414C-232A-6B00-B3C8-9F6BDECED846 + /// ``` + @Test + @SneakyThrows + void example() { + long ticks = 0x1EC9414C232AB00L; + long counter = 0x33C8; + Timestamp timestamp = Timestamp.fromGregorian(ticks, counter); + NodeId nodeId = NodeId.of(new byte[]{(byte) 0x9F, 0x6B, (byte) 0xDE, (byte) 0xCE, (byte) 0xD8, 0x46}); + UUID uuid = V6.of(timestamp, nodeId); + Assertions.assertEquals("1ec9414c-232a-6b00-b3c8-9f6bdeced846", uuid.toString()); + Assertions.assertEquals(6, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V7Tests.java b/src/test/java/io/github/honhimw/uuid/V7Tests.java index e4d7e36..22ff329 100644 --- a/src/test/java/io/github/honhimw/uuid/V7Tests.java +++ b/src/test/java/io/github/honhimw/uuid/V7Tests.java @@ -68,4 +68,28 @@ void precision20() { Assertions.assertEquals(now, resolved); } + /// [Example of a UUIDv7 Value](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv7-value) + /// ```text + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// unix_ts_ms 48 0x017F22E279B0 + /// ver 4 0x7 + /// rand_a 12 0xCC3 + /// var 2 0b10 + /// rand_b 62 0b01, 0x8C4DC0C0C07398F + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F + /// ``` + @Test + @SneakyThrows + void example() { + UUID uuid = UuidBuilder.fromUnixTimestampMillis(1645557742000L, 0x0CC3_18C4_DC0C_0C07L, 0x398F).build(); + Assertions.assertEquals("017f22e2-79b0-7cc3-98c4-dc0c0c07398f", uuid.toString()); + Assertions.assertEquals(7, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + } diff --git a/src/test/java/io/github/honhimw/uuid/V8Tests.java b/src/test/java/io/github/honhimw/uuid/V8Tests.java new file mode 100644 index 0000000..775816b --- /dev/null +++ b/src/test/java/io/github/honhimw/uuid/V8Tests.java @@ -0,0 +1,98 @@ +package io.github.honhimw.uuid; + +import io.github.honhimw.uuid.gen.AbstractGenerator; +import io.github.honhimw.uuid.gen.AbstractNameBasedGenerator; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.security.MessageDigest; +import java.util.UUID; + +/// @author honhimW +/// @since 2026-08-24 + +public class V8Tests { + + /// [Example of a UUIDv8 Value (Time-Based)](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv8-value-t) + /// ```text + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// custom_a 48 0x2489E9AD2EE2 + /// ver 4 0x8 + /// custom_b 12 0xE00 + /// var 2 0b10 + /// custom_c 62 0b00, 0xEC932D5F69181C0 + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 + /// ``` + @Test + @SneakyThrows + void timeBased() { + Bytes bytes = new Bytes(16); + bytes + // 60-bits timestamp + .putLong(0x2489E9AD2EE2E00L << 4) + // random data + .putLong(0xEC932D5F69181C0L) + // skipping version 4 bits + .partialShiftRight(48, 12, 4) + ; + UuidBuilder builder = UuidBuilder.fromBytes(bytes.unwrap()); + UUID uuid = builder.version(Version.CUSTOM).variant(Variant.RFC4122).build(); + Assertions.assertEquals("2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", uuid.toString().toUpperCase()); + Assertions.assertEquals(8, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + + /// [Example of a UUIDv8 Value (Name-Based)](https://www.rfc-editor.org/rfc/rfc9562.html#name-example-of-a-uuidv8-value-n) + /// ```text + /// Namespace (DNS): 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + /// Name: www.example.com + /// ---------------------------------------------------------------- + /// SHA-256: + /// 5c146b143c524afd938a375d0df1fbf6fe12a66b645f72f6158759387e51f3c8 + /// + /// ------------------------------------------- + /// field bits value + /// ------------------------------------------- + /// custom_a 48 0x5c146b143c52 + /// ver 4 0x8 + /// custom_b 12 0xafd + /// var 2 0b10 + /// custom_c 62 0b00, 0x38a375d0df1fbf6 + /// ------------------------------------------- + /// total 128 + /// ------------------------------------------- + /// final: 5c146b14-3c52-8afd-938a-375d0df1fbf6 + /// ``` + @Test + @SneakyThrows + void nameBased() { + Generator.NameBased generator = new AbstractNameBasedGenerator(UUIDs.NAMESPACE_DNS) { + @Override + protected String algorithm() { + return "SHA256"; + } + + @Override + public UUID of(byte[] name) { + MessageDigest md = getDigester(); + byte[] digest = md.digest(name); + digest = Bytes.copyOf(digest, 16); + return UuidBuilder.fromBytes(digest) + .variant(Variant.RFC4122) + .version(Version.CUSTOM) + .build(); + } + }; + UUID uuid = generator.of("www.example.com"); + Assertions.assertEquals("5c146b14-3c52-8afd-938a-375d0df1fbf6", uuid.toString()); + Assertions.assertEquals(8, uuid.version()); + Assertions.assertEquals(2, uuid.variant()); + } + +}