309 lines
6.3 KiB
Go
309 lines
6.3 KiB
Go
package ulid
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func getTestRandomSource() *rand.Rand {
|
|
// nolint
|
|
return rand.New(rand.NewSource(0))
|
|
}
|
|
|
|
func TestTimeMSBytes(t *testing.T) {
|
|
runAll := true
|
|
|
|
type testData struct {
|
|
TestName string
|
|
RunIt bool
|
|
Time time.Time
|
|
Expected []byte
|
|
Error bool
|
|
}
|
|
|
|
tests := []testData{
|
|
{
|
|
TestName: "normal time",
|
|
RunIt: false || runAll,
|
|
Time: time.Date(2024, 02, 16, 14, 02, 15, 17, time.UTC),
|
|
Expected: []byte{0x01, 0x8D, 0xB2, 0x39, 0x96, 0x58},
|
|
Error: false,
|
|
},
|
|
{
|
|
TestName: "zero time",
|
|
RunIt: false || runAll,
|
|
Time: time.Time{}, // zero time overflows when using Unix epoch
|
|
Expected: []byte{},
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "max time",
|
|
RunIt: false || runAll,
|
|
Time: time.UnixMilli(1 << 48),
|
|
Expected: []byte{},
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "max time minus 1",
|
|
RunIt: false || runAll,
|
|
Time: time.UnixMilli(int64(1<<48) - 1),
|
|
Expected: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
|
Error: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.TestName, func(t *testing.T) {
|
|
if !test.RunIt {
|
|
t.SkipNow()
|
|
}
|
|
|
|
output, err := TimeMSBytes(test.Time)
|
|
if test.Error {
|
|
if err == nil {
|
|
t.Errorf("expected an error")
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
errMsg := fmt.Sprintf("expected: %X, received %X", test.Expected, output)
|
|
if len(test.Expected) != len(output) {
|
|
t.Fatal(errMsg)
|
|
}
|
|
for i, b := range test.Expected {
|
|
if b != output[i] {
|
|
t.Error(errMsg)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewULID(t *testing.T) {
|
|
runAll := true
|
|
|
|
type testData struct {
|
|
TestName string
|
|
RunIt bool
|
|
Time time.Time
|
|
Entropy io.Reader
|
|
Expected []byte
|
|
Error bool
|
|
}
|
|
|
|
tests := []testData{
|
|
{
|
|
TestName: "nil entropy",
|
|
RunIt: false || runAll,
|
|
Time: time.Time{},
|
|
Entropy: nil,
|
|
Expected: nil,
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "Unix zero time",
|
|
RunIt: false || runAll,
|
|
Time: time.Unix(0, 0),
|
|
Entropy: getTestRandomSource(),
|
|
Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x94, 0xFD, 0xC2, 0xFA, 0x2F, 0xFC, 0xC0, 0x41, 0xD3},
|
|
Error: false,
|
|
},
|
|
{
|
|
TestName: "time overflow",
|
|
RunIt: false || runAll,
|
|
Time: time.Time{}, // zero time overflows when using Unix epoch time
|
|
Entropy: getTestRandomSource(),
|
|
Expected: nil,
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "seed 0, real time",
|
|
RunIt: false || runAll,
|
|
Time: time.Date(2024, 02, 16, 14, 02, 15, 17, time.UTC),
|
|
Entropy: getTestRandomSource(),
|
|
Expected: []byte{0x01, 0x8D, 0xB2, 0x39, 0x96, 0x58, 0x01, 0x94, 0xFD, 0xC2, 0xFA, 0x2F, 0xFC, 0xC0, 0x41, 0xD3},
|
|
Error: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.TestName, func(t *testing.T) {
|
|
if !test.RunIt {
|
|
t.SkipNow()
|
|
}
|
|
|
|
output, err := NewULID(test.Time, test.Entropy)
|
|
if test.Error {
|
|
if err == nil {
|
|
t.Errorf("expected an error")
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
errMsg := fmt.Sprintf("expected: %X, received %X", test.Expected, output)
|
|
if len(test.Expected) != len(output) {
|
|
t.Fatal(errMsg)
|
|
}
|
|
for i, b := range test.Expected {
|
|
if b != output[i] {
|
|
t.Fatal(errMsg)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestULIDString(t *testing.T) {
|
|
runAll := true
|
|
|
|
type testData struct {
|
|
TestName string
|
|
RunIt bool
|
|
Time time.Time
|
|
Entropy io.Reader
|
|
Expected string
|
|
Error bool
|
|
}
|
|
|
|
tests := []testData{
|
|
{
|
|
TestName: "nil entropy",
|
|
RunIt: false || runAll,
|
|
Time: time.Time{},
|
|
Entropy: nil,
|
|
Expected: "",
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "Unix zero time",
|
|
RunIt: false || runAll,
|
|
Time: time.Unix(0, 0),
|
|
Entropy: getTestRandomSource(),
|
|
Expected: "000000000006AFVGQT5ZYC0GEK",
|
|
Error: false,
|
|
},
|
|
{
|
|
TestName: "time overflow",
|
|
RunIt: false || runAll,
|
|
Time: time.Time{}, // zero time overflows when using Unix epoch time
|
|
Entropy: getTestRandomSource(),
|
|
Expected: "",
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "seed 0, real time",
|
|
RunIt: false || runAll,
|
|
Time: time.Date(2024, 02, 16, 14, 02, 15, 17, time.UTC),
|
|
Entropy: getTestRandomSource(),
|
|
Expected: "01HPS3K5JR06AFVGQT5ZYC0GEK",
|
|
Error: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.TestName, func(t *testing.T) {
|
|
if !test.RunIt {
|
|
t.SkipNow()
|
|
}
|
|
|
|
output, err := NewULIDString(test.Time, test.Entropy)
|
|
if test.Error {
|
|
if err == nil {
|
|
t.Errorf("expected an error")
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
if test.Expected != output {
|
|
log.Fatalf("expected: %s, received %s", test.Expected, output)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestULIDFromString(t *testing.T) {
|
|
runAll := true
|
|
|
|
type testData struct {
|
|
TestName string
|
|
RunIt bool
|
|
Input string
|
|
Expected []byte
|
|
Error bool
|
|
}
|
|
|
|
tests := []testData{
|
|
{
|
|
TestName: "empty string",
|
|
RunIt: false || runAll,
|
|
Input: "",
|
|
Expected: nil,
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "valid ulid",
|
|
RunIt: false || runAll,
|
|
Input: "01HPS3K5JR06AFVGQT5ZYC0GEK",
|
|
Expected: []byte{1, 141, 178, 57, 150, 88, 1, 148, 253, 194, 250, 47, 252, 192, 65, 211},
|
|
Error: false,
|
|
},
|
|
{
|
|
TestName: "time overflow",
|
|
RunIt: false || runAll,
|
|
Input: "ZZZZZZZZZZZZZZZZZZZZZZZZZZ",
|
|
Expected: nil,
|
|
Error: true,
|
|
},
|
|
{
|
|
TestName: "max ULID",
|
|
RunIt: false || runAll,
|
|
Input: "7ZZZZZZZZZZZZZZZZZZZZZZZZZ",
|
|
Expected: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
|
Error: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.TestName, func(t *testing.T) {
|
|
if !test.RunIt {
|
|
t.SkipNow()
|
|
}
|
|
|
|
output, err := ParseULID(test.Input)
|
|
if test.Error {
|
|
if err == nil {
|
|
t.Errorf("expected an error")
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
|
|
msg := fmt.Sprintf("expected %b, got %b", test.Expected, output)
|
|
if len(test.Expected) != len(output) {
|
|
t.Fatalf(msg)
|
|
}
|
|
|
|
for i := range test.Expected {
|
|
if test.Expected[i] != output[i] {
|
|
t.Errorf(msg)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|