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