Skip to content

Commit a0f3576

Browse files
committed
Add tests and fix bugs
1 parent e8754df commit a0f3576

11 files changed

+304
-104
lines changed

.editorconfig

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*.{fs,fsx,fsi}]
7+
fsharp_bar_before_discriminated_union_declaration = true
8+
fsharp_multiline_block_brackets_on_same_column = true
9+
fsharp_multiline_bracket_style = aligned

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ bin/
33
obj/
44

55
# Benchmark Results
6-
BenchmarkDotNet.Artifacts/
6+
BenchmarkDotNet.Artifacts/
7+
8+
# Visual Studio
9+
.vs/

UUIDv7.Benchmarks/Program.fs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
open System
2+
open System.Diagnostics
3+
open BenchmarkDotNet.Attributes
4+
5+
open UUIDv7
6+
open BenchmarkDotNet.Running
7+
8+
[<MemoryDiagnoser>]
9+
type Benchmark1() =
10+
11+
[<Benchmark>]
12+
member __.Test1k() =
13+
let mutable uuid = UUIDv7()
14+
15+
for i in 0..1_000 do
16+
uuid <- UUIDv7.New()
17+
18+
uuid
19+
20+
[<Benchmark>]
21+
member __.Test1M() =
22+
let mutable uuid = UUIDv7.New()
23+
24+
for i in 0..1_000_000 do
25+
uuid <- UUIDv7.New()
26+
27+
uuid
28+
29+
[<Benchmark>]
30+
member __.Test10M() =
31+
let mutable uuid = UUIDv7.New()
32+
33+
for i in 0..10_000_000 do
34+
uuid <- UUIDv7.New()
35+
36+
uuid
37+
38+
[<Benchmark>]
39+
member __.Test1kToString() =
40+
let mutable s = ""
41+
42+
for i in 0..1_000 do
43+
s <- UUIDv7.New().ToString()
44+
45+
s
46+
47+
[<Benchmark>]
48+
member __.Test1kGuid() =
49+
let mutable s = Guid.Empty
50+
51+
for i in 0..1_000 do
52+
s <- Guid.NewGuid()
53+
54+
s
55+
56+
57+
[<EntryPoint>]
58+
let main _ =
59+
let _ = BenchmarkRunner.Run<Benchmark1>()
60+
0
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net7.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<Compile Include="Program.fs" />
10+
</ItemGroup>
11+
<ItemGroup>
12+
<ProjectReference Include="../UUIDv7/UUIDv7.fsproj" />
13+
</ItemGroup>
14+
<ItemGroup>
15+
<PackageReference Include="BenchmarkDotNet" Version="0.13.9" />
16+
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.9" />
17+
</ItemGroup>
18+
19+
</Project>

UUIDv7.Tests/Program.fs

+77-39
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,98 @@
1-
open System
2-
open System.Diagnostics
3-
open BenchmarkDotNet.Attributes
1+
module UUIDv7Tests
2+
3+
open System
4+
open Expecto
45

56
open UUIDv7
6-
open BenchmarkDotNet.Running
77

8-
[<MemoryDiagnoser>]
9-
type Benchmark1() =
8+
let checkInvariants (uuid: UUIDv7) =
9+
let guid = uuid.ToGuid()
10+
let uuidString = uuid.ToString()
11+
let guidString = guid.ToString("D")
12+
13+
"UUIDv7 should be valid Guid"
14+
|> Expect.equal uuidString guidString
15+
16+
"UUIDv7 should have valid Variant"
17+
|> Expect.equal uuid.Variant 2UL
18+
19+
"UUIDv7 should have valid Version"
20+
|> Expect.equal uuid.Version 7UL
21+
22+
"UUID7 Random bits are non-zero"
23+
|> Expect.isGreaterThan (uuid.Low &&& 0xFFFF_FFFF_FFFFUL) 0UL
1024

11-
[<Benchmark>]
12-
member __.Test1k() =
13-
let mutable uuid = UUIDv7()
1425

