ulid/ulid_test.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)
}
}
}
})
}
}