dotnet 9 and sequential id
This commit is contained in:
@@ -36,7 +36,7 @@ public class Decode
|
||||
var actualBytesArray = Base32.Decode(str);
|
||||
actualBytesArray.Should().Equal(expected);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("ZFXJMF5N====", new byte[] { 0b11001001, 0b01101110, 0b10010110, 0b00010111, 0b10101101, })]
|
||||
[InlineData("CPIKTMY=====", new byte[] { 0b00010011, 0b11010000, 0b10101001, 0b10110011, })]
|
||||
@@ -72,7 +72,7 @@ public class Decode
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
public void WhenCalledWithNullString_ShouldReturnEmptyArray(string testString)
|
||||
public void WhenCalledWithNullString_ShouldReturnEmptyArray(string? testString)
|
||||
{
|
||||
Base32.Decode(testString).Should().BeEmpty();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ public class Encode
|
||||
[InlineData("GSHXGB5ORKNDSFLSU2YWALI=")]
|
||||
[InlineData("TMFSC64ZZNPQSNGCFIODS7TR")]
|
||||
[InlineData("ZTDUBU4QZFFMDJKBII334EIB")]
|
||||
[InlineData("2IO2HTALCXZWCBD2AAAAAAAAAAAA====")]
|
||||
[InlineData("WXYEOQUZULMCY6ZQTDOLTRUZZMKQ====")]
|
||||
[InlineData("FG4M3ZQM3TVWDMBUP5L7N7V3JS7KBM2E")]
|
||||
public void WhenDecodedFromString_ShouldBeEncodedToTheSameString(string testString)
|
||||
{
|
||||
var resultBytes = Base32.Decode(testString);
|
||||
@@ -34,6 +37,8 @@ public class Encode
|
||||
[Theory]
|
||||
[InlineData("FG4M3ZQM3TVWDMBUP5L7N7V3JS7KBM2E", new byte[] { 0x29, 0xb8, 0xcd, 0xe6, 0x0c, 0xdc, 0xeb, 0x61, 0xb0, 0x34, 0x7f, 0x57, 0xf6, 0xfe, 0xbb, 0x4c, 0xbe, 0xa0, 0xb3, 0x44, })]
|
||||
[InlineData("WXYEOQUZULMCY6ZQTDOLTRUZZMKQ====", new byte[] { 0xb5, 0xf0, 0x47, 0x42, 0x99, 0xa2, 0xd8, 0x2c, 0x7b, 0x30, 0x98, 0xdc, 0xb9, 0xc6, 0x99, 0xcb, 0x15, })]
|
||||
[InlineData("2IO2HTALCXZWCBD2AAAAAAAAAAAA====", new byte[] { 0xd2, 0x1d, 0xa3, 0xcc, 0x0b, 0x15, 0xf3, 0x61, 0x04, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, })]
|
||||
[InlineData("2IO2HTALCXZWCBD2AAAAAAAA", new byte[] { 0xd2, 0x1d, 0xa3, 0xcc, 0x0b, 0x15, 0xf3, 0x61, 0x04, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, })]
|
||||
[InlineData("2IO2HTALCXZWCBD2", new byte[] { 0xd2, 0x1d, 0xa3, 0xcc, 0x0b, 0x15, 0xf3, 0x61, 0x04, 0x7a, })]
|
||||
[InlineData("ZFXJMF5N", new byte[] { 0b11001001, 0b01101110, 0b10010110, 0b00010111, 0b10101101, })]
|
||||
[InlineData("CPIKTMY=", new byte[] { 0b00010011, 0b11010000, 0b10101001, 0b10110011, })]
|
||||
@@ -48,7 +53,7 @@ public class Encode
|
||||
[Theory]
|
||||
[InlineData(new byte[] { })]
|
||||
[InlineData(null)]
|
||||
public void WhenCalledWithEmptyByteArray_ShouldReturnEmptyString(byte[] testArray)
|
||||
public void WhenCalledWithEmptyByteArray_ShouldReturnEmptyString(byte[]? testArray)
|
||||
{
|
||||
var actualBase32 = Base32.Encode(testArray);
|
||||
actualBase32.Should().Be(string.Empty);
|
||||
@@ -57,7 +62,7 @@ public class Encode
|
||||
[Theory]
|
||||
[InlineData(new byte[] { })]
|
||||
[InlineData(null)]
|
||||
public void WhenCalledWithEmptyByteArray_ShouldReturnZeroAndNotChangeOutput(byte[] testArray)
|
||||
public void WhenCalledWithEmptyByteArray_ShouldReturnZeroAndNotChangeOutput(byte[]? testArray)
|
||||
{
|
||||
char[] output = ['1', '2', '3', '4'];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -3,15 +3,15 @@ namespace Just.Core.Tests.GuidV8Tests;
|
||||
public class NewGuid
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
-25000000, -10000000, -5000000, -2000000, -1000000, -500000, -250000, -100000, -25000, -10000, -5000,
|
||||
-2500, -1000, -500, -499, -497, -450, -300, -200, -50, -1, 0, 1, 2, 5, 10, 20, 50, 100, 200, 350, 500, 1000,
|
||||
2500, 5000, 10000, 25000, 100000, 250000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000, 250000000)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
-25000000, -10000000, -5000000, -2000000, -1000000, -500000, -250000, -100000, -25000, -10000, -5000,
|
||||
-2500, -1000, -500, -499, -497, -450, -300, -200, -50, -1, 0, 1, 2, 5, 10, 20, 50, 100, 200, 350, 500, 1000,
|
||||
2500, 5000, 10000, 25000, 100000, 250000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000, 250000000)]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
-9863, -9740, -9214, -8878, -8674, -8652, -8640, -8565, -8518, -8449,
|
||||
-8390, -8193, -8108, -7808, -7501, -7203, -7133, -7020, -6983, -6855,
|
||||
-6576, -6162, -5630, -5505, -5472, -5382, -4706, -4680, -4509, -4454,
|
||||
@@ -22,7 +22,7 @@ public class NewGuid
|
||||
4163, 4198, 4366, 4662, 4746, 4879, 5467, 5601, 5912, 5979,
|
||||
6128, 6277, 6323, 6437, 6699, 6853, 7556, 7776, 7795, 8099,
|
||||
8336, 8592, 8682, 8683, 8818, 8904, 9375, 9466, 9551, 9708)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
-9863, -9740, -9214, -8878, -8674, -8652, -8640, -8565, -8518, -8449,
|
||||
-8390, -8193, -8108, -7808, -7501, -7203, -7133, -7020, -6983, -6855,
|
||||
-6576, -6162, -5630, -5505, -5472, -5382, -4706, -4680, -4509, -4454,
|
||||
@@ -33,7 +33,7 @@ public class NewGuid
|
||||
4163, 4198, 4366, 4662, 4746, 4879, 5467, 5601, 5912, 5979,
|
||||
6128, 6277, 6323, 6437, 6699, 6853, 7556, 7776, 7795, 8099,
|
||||
8336, 8592, 8682, 8683, 8818, 8904, 9375, 9466, 9551, 9708)]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
5635912, 6673780, 17277183, 17512959, 19098799, 21672621, 30581958, 30824885, 31874213, 35192781,
|
||||
36337094, 37752116, 38387215, 39154682, 40525427, 52288093, 55218356, 59065156, 65231785, 75430932,
|
||||
76289058, 79078058, 85770685, 85925884, 94726743, 94864163, 95781967, 96150006, 96482085, 102570414,
|
||||
@@ -44,7 +44,7 @@ public class NewGuid
|
||||
292563035, 299285016, 303834917, 310357836, 315078337, 316367236, 318311758, 318873972, 319675272, 321784171,
|
||||
324204294, 327667283, 330287252, 338438172, 349863360, 360777768, 366398711, 368637150, 368776734, 371900343,
|
||||
379094084, 379818879, 381448333, 381814627, 382393101, 382483709, 385600870, 389455134, 396115960, 399364095)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
5635912, 6673780, 17277183, 17512959, 19098799, 21672621, 30581958, 30824885, 31874213, 35192781,
|
||||
36337094, 37752116, 38387215, 39154682, 40525427, 52288093, 55218356, 59065156, 65231785, 75430932,
|
||||
76289058, 79078058, 85770685, 85925884, 94726743, 94864163, 95781967, 96150006, 96482085, 102570414,
|
||||
@@ -55,7 +55,7 @@ public class NewGuid
|
||||
292563035, 299285016, 303834917, 310357836, 315078337, 316367236, 318311758, 318873972, 319675272, 321784171,
|
||||
324204294, 327667283, 330287252, 338438172, 349863360, 360777768, 366398711, 368637150, 368776734, 371900343,
|
||||
379094084, 379818879, 381448333, 381814627, 382393101, 382483709, 385600870, 389455134, 396115960, 399364095)]
|
||||
public void Guids_Differing_By_Minutes_Should_Be_Sortable(GuidV8Entropy entropy, params int[] seconds)
|
||||
public void Guids_Differing_By_Minutes_Should_Be_Sortable(RngEntropy entropy, params int[] seconds)
|
||||
{
|
||||
var rng = new Random(25);
|
||||
var referenceTime = new DateTime(2024, 05, 17, 15, 36, 13, 771, DateTimeKind.Utc);
|
||||
@@ -77,15 +77,15 @@ public class NewGuid
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
-250000000, -25000000, -10000000, -5000000, -2000000, -1000000, -500000, -250000, -100000, -25000, -10000, -5000,
|
||||
-2500, -1000, -500, -499, -497, -450, -300, -200, -50, -1, 0, 1, 2, 5, 10, 20, 50, 100, 200, 350, 500, 1000,
|
||||
2500, 5000, 10000, 25000, 100000, 250000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000, 2100000000)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
-250000000, -25000000, -10000000, -5000000, -2000000, -1000000, -500000, -250000, -100000, -25000, -10000, -5000,
|
||||
-2500, -1000, -500, -499, -497, -450, -300, -200, -50, -1, 0, 1, 2, 5, 10, 20, 50, 100, 200, 350, 500, 1000,
|
||||
2500, 5000, 10000, 25000, 100000, 250000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000, 2100000000)]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
-9863, -9740, -9214, -8878, -8674, -8652, -8640, -8565, -8518, -8449,
|
||||
-8390, -8193, -8108, -7808, -7501, -7203, -7133, -7020, -6983, -6855,
|
||||
-6576, -6162, -5630, -5505, -5472, -5382, -4706, -4680, -4509, -4454,
|
||||
@@ -96,7 +96,7 @@ public class NewGuid
|
||||
4163, 4198, 4366, 4662, 4746, 4879, 5467, 5601, 5912, 5979,
|
||||
6128, 6277, 6323, 6437, 6699, 6853, 7556, 7776, 7795, 8099,
|
||||
8336, 8592, 8682, 8683, 8818, 8904, 9375, 9466, 9551, 9708)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
-9863, -9740, -9214, -8878, -8674, -8652, -8640, -8565, -8518, -8449,
|
||||
-8390, -8193, -8108, -7808, -7501, -7203, -7133, -7020, -6983, -6855,
|
||||
-6576, -6162, -5630, -5505, -5472, -5382, -4706, -4680, -4509, -4454,
|
||||
@@ -107,7 +107,7 @@ public class NewGuid
|
||||
4163, 4198, 4366, 4662, 4746, 4879, 5467, 5601, 5912, 5979,
|
||||
6128, 6277, 6323, 6437, 6699, 6853, 7556, 7776, 7795, 8099,
|
||||
8336, 8592, 8682, 8683, 8818, 8904, 9375, 9466, 9551, 9708)]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
6629058, 24114993, 40561510, 46245969, 46876997, 48747281, 80489854, 110237218, 117445694, 118974860,
|
||||
135132579, 141760591, 149114066, 158322437, 159065333, 164925904, 173848639, 175086337, 175704556, 176335514,
|
||||
200302773, 207133553, 230088723, 234521706, 239587338, 263755571, 264571928, 290118284, 292346548, 319322378,
|
||||
@@ -118,7 +118,7 @@ public class NewGuid
|
||||
749379956, 757561933, 758668417, 761735205, 770349479, 797570403, 805896481, 809050934, 821655964, 821980469,
|
||||
830824227, 840429528, 851772315, 859717719, 859763860, 867675943, 912124563, 914880620, 923914294, 930298008,
|
||||
932610035, 937468680, 945565998, 949277691, 949397209, 951283050, 953249971, 953953188, 976210158, 982233484, 982233485)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
6629058, 24114993, 40561510, 46245969, 46876997, 48747281, 80489854, 110237218, 117445694, 118974860,
|
||||
135132579, 141760591, 149114066, 158322437, 159065333, 164925904, 173848639, 175086337, 175704556, 176335514,
|
||||
200302773, 207133553, 230088723, 234521706, 239587338, 263755571, 264571928, 290118284, 292346548, 319322378,
|
||||
@@ -129,7 +129,7 @@ public class NewGuid
|
||||
749379956, 757561933, 758668417, 761735205, 770349479, 797570403, 805896481, 809050934, 821655964, 821980469,
|
||||
830824227, 840429528, 851772315, 859717719, 859763860, 867675943, 912124563, 914880620, 923914294, 930298008,
|
||||
932610035, 937468680, 945565998, 949277691, 949397209, 951283050, 953249971, 953953188, 976210158, 982233484, 982233485)]
|
||||
public void Guids_Differing_By_Seconds_Should_Be_Sortable(GuidV8Entropy entropy, params int[] seconds)
|
||||
public void Guids_Differing_By_Seconds_Should_Be_Sortable(RngEntropy entropy, params int[] seconds)
|
||||
{
|
||||
var rng = new Random(25);
|
||||
var referenceTime = new DateTime(2024, 05, 17, 15, 36, 13, 771, DateTimeKind.Utc);
|
||||
@@ -151,15 +151,15 @@ public class NewGuid
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
-250000000, -25000000, -10000000, -5000000, -2000000, -1000000, -500000, -250000, -100000, -25000, -10000, -5000,
|
||||
-2500, -1000, -500, -499, -497, -450, -300, -200, -50, -1, 0, 1, 2, 5, 10, 20, 50, 100, 200, 350, 500, 1000,
|
||||
2500, 5000, 10000, 25000, 100000, 250000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000, 2100000000)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
-250000000, -25000000, -10000000, -5000000, -2000000, -1000000, -500000, -250000, -100000, -25000, -10000, -5000,
|
||||
-2500, -1000, -500, -499, -497, -450, -300, -200, -50, -1, 0, 1, 2, 5, 10, 20, 50, 100, 200, 350, 500, 1000,
|
||||
2500, 5000, 10000, 25000, 100000, 250000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000, 2100000000)]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
-9863, -9740, -9214, -8878, -8674, -8652, -8640, -8565, -8518, -8449,
|
||||
-8390, -8193, -8108, -7808, -7501, -7203, -7133, -7020, -6983, -6855,
|
||||
-6576, -6162, -5630, -5505, -5472, -5382, -4706, -4680, -4509, -4454,
|
||||
@@ -170,7 +170,7 @@ public class NewGuid
|
||||
4163, 4198, 4366, 4662, 4746, 4879, 5467, 5601, 5912, 5979,
|
||||
6128, 6277, 6323, 6437, 6699, 6853, 7556, 7776, 7795, 8099,
|
||||
8336, 8592, 8682, 8683, 8818, 8904, 9375, 9466, 9551, 9708)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
-9863, -9740, -9214, -8878, -8674, -8652, -8640, -8565, -8518, -8449,
|
||||
-8390, -8193, -8108, -7808, -7501, -7203, -7133, -7020, -6983, -6855,
|
||||
-6576, -6162, -5630, -5505, -5472, -5382, -4706, -4680, -4509, -4454,
|
||||
@@ -181,7 +181,7 @@ public class NewGuid
|
||||
4163, 4198, 4366, 4662, 4746, 4879, 5467, 5601, 5912, 5979,
|
||||
6128, 6277, 6323, 6437, 6699, 6853, 7556, 7776, 7795, 8099,
|
||||
8336, 8592, 8682, 8683, 8818, 8904, 9375, 9466, 9551, 9708)]
|
||||
[InlineData(GuidV8Entropy.Weak,
|
||||
[InlineData(RngEntropy.Weak,
|
||||
6629058, 24114993, 40561510, 46245969, 46876997, 48747281, 80489854, 110237218, 117445694, 118974860,
|
||||
135132579, 141760591, 149114066, 158322437, 159065333, 164925904, 173848639, 175086337, 175704556, 176335514,
|
||||
200302773, 207133553, 230088723, 234521706, 239587338, 263755571, 264571928, 290118284, 292346548, 319322378,
|
||||
@@ -192,7 +192,7 @@ public class NewGuid
|
||||
749379956, 757561933, 758668417, 761735205, 770349479, 797570403, 805896481, 809050934, 821655964, 821980469,
|
||||
830824227, 840429528, 851772315, 859717719, 859763860, 867675943, 912124563, 914880620, 923914294, 930298008,
|
||||
932610035, 937468680, 945565998, 949277691, 949397209, 951283050, 953249971, 953953188, 976210158, 982233484, 982233485)]
|
||||
[InlineData(GuidV8Entropy.Strong,
|
||||
[InlineData(RngEntropy.Strong,
|
||||
6629058, 24114993, 40561510, 46245969, 46876997, 48747281, 80489854, 110237218, 117445694, 118974860,
|
||||
135132579, 141760591, 149114066, 158322437, 159065333, 164925904, 173848639, 175086337, 175704556, 176335514,
|
||||
200302773, 207133553, 230088723, 234521706, 239587338, 263755571, 264571928, 290118284, 292346548, 319322378,
|
||||
@@ -203,7 +203,7 @@ public class NewGuid
|
||||
749379956, 757561933, 758668417, 761735205, 770349479, 797570403, 805896481, 809050934, 821655964, 821980469,
|
||||
830824227, 840429528, 851772315, 859717719, 859763860, 867675943, 912124563, 914880620, 923914294, 930298008,
|
||||
932610035, 937468680, 945565998, 949277691, 949397209, 951283050, 953249971, 953953188, 976210158, 982233484, 982233485)]
|
||||
public void Guids_Differing_By_Milliseconds_Should_Be_Sortable(GuidV8Entropy entropy, params int[] seconds)
|
||||
public void Guids_Differing_By_Milliseconds_Should_Be_Sortable(RngEntropy entropy, params int[] seconds)
|
||||
{
|
||||
var rng = new Random(26);
|
||||
var referenceTime = new DateTime(2024, 05, 17, 15, 36, 13, 771, DateTimeKind.Utc);
|
||||
|
||||
140
Core.Tests/SeqIdTests/NextId.cs
Normal file
140
Core.Tests/SeqIdTests/NextId.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
namespace Just.Core.Tests.SeqIdTests;
|
||||
|
||||
public class NextId
|
||||
{
|
||||
private static readonly DateTime TestEpoch = new(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
private readonly SeqId _seqId = new(TestEpoch);
|
||||
|
||||
private const int TimestampShift = 22; // 63 - 41 = 22
|
||||
private const long TimestampMask = 0x1FFFFFFFFFF; // 41 bits mask
|
||||
private const int SeqShift = 14; // TimestampShift - 8 = 14
|
||||
private const long SeqMask = 0xFF; // 8 bits mask
|
||||
private const long RandMask = 0x3FFF; // 14 bits mask (since 2^14 = 16384)
|
||||
|
||||
[Fact]
|
||||
public void NextId_ShouldHaveCorrectBitStructure()
|
||||
{
|
||||
// Arrange
|
||||
var time = TestEpoch.AddMilliseconds(500);
|
||||
|
||||
// Act
|
||||
long id = _seqId.Next(time);
|
||||
|
||||
// Assert
|
||||
long timestampPart = (id >> TimestampShift) & TimestampMask;
|
||||
long sequencePart = (id >> SeqShift) & SeqMask;
|
||||
long randomPart = id & RandMask;
|
||||
|
||||
timestampPart.Should().Be(500);
|
||||
sequencePart.Should().Be(0);
|
||||
randomPart.Should().BeInRange(0, RandMask);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextId_ShouldIncrementSequenceForSameTimestamp()
|
||||
{
|
||||
// Arrange
|
||||
var time = TestEpoch.AddMilliseconds(100);
|
||||
|
||||
// Act
|
||||
long id1 = _seqId.Next(time);
|
||||
long id2 = _seqId.Next(time);
|
||||
|
||||
// Assert
|
||||
long sequence1 = (id1 >> SeqShift) & SeqMask;
|
||||
long sequence2 = (id2 >> SeqShift) & SeqMask;
|
||||
|
||||
sequence2.Should().Be(sequence1 + 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextId_ShouldResetSequenceForNewTimestamp()
|
||||
{
|
||||
// Arrange
|
||||
var time1 = TestEpoch.AddMilliseconds(100);
|
||||
var time2 = time1.AddMilliseconds(1);
|
||||
|
||||
// Act
|
||||
_ = _seqId.Next(time1); // Sequence increments to 0
|
||||
_ = _seqId.Next(time1); // Sequence increments to 1
|
||||
long id = _seqId.Next(time2); // Should reset to 0
|
||||
|
||||
// Assert
|
||||
long sequence = (id >> SeqShift) & SeqMask;
|
||||
sequence.Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextId_ShouldThrowWhenTimestampDecreases()
|
||||
{
|
||||
// Arrange
|
||||
var time1 = TestEpoch.AddMilliseconds(200);
|
||||
var time2 = TestEpoch.AddMilliseconds(100);
|
||||
|
||||
// Act & Assert
|
||||
_seqId.Next(time1); // First call sets last timestamp
|
||||
Action act = () => _seqId.Next(time2);
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("Refused to create new SeqId. Last timestamp is in the future.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextId_ShouldThrowWhenSequenceExhausted()
|
||||
{
|
||||
// Arrange
|
||||
var time = TestEpoch.AddMilliseconds(200);
|
||||
|
||||
// Act & Assert
|
||||
for (int i = 0; i < 255; i++)
|
||||
{
|
||||
_seqId.Next(time); // Exhauste sequence
|
||||
}
|
||||
Action act = () => _seqId.Next(time);
|
||||
act.Should().Throw<IndexOutOfRangeException>()
|
||||
.WithMessage("Refused to create new SeqId. Sequence exhausted.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextId_WithStrongEntropy_ShouldSetLower14Bits()
|
||||
{
|
||||
// Arrange
|
||||
var time = TestEpoch.AddMilliseconds(300);
|
||||
|
||||
// Act
|
||||
long id = _seqId.Next(time, RngEntropy.Strong);
|
||||
|
||||
// Assert
|
||||
long randomPart = id & RandMask;
|
||||
randomPart.Should().BeInRange(0, RandMask);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextId_WithWeakEntropy_ShouldSetLower14Bits()
|
||||
{
|
||||
// Arrange
|
||||
var time = TestEpoch.AddMilliseconds(400);
|
||||
|
||||
// Act
|
||||
long id = _seqId.Next(time, RngEntropy.Weak);
|
||||
|
||||
// Assert
|
||||
long randomPart = id & RandMask;
|
||||
randomPart.Should().BeInRange(0, RandMask);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultInstance_NextId_ShouldUseDefaultEpoch()
|
||||
{
|
||||
// Arrange
|
||||
var now = DateTime.UtcNow;
|
||||
var defaultEpoch = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
long expectedTimestamp = (long)(now - defaultEpoch).TotalMilliseconds;
|
||||
|
||||
// Act
|
||||
long id = SeqId.NextId();
|
||||
|
||||
// Assert
|
||||
long timestampPart = (id >> TimestampShift) & TimestampMask;
|
||||
timestampPart.Should().BeCloseTo(expectedTimestamp & TimestampMask, 1); // Mask handles overflow
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user