1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-26 00:29:47 +02:00
documize/core/uniqueid/xid/id_test.go

397 lines
9.1 KiB
Go
Raw Normal View History

package xid
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"reflect"
"testing"
"time"
)
type IDParts struct {
id ID
timestamp int64
machine []byte
pid uint16
counter int32
}
var IDs = []IDParts{
IDParts{
ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9},
1300816219,
[]byte{0x60, 0xf4, 0x86},
0xe428,
4271561,
},
IDParts{
ID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
0,
[]byte{0x00, 0x00, 0x00},
0x0000,
0,
},
IDParts{
ID{0x00, 0x00, 0x00, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00, 0x00, 0x01},
0,
[]byte{0xaa, 0xbb, 0xcc},
0xddee,
1,
},
}
func TestIDPartsExtraction(t *testing.T) {
for i, v := range IDs {
t.Run(fmt.Sprintf("Test%d", i), func(t *testing.T) {
if got, want := v.id.Time(), time.Unix(v.timestamp, 0); got != want {
t.Errorf("Time() = %v, want %v", got, want)
}
if got, want := v.id.Machine(), v.machine; !bytes.Equal(got, want) {
t.Errorf("Machine() = %v, want %v", got, want)
}
if got, want := v.id.Pid(), v.pid; got != want {
t.Errorf("Pid() = %v, want %v", got, want)
}
if got, want := v.id.Counter(), v.counter; got != want {
t.Errorf("Counter() = %v, want %v", got, want)
}
})
}
}
func TestNew(t *testing.T) {
// Generate 10 ids
ids := make([]ID, 10)
for i := 0; i < 10; i++ {
ids[i] = New()
}
for i := 1; i < 10; i++ {
prevID := ids[i-1]
id := ids[i]
// Test for uniqueness among all other 9 generated ids
for j, tid := range ids {
if j != i {
if id.Compare(tid) == 0 {
t.Errorf("generated ID is not unique (%d/%d)", i, j)
}
}
}
// Check that timestamp was incremented and is within 30 seconds of the previous one
secs := id.Time().Sub(prevID.Time()).Seconds()
if secs < 0 || secs > 30 {
t.Error("wrong timestamp in generated ID")
}
// Check that machine ids are the same
if !bytes.Equal(id.Machine(), prevID.Machine()) {
t.Error("machine ID not equal")
}
// Check that pids are the same
if id.Pid() != prevID.Pid() {
t.Error("pid not equal")
}
// Test for proper increment
if got, want := int(id.Counter()-prevID.Counter()), 1; got != want {
t.Errorf("wrong increment in generated ID, delta=%v, want %v", got, want)
}
}
}
func TestIDString(t *testing.T) {
id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
if got, want := id.String(), "9m4e2mr0ui3e8a215n4g"; got != want {
t.Errorf("String() = %v, want %v", got, want)
}
}
func TestFromString(t *testing.T) {
got, err := FromString("9m4e2mr0ui3e8a215n4g")
if err != nil {
t.Fatal(err)
}
want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
if got != want {
t.Errorf("FromString() = %v, want %v", got, want)
}
}
func TestFromStringInvalid(t *testing.T) {
_, err := FromString("invalid")
if err != ErrInvalidID {
t.Errorf("FromString(invalid) err=%v, want %v", err, ErrInvalidID)
}
}
type jsonType struct {
ID *ID
Str string
}
func TestIDJSONMarshaling(t *testing.T) {
id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
v := jsonType{ID: &id, Str: "test"}
data, err := json.Marshal(&v)
if err != nil {
t.Fatal(err)
}
if got, want := string(data), `{"ID":"9m4e2mr0ui3e8a215n4g","Str":"test"}`; got != want {
t.Errorf("json.Marshal() = %v, want %v", got, want)
}
}
func TestIDJSONUnmarshaling(t *testing.T) {
data := []byte(`{"ID":"9m4e2mr0ui3e8a215n4g","Str":"test"}`)
v := jsonType{}
err := json.Unmarshal(data, &v)
if err != nil {
t.Fatal(err)
}
want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
if got := *v.ID; got.Compare(want) != 0 {
t.Errorf("json.Unmarshal() = %v, want %v", got, want)
}
}
func TestIDJSONUnmarshalingError(t *testing.T) {
v := jsonType{}
err := json.Unmarshal([]byte(`{"ID":"9M4E2MR0UI3E8A215N4G"}`), &v)
if err != ErrInvalidID {
t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
}
err = json.Unmarshal([]byte(`{"ID":"TYjhW2D0huQoQS"}`), &v)
if err != ErrInvalidID {
t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
}
err = json.Unmarshal([]byte(`{"ID":"TYjhW2D0huQoQS3kdk"}`), &v)
if err != ErrInvalidID {
t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
}
}
func TestIDDriverValue(t *testing.T) {
id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
got, err := id.Value()
if err != nil {
t.Fatal(err)
}
if want := "9m4e2mr0ui3e8a215n4g"; got != want {
t.Errorf("Value() = %v, want %v", got, want)
}
}
func TestIDDriverScan(t *testing.T) {
got := ID{}
err := got.Scan("9m4e2mr0ui3e8a215n4g")
if err != nil {
t.Fatal(err)
}
want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
if got.Compare(want) != 0 {
t.Errorf("Scan() = %v, want %v", got, want)
}
}
func TestIDDriverScanError(t *testing.T) {
id := ID{}
if got, want := id.Scan(0), errors.New("xid: scanning unsupported type: int"); !reflect.DeepEqual(got, want) {
t.Errorf("Scan() err=%v, want %v", got, want)
}
if got, want := id.Scan("0"), ErrInvalidID; got != want {
t.Errorf("Scan() err=%v, want %v", got, want)
}
}
func TestIDDriverScanByteFromDatabase(t *testing.T) {
got := ID{}
bs := []byte("9m4e2mr0ui3e8a215n4g")
err := got.Scan(bs)
if err != nil {
t.Fatal(err)
}
want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
if got.Compare(want) != 0 {
t.Errorf("Scan() = %v, want %v", got, want)
}
}
func BenchmarkNew(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = New()
}
})
}
func BenchmarkNewString(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = New().String()
}
})
}
func BenchmarkFromString(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = FromString("9m4e2mr0ui3e8a215n4g")
}
})
}
// func BenchmarkUUIDv1(b *testing.B) {
// b.RunParallel(func(pb *testing.PB) {
// for pb.Next() {
// _ = uuid.NewV1().String()
// }
// })
// }
// func BenchmarkUUIDv4(b *testing.B) {
// b.RunParallel(func(pb *testing.PB) {
// for pb.Next() {
// _ = uuid.NewV4().String()
// }
// })
// }
func TestID_IsNil(t *testing.T) {
tests := []struct {
name string
id ID
want bool
}{
{
name: "ID not nil",
id: New(),
want: false,
},
{
name: "Nil ID",
id: ID{},
want: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
if got, want := tt.id.IsNil(), tt.want; got != want {
t.Errorf("IsNil() = %v, want %v", got, want)
}
})
}
}
func TestNilID(t *testing.T) {
got := ID{}
if want := NilID(); !reflect.DeepEqual(got, want) {
t.Error("NilID() not equal ID{}")
}
}
func TestNilID_IsNil(t *testing.T) {
if !NilID().IsNil() {
t.Error("NilID().IsNil() is not true")
}
}
func TestFromBytes_Invariant(t *testing.T) {
want := New()
got, err := FromBytes(want.Bytes())
if err != nil {
t.Fatal(err)
}
if got.Compare(want) != 0 {
t.Error("FromBytes(id.Bytes()) != id")
}
}
func TestFromBytes_InvalidBytes(t *testing.T) {
cases := []struct {
length int
shouldFail bool
}{
{11, true},
{12, false},
{13, true},
}
for _, c := range cases {
b := make([]byte, c.length, c.length)
_, err := FromBytes(b)
if got, want := err != nil, c.shouldFail; got != want {
t.Errorf("FromBytes() error got %v, want %v", got, want)
}
}
}
func TestID_Compare(t *testing.T) {
pairs := []struct {
left ID
right ID
expected int
}{
{IDs[1].id, IDs[0].id, -1},
{ID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, IDs[2].id, -1},
{IDs[0].id, IDs[0].id, 0},
}
for _, p := range pairs {
if p.expected != p.left.Compare(p.right) {
t.Errorf("%s Compare to %s should return %d", p.left, p.right, p.expected)
}
if -1*p.expected != p.right.Compare(p.left) {
t.Errorf("%s Compare to %s should return %d", p.right, p.left, -1*p.expected)
}
}
}
var IDList = []ID{IDs[0].id, IDs[1].id, IDs[2].id}
func TestSorter_Len(t *testing.T) {
if got, want := sorter([]ID{}).Len(), 0; got != want {
t.Errorf("Len() %v, want %v", got, want)
}
if got, want := sorter(IDList).Len(), 3; got != want {
t.Errorf("Len() %v, want %v", got, want)
}
}
func TestSorter_Less(t *testing.T) {
sorter := sorter(IDList)
if !sorter.Less(1, 0) {
t.Errorf("Less(1, 0) not true")
}
if sorter.Less(2, 1) {
t.Errorf("Less(2, 1) true")
}
if sorter.Less(0, 0) {
t.Errorf("Less(0, 0) true")
}
}
func TestSorter_Swap(t *testing.T) {
ids := make([]ID, 0)
ids = append(ids, IDList...)
sorter := sorter(ids)
sorter.Swap(0, 1)
if got, want := ids[0], IDList[1]; !reflect.DeepEqual(got, want) {
t.Error("ids[0] != IDList[1]")
}
if got, want := ids[1], IDList[0]; !reflect.DeepEqual(got, want) {
t.Error("ids[1] != IDList[0]")
}
sorter.Swap(2, 2)
if got, want := ids[2], IDList[2]; !reflect.DeepEqual(got, want) {
t.Error("ids[2], IDList[2]")
}
}
func TestSort(t *testing.T) {
ids := make([]ID, 0)
ids = append(ids, IDList...)
Sort(ids)
if got, want := ids, []ID{IDList[1], IDList[2], IDList[0]}; !reflect.DeepEqual(got, want) {
t.Fail()
}
}