1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-24 23:59:47 +02:00
documize/core/uniqueid/xid/id_test.go
Harvey Kandola 391c143483 Change RefID field size from 16 to 20 with updated algo
Xid dependency updated.

Moved to 20 length ID values.

Added new revision number to version and meta information. Revision number is timestamp format.
2018-10-04 21:03:47 +01:00

396 lines
9.1 KiB
Go
Executable file

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()
}
}