Skip to content

Commit e600fe5

Browse files
committed
main: dedicate a file for generators
1 parent 012ba3d commit e600fe5

File tree

4 files changed

+203
-178
lines changed

4 files changed

+203
-178
lines changed

generator.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright Chrono Technologies LLC
2+
// SPDX-License-Identifier: MIT
3+
4+
package main
5+
6+
import (
7+
"time"
8+
9+
"github.com/google/uuid"
10+
)
11+
12+
func generateUUIDV4() (uuid.UUID, error) {
13+
return uuid.NewRandom()
14+
}
15+
16+
func generateUUIDV7(customTime string) (uuid.UUID, error) {
17+
var err error
18+
var ret uuid.UUID
19+
var timestamp time.Time
20+
21+
if ret, err = uuid.NewV7(); err != nil {
22+
return uuid.UUID{}, err
23+
}
24+
25+
if len(customTime) == 0 {
26+
return ret, nil
27+
}
28+
29+
if timestamp, err = parseTimeInput(customTime); err != nil {
30+
return uuid.UUID{}, err
31+
}
32+
33+
// replace the first 6-bytes with the custom timestamp
34+
msec := timestamp.UnixMilli()
35+
36+
ret[0] = byte(msec >> 40)
37+
ret[1] = byte(msec >> 32)
38+
ret[2] = byte(msec >> 24)
39+
ret[3] = byte(msec >> 16)
40+
ret[4] = byte(msec >> 8)
41+
ret[5] = byte(msec)
42+
43+
return ret, nil
44+
}

generator_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright Chrono Technologies LLC
2+
// SPDX-License-Identifier: MIT
3+
4+
package main
5+
6+
import (
7+
"testing"
8+
"time"
9+
10+
"github.com/google/uuid"
11+
)
12+
13+
func TestGenerateUUIDV7WithCustomTime(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
input string
17+
wantTime time.Time
18+
wantErr bool
19+
}{
20+
{
21+
name: "with invalid string",
22+
input: "not-a-time",
23+
wantTime: time.Time{},
24+
wantErr: true,
25+
},
26+
{
27+
name: "with pre-1970 date string",
28+
input: "1969-12-31",
29+
wantTime: time.Time{},
30+
wantErr: true,
31+
},
32+
{
33+
name: "with pre-1970 rfc3339 format",
34+
input: "1969-12-31T23:59:59Z",
35+
wantTime: time.Time{},
36+
wantErr: true,
37+
},
38+
{
39+
name: "with pre-1970 iso8601 with offset",
40+
input: "1969-12-31T18:59:59-05:00",
41+
wantTime: time.Time{},
42+
wantErr: true,
43+
},
44+
{
45+
name: "with just before unix epoch",
46+
input: "1969-12-31T23:59:59.999Z",
47+
wantTime: time.Time{},
48+
wantErr: true,
49+
},
50+
{
51+
name: "with negative unix timestamp (seconds)",
52+
input: "-1687689000",
53+
wantTime: time.Time{},
54+
wantErr: true,
55+
},
56+
{
57+
name: "with negative unix timestamp (milliseconds)",
58+
input: "-1687689000123",
59+
wantTime: time.Time{},
60+
wantErr: true,
61+
},
62+
{
63+
name: "with unix epoch boundary",
64+
input: "1970-01-01T00:00:00Z",
65+
wantTime: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
66+
wantErr: false,
67+
},
68+
{
69+
name: "with only date",
70+
input: "2023-06-15",
71+
wantTime: time.Date(2023, 6, 15, 0, 0, 0, 0, time.UTC),
72+
wantErr: false,
73+
},
74+
{
75+
name: "with timezone-less datetime",
76+
input: "2023-06-15 10:30:00",
77+
wantTime: time.Date(2023, 6, 15, 10, 30, 0, 0, time.UTC),
78+
wantErr: false,
79+
},
80+
{
81+
name: "with seconds-less datetime",
82+
input: "2023-06-15 10:30",
83+
wantTime: time.Date(2023, 6, 15, 10, 30, 0, 0, time.UTC),
84+
wantErr: false,
85+
},
86+
{
87+
name: "with rfc3339 format",
88+
input: "2025-06-15T10:30:00.123Z",
89+
wantTime: time.Date(2025, 6, 15, 10, 30, 0, 123000000, time.UTC),
90+
wantErr: false,
91+
},
92+
{
93+
name: "with iso8601 format including timezone",
94+
input: "2025-06-15T10:30:00Z",
95+
wantTime: time.Date(2025, 6, 15, 10, 30, 0, 0, time.UTC),
96+
wantErr: false,
97+
},
98+
{
99+
name: "with iso8601 format including offset",
100+
input: "2023-06-15T10:30:00-07:00",
101+
wantTime: time.Date(2023, 6, 15, 17, 30, 0, 0, time.UTC),
102+
wantErr: false,
103+
},
104+
{
105+
name: "with unix timestamp (seconds)",
106+
input: "1687689000",
107+
wantTime: time.Unix(1687689000, 0),
108+
wantErr: false,
109+
},
110+
{
111+
name: "with unix timestamp (milliseconds)",
112+
input: "1687689000123",
113+
wantTime: time.UnixMilli(1687689000123),
114+
wantErr: false,
115+
},
116+
}
117+
118+
for _, test := range tests {
119+
t.Run(test.name, func(t *testing.T) {
120+
result, err := generateUUIDV7(test.input)
121+
122+
if test.wantErr {
123+
if err == nil {
124+
t.Errorf("expected error but got none")
125+
}
126+
return
127+
}
128+
129+
if err != nil {
130+
t.Errorf("unexpected error: %v", err)
131+
return
132+
}
133+
134+
if result.Version() != uuidV7 {
135+
t.Fatalf("unexpected uuid version, got: %d", result.Version())
136+
}
137+
138+
extractedTime := extractTimeFromUUIDV7(result)
139+
140+
if !extractedTime.Equal(test.wantTime) {
141+
t.Errorf("Time mismatch: got %v, want %v", extractedTime, test.wantTime)
142+
}
143+
})
144+
}
145+
}
146+
147+
func extractTimeFromUUIDV7(u uuid.UUID) time.Time {
148+
msec := int64(u[0])<<40 | int64(u[1])<<32 | int64(u[2])<<24 |
149+
int64(u[3])<<16 | int64(u[4])<<8 | int64(u[5])
150+
151+
return time.UnixMilli(msec)
152+
}

