github.com/andersfylling/snowflake/v5@v5.0.1/snowflake_test.go (about)

     1  package snowflake
     2  
     3  import (
     4  	"encoding"
     5  	"encoding/json"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  func TestSnowflake_Date(t *testing.T) {
    11  	s := Snowflake(0)
    12  	a := s.Date()
    13  	if diff := a.Sub(time.Unix(int64(EpochDiscord)/1000, 0)); diff != 0 {
    14  		t.Error("expected Date subtracted the epoch to be 0. Got ", diff)
    15  	}
    16  
    17  	s = NewSnowflake(228846961774559232)
    18  	if s.Date().Unix() != 1474631767 {
    19  		t.Error("date is incorrect")
    20  	}
    21  }
    22  
    23  func TestASCIITrick(t *testing.T) {
    24  	if int('n'+'u'+'l')*2 < 4*'9' {
    25  		t.Error("unable to sum ascii chars")
    26  	}
    27  }
    28  
    29  func TestString(t *testing.T) {
    30  	var b []byte
    31  	var err error
    32  	id := NewSnowflake(uint64(435834986943))
    33  	if id.String() != "435834986943" {
    34  		t.Errorf("String conversion failed. Got %s, wants %s", id.String(), "435834986943")
    35  	}
    36  
    37  	if id.HexString() != "6579ca21bf" {
    38  		t.Errorf("String conversion for Hex failed. Got %s, wants %s", id.HexString(), "6579ca21bf")
    39  	}
    40  
    41  	if id.HexPrettyString() != "0x6579ca21bf" {
    42  		t.Errorf("String conversion for Pretty Hex failed. Got %s, wants %s", id.HexPrettyString(), "0x6579ca21bf")
    43  	}
    44  
    45  	b, err = id.MarshalBinary()
    46  	if err != nil {
    47  		t.Error(err)
    48  	}
    49  	if string(b) != "110010101111001110010100010000110111111" {
    50  		t.Errorf("String conversion for binary failed. Got %s, wants %s", string(b), "110010101111001110010100010000110111111")
    51  	}
    52  }
    53  
    54  func TestSnowflake_IsZero(t *testing.T) {
    55  	id := Snowflake(0)
    56  	if !id.IsZero() {
    57  		t.Errorf("snowflake should be considered empty when value is 0")
    58  	}
    59  	id = Snowflake(1)
    60  	if id.IsZero() {
    61  		t.Errorf("snowflake should contain data")
    62  	}
    63  }
    64  
    65  func TestBinaryMarshalling(t *testing.T) {
    66  	if _, ok := interface{}((*Snowflake)(nil)).(encoding.BinaryMarshaler); !ok {
    67  		t.Error("does not implement encoding.BinaryMarshaler")
    68  	}
    69  
    70  	id := NewSnowflake(4598345)
    71  	b, err := id.MarshalBinary()
    72  	if err != nil {
    73  		t.Error(err)
    74  	}
    75  
    76  	id2 := NewSnowflake(4534)
    77  	err = id2.UnmarshalBinary(b)
    78  	if err != nil {
    79  		t.Error(err)
    80  	}
    81  
    82  	if id2 != id {
    83  		t.Errorf("Value differs. Got %d, wants %d", id2, id)
    84  	}
    85  }
    86  
    87  func TestTextMarshalling(t *testing.T) {
    88  	if _, ok := interface{}((*Snowflake)(nil)).(encoding.TextMarshaler); !ok {
    89  		t.Error("does not implement encoding.TextMarshaler")
    90  	}
    91  
    92  	target := "80351110224678912"
    93  
    94  	id := NewSnowflake(4534)
    95  	err := id.UnmarshalText([]byte(target))
    96  	if err != nil {
    97  		t.Error(err)
    98  	}
    99  
   100  	b, err := id.MarshalText()
   101  	if err != nil {
   102  		t.Error(err)
   103  	}
   104  
   105  	if string(b) != target {
   106  		t.Errorf("Value differs. Got %s, wants %s", string(b), target)
   107  	}
   108  }
   109  
   110  func TestJSONMarshalling(t *testing.T) {
   111  	if _, ok := interface{}((*Snowflake)(nil)).(json.Marshaler); !ok {
   112  		t.Error("does not implement json.Marshaler")
   113  	}
   114  
   115  	target := `"80351110224678912"`
   116  
   117  	id := NewSnowflake(0)
   118  	err := json.Unmarshal([]byte(target), &id)
   119  	if err != nil {
   120  		t.Error(err)
   121  	}
   122  
   123  	b, err := json.Marshal(id)
   124  	if err != nil {
   125  		t.Error(err)
   126  	}
   127  
   128  	if string(b) != target {
   129  		t.Errorf("Incorrect snowflake value. Got %s, wants %s", string(b), target)
   130  	}
   131  
   132  	id = NewSnowflake(0)
   133  	b, err = json.Marshal(&id)
   134  	if err != nil {
   135  		t.Error(err)
   136  	}
   137  	if string(b) != `null` {
   138  		t.Error("expected 0 Snowflake to display as null, got " + string(b))
   139  	}
   140  
   141  	if err = json.Unmarshal([]byte("1"), &id); err != nil {
   142  		t.Fatal(err)
   143  	}
   144  }
   145  
   146  type testSet struct {
   147  	result uint64
   148  	data   []byte
   149  }
   150  
   151  func TestSnowflake_UnmarshalJSON(t *testing.T) {
   152  	data := []testSet{
   153  		{8994537984753, []byte(`{"id":"8994537984753"}`)},
   154  		{4573485, []byte(`{"id":"4573485"}`)},
   155  		{2349872349, []byte(`{"id":"00002349872349"}`)},
   156  		{435453, []byte(`{"id":"435453"}`)},
   157  		{4987598525434463, []byte(`{"id":"4987598525434463"}`)},
   158  		{69696969, []byte(`{"id":69696969}`)},
   159  		{59823042, []byte(`{"id":"059823042"}`)},
   160  		{698734534634, []byte(`{"id":"698734534634"}`)},
   161  		{24795873495, []byte(`{"id":"024795873495"}`)},
   162  		{598360703000, []byte(`{"id":"0598360703000"}`)},
   163  		{0, []byte(`{"id":null}`)},
   164  		{0, []byte(`{"id":0}`)},
   165  		{1, []byte(`{"id":1}`)},
   166  		{(1 << 63) | 1, []byte(`{"id":-1}`)},
   167  		{0, []byte(`{"id":"0"}`)},
   168  		{10, []byte(`{"id":10}`)},
   169  	}
   170  
   171  	type Foo struct {
   172  		Bar Snowflake `json:"id,omitempty"`
   173  	}
   174  
   175  	foo := &Foo{}
   176  	for i := range data {
   177  		wants := data[i].result
   178  		input := data[i].data
   179  		err := json.Unmarshal(input, foo)
   180  		if err != nil {
   181  			t.Error(err.Error() + " | " + "given input of: " + string(input))
   182  		}
   183  
   184  		if uint64(foo.Bar) != wants {
   185  			t.Errorf("incorrect snowflake ID. Got %d, wants %d", foo.Bar, wants)
   186  		}
   187  	}
   188  
   189  	// fail on letters in snowflake ID's
   190  	evilJSON := []byte("{\"id\":\"89945379a84753\"}")
   191  	err := json.Unmarshal(evilJSON, foo)
   192  	if err == nil {
   193  		t.Error("expected to fail, but continued to parse string as uint64")
   194  	}
   195  	signedIntJSON := []byte("{\"id\":\"-234234\"}")
   196  	if err := json.Unmarshal(signedIntJSON, foo); err != nil {
   197  		t.Error(err)
   198  	}
   199  }
   200  
   201  func BenchmarkUnmarshalJSON(b *testing.B) {
   202  	dataSets := [][]byte{
   203  		[]byte("\"8994537984753\""),
   204  		[]byte("\"4573485\""),
   205  		[]byte("\"00002349872349\""),
   206  		[]byte("\"435453\""),
   207  		[]byte("\"4987598525434463\""),
   208  		[]byte("\"059823042\""),
   209  		[]byte("\"698734534634\""),
   210  		[]byte("\"024795873495\""),
   211  		[]byte("\"0598360703000\""),
   212  	}
   213  	b.Run("string", func(b *testing.B) {
   214  		var result string
   215  		var i int
   216  		length := len(dataSets)
   217  		for n := 0; n < b.N; n++ {
   218  			result = string(dataSets[i])
   219  			i++
   220  			if i == length {
   221  				i = 0
   222  			}
   223  		}
   224  		if result == "" {
   225  		}
   226  	})
   227  	b.Run("snowflake", func(b *testing.B) {
   228  		var s Snowflake
   229  		var i int
   230  		length := len(dataSets)
   231  		for n := 0; n < b.N; n++ {
   232  			if err := s.UnmarshalJSON(dataSets[i]); err != nil {
   233  				b.Error(err)
   234  			}
   235  			i++
   236  			if i == length {
   237  				i = 0
   238  			}
   239  		}
   240  	})
   241  	type fooOld struct {
   242  		Foo string `json:"id"`
   243  	}
   244  	type fooNew struct {
   245  		Foo Snowflake `json:"id"`
   246  	}
   247  	dataSetsJSON := [][]byte{
   248  		[]byte("{\"id\":\"8994537984753\"}"),
   249  		[]byte("{\"id\":\"4573485\"}"),
   250  		[]byte("{\"id\":\"00002349872349\"}"),
   251  		[]byte("{\"id\":\"435453\"}"),
   252  		[]byte("{\"id\":\"4987598525434463\"}"),
   253  		[]byte("{\"id\":\"059823042\"}"),
   254  		[]byte("{\"id\":\"698734534634\"}"),
   255  		[]byte("{\"id\":\"024795873495\"}"),
   256  		[]byte("{\"id\":\"0598360703000\"}"),
   257  		[]byte("{\"id\":null}"),
   258  	}
   259  	b.Run("string-struct", func(b *testing.B) {
   260  		foo := &fooOld{}
   261  		var i int
   262  		length := len(dataSetsJSON)
   263  		for n := 0; n < b.N; n++ {
   264  			_ = json.Unmarshal(dataSetsJSON[i], foo)
   265  			i++
   266  			if i == length {
   267  				i = 0
   268  			}
   269  		}
   270  	})
   271  	b.Run("snowflake-struct", func(b *testing.B) {
   272  		foo := &fooNew{}
   273  		var i int
   274  		length := len(dataSetsJSON)
   275  		for n := 0; n < b.N; n++ {
   276  			_ = json.Unmarshal(dataSetsJSON[i], foo)
   277  			i++
   278  			if i == length {
   279  				i = 0
   280  			}
   281  		}
   282  	})
   283  }
   284  
   285  var sink_nullcheck bool
   286  var sink_nullcheck2 bool
   287  var sink_nullcheck3 bool
   288  
   289  func BenchmarkNullCheck(b *testing.B) {
   290  	// this trick isn't needed any longer, as we assume none string values starting with n, with a length of 4 is null
   291  	b.Run("asci-sum", func(b *testing.B) {
   292  		data := []byte(`null`)
   293  		length := len(data)
   294  		start := 0
   295  		for n := 0; n < b.N; n++ {
   296  			sink_nullcheck = length < 6 && int(data[start])+int(data[start+1])+int(data[start+2])+int(data[start+3]) == int('n'+'u'+'l'+'l')
   297  		}
   298  	})
   299  	b.Run("branched", func(b *testing.B) {
   300  		data := []byte(`null`)
   301  		length := len(data)
   302  		start := 0
   303  		for n := 0; n < b.N; n++ {
   304  			sink_nullcheck2 = length < 6 && data[start] == 'n' && data[start+1] == 'u' && data[start+2] == 'l' && data[start+3] == 'l'
   305  		}
   306  	})
   307  	b.Run("string", func(b *testing.B) {
   308  		data := []byte(`null`)
   309  		length := len(data)
   310  		for n := 0; n < b.N; n++ {
   311  			sink_nullcheck3 = length == 4 && string(data) == "null"
   312  		}
   313  	})
   314  	b.Run("assuming", func(b *testing.B) {
   315  		data := []byte(`null`)
   316  		length := len(data)
   317  		start := 0
   318  		for n := 0; n < b.N; n++ {
   319  			sink_nullcheck3 = length == 4 && data[start] == 'n'
   320  		}
   321  	})
   322  }