2016-06-01 16:15:57 -05:00
|
|
|
package snowflake
|
2016-05-25 14:57:33 -05:00
|
|
|
|
2016-07-26 11:35:39 -07:00
|
|
|
import (
|
|
|
|
"bytes"
|
2017-06-16 09:02:15 -07:00
|
|
|
"reflect"
|
2016-07-26 11:35:39 -07:00
|
|
|
"testing"
|
|
|
|
)
|
2016-05-25 14:57:33 -05:00
|
|
|
|
2019-04-12 17:06:54 -05:00
|
|
|
//******************************************************************************
|
|
|
|
// General Test funcs
|
|
|
|
|
2019-04-12 17:30:32 -05:00
|
|
|
func TestNewNode(t *testing.T) {
|
|
|
|
|
|
|
|
_, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = NewNode(5000)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("no error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:06:54 -05:00
|
|
|
// lazy check if Generate will create duplicate IDs
|
|
|
|
// would be good to later enhance this with more smarts
|
2019-04-11 20:34:59 -05:00
|
|
|
func TestGenerateDuplicateID(t *testing.T) {
|
|
|
|
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
|
|
|
|
var x, y ID
|
2019-04-12 17:06:54 -05:00
|
|
|
for i := 0; i < 1000000; i++ {
|
2019-04-11 20:34:59 -05:00
|
|
|
y = node.Generate()
|
|
|
|
if x == y {
|
|
|
|
t.Errorf("x(%d) & y(%d) are the same", x, y)
|
|
|
|
}
|
|
|
|
x = y
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-10 01:02:19 +00:00
|
|
|
// I feel like there's probably a better way
|
|
|
|
func TestRace(t *testing.T) {
|
|
|
|
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for i := 0; i < 1000000000; i++ {
|
|
|
|
|
|
|
|
NewNode(1)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
for i := 0; i < 4000; i++ {
|
|
|
|
|
|
|
|
node.Generate()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:06:54 -05:00
|
|
|
//******************************************************************************
|
|
|
|
// Converters/Parsers Test funcs
|
|
|
|
// We should have funcs here to test conversion both ways for everything
|
|
|
|
|
|
|
|
func TestPrintAll(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
id := node.Generate()
|
|
|
|
|
|
|
|
t.Logf("Int64 : %#v", id.Int64())
|
|
|
|
t.Logf("String : %#v", id.String())
|
|
|
|
t.Logf("Base2 : %#v", id.Base2())
|
|
|
|
t.Logf("Base32 : %#v", id.Base32())
|
|
|
|
t.Logf("Base36 : %#v", id.Base36())
|
|
|
|
t.Logf("Base58 : %#v", id.Base58())
|
|
|
|
t.Logf("Base64 : %#v", id.Base64())
|
|
|
|
t.Logf("Bytes : %#v", id.Bytes())
|
|
|
|
t.Logf("IntBytes : %#v", id.IntBytes())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInt64(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
i := oID.Int64()
|
|
|
|
|
|
|
|
pID := ParseInt64(i)
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
mi := int64(1116766490855473152)
|
|
|
|
pID = ParseInt64(mi)
|
|
|
|
if pID.Int64() != mi {
|
|
|
|
t.Fatalf("pID %v != mi %v", pID.Int64(), mi)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestString(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
si := oID.String()
|
|
|
|
|
|
|
|
pID, err := ParseString(si)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := `1116766490855473152`
|
|
|
|
_, err = ParseString(ms)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = `1112316766490855473152`
|
|
|
|
_, err = ParseString(ms)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("no error parsing %s", ms)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBase2(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
i := oID.Base2()
|
|
|
|
|
|
|
|
pID, err := ParseBase2(i)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := `111101111111101110110101100101001000000000000000000000000000`
|
|
|
|
_, err = ParseBase2(ms)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = `1112316766490855473152`
|
|
|
|
_, err = ParseBase2(ms)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("no error parsing %s", ms)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBase32(t *testing.T) {
|
|
|
|
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
|
|
|
|
sf := node.Generate()
|
|
|
|
b32i := sf.Base32()
|
|
|
|
psf, err := ParseBase32([]byte(b32i))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if sf != psf {
|
|
|
|
t.Fatal("Parsed does not match String.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBase36(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
i := oID.Base36()
|
|
|
|
|
|
|
|
pID, err := ParseBase36(i)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := `8hgmw4blvlkw`
|
|
|
|
_, err = ParseBase36(ms)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = `68h5gmw443blv2lk1w`
|
|
|
|
_, err = ParseBase36(ms)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("no error parsing, %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBase58(t *testing.T) {
|
|
|
|
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
|
|
|
|
sf := node.Generate()
|
|
|
|
b58 := sf.Base58()
|
|
|
|
psf, err := ParseBase58([]byte(b58))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if sf != psf {
|
|
|
|
t.Fatal("Parsed does not match String.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBase64(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
i := oID.Base64()
|
|
|
|
|
|
|
|
pID, err := ParseBase64(i)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := `MTExNjgxOTQ5NDY2MDk5NzEyMA==`
|
|
|
|
_, err = ParseBase64(ms)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = `MTExNjgxOTQ5NDY2MDk5NzEyMA`
|
|
|
|
_, err = ParseBase64(ms)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("no error parsing, %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBytes(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
i := oID.Bytes()
|
|
|
|
|
|
|
|
pID, err := ParseBytes(i)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %s", err)
|
|
|
|
}
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := []byte{0x31, 0x31, 0x31, 0x36, 0x38, 0x32, 0x31, 0x36, 0x37, 0x39, 0x35, 0x37, 0x30, 0x34, 0x31, 0x39, 0x37, 0x31, 0x32}
|
|
|
|
_, err = ParseBytes(ms)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error parsing, %#v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = []byte{0xFF, 0xFF, 0xFF, 0x31, 0x31, 0x31, 0x36, 0x38, 0x32, 0x31, 0x36, 0x37, 0x39, 0x35, 0x37, 0x30, 0x34, 0x31, 0x39, 0x37, 0x31, 0x32}
|
|
|
|
_, err = ParseBytes(ms)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("no error parsing, %#v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIntBytes(t *testing.T) {
|
|
|
|
node, err := NewNode(0)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating NewNode, %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
oID := node.Generate()
|
|
|
|
i := oID.IntBytes()
|
|
|
|
|
|
|
|
pID := ParseIntBytes(i)
|
|
|
|
if pID != oID {
|
|
|
|
t.Fatalf("pID %v != oID %v", pID, oID)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := [8]uint8{0xf, 0x7f, 0xc0, 0xfc, 0x2f, 0x80, 0x0, 0x0}
|
|
|
|
mi := int64(1116823421972381696)
|
|
|
|
pID = ParseIntBytes(ms)
|
|
|
|
if pID.Int64() != mi {
|
|
|
|
t.Fatalf("pID %v != mi %v", pID.Int64(), mi)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
// Marshall Test Methods
|
|
|
|
|
2016-06-10 20:33:36 +02:00
|
|
|
func TestMarshalJSON(t *testing.T) {
|
|
|
|
id := ID(13587)
|
|
|
|
expected := "\"13587\""
|
|
|
|
|
|
|
|
bytes, err := id.MarshalJSON()
|
|
|
|
if err != nil {
|
2019-04-12 17:06:54 -05:00
|
|
|
t.Fatalf("Unexpected error during MarshalJSON")
|
2016-06-10 20:33:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if string(bytes) != expected {
|
2019-04-12 17:06:54 -05:00
|
|
|
t.Fatalf("Got %s, expected %s", string(bytes), expected)
|
2016-06-10 20:33:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 11:35:39 -07:00
|
|
|
func TestMarshalsIntBytes(t *testing.T) {
|
|
|
|
id := ID(13587).IntBytes()
|
|
|
|
expected := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x35, 0x13}
|
|
|
|
if !bytes.Equal(id[:], expected) {
|
2019-04-12 17:06:54 -05:00
|
|
|
t.Fatalf("Expected ID to be encoded as %v, got %v", expected, id)
|
2016-07-26 11:35:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-10 20:33:36 +02:00
|
|
|
func TestUnmarshalJSON(t *testing.T) {
|
2017-06-16 09:02:15 -07:00
|
|
|
tt := []struct {
|
|
|
|
json string
|
2019-04-10 01:12:21 +00:00
|
|
|
expectedID ID
|
2017-06-16 09:02:15 -07:00
|
|
|
expectedErr error
|
|
|
|
}{
|
|
|
|
{`"13587"`, 13587, nil},
|
|
|
|
{`1`, 0, JSONSyntaxError{[]byte(`1`)}},
|
|
|
|
{`"invalid`, 0, JSONSyntaxError{[]byte(`"invalid`)}},
|
2016-06-10 20:33:36 +02:00
|
|
|
}
|
|
|
|
|
2017-06-16 09:02:15 -07:00
|
|
|
for _, tc := range tt {
|
|
|
|
var id ID
|
|
|
|
err := id.UnmarshalJSON([]byte(tc.json))
|
|
|
|
if !reflect.DeepEqual(err, tc.expectedErr) {
|
2019-04-12 17:06:54 -05:00
|
|
|
t.Fatalf("Expected to get error '%s' decoding JSON, but got '%s'", tc.expectedErr, err)
|
2017-06-16 09:02:15 -07:00
|
|
|
}
|
|
|
|
|
2019-04-10 01:12:21 +00:00
|
|
|
if id != tc.expectedID {
|
2019-04-12 17:06:54 -05:00
|
|
|
t.Fatalf("Expected to get ID '%s' decoding JSON, but got '%s'", tc.expectedID, id)
|
2017-06-16 09:02:15 -07:00
|
|
|
}
|
2016-06-10 20:33:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:06:54 -05:00
|
|
|
// ****************************************************************************
|
|
|
|
// Benchmark Methods
|
2018-03-12 20:56:32 +00:00
|
|
|
|
|
|
|
func BenchmarkParseBase32(b *testing.B) {
|
|
|
|
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
sf := node.Generate()
|
|
|
|
b32i := sf.Base32()
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
|
|
ParseBase32([]byte(b32i))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func BenchmarkBase32(b *testing.B) {
|
|
|
|
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
sf := node.Generate()
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
|
|
sf.Base32()
|
|
|
|
}
|
|
|
|
}
|
2017-02-21 09:58:29 -06:00
|
|
|
func BenchmarkParseBase58(b *testing.B) {
|
|
|
|
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
sf := node.Generate()
|
|
|
|
b58 := sf.Base58()
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
|
|
ParseBase58([]byte(b58))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func BenchmarkBase58(b *testing.B) {
|
|
|
|
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
sf := node.Generate()
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
|
|
sf.Base58()
|
|
|
|
}
|
|
|
|
}
|
2016-05-25 14:57:33 -05:00
|
|
|
func BenchmarkGenerate(b *testing.B) {
|
|
|
|
|
2016-06-01 14:59:26 -05:00
|
|
|
node, _ := NewNode(1)
|
2016-05-25 14:57:33 -05:00
|
|
|
|
|
|
|
b.ReportAllocs()
|
2016-06-04 15:50:03 -05:00
|
|
|
|
|
|
|
b.ResetTimer()
|
2016-05-25 14:57:33 -05:00
|
|
|
for n := 0; n < b.N; n++ {
|
2016-06-10 20:33:36 +02:00
|
|
|
_ = node.Generate()
|
2016-05-25 14:57:33 -05:00
|
|
|
}
|
2016-06-04 15:50:03 -05:00
|
|
|
}
|
|
|
|
|
2019-04-10 01:32:30 +00:00
|
|
|
func BenchmarkGenerateMaxSequence(b *testing.B) {
|
|
|
|
|
|
|
|
NodeBits = 1
|
|
|
|
StepBits = 21
|
|
|
|
node, _ := NewNode(1)
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
|
|
_ = node.Generate()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-04 15:50:03 -05:00
|
|
|
func BenchmarkUnmarshal(b *testing.B) {
|
2016-06-11 03:48:54 +02:00
|
|
|
// Generate the ID to unmarshal
|
2016-06-04 15:50:03 -05:00
|
|
|
node, _ := NewNode(1)
|
2016-06-10 20:33:36 +02:00
|
|
|
id := node.Generate()
|
2016-06-11 03:48:54 +02:00
|
|
|
bytes, _ := id.MarshalJSON()
|
|
|
|
|
2016-06-04 15:50:03 -05:00
|
|
|
var id2 ID
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
2016-06-11 03:48:54 +02:00
|
|
|
_ = id2.UnmarshalJSON(bytes)
|
2016-06-04 15:50:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMarshal(b *testing.B) {
|
2016-06-11 03:48:54 +02:00
|
|
|
// Generate the ID to marshal
|
2016-06-04 15:50:03 -05:00
|
|
|
node, _ := NewNode(1)
|
2016-06-10 20:33:36 +02:00
|
|
|
id := node.Generate()
|
2016-05-25 14:57:33 -05:00
|
|
|
|
2016-06-04 15:50:03 -05:00
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
|
|
_, _ = id.MarshalJSON()
|
|
|
|
}
|
2016-05-25 14:57:33 -05:00
|
|
|
}
|