Skip to content

Commit

Permalink
UUID Ver7 in UUID Generator Tool. (#45)
Browse files Browse the repository at this point in the history
* Add UUIDv7 in UUIDGenerator Tool.

* Update Description.

* Update unit test (UuidHelper).

* Use RandomNumberGenerator.

* Update unit test.
  • Loading branch information
niyari authored Jun 25, 2024
1 parent 71ae6f0 commit d00b7c6
Show file tree
Hide file tree
Showing 44 changed files with 205 additions and 21 deletions.
31 changes: 19 additions & 12 deletions src/DevToys.Tools.UnitTests/Tools/Helpers/UuidHelperTests.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
using DevToys.Tools.Helpers;
using System.Text.RegularExpressions;
using DevToys.Tools.Helpers;
using DevToys.Tools.Models;

namespace DevToys.Tools.UnitTests.Tools.Helpers;

public class UuidHelperTests
{
[Theory]
[InlineData(UuidVersion.One, true, true)]
[InlineData(UuidVersion.One, false, true)]
[InlineData(UuidVersion.One, true, false)]
[InlineData(UuidVersion.One, false, false)]
[InlineData(UuidVersion.Four, true, true)]
[InlineData(UuidVersion.Four, false, true)]
[InlineData(UuidVersion.Four, true, false)]
[InlineData(UuidVersion.Four, false, false)]
internal void GenerateUuid(UuidVersion uuidVersion, bool hyphens, bool uppercase)
[InlineData(UuidVersion.One, true, true, 1)]
[InlineData(UuidVersion.One, false, true, 1)]
[InlineData(UuidVersion.One, true, false, 1)]
[InlineData(UuidVersion.One, false, false, 1)]
[InlineData(UuidVersion.Four, true, true, 4)]
[InlineData(UuidVersion.Four, false, true, 4)]
[InlineData(UuidVersion.Four, true, false, 4)]
[InlineData(UuidVersion.Four, false, false, 4)]
[InlineData(UuidVersion.Seven, true, true, 7)]
[InlineData(UuidVersion.Seven, false, true, 7)]
[InlineData(UuidVersion.Seven, true, false, 7)]
[InlineData(UuidVersion.Seven, false, false, 7)]
internal void GenerateUuid(UuidVersion uuidVersion, bool hyphens, bool uppercase, int version)
{
string newUuid
= UuidHelper.GenerateUuid(
uuidVersion,
hyphens,
uppercase);
TestUuid(newUuid, hyphens, uppercase);
TestUuid(newUuid, hyphens, uppercase, version);
}

private static void TestUuid(string uuid, bool hyphens, bool uppercase)
private static void TestUuid(string uuid, bool hyphens, bool uppercase, int version)
{
Guid.TryParse(uuid, out _).Should().BeTrue();
uuid.Contains('-').Should().Be(hyphens);
uuid.Length.Should().Be(hyphens ? 36 : 32);
uuid.Should().Be(uppercase ? uuid.ToUpperInvariant() : uuid.ToLowerInvariant());
string pattern = "^[0-9a-f]{8}-?[0-9a-f]{4}-?" + version + "[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$";
Regex.IsMatch(uuid.ToLowerInvariant(), pattern).Should().BeTrue();
}
}
57 changes: 52 additions & 5 deletions src/DevToys.Tools/Helpers/UuidHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DevToys.Tools.Models;
using System.Security.Cryptography;
using DevToys.Tools.Models;

namespace DevToys.Tools.Helpers;
internal static class UuidHelper
Expand All @@ -8,15 +9,20 @@ private enum GuidVersion
TimeBased = 0x01,
Reserved = 0x02,
NameBased = 0x03,
Random = 0x04
Random = 0x04,
NameBasedV5 = 0x05,
UuidV6 = 0x06,
UnixEpoch = 0x07
}

private static readonly Random random = new();
private static readonly RandomNumberGenerator cRandom = RandomNumberGenerator.Create();

