1// Copyright 2016 The Oklog Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package ulid_test
15
16import (
17	"bytes"
18	crand "crypto/rand"
19	"fmt"
20	"io"
21	"math"
22	"math/rand"
23	"strings"
24	"testing"
25	"testing/iotest"
26	"testing/quick"
27	"time"
28
29	"github.com/oklog/ulid"
30)
31
32func ExampleULID() {
33	t := time.Unix(1000000, 0)
34	entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0)
35	fmt.Println(ulid.MustNew(ulid.Timestamp(t), entropy))
36	// Output: 0000XSNJG0MQJHBF4QX1EFD6Y3
37}
38
39func TestNew(t *testing.T) {
40	t.Parallel()
41
42	t.Run("ULID", testULID(func(ms uint64, e io.Reader) ulid.ULID {
43		id, err := ulid.New(ms, e)
44		if err != nil {
45			t.Fatal(err)
46		}
47		return id
48	}))
49
50	t.Run("Error", func(t *testing.T) {
51		_, err := ulid.New(ulid.MaxTime()+1, nil)
52		if got, want := err, ulid.ErrBigTime; got != want {
53			t.Errorf("got err %v, want %v", got, want)
54		}
55
56		_, err = ulid.New(0, strings.NewReader(""))
57		if got, want := err, io.EOF; got != want {
58			t.Errorf("got err %v, want %v", got, want)
59		}
60	})
61}
62
63func TestMustNew(t *testing.T) {
64	t.Parallel()
65
66	t.Run("ULID", testULID(ulid.MustNew))
67
68	t.Run("Panic", func(t *testing.T) {
69		defer func() {
70			if got, want := recover(), io.EOF; got != want {
71				t.Errorf("panic with err %v, want %v", got, want)
72			}
73		}()
74		_ = ulid.MustNew(0, strings.NewReader(""))
75	})
76}
77
78func TestMustParse(t *testing.T) {
79	t.Parallel()
80
81	for _, tc := range []struct {
82		name string
83		fn   func(string) ulid.ULID
84	}{
85		{"MustParse", ulid.MustParse},
86		{"MustParseStrict", ulid.MustParseStrict},
87	} {
88		t.Run(tc.name, func(t *testing.T) {
89			defer func() {
90				if got, want := recover(), ulid.ErrDataSize; got != want {
91					t.Errorf("got panic %v, want %v", got, want)
92				}
93			}()
94			_ = tc.fn("")
95		})
96
97	}
98}
99
100func testULID(mk func(uint64, io.Reader) ulid.ULID) func(*testing.T) {
101	return func(t *testing.T) {
102		want := ulid.ULID{0x0, 0x0, 0x0, 0x1, 0x86, 0xa0}
103		if got := mk(1e5, nil); got != want { // optional entropy
104			t.Errorf("\ngot  %#v\nwant %#v", got, want)
105		}
106
107		entropy := bytes.Repeat([]byte{0xFF}, 16)
108		copy(want[6:], entropy)
109		if got := mk(1e5, bytes.NewReader(entropy)); got != want {
110			t.Errorf("\ngot  %#v\nwant %#v", got, want)
111		}
112	}
113}
114
115func TestRoundTrips(t *testing.T) {
116	t.Parallel()
117
118	prop := func(id ulid.ULID) bool {
119		bin, err := id.MarshalBinary()
120		if err != nil {
121			t.Fatal(err)
122		}
123
124		txt, err := id.MarshalText()
125		if err != nil {
126			t.Fatal(err)
127		}
128
129		var a ulid.ULID
130		if err = a.UnmarshalBinary(bin); err != nil {
131			t.Fatal(err)
132		}
133
134		var b ulid.ULID
135		if err = b.UnmarshalText(txt); err != nil {
136			t.Fatal(err)
137		}
138
139		return id == a && b == id &&
140			id == ulid.MustParse(id.String()) &&
141			id == ulid.MustParseStrict(id.String())
142	}
143
144	err := quick.Check(prop, &quick.Config{MaxCount: 1E5})
145	if err != nil {
146		t.Fatal(err)
147	}
148}
149
150func TestMarshalingErrors(t *testing.T) {
151	t.Parallel()
152
153	var id ulid.ULID
154	for _, tc := range []struct {
155		name string
156		fn   func([]byte) error
157		err  error
158	}{
159		{"UnmarshalBinary", id.UnmarshalBinary, ulid.ErrDataSize},
160		{"UnmarshalText", id.UnmarshalText, ulid.ErrDataSize},
161		{"MarshalBinaryTo", id.MarshalBinaryTo, ulid.ErrBufferSize},
162		{"MarshalTextTo", id.MarshalTextTo, ulid.ErrBufferSize},
163	} {
164		t.Run(tc.name, func(t *testing.T) {
165			if got, want := tc.fn([]byte{}), tc.err; got != want {
166				t.Errorf("got err %v, want %v", got, want)
167			}
168		})
169
170	}
171}
172
173func TestParseStrictInvalidCharacters(t *testing.T) {
174	t.Parallel()
175
176	type testCase struct {
177		name  string
178		input string
179	}
180	testCases := []testCase{}
181	base := "0000XSNJG0MQJHBF4QX1EFD6Y3"
182	for i := 0; i < ulid.EncodedSize; i++ {
183		testCases = append(testCases, testCase{
184			name:  fmt.Sprintf("Invalid 0xFF at index %d", i),
185			input: base[:i] + "\xff" + base[i+1:],
186		})
187		testCases = append(testCases, testCase{
188			name:  fmt.Sprintf("Invalid 0x00 at index %d", i),
189			input: base[:i] + "\x00" + base[i+1:],
190		})
191	}
192
193	for _, tt := range testCases {
194		t.Run(tt.name, func(t *testing.T) {
195			_, err := ulid.ParseStrict(tt.input)
196			if err != ulid.ErrInvalidCharacters {
197				t.Errorf("Parse(%q): got err %v, want %v", tt.input, err, ulid.ErrInvalidCharacters)
198			}
199		})
200	}
201}
202
203func TestAlizainCompatibility(t *testing.T) {
204	t.Parallel()
205
206	ts := uint64(1469918176385)
207	got := ulid.MustNew(ts, bytes.NewReader(make([]byte, 16)))
208	want := ulid.MustParse("01ARYZ6S410000000000000000")
209	if got != want {
210		t.Fatalf("with time=%d, got %q, want %q", ts, got, want)
211	}
212}
213
214func TestEncoding(t *testing.T) {
215	t.Parallel()
216
217	enc := make(map[rune]bool, len(ulid.Encoding))
218	for _, r := range ulid.Encoding {
219		enc[r] = true
220	}
221
222	prop := func(id ulid.ULID) bool {
223		for _, r := range id.String() {
224			if !enc[r] {
225				return false
226			}
227		}
228		return true
229	}
230
231	if err := quick.Check(prop, &quick.Config{MaxCount: 1E5}); err != nil {
232		t.Fatal(err)
233	}
234}
235
236func TestLexicographicalOrder(t *testing.T) {
237	t.Parallel()
238
239	prop := func(a, b ulid.ULID) bool {
240		t1, t2 := a.Time(), b.Time()
241		s1, s2 := a.String(), b.String()
242		ord := bytes.Compare(a[:], b[:])
243		return t1 == t2 ||
244			(t1 > t2 && s1 > s2 && ord == +1) ||
245			(t1 < t2 && s1 < s2 && ord == -1)
246	}
247
248	top := ulid.MustNew(ulid.MaxTime(), nil)
249	for i := 0; i < 10; i++ { // test upper boundary state space
250		next := ulid.MustNew(top.Time()-1, nil)
251		if !prop(top, next) {
252			t.Fatalf("bad lexicographical order: (%v, %q) > (%v, %q) == false",
253				top.Time(), top,
254				next.Time(), next,
255			)
256		}
257		top = next
258	}
259
260	if err := quick.Check(prop, &quick.Config{MaxCount: 1E6}); err != nil {
261		t.Fatal(err)
262	}
263}
264
265func TestCaseInsensitivity(t *testing.T) {
266	t.Parallel()
267
268	upper := func(id ulid.ULID) (out ulid.ULID) {
269		return ulid.MustParse(strings.ToUpper(id.String()))
270	}
271
272	lower := func(id ulid.ULID) (out ulid.ULID) {
273		return ulid.MustParse(strings.ToLower(id.String()))
274	}
275
276	err := quick.CheckEqual(upper, lower, nil)
277	if err != nil {
278		t.Fatal(err)
279	}
280}
281
282func TestParseRobustness(t *testing.T) {
283	t.Parallel()
284
285	cases := [][]byte{
286		{0x1, 0xc0, 0x73, 0x62, 0x4a, 0xaf, 0x39, 0x78, 0x51, 0x4e, 0xf8, 0x44, 0x3b,
287			0xb2, 0xa8, 0x59, 0xc7, 0x5f, 0xc3, 0xcc, 0x6a, 0xf2, 0x6d, 0x5a, 0xaa, 0x20},
288	}
289
290	for _, tc := range cases {
291		if _, err := ulid.Parse(string(tc)); err != nil {
292			t.Error(err)
293		}
294	}
295
296	prop := func(s [26]byte) (ok bool) {
297		defer func() {
298			if err := recover(); err != nil {
299				t.Error(err)
300				ok = false
301			}
302		}()
303
304		// quick.Check doesn't constrain input,
305		// so we need to do so artificially.
306		if s[0] > '7' {
307			s[0] %= '7'
308		}
309
310		var err error
311		if _, err = ulid.Parse(string(s[:])); err != nil {
312			t.Error(err)
313		}
314
315		return err == nil
316	}
317
318	err := quick.Check(prop, &quick.Config{MaxCount: 1E4})
319	if err != nil {
320		t.Fatal(err)
321	}
322}
323
324func TestNow(t *testing.T) {
325	t.Parallel()
326
327	before := ulid.Now()
328	after := ulid.Timestamp(time.Now().UTC().Add(time.Millisecond))
329
330	if before >= after {
331		t.Fatalf("clock went mad: before %v, after %v", before, after)
332	}
333}
334
335func TestTimestamp(t *testing.T) {
336	t.Parallel()
337
338	tm := time.Unix(1, 1000) // will be truncated
339	if got, want := ulid.Timestamp(tm), uint64(1000); got != want {
340		t.Errorf("for %v, got %v, want %v", tm, got, want)
341	}
342
343	mt := ulid.MaxTime()
344	dt := time.Unix(int64(mt/1000), int64((mt%1000)*1000000)).Truncate(time.Millisecond)
345	ts := ulid.Timestamp(dt)
346	if got, want := ts, mt; got != want {
347		t.Errorf("got timestamp %d, want %d", got, want)
348	}
349}
350
351func TestTime(t *testing.T) {
352	t.Parallel()
353
354	original := time.Now()
355	diff := original.Sub(ulid.Time(ulid.Timestamp(original)))
356	if diff >= time.Millisecond {
357		t.Errorf("difference between original and recovered time (%d) greater"+
358			"than a millisecond", diff)
359	}
360
361}
362
363func TestTimestampRoundTrips(t *testing.T) {
364	t.Parallel()
365
366	prop := func(ts uint64) bool {
367		return ts == ulid.Timestamp(ulid.Time(ts))
368	}
369
370	err := quick.Check(prop, &quick.Config{MaxCount: 1E5})
371	if err != nil {
372		t.Fatal(err)
373	}
374}
375
376func TestULIDTime(t *testing.T) {
377	t.Parallel()
378
379	maxTime := ulid.MaxTime()
380
381	var id ulid.ULID
382	if got, want := id.SetTime(maxTime+1), ulid.ErrBigTime; got != want {
383		t.Errorf("got err %v, want %v", got, want)
384	}
385
386	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
387	for i := 0; i < 1e6; i++ {
388		ms := uint64(rng.Int63n(int64(maxTime)))
389
390		var id ulid.ULID
391		if err := id.SetTime(ms); err != nil {
392			t.Fatal(err)
393		}
394
395		if got, want := id.Time(), ms; got != want {
396			t.Fatalf("\nfor %v:\ngot  %v\nwant %v", id, got, want)
397		}
398	}
399}
400
401func TestEntropy(t *testing.T) {
402	t.Parallel()
403
404	var id ulid.ULID
405	if got, want := id.SetEntropy([]byte{}), ulid.ErrDataSize; got != want {
406		t.Errorf("got err %v, want %v", got, want)
407	}
408
409	prop := func(e [10]byte) bool {
410		var id ulid.ULID
411		if err := id.SetEntropy(e[:]); err != nil {
412			t.Fatalf("got err %v", err)
413		}
414
415		got, want := id.Entropy(), e[:]
416		eq := bytes.Equal(got, want)
417		if !eq {
418			t.Errorf("\n(!= %v\n    %v)", got, want)
419		}
420
421		return eq
422	}
423
424	if err := quick.Check(prop, nil); err != nil {
425		t.Fatal(err)
426	}
427}
428
429func TestEntropyRead(t *testing.T) {
430	t.Parallel()
431
432	prop := func(e [10]byte) bool {
433		flakyReader := iotest.HalfReader(bytes.NewReader(e[:]))
434
435		id, err := ulid.New(ulid.Now(), flakyReader)
436		if err != nil {
437			t.Fatalf("got err %v", err)
438		}
439
440		got, want := id.Entropy(), e[:]
441		eq := bytes.Equal(got, want)
442		if !eq {
443			t.Errorf("\n(!= %v\n    %v)", got, want)
444		}
445
446		return eq
447	}
448
449	if err := quick.Check(prop, &quick.Config{MaxCount: 1E4}); err != nil {
450		t.Fatal(err)
451	}
452}
453
454func TestCompare(t *testing.T) {
455	t.Parallel()
456
457	a := func(a, b ulid.ULID) int {
458		return strings.Compare(a.String(), b.String())
459	}
460
461	b := func(a, b ulid.ULID) int {
462		return a.Compare(b)
463	}
464
465	err := quick.CheckEqual(a, b, &quick.Config{MaxCount: 1E5})
466	if err != nil {
467		t.Error(err)
468	}
469}
470
471func TestOverflowHandling(t *testing.T) {
472	for s, want := range map[string]error{
473		"00000000000000000000000000": nil,
474		"70000000000000000000000000": nil,
475		"7ZZZZZZZZZZZZZZZZZZZZZZZZZ": nil,
476		"80000000000000000000000000": ulid.ErrOverflow,
477		"80000000000000000000000001": ulid.ErrOverflow,
478		"ZZZZZZZZZZZZZZZZZZZZZZZZZZ": ulid.ErrOverflow,
479	} {
480		if _, have := ulid.Parse(s); want != have {
481			t.Errorf("%s: want error %v, have %v", s, want, have)
482		}
483	}
484}
485
486func TestScan(t *testing.T) {
487	id := ulid.MustNew(123, crand.Reader)
488
489	for _, tc := range []struct {
490		name string
491		in   interface{}
492		out  ulid.ULID
493		err  error
494	}{
495		{"string", id.String(), id, nil},
496		{"bytes", id[:], id, nil},
497		{"nil", nil, ulid.ULID{}, nil},
498		{"other", 44, ulid.ULID{}, ulid.ErrScanValue},
499	} {
500		tc := tc
501		t.Run(tc.name, func(t *testing.T) {
502			t.Parallel()
503
504			var out ulid.ULID
505			err := out.Scan(tc.in)
506			if got, want := out, tc.out; got.Compare(want) != 0 {
507				t.Errorf("got ULID %s, want %s", got, want)
508			}
509
510			if got, want := fmt.Sprint(err), fmt.Sprint(tc.err); got != want {
511				t.Errorf("got err %q, want %q", got, want)
512			}
513		})
514	}
515}
516
517func TestMonotonic(t *testing.T) {
518	now := ulid.Now()
519	for _, e := range []struct {
520		name string
521		mk   func() io.Reader
522	}{
523		{"cryptorand", func() io.Reader { return crand.Reader }},
524		{"mathrand", func() io.Reader { return rand.New(rand.NewSource(int64(now))) }},
525	} {
526		for _, inc := range []uint64{
527			0,
528			1,
529			2,
530			math.MaxUint8 + 1,
531			math.MaxUint16 + 1,
532			math.MaxUint32 + 1,
533		} {
534			inc := inc
535			entropy := ulid.Monotonic(e.mk(), uint64(inc))
536
537			t.Run(fmt.Sprintf("entropy=%s/inc=%d", e.name, inc), func(t *testing.T) {
538				t.Parallel()
539
540				var prev ulid.ULID
541				for i := 0; i < 10000; i++ {
542					next, err := ulid.New(123, entropy)
543					if err != nil {
544						t.Fatal(err)
545					}
546
547					if prev.Compare(next) >= 0 {
548						t.Fatalf("prev: %v %v > next: %v %v",
549							prev.Time(), prev.Entropy(), next.Time(), next.Entropy())
550					}
551
552					prev = next
553				}
554			})
555		}
556	}
557}
558
559func TestMonotonicOverflow(t *testing.T) {
560	t.Parallel()
561
562	entropy := ulid.Monotonic(
563		io.MultiReader(
564			bytes.NewReader(bytes.Repeat([]byte{0xFF}, 10)), // Entropy for first ULID
565			crand.Reader, // Following random entropy
566		),
567		0,
568	)
569
570	prev, err := ulid.New(0, entropy)
571	if err != nil {
572		t.Fatal(err)
573	}
574
575	next, err := ulid.New(prev.Time(), entropy)
576	if have, want := err, ulid.ErrMonotonicOverflow; have != want {
577		t.Errorf("have ulid: %v %v err: %v, want err: %v",
578			next.Time(), next.Entropy(), have, want)
579	}
580}
581
582func BenchmarkNew(b *testing.B) {
583	benchmarkMakeULID(b, func(timestamp uint64, entropy io.Reader) {
584		_, _ = ulid.New(timestamp, entropy)
585	})
586}
587
588func BenchmarkMustNew(b *testing.B) {
589	benchmarkMakeULID(b, func(timestamp uint64, entropy io.Reader) {
590		_ = ulid.MustNew(timestamp, entropy)
591	})
592}
593
594func benchmarkMakeULID(b *testing.B, f func(uint64, io.Reader)) {
595	b.ReportAllocs()
596	b.SetBytes(int64(len(ulid.ULID{})))
597
598	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
599
600	for _, tc := range []struct {
601		name       string
602		timestamps []uint64
603		entropy    io.Reader
604	}{
605		{"WithCrypoEntropy", []uint64{123}, crand.Reader},
606		{"WithEntropy", []uint64{123}, rng},
607		{"WithMonotonicEntropy_SameTimestamp_Inc0", []uint64{123}, ulid.Monotonic(rng, 0)},
608		{"WithMonotonicEntropy_DifferentTimestamp_Inc0", []uint64{122, 123}, ulid.Monotonic(rng, 0)},
609		{"WithMonotonicEntropy_SameTimestamp_Inc1", []uint64{123}, ulid.Monotonic(rng, 1)},
610		{"WithMonotonicEntropy_DifferentTimestamp_Inc1", []uint64{122, 123}, ulid.Monotonic(rng, 1)},
611		{"WithCryptoMonotonicEntropy_SameTimestamp_Inc1", []uint64{123}, ulid.Monotonic(crand.Reader, 1)},
612		{"WithCryptoMonotonicEntropy_DifferentTimestamp_Inc1", []uint64{122, 123}, ulid.Monotonic(crand.Reader, 1)},
613		{"WithoutEntropy", []uint64{123}, nil},
614	} {
615		tc := tc
616		b.Run(tc.name, func(b *testing.B) {
617			b.StopTimer()
618			b.ResetTimer()
619			b.StartTimer()
620			for i := 0; i < b.N; i++ {
621				f(tc.timestamps[i%len(tc.timestamps)], tc.entropy)
622			}
623		})
624	}
625}
626
627func BenchmarkParse(b *testing.B) {
628	const s = "0000XSNJG0MQJHBF4QX1EFD6Y3"
629	b.SetBytes(int64(len(s)))
630	for i := 0; i < b.N; i++ {
631		_, _ = ulid.Parse(s)
632	}
633}
634
635func BenchmarkParseStrict(b *testing.B) {
636	const s = "0000XSNJG0MQJHBF4QX1EFD6Y3"
637	b.SetBytes(int64(len(s)))
638	for i := 0; i < b.N; i++ {
639		_, _ = ulid.ParseStrict(s)
640	}
641}
642
643func BenchmarkMustParse(b *testing.B) {
644	const s = "0000XSNJG0MQJHBF4QX1EFD6Y3"
645	b.SetBytes(int64(len(s)))
646	for i := 0; i < b.N; i++ {
647		_ = ulid.MustParse(s)
648	}
649}
650
651func BenchmarkString(b *testing.B) {
652	entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
653	id := ulid.MustNew(123456, entropy)
654	b.SetBytes(int64(len(id)))
655	b.ResetTimer()
656	for i := 0; i < b.N; i++ {
657		_ = id.String()
658	}
659}
660
661func BenchmarkMarshal(b *testing.B) {
662	entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
663	buf := make([]byte, ulid.EncodedSize)
664	id := ulid.MustNew(123456, entropy)
665
666	b.Run("Text", func(b *testing.B) {
667		b.SetBytes(int64(len(id)))
668		b.ResetTimer()
669		for i := 0; i < b.N; i++ {
670			_, _ = id.MarshalText()
671		}
672	})
673
674	b.Run("TextTo", func(b *testing.B) {
675		b.SetBytes(int64(len(id)))
676		b.ResetTimer()
677		for i := 0; i < b.N; i++ {
678			_ = id.MarshalTextTo(buf)
679		}
680	})
681
682	b.Run("Binary", func(b *testing.B) {
683		b.SetBytes(int64(len(id)))
684		b.ResetTimer()
685		for i := 0; i < b.N; i++ {
686			_, _ = id.MarshalBinary()
687		}
688	})
689
690	b.Run("BinaryTo", func(b *testing.B) {
691		b.SetBytes(int64(len(id)))
692		b.ResetTimer()
693		for i := 0; i < b.N; i++ {
694			_ = id.MarshalBinaryTo(buf)
695		}
696	})
697}
698
699func BenchmarkUnmarshal(b *testing.B) {
700	var id ulid.ULID
701	s := "0000XSNJG0MQJHBF4QX1EFD6Y3"
702	txt := []byte(s)
703	bin, _ := ulid.MustParse(s).MarshalBinary()
704
705	b.Run("Text", func(b *testing.B) {
706		b.SetBytes(int64(len(txt)))
707		b.ResetTimer()
708		for i := 0; i < b.N; i++ {
709			_ = id.UnmarshalText(txt)
710		}
711	})
712
713	b.Run("Binary", func(b *testing.B) {
714		b.SetBytes(int64(len(bin)))
715		b.ResetTimer()
716		for i := 0; i < b.N; i++ {
717			_ = id.UnmarshalBinary(bin)
718		}
719	})
720}
721
722func BenchmarkNow(b *testing.B) {
723	b.SetBytes(8)
724	b.ResetTimer()
725	for i := 0; i < b.N; i++ {
726		_ = ulid.Now()
727	}
728}
729
730func BenchmarkTimestamp(b *testing.B) {
731	now := time.Now()
732	b.SetBytes(8)
733	b.ResetTimer()
734	for i := 0; i < b.N; i++ {
735		_ = ulid.Timestamp(now)
736	}
737}
738
739func BenchmarkTime(b *testing.B) {
740	id := ulid.MustNew(123456789, nil)
741	b.SetBytes(8)
742	b.ResetTimer()
743	for i := 0; i < b.N; i++ {
744		_ = id.Time()
745	}
746}
747
748func BenchmarkSetTime(b *testing.B) {
749	var id ulid.ULID
750	b.SetBytes(8)
751	b.ResetTimer()
752	for i := 0; i < b.N; i++ {
753		_ = id.SetTime(123456789)
754	}
755}
756
757func BenchmarkEntropy(b *testing.B) {
758	id := ulid.MustNew(0, strings.NewReader("ABCDEFGHIJKLMNOP"))
759	b.SetBytes(10)
760	b.ResetTimer()
761	for i := 0; i < b.N; i++ {
762		_ = id.Entropy()
763	}
764}
765
766func BenchmarkSetEntropy(b *testing.B) {
767	var id ulid.ULID
768	e := []byte("ABCDEFGHIJKLMNOP")
769	b.SetBytes(10)
770	b.ResetTimer()
771	for i := 0; i < b.N; i++ {
772		_ = id.SetEntropy(e)
773	}
774}
775
776func BenchmarkCompare(b *testing.B) {
777	id, other := ulid.MustNew(12345, nil), ulid.MustNew(54321, nil)
778	b.SetBytes(int64(len(id) * 2))
779	b.ResetTimer()
780	for i := 0; i < b.N; i++ {
781		_ = id.Compare(other)
782	}
783}
784