15-
for i in 0..1_000 do
16-
uuid <- UUIDv7.New()
26+
[<Tests>]
27+
let tests =
28+
testList
29+
"UUIDv7"
30+
[
31+
test "UUIDv7s are generated in order" {
32+
let rng = Random(123)
1733

18-
uuid
34+
for i in 1..100 do
35+
let count = rng.Next(2, 10_000)
36+
let uuids = Array.init count (fun _ -> UUIDv7.New())
37+
let sorted = uuids |> Array.sort
38+
Expect.equal sorted uuids "UUIDv7 should be generated in order"
39+
for i in 0..count-2 do
40+
Expect.isLessThan uuids.[i] uuids.[i+1] "UUIDv7 should be generated in order"
1941

20-
[<Benchmark>]
21-
member __.Test1M() =
22-
let mutable uuid = UUIDv7.New()
42+
for uuid in uuids do
43+
checkInvariants uuid
44+
}
2345

24-
for i in 0..1_000_000 do
25-
uuid <- UUIDv7.New()
46+
test "UUIDv7 contains unix seconds in first bits" {
47+
let rng = Random(123)
2648

27-
uuid
49+
for i in 1..100 do
50+
let uuid = UUIDv7.New()
51+
let unixTime = uuid.ToUnixTimeSeconds()
52+
let now = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
2853

29-
[<Benchmark>]
30-
member __.Test10M() =
31-
let mutable uuid = UUIDv7.New()
54+
Expect.isLessThanOrEqual
55+
(abs (unixTime - now))
56+
1L
57+
"UUIDv7 should contain unix seconds in first bits"
3258

33-
for i in 0..10_000_000 do
34-
uuid <- UUIDv7.New()
59+
Threading.Thread.Sleep(rng.Next(1, 100))
60+
checkInvariants uuid
61+
}
3562

36-
uuid
63+
test "UUID7 HighBits are always equal or increasing" {
64+
let highBits = UUIDv7Helpers.HighBits()
3765

38-
[<Benchmark>]
39-
member __.Test1kToString() =
40-
let mutable s = ""
66+
for i in 1..10_000_000 do
67+
let highBits0 = highBits.Next()
68+
let highBits1 = highBits.Next()
69+
let highBits2 = highBits.Next()
70+
let highBits3 = highBits.Next()
71+
let highBits4 = highBits.Next()
4172

42-
for i in 0..1_000 do
43-
s <- UUIDv7.New().ToString()
73+
Expect.isLessThanOrEqual highBits0 highBits1 "UUID7 HighBits is always equal or increasing 1"
74+
Expect.isLessThanOrEqual highBits1 highBits2 "UUID7 HighBits is always equal or increasing 2"
75+
Expect.isLessThanOrEqual highBits2 highBits3 "UUID7 HighBits is always equal or increasing 3"
76+
Expect.isLessThanOrEqual highBits3 highBits4 "UUID7 HighBits is always equal or increasing 4"
77+
}
4478

45-
s
79+
test "UUID7 LowBits are always increasing" {
80+
let highBits = UUIDv7Helpers.HighBits()
81+
let lowBits = UUIDv7Helpers.LowBits()
82+
let mutable highBits0 = highBits.Next()
4683

47-
[<Benchmark>]
48-
member __.Test1kGuid() =
49-
let mutable s = Guid.Empty
84+
for i in 1..10_000_000 do
85+
let lowBits0 = lowBits.TryNext(highBits0)
86+
let lowBits1 = lowBits.TryNext(highBits0)
5087

51-
for i in 0..1_000 do
52-
s <- Guid.NewGuid()
88+
match lowBits0, lowBits1 with
89+
| ValueSome lowBits0, ValueSome lowBits1 ->
90+
Expect.isLessThan lowBits0 lowBits1 "UUID7 LowBits is always increasing"
91+
| _ -> highBits0 <- highBits.Next()
92+
}
93+
]
5394

54-
s
5595

5696

5797
[<EntryPoint>]
58-
let main _ =
59-
let _ = BenchmarkRunner.Run<Benchmark1>()
60-
0
98+
let main args = runTestsInAssemblyWithCLIArgs [] args

UUIDv7.Tests/UUIDv7.Tests.fsproj

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
<ProjectReference Include="../UUIDv7/UUIDv7.fsproj" />
1313
</ItemGroup>
1414
<ItemGroup>
15-
<PackageReference Include="BenchmarkDotNet" Version="0.13.9" />
16-
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.9" />
15+
<PackageReference Include="expecto" Version="10.1.0" />
16+
<PackageReference Include="expecto.fscheck" Version="10.1.0" />
17+
<PackageReference Include="yolodev.expecto.testsdk" Version="0.14.2" />
1718
</ItemGroup>
1819

1920
</Project>

UUIDv7.sln

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.0.31903.59
@@ -7,6 +7,15 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UUIDv7", "UUIDv7\UUIDv7.fsp
77
EndProject
88
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UUIDv7.Tests", "UUIDv7.Tests\UUIDv7.Tests.fsproj", "{3671DE56-B48B-414B-8B86-9B37F85DE01F}"
99
EndProject
10+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UUIDv7.Benchmarks", "UUIDv7.Benchmarks\UUIDv7.Benchmarks.fsproj", "{1202DB42-43FA-4BD2-B8BB-FC96FF9FCDBC}"
11+
EndProject
12+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{C77E7FD0-E977-4FD6-8C28-6DBF9BFF70BF}"
13+
ProjectSection(SolutionItems) = preProject
14+
.editorconfig = .editorconfig
15+
.gitignore = .gitignore
16+
LICENSE = LICENSE
17+
EndProjectSection
18+
EndProject
1019
Global
1120
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1221
Debug|Any CPU = Debug|Any CPU
@@ -24,5 +33,9 @@ Global
2433
{3671DE56-B48B-414B-8B86-9B37F85DE01F}.Debug|Any CPU.Build.0 = Debug|Any CPU
2534
{3671DE56-B48B-414B-8B86-9B37F85DE01F}.Release|Any CPU.ActiveCfg = Release|Any CPU
2635
{3671DE56-B48B-414B-8B86-9B37F85DE01F}.Release|Any CPU.Build.0 = Release|Any CPU
36+
{1202DB42-43FA-4BD2-B8BB-FC96FF9FCDBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37+
{1202DB42-43FA-4BD2-B8BB-FC96FF9FCDBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
38+
{1202DB42-43FA-4BD2-B8BB-FC96FF9FCDBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
39+
{1202DB42-43FA-4BD2-B8BB-FC96FF9FCDBC}.Release|Any CPU.Build.0 = Release|Any CPU
2740
EndGlobalSection
2841
EndGlobal

UUIDv7/AssemblyInfo.fs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module AssemblyInfo
2+
3+
open System
4+
open System.Reflection
5+
open System.Runtime.InteropServices
6+
open System.Runtime.CompilerServices
7+
8+
[<assembly: InternalsVisibleTo("UUIDv7.Tests")>]
9+
do ()

0 commit comments

Comments
 (0)