private static readonly DateTimeOffset gregorianCalendarStart = new(1582, 10, 15, 0, 0, 0, TimeSpan.Zero);
private const int VariantByte = 8;
private const int VariantByteMask = 0x3f;
private const int VariantByteShift = 0x80;
private const int VariantByteShiftRFC = 0x80;
private const int VersionByte = 7;
private const int VersionByteMask = 0x0f;
private const int VersionByteShift = 4;
Expand All @@ -42,6 +48,10 @@ internal static string GenerateUuid(UuidVersion version, bool hyphens, bool uppe
{
uuid = GenerateTimeBasedGuid().ToString(guidStringFormat);
}
else if (version == UuidVersion.Seven)
{
uuid = GenerateUUIDv7().ToString(guidStringFormat);
}
else
{
uuid = Guid.NewGuid().ToString(guidStringFormat);
Expand Down Expand Up @@ -85,6 +95,43 @@ private static Guid GenerateTimeBasedGuid()
return new Guid(guid);
}

private static Guid GenerateUUIDv7()
{
// TTTTTTTT-TTTT-7aaa-rRRR-RRRRRRRRRRRR
// T=unix_ts_ms 7=version a=rand_a r=variant R=rand_b

// RRRRRRRR-RRRR-RRRR-RRRR-RRRRRRRRRRRR
byte[] guid = new byte[ByteArraySize];
cRandom.GetBytes(guid);

// timestamp
// If more precise timestamping or monotonicity is needed,
// the 12-bit space in rand_a and some space in rand_b can be used.
DateTimeOffset dateTime = DateTimeOffset.UtcNow;
long timestamp = dateTime.ToUnixTimeMilliseconds();

// 48-bit big-endian unsigned number of the Unix Epoch timestamp in milliseconds.
// TTTTTTTT-TTTT-****-****-************
guid[0] = (byte)((timestamp >> 40) & 0xFF);
guid[1] = (byte)((timestamp >> 32) & 0xFF);
guid[2] = (byte)((timestamp >> 24) & 0xFF);
guid[3] = (byte)((timestamp >> 16) & 0xFF);
guid[4] = (byte)((timestamp >> 8) & 0xFF);
guid[5] = (byte)(timestamp & 0xFF);

// set the version
// ********-****-7***-****-************
guid[6] &= (byte)VersionByteMask;
guid[6] |= (byte)((byte)GuidVersion.UnixEpoch << VersionByteShift);

// set the variant
// ********-****-****-r***-************
guid[8] &= (byte)VariantByteMask;
guid[8] |= (byte)VariantByteShiftRFC;

return new Guid(BitConverter.ToString(guid).Replace("-", ""));
}

public static byte[] GenerateNodeBytes()
{
byte[]? node = new byte[6];
Expand All @@ -101,14 +148,14 @@ public static byte[] GenerateClockSequenceBytes(DateTime dt)

if (bytes.Length == 0)
{
return new byte[] { 0x0, 0x0 };
return [0x0, 0x0];
}

if (bytes.Length == 1)
{
return new byte[] { 0x0, bytes[0] };
return [0x0, bytes[0]];
}

return new byte[] { bytes[0], bytes[1] };
return [bytes[0], bytes[1]];
}
}
3 changes: 2 additions & 1 deletion src/DevToys.Tools/Models/UuidVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
internal enum UuidVersion
{
One,
Four
Four,
Seven
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Zvolte verzi UUID, která se má vygenerovat</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Vælg den UUID-version, der skal genereres</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Wähle die zu generierende UUID-Version</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Seleccione la versión de UUID a generar</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Sélectionner la version du UUID à générer</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>生成する UUID のバージョン</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
<data name="UuidVersionOne" xml:space="preserve">
<value>1</value>
</data>
<data name="UuidVersionSeven" xml:space="preserve">
<value>7</value>
</data>
<data name="VersionDescription" xml:space="preserve">
<value>Choose the version of UUID to generate</value>
</data>
Expand Down
Loading

0 comments on commit d00b7c6

Please sign in to comment.