...

Source file src/github.com/rs/xid/id_test.go

Documentation: github.com/rs/xid

     1  package xid
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"math/rand"
     9  	"reflect"
    10  	"testing"
    11  	"testing/quick"
    12  	"time"
    13  )
    14  
    15  type IDParts struct {
    16  	id        ID
    17  	timestamp int64
    18  	machine   []byte
    19  	pid       uint16
    20  	counter   int32
    21  }
    22  
    23  var IDs = []IDParts{
    24  	{
    25  		ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9},
    26  		1300816219,
    27  		[]byte{0x60, 0xf4, 0x86},
    28  		0xe428,
    29  		4271561,
    30  	},
    31  	{
    32  		ID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    33  		0,
    34  		[]byte{0x00, 0x00, 0x00},
    35  		0x0000,
    36  		0,
    37  	},
    38  	{
    39  		ID{0x00, 0x00, 0x00, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00, 0x00, 0x01},
    40  		0,
    41  		[]byte{0xaa, 0xbb, 0xcc},
    42  		0xddee,
    43  		1,
    44  	},
    45  }
    46  
    47  func TestIDPartsExtraction(t *testing.T) {
    48  	for i, v := range IDs {
    49  		t.Run(fmt.Sprintf("Test%d", i), func(t *testing.T) {
    50  			if got, want := v.id.Time(), time.Unix(v.timestamp, 0); got != want {
    51  				t.Errorf("Time() = %v, want %v", got, want)
    52  			}
    53  			if got, want := v.id.Machine(), v.machine; !bytes.Equal(got, want) {
    54  				t.Errorf("Machine() = %v, want %v", got, want)
    55  			}
    56  			if got, want := v.id.Pid(), v.pid; got != want {
    57  				t.Errorf("Pid() = %v, want %v", got, want)
    58  			}
    59  			if got, want := v.id.Counter(), v.counter; got != want {
    60  				t.Errorf("Counter() = %v, want %v", got, want)
    61  			}
    62  		})
    63  	}
    64  }
    65  
    66  func TestNew(t *testing.T) {
    67  	// Generate 10 ids
    68  	ids := make([]ID, 10)
    69  	for i := 0; i < 10; i++ {
    70  		ids[i] = New()
    71  	}
    72  	for i := 1; i < 10; i++ {
    73  		prevID := ids[i-1]
    74  		id := ids[i]
    75  		// Test for uniqueness among all other 9 generated ids
    76  		for j, tid := range ids {
    77  			if j != i {
    78  				if id.Compare(tid) == 0 {
    79  					t.Errorf("generated ID is not unique (%d/%d)", i, j)
    80  				}
    81  			}
    82  		}
    83  		// Check that timestamp was incremented and is within 30 seconds of the previous one
    84  		secs := id.Time().Sub(prevID.Time()).Seconds()
    85  		if secs < 0 || secs > 30 {
    86  			t.Error("wrong timestamp in generated ID")
    87  		}
    88  		// Check that machine ids are the same
    89  		if !bytes.Equal(id.Machine(), prevID.Machine()) {
    90  			t.Error("machine ID not equal")
    91  		}
    92  		// Check that pids are the same
    93  		if id.Pid() != prevID.Pid() {
    94  			t.Error("pid not equal")
    95  		}
    96  		// Test for proper increment
    97  		if got, want := int(id.Counter()-prevID.Counter()), 1; got != want {
    98  			t.Errorf("wrong increment in generated ID, delta=%v, want %v", got, want)
    99  		}
   100  	}
   101  }
   102  
   103  func TestIDString(t *testing.T) {
   104  	id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   105  	if got, want := id.String(), "9m4e2mr0ui3e8a215n4g"; got != want {
   106  		t.Errorf("String() = %v, want %v", got, want)
   107  	}
   108  }
   109  
   110  func TestIDEncode(t *testing.T) {
   111  	id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   112  	text := make([]byte, encodedLen)
   113  	if got, want := string(id.Encode(text)), "9m4e2mr0ui3e8a215n4g"; got != want {
   114  		t.Errorf("Encode() = %v, want %v", got, want)
   115  	}
   116  }
   117  
   118  func TestFromString(t *testing.T) {
   119  	got, err := FromString("9m4e2mr0ui3e8a215n4g")
   120  	if err != nil {
   121  		t.Fatal(err)
   122  	}
   123  	want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   124  	if got != want {
   125  		t.Errorf("FromString() = %v, want %v", got, want)
   126  	}
   127  }
   128  
   129  func TestFromStringInvalid(t *testing.T) {
   130  	_, err := FromString("invalid")
   131  	if err != ErrInvalidID {
   132  		t.Errorf("FromString(invalid) err=%v, want %v", err, ErrInvalidID)
   133  	}
   134  }
   135  
   136  type jsonType struct {
   137  	ID  *ID
   138  	Str string
   139  }
   140  
   141  func TestIDJSONMarshaling(t *testing.T) {
   142  	id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   143  	v := jsonType{ID: &id, Str: "test"}
   144  	data, err := json.Marshal(&v)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  	if got, want := string(data), `{"ID":"9m4e2mr0ui3e8a215n4g","Str":"test"}`; got != want {
   149  		t.Errorf("json.Marshal() = %v, want %v", got, want)
   150  	}
   151  }
   152  
   153  func TestIDJSONUnmarshaling(t *testing.T) {
   154  	data := []byte(`{"ID":"9m4e2mr0ui3e8a215n4g","Str":"test"}`)
   155  	v := jsonType{}
   156  	err := json.Unmarshal(data, &v)
   157  	if err != nil {
   158  		t.Fatal(err)
   159  	}
   160  	want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   161  	if got := *v.ID; got.Compare(want) != 0 {
   162  		t.Errorf("json.Unmarshal() = %v, want %v", got, want)
   163  	}
   164  
   165  }
   166  
   167  func TestIDJSONUnmarshalingError(t *testing.T) {
   168  	v := jsonType{}
   169  	err := json.Unmarshal([]byte(`{"ID":"9M4E2MR0UI3E8A215N4G"}`), &v)
   170  	if err != ErrInvalidID {
   171  		t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
   172  	}
   173  	err = json.Unmarshal([]byte(`{"ID":"TYjhW2D0huQoQS"}`), &v)
   174  	if err != ErrInvalidID {
   175  		t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
   176  	}
   177  	err = json.Unmarshal([]byte(`{"ID":"TYjhW2D0huQoQS3kdk"}`), &v)
   178  	if err != ErrInvalidID {
   179  		t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
   180  	}
   181  	err = json.Unmarshal([]byte(`{"ID":1}`), &v)
   182  	if err != ErrInvalidID {
   183  		t.Errorf("json.Unmarshal() err=%v, want %v", err, ErrInvalidID)
   184  	}
   185  }
   186  
   187  func TestIDDriverValue(t *testing.T) {
   188  	id := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   189  	got, err := id.Value()
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  	if want := "9m4e2mr0ui3e8a215n4g"; got != want {
   194  		t.Errorf("Value() = %v, want %v", got, want)
   195  	}
   196  }
   197  
   198  func TestIDDriverScan(t *testing.T) {
   199  	got := ID{}
   200  	err := got.Scan("9m4e2mr0ui3e8a215n4g")
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  	want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   205  	if got.Compare(want) != 0 {
   206  		t.Errorf("Scan() = %v, want %v", got, want)
   207  	}
   208  }
   209  
   210  func TestIDDriverScanError(t *testing.T) {
   211  	id := ID{}
   212  	if got, want := id.Scan(0), errors.New("xid: scanning unsupported type: int"); !reflect.DeepEqual(got, want) {
   213  		t.Errorf("Scan() err=%v, want %v", got, want)
   214  	}
   215  	if got, want := id.Scan("0"), ErrInvalidID; got != want {
   216  		t.Errorf("Scan() err=%v, want %v", got, want)
   217  	}
   218  }
   219  
   220  func TestIDDriverScanByteFromDatabase(t *testing.T) {
   221  	got := ID{}
   222  	bs := []byte("9m4e2mr0ui3e8a215n4g")
   223  	err := got.Scan(bs)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	want := ID{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
   228  	if got.Compare(want) != 0 {
   229  		t.Errorf("Scan() = %v, want %v", got, want)
   230  	}
   231  }
   232  
   233  func BenchmarkNew(b *testing.B) {
   234  	b.RunParallel(func(pb *testing.PB) {
   235  		for pb.Next() {
   236  			_ = New()
   237  		}
   238  	})
   239  }
   240  
   241  func BenchmarkNewString(b *testing.B) {
   242  	b.RunParallel(func(pb *testing.PB) {
   243  		for pb.Next() {
   244  			_ = New().String()
   245  		}
   246  	})
   247  }
   248  
   249  func BenchmarkFromString(b *testing.B) {
   250  	b.RunParallel(func(pb *testing.PB) {
   251  		for pb.Next() {
   252  			_, _ = FromString("9m4e2mr0ui3e8a215n4g")
   253  		}
   254  	})
   255  }
   256  
   257  func TestFromStringQuick(t *testing.T) {
   258  	f := func(id1 ID, c byte) bool {
   259  		s1 := id1.String()
   260  		for i := range s1 {
   261  			s2 := []byte(s1)
   262  			s2[i] = c
   263  			id2, err := FromString(string(s2))
   264  			if id1 == id2 && err == nil && c != s1[i] {
   265  				t.Logf("comparing XIDs:\na: %q\nb: %q (index %d changed to %c)", s1, s2, i, c)
   266  				return false
   267  			}
   268  		}
   269  		return true
   270  	}
   271  	err := quick.Check(f, &quick.Config{
   272  		Values: func(args []reflect.Value, r *rand.Rand) {
   273  			i := r.Intn(len(encoding))
   274  			args[0] = reflect.ValueOf(New())
   275  			args[1] = reflect.ValueOf(byte(encoding[i]))
   276  		},
   277  		MaxCount: 1000,
   278  	})
   279  	if err != nil {
   280  		t.Error(err)
   281  	}
   282  }
   283  
   284  func TestFromStringQuickInvalidChars(t *testing.T) {
   285  	f := func(id1 ID, c byte) bool {
   286  		s1 := id1.String()
   287  		for i := range s1 {
   288  			s2 := []byte(s1)
   289  			s2[i] = c
   290  			id2, err := FromString(string(s2))
   291  			if id1 == id2 && err == nil && c != s1[i] {
   292  				t.Logf("comparing XIDs:\na: %q\nb: %q (index %d changed to %c)", s1, s2, i, c)
   293  				return false
   294  			}
   295  		}
   296  		return true
   297  	}
   298  	err := quick.Check(f, &quick.Config{
   299  		Values: func(args []reflect.Value, r *rand.Rand) {
   300  			i := r.Intn(0xFF)
   301  			args[0] = reflect.ValueOf(New())
   302  			args[1] = reflect.ValueOf(byte(i))
   303  		},
   304  		MaxCount: 2000,
   305  	})
   306  	if err != nil {
   307  		t.Error(err)
   308  	}
   309  }
   310  
   311  // func BenchmarkUUIDv1(b *testing.B) {
   312  // 	b.RunParallel(func(pb *testing.PB) {
   313  // 		for pb.Next() {
   314  // 			_ = uuid.NewV1().String()
   315  // 		}
   316  // 	})
   317  // }
   318  
   319  // func BenchmarkUUIDv4(b *testing.B) {
   320  // 	b.RunParallel(func(pb *testing.PB) {
   321  // 		for pb.Next() {
   322  // 			_ = uuid.NewV4().String()
   323  // 		}
   324  // 	})
   325  // }
   326  
   327  func TestID_IsNil(t *testing.T) {
   328  	tests := []struct {
   329  		name string
   330  		id   ID
   331  		want bool
   332  	}{
   333  		{
   334  			name: "ID not nil",
   335  			id:   New(),
   336  			want: false,
   337  		},
   338  		{
   339  			name: "Nil ID",
   340  			id:   ID{},
   341  			want: true,
   342  		},
   343  	}
   344  	for _, tt := range tests {
   345  		tt := tt
   346  		t.Run(tt.name, func(t *testing.T) {
   347  			if got, want := tt.id.IsNil(), tt.want; got != want {
   348  				t.Errorf("IsNil() = %v, want %v", got, want)
   349  			}
   350  		})
   351  	}
   352  }
   353  
   354  func TestNilID(t *testing.T) {
   355  	got := ID{}
   356  	if want := NilID(); !reflect.DeepEqual(got, want) {
   357  		t.Error("NilID() not equal ID{}")
   358  	}
   359  }
   360  
   361  func TestNilID_IsNil(t *testing.T) {
   362  	if !NilID().IsNil() {
   363  		t.Error("NilID().IsNil() is not true")
   364  	}
   365  }
   366  
   367  func TestFromBytes_Invariant(t *testing.T) {
   368  	want := New()
   369  	got, err := FromBytes(want.Bytes())
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	if got.Compare(want) != 0 {
   374  		t.Error("FromBytes(id.Bytes()) != id")
   375  	}
   376  }
   377  
   378  func TestFromBytes_InvalidBytes(t *testing.T) {
   379  	cases := []struct {
   380  		length     int
   381  		shouldFail bool
   382  	}{
   383  		{11, true},
   384  		{12, false},
   385  		{13, true},
   386  	}
   387  	for _, c := range cases {
   388  		b := make([]byte, c.length)
   389  		_, err := FromBytes(b)
   390  		if got, want := err != nil, c.shouldFail; got != want {
   391  			t.Errorf("FromBytes() error got %v, want %v", got, want)
   392  		}
   393  	}
   394  }
   395  
   396  func TestID_Compare(t *testing.T) {
   397  	pairs := []struct {
   398  		left     ID
   399  		right    ID
   400  		expected int
   401  	}{
   402  		{IDs[1].id, IDs[0].id, -1},
   403  		{ID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, IDs[2].id, -1},
   404  		{IDs[0].id, IDs[0].id, 0},
   405  	}
   406  	for _, p := range pairs {
   407  		if p.expected != p.left.Compare(p.right) {
   408  			t.Errorf("%s Compare to %s should return %d", p.left, p.right, p.expected)
   409  		}
   410  		if -1*p.expected != p.right.Compare(p.left) {
   411  			t.Errorf("%s Compare to %s should return %d", p.right, p.left, -1*p.expected)
   412  		}
   413  	}
   414  }
   415  
   416  var IDList = []ID{IDs[0].id, IDs[1].id, IDs[2].id}
   417  
   418  func TestSorter_Len(t *testing.T) {
   419  	if got, want := sorter([]ID{}).Len(), 0; got != want {
   420  		t.Errorf("Len() %v, want %v", got, want)
   421  	}
   422  	if got, want := sorter(IDList).Len(), 3; got != want {
   423  		t.Errorf("Len() %v, want %v", got, want)
   424  	}
   425  }
   426  
   427  func TestSorter_Less(t *testing.T) {
   428  	sorter := sorter(IDList)
   429  	if !sorter.Less(1, 0) {
   430  		t.Errorf("Less(1, 0) not true")
   431  	}
   432  	if sorter.Less(2, 1) {
   433  		t.Errorf("Less(2, 1) true")
   434  	}
   435  	if sorter.Less(0, 0) {
   436  		t.Errorf("Less(0, 0) true")
   437  	}
   438  }
   439  
   440  func TestSorter_Swap(t *testing.T) {
   441  	ids := make([]ID, 0)
   442  	ids = append(ids, IDList...)
   443  	sorter := sorter(ids)
   444  	sorter.Swap(0, 1)
   445  	if got, want := ids[0], IDList[1]; !reflect.DeepEqual(got, want) {
   446  		t.Error("ids[0] != IDList[1]")
   447  	}
   448  	if got, want := ids[1], IDList[0]; !reflect.DeepEqual(got, want) {
   449  		t.Error("ids[1] != IDList[0]")
   450  	}
   451  	sorter.Swap(2, 2)
   452  	if got, want := ids[2], IDList[2]; !reflect.DeepEqual(got, want) {
   453  		t.Error("ids[2], IDList[2]")
   454  	}
   455  }
   456  
   457  func TestSort(t *testing.T) {
   458  	ids := make([]ID, 0)
   459  	ids = append(ids, IDList...)
   460  	Sort(ids)
   461  	if got, want := ids, []ID{IDList[1], IDList[2], IDList[0]}; !reflect.DeepEqual(got, want) {
   462  		t.Fail()
   463  	}
   464  }
   465  

View as plain text