main.go

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Copyright Chrono Technologies LLC
2+
// SPDX-License-Identifier: MIT
3+
14
package main
25

36
import (
@@ -144,40 +147,6 @@ func generateHex(c *cli.Context) error {
144147
return nil
145148
}
146149

147-
func generateUUIDV4() (uuid.UUID, error) {
148-
return uuid.NewRandom()
149-
}
150-
151-
func generateUUIDV7(customTime string) (uuid.UUID, error) {
152-
var err error
153-
var ret uuid.UUID
154-
var timestamp time.Time
155-
156-
if ret, err = uuid.NewV7(); err != nil {
157-
return uuid.UUID{}, err
158-
}
159-
160-
if len(customTime) == 0 {
161-
return ret, nil
162-
}
163-
164-
if timestamp, err = parseTimeInput(customTime); err != nil {
165-
return uuid.UUID{}, err
166-
}
167-
168-
// replace the first 6-bytes with the custom timestamp
169-
msec := timestamp.UnixMilli()
170-
171-
ret[0] = byte(msec >> 40)
172-
ret[1] = byte(msec >> 32)
173-
ret[2] = byte(msec >> 24)
174-
ret[3] = byte(msec >> 16)
175-
ret[4] = byte(msec >> 8)
176-
ret[5] = byte(msec)
177-
178-
return ret, nil
179-
}
180-
181150
// generateUUID generates one or more UUID strings in hexadeicmal. It defaults
182151
// to generating version 7 UUIDs but also supports the widely used version 4.
183152
func generateUUID(c *cli.Context) error {
@@ -245,7 +214,7 @@ func generateBase64(c *cli.Context) error {
245214
return paintError(errBlankDelimiter)
246215
}
247216

248-
for i := 0; i < iterations; i++ {
217+
for i := range iterations {
249218
src, err := randomBytes(c.Int(bytesParam))
250219

251220
if err != nil {

0 commit comments

Comments
 (0)