git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/uuid/uuid_test.go (about) 1 // Copyright 2016 Google Inc. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package uuid 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "os" 12 "runtime" 13 "strings" 14 "testing" 15 "time" 16 "unsafe" 17 ) 18 19 type test struct { 20 in string 21 version Version 22 variant Variant 23 isuuid bool 24 } 25 26 var tests = []test{ 27 {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, 28 {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, 29 {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, 30 {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, 31 {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, 32 {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, 33 {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, 34 {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, 35 {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, 36 {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, 37 {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, 38 {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, 39 {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, 40 {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, 41 {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, 42 {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, 43 44 {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 45 {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 46 {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 47 {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, 48 {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, 49 {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, 50 {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, 51 {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, 52 {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, 53 {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, 54 {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, 55 {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, 56 {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, 57 {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, 58 {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, 59 {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, 60 {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, 61 {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, 62 63 {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, 64 {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, 65 {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, 66 {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, 67 {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, 68 {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, 69 70 {"{f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, RFC4122, true}, 71 {"{f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, Invalid, false}, 72 {"f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, Invalid, false}, 73 74 {"f47ac10b58cc037285670e02b2c3d479", 0, RFC4122, true}, 75 {"f47ac10b58cc037285670e02b2c3d4790", 0, Invalid, false}, 76 {"f47ac10b58cc037285670e02b2c3d47", 0, Invalid, false}, 77 78 {"01ee836c-e7c9-619d-929a-525400475911", 6, RFC4122, true}, 79 {"018bd12c-58b0-7683-8a5b-8752d0e86651", 7, RFC4122, true}, 80 } 81 82 var constants = []struct { 83 c interface{} 84 name string 85 }{ 86 {Person, "Person"}, 87 {Group, "Group"}, 88 {Org, "Org"}, 89 {Invalid, "Invalid"}, 90 {RFC4122, "RFC4122"}, 91 {Reserved, "Reserved"}, 92 {Microsoft, "Microsoft"}, 93 {Future, "Future"}, 94 {Domain(17), "Domain17"}, 95 {Variant(42), "BadVariant42"}, 96 } 97 98 func testTest(t *testing.T, in string, tt test) { 99 uuid, err := Parse(in) 100 if ok := (err == nil); ok != tt.isuuid { 101 t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) 102 } 103 if err != nil { 104 return 105 } 106 107 if v := uuid.Variant(); v != tt.variant { 108 t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) 109 } 110 if v := uuid.Version(); v != tt.version { 111 t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) 112 } 113 } 114 115 func testBytes(t *testing.T, in []byte, tt test) { 116 uuid, err := ParseBytes(in) 117 if ok := (err == nil); ok != tt.isuuid { 118 t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid) 119 } 120 if err != nil { 121 return 122 } 123 suuid, _ := Parse(string(in)) 124 if uuid != suuid { 125 t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid) 126 } 127 } 128 129 func TestUUID(t *testing.T) { 130 for _, tt := range tests { 131 testTest(t, tt.in, tt) 132 testTest(t, strings.ToUpper(tt.in), tt) 133 testBytes(t, []byte(tt.in), tt) 134 } 135 } 136 137 func TestFromBytes(t *testing.T) { 138 b := []byte{ 139 0x7d, 0x44, 0x48, 0x40, 140 0x9d, 0xc0, 141 0x11, 0xd1, 142 0xb2, 0x45, 143 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 144 } 145 uuid, err := FromBytes(b) 146 if err != nil { 147 t.Fatalf("%s", err) 148 } 149 for i := 0; i < len(uuid); i++ { 150 if b[i] != uuid[i] { 151 t.Fatalf("FromBytes() got %v expected %v\b", uuid[:], b) 152 } 153 } 154 } 155 156 func TestConstants(t *testing.T) { 157 for x, tt := range constants { 158 v, ok := tt.c.(fmt.Stringer) 159 if !ok { 160 t.Errorf("%x: %v: not a stringer", x, v) 161 } else if s := v.String(); s != tt.name { 162 v, _ := tt.c.(int) 163 t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name) 164 } 165 } 166 } 167 168 func TestRandomUUID(t *testing.T) { 169 m := make(map[string]bool) 170 for x := 1; x < 32; x++ { 171 uuid := NewV4() 172 s := uuid.String() 173 if m[s] { 174 t.Errorf("NewRandom returned duplicated UUID %s", s) 175 } 176 m[s] = true 177 if v := uuid.Version(); v != 4 { 178 t.Errorf("Random UUID of version %s", v) 179 } 180 if uuid.Variant() != RFC4122 { 181 t.Errorf("Random UUID is variant %d", uuid.Variant()) 182 } 183 } 184 } 185 186 func TestRandomUUID_Pooled(t *testing.T) { 187 defer DisableRandPool() 188 EnableRandPool() 189 m := make(map[string]bool) 190 for x := 1; x < 128; x++ { 191 uuid := NewV4() 192 s := uuid.String() 193 if m[s] { 194 t.Errorf("NewRandom returned duplicated UUID %s", s) 195 } 196 m[s] = true 197 if v := uuid.Version(); v != 4 { 198 t.Errorf("Random UUID of version %s", v) 199 } 200 if uuid.Variant() != RFC4122 { 201 t.Errorf("Random UUID is variant %d", uuid.Variant()) 202 } 203 } 204 } 205 206 func TestNewV4(t *testing.T) { 207 m := make(map[UUID]bool) 208 for x := 1; x < 32; x++ { 209 s := NewV4() 210 if m[s] { 211 t.Errorf("New returned duplicated UUID %s", s) 212 } 213 m[s] = true 214 uuid, err := Parse(s.String()) 215 if err != nil { 216 t.Errorf("New.String() returned %q which does not decode", s) 217 continue 218 } 219 if v := uuid.Version(); v != 4 { 220 t.Errorf("Random UUID of version %s", v) 221 } 222 if uuid.Variant() != RFC4122 { 223 t.Errorf("Random UUID is variant %d", uuid.Variant()) 224 } 225 } 226 } 227 228 func TestClockSeq(t *testing.T) { 229 // Fake time.Now for this test to return a monotonically advancing time; restore it at end. 230 defer func(orig func() time.Time) { timeNow = orig }(timeNow) 231 monTime := time.Now() 232 timeNow = func() time.Time { 233 monTime = monTime.Add(1 * time.Second) 234 return monTime 235 } 236 237 SetClockSequence(-1) 238 uuid1, err := NewUUID() 239 if err != nil { 240 t.Fatalf("could not create UUID: %v", err) 241 } 242 uuid2, err := NewUUID() 243 if err != nil { 244 t.Fatalf("could not create UUID: %v", err) 245 } 246 247 if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 { 248 t.Errorf("clock sequence %d != %d", s1, s2) 249 } 250 251 SetClockSequence(-1) 252 uuid2, err = NewUUID() 253 if err != nil { 254 t.Fatalf("could not create UUID: %v", err) 255 } 256 257 // Just on the very off chance we generated the same sequence 258 // two times we try again. 259 if uuid1.ClockSequence() == uuid2.ClockSequence() { 260 SetClockSequence(-1) 261 uuid2, err = NewUUID() 262 if err != nil { 263 t.Fatalf("could not create UUID: %v", err) 264 } 265 } 266 if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 { 267 t.Errorf("Duplicate clock sequence %d", s1) 268 } 269 270 SetClockSequence(0x1234) 271 uuid1, err = NewUUID() 272 if err != nil { 273 t.Fatalf("could not create UUID: %v", err) 274 } 275 if seq := uuid1.ClockSequence(); seq != 0x1234 { 276 t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq) 277 } 278 } 279 280 func TestCoding(t *testing.T) { 281 text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" 282 urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" 283 data := UUID{ 284 0x7d, 0x44, 0x48, 0x40, 285 0x9d, 0xc0, 286 0x11, 0xd1, 287 0xb2, 0x45, 288 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 289 } 290 if v := data.String(); v != text { 291 t.Errorf("%x: encoded to %s, expected %s", data, v, text) 292 } 293 if v := data.URN(); v != urn { 294 t.Errorf("%x: urn is %s, expected %s", data, v, urn) 295 } 296 297 uuid, err := Parse(text) 298 if err != nil { 299 t.Errorf("Parse returned unexpected error %v", err) 300 } 301 if data != uuid { 302 t.Errorf("%s: decoded to %s, expected %s", text, uuid, data) 303 } 304 } 305 306 func TestVersion1(t *testing.T) { 307 uuid1, err := NewUUID() 308 if err != nil { 309 t.Fatalf("could not create UUID: %v", err) 310 } 311 uuid2, err := NewUUID() 312 if err != nil { 313 t.Fatalf("could not create UUID: %v", err) 314 } 315 316 if uuid1 == uuid2 { 317 t.Errorf("%s:duplicate uuid", uuid1) 318 } 319 if v := uuid1.Version(); v != 1 { 320 t.Errorf("%s: version %s expected 1", uuid1, v) 321 } 322 if v := uuid2.Version(); v != 1 { 323 t.Errorf("%s: version %s expected 1", uuid2, v) 324 } 325 n1 := uuid1.NodeID() 326 n2 := uuid2.NodeID() 327 if !bytes.Equal(n1, n2) { 328 t.Errorf("Different nodes %x != %x", n1, n2) 329 } 330 t1 := uuid1.Time() 331 t2 := uuid2.Time() 332 q1 := uuid1.ClockSequence() 333 q2 := uuid2.ClockSequence() 334 335 switch { 336 case t1 == t2 && q1 == q2: 337 t.Error("time stopped") 338 case t1 > t2 && q1 == q2: 339 t.Error("time reversed") 340 case t1 < t2 && q1 != q2: 341 t.Error("clock sequence changed unexpectedly") 342 } 343 } 344 345 func TestNode(t *testing.T) { 346 // This test is mostly to make sure we don't leave nodeMu locked. 347 ifname = "" 348 if ni := NodeInterface(); ni != "" { 349 t.Errorf("NodeInterface got %q, want %q", ni, "") 350 } 351 if SetNodeInterface("xyzzy") { 352 t.Error("SetNodeInterface succeeded on a bad interface name") 353 } 354 if !SetNodeInterface("") { 355 t.Error("SetNodeInterface failed") 356 } 357 if runtime.GOARCH != "js" { 358 if ni := NodeInterface(); ni == "" { 359 t.Error("NodeInterface returned an empty string") 360 } 361 } 362 363 ni := NodeID() 364 if len(ni) != 6 { 365 t.Errorf("ni got %d bytes, want 6", len(ni)) 366 } 367 hasData := false 368 for _, b := range ni { 369 if b != 0 { 370 hasData = true 371 } 372 } 373 if !hasData { 374 t.Error("nodeid is all zeros") 375 } 376 377 id := []byte{1, 2, 3, 4, 5, 6, 7, 8} 378 SetNodeID(id) 379 ni = NodeID() 380 if !bytes.Equal(ni, id[:6]) { 381 t.Errorf("got nodeid %v, want %v", ni, id[:6]) 382 } 383 384 if ni := NodeInterface(); ni != "user" { 385 t.Errorf("got interface %q, want %q", ni, "user") 386 } 387 } 388 389 func TestNodeAndTime(t *testing.T) { 390 // Time is February 5, 1998 12:30:23.136364800 AM GMT 391 392 uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") 393 if err != nil { 394 t.Fatalf("Parser returned unexpected error %v", err) 395 } 396 node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} 397 398 ts := uuid.Time() 399 c := time.Unix(ts.UnixTime()) 400 want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) 401 if !c.Equal(want) { 402 t.Errorf("Got time %v, want %v", c, want) 403 } 404 if !bytes.Equal(node, uuid.NodeID()) { 405 t.Errorf("Expected node %v got %v", node, uuid.NodeID()) 406 } 407 } 408 409 func TestMD5(t *testing.T) { 410 uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String() 411 want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" 412 if uuid != want { 413 t.Errorf("MD5: got %q expected %q", uuid, want) 414 } 415 } 416 417 func TestSHA1(t *testing.T) { 418 uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String() 419 want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" 420 if uuid != want { 421 t.Errorf("SHA1: got %q expected %q", uuid, want) 422 } 423 } 424 425 func TestNodeID(t *testing.T) { 426 nid := []byte{1, 2, 3, 4, 5, 6} 427 SetNodeInterface("") 428 s := NodeInterface() 429 if runtime.GOARCH != "js" { 430 if s == "" || s == "user" { 431 t.Errorf("NodeInterface %q after SetInterface", s) 432 } 433 } 434 node1 := NodeID() 435 if node1 == nil { 436 t.Error("NodeID nil after SetNodeInterface", s) 437 } 438 SetNodeID(nid) 439 s = NodeInterface() 440 if s != "user" { 441 t.Errorf("Expected NodeInterface %q got %q", "user", s) 442 } 443 node2 := NodeID() 444 if node2 == nil { 445 t.Error("NodeID nil after SetNodeID", s) 446 } 447 if bytes.Equal(node1, node2) { 448 t.Error("NodeID not changed after SetNodeID", s) 449 } else if !bytes.Equal(nid, node2) { 450 t.Errorf("NodeID is %x, expected %x", node2, nid) 451 } 452 } 453 454 func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) { 455 if err != nil { 456 t.Errorf("%s failed: %v", name, err) 457 return 458 } 459 if v := uuid.Version(); v != 2 { 460 t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v) 461 return 462 } 463 if v := uuid.Domain(); v != domain { 464 t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v) 465 } 466 if v := uuid.ID(); v != id { 467 t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v) 468 } 469 } 470 471 func TestDCE(t *testing.T) { 472 uuid, err := NewDCESecurity(42, 12345678) 473 testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678) 474 uuid, err = NewDCEPerson() 475 testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid())) 476 uuid, err = NewDCEGroup() 477 testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid())) 478 } 479 480 type badRand struct{} 481 482 func (r badRand) Read(buf []byte) (int, error) { 483 for i := range buf { 484 buf[i] = byte(i) 485 } 486 return len(buf), nil 487 } 488 489 func TestBadRand(t *testing.T) { 490 SetRand(badRand{}) 491 uuid1 := NewV4() 492 uuid2 := NewV4() 493 if uuid1 != uuid2 { 494 t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2) 495 } 496 SetRand(nil) 497 uuid1 = NewV4() 498 uuid2 = NewV4() 499 if uuid1 == uuid2 { 500 t.Errorf("unexpected duplicates, got %q", uuid1) 501 } 502 } 503 504 func TestSetRand(t *testing.T) { 505 myString := "805-9dd6-1a877cb526c678e71d38-7122-44c0-9b7c-04e7001cc78783ac3e82-47a3-4cc3-9951-13f3339d88088f5d685a-11f7-4078-ada9-de44ad2daeb7" 506 507 SetRand(strings.NewReader(myString)) 508 uuid1 := NewV4() 509 uuid2 := NewV4() 510 511 SetRand(strings.NewReader(myString)) 512 uuid3 := NewV4() 513 uuid4 := NewV4() 514 515 if uuid1 != uuid3 { 516 t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) 517 } 518 if uuid2 != uuid4 { 519 t.Errorf("expected duplicates, got %q and %q", uuid2, uuid4) 520 } 521 } 522 523 func TestRandomFromReader(t *testing.T) { 524 myString := "8059ddhdle77cb52" 525 r := bytes.NewReader([]byte(myString)) 526 r2 := bytes.NewReader([]byte(myString)) 527 uuid1, err := NewRandomFromReader(r) 528 if err != nil { 529 t.Errorf("failed generating UUID from a reader") 530 } 531 _, err = NewRandomFromReader(r) 532 if err == nil { 533 t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewRandomFromReader may not be using the provided reader") 534 } 535 uuid3, err := NewRandomFromReader(r2) 536 if err != nil { 537 t.Errorf("failed generating UUID from a reader") 538 } 539 if uuid1 != uuid3 { 540 t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) 541 } 542 } 543 544 func TestRandPool(t *testing.T) { 545 myString := "8059ddhdle77cb52" 546 EnableRandPool() 547 SetRand(strings.NewReader(myString)) 548 _, err := newRandom() 549 if err == nil { 550 t.Errorf("expecting an error as reader has no more bytes") 551 } 552 DisableRandPool() 553 SetRand(strings.NewReader(myString)) 554 _, err = newRandom() 555 if err != nil { 556 t.Errorf("failed generating UUID from a reader") 557 } 558 } 559 560 func TestWrongLength(t *testing.T) { 561 _, err := Parse("12345") 562 if err == nil { 563 t.Errorf("expected ‘12345’ was invalid") 564 } else if err.Error() != "invalid UUID length: 5" { 565 t.Errorf("expected a different error message for an invalid length") 566 } 567 } 568 569 func TestIsWrongLength(t *testing.T) { 570 _, err := Parse("12345") 571 if !IsInvalidLengthError(err) { 572 t.Errorf("expected error type is invalidLengthError") 573 } 574 } 575 576 func FuzzParse(f *testing.F) { 577 for _, tt := range tests { 578 f.Add(tt.in) 579 f.Add(strings.ToUpper(tt.in)) 580 } 581 f.Fuzz(func(t *testing.T, in string) { 582 Parse(in) 583 }) 584 } 585 586 func FuzzParseBytes(f *testing.F) { 587 for _, tt := range tests { 588 f.Add([]byte(tt.in)) 589 } 590 f.Fuzz(func(t *testing.T, in []byte) { 591 ParseBytes(in) 592 }) 593 } 594 595 func FuzzFromBytes(f *testing.F) { 596 // Copied from TestFromBytes. 597 f.Add([]byte{ 598 0x7d, 0x44, 0x48, 0x40, 599 0x9d, 0xc0, 600 0x11, 0xd1, 601 0xb2, 0x45, 602 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 603 }) 604 f.Fuzz(func(t *testing.T, in []byte) { 605 FromBytes(in) 606 }) 607 } 608 609 // TestValidate checks various scenarios for the Validate function 610 func TestValidate(t *testing.T) { 611 testCases := []struct { 612 name string 613 input string 614 expect error 615 }{ 616 {"Valid UUID", "123e4567-e89b-12d3-a456-426655440000", nil}, 617 {"Valid UUID with URN", "urn:uuid:123e4567-e89b-12d3-a456-426655440000", nil}, 618 {"Valid UUID with Braces", "{123e4567-e89b-12d3-a456-426655440000}", nil}, 619 {"Valid UUID No Hyphens", "123e4567e89b12d3a456426655440000", nil}, 620 {"Invalid UUID", "invalid-uuid", errors.New("invalid UUID length: 12")}, 621 {"Invalid Length", "123", fmt.Errorf("invalid UUID length: %d", len("123"))}, 622 {"Invalid URN Prefix", "urn:test:123e4567-e89b-12d3-a456-426655440000", fmt.Errorf("invalid urn prefix: %q", "urn:test:")}, 623 {"Invalid Brackets", "[123e4567-e89b-12d3-a456-426655440000]", fmt.Errorf("invalid bracketed UUID format")}, 624 {"Invalid UUID Format", "12345678gabc1234abcd1234abcd1234", fmt.Errorf("invalid UUID format")}, 625 } 626 627 for _, tc := range testCases { 628 t.Run(tc.name, func(t *testing.T) { 629 err := Validate(tc.input) 630 if (err != nil) != (tc.expect != nil) || (err != nil && err.Error() != tc.expect.Error()) { 631 t.Errorf("Validate(%q) = %v, want %v", tc.input, err, tc.expect) 632 } 633 }) 634 } 635 } 636 637 var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479" 638 var asBytes = []byte(asString) 639 640 func BenchmarkParse(b *testing.B) { 641 for i := 0; i < b.N; i++ { 642 _, err := Parse(asString) 643 if err != nil { 644 b.Fatal(err) 645 } 646 } 647 } 648 649 func BenchmarkParseBytes(b *testing.B) { 650 for i := 0; i < b.N; i++ { 651 _, err := ParseBytes(asBytes) 652 if err != nil { 653 b.Fatal(err) 654 } 655 } 656 } 657 658 // parseBytesUnsafe is to benchmark using unsafe. 659 func parseBytesUnsafe(b []byte) (UUID, error) { 660 return Parse(*(*string)(unsafe.Pointer(&b))) 661 } 662 663 func BenchmarkParseBytesUnsafe(b *testing.B) { 664 for i := 0; i < b.N; i++ { 665 _, err := parseBytesUnsafe(asBytes) 666 if err != nil { 667 b.Fatal(err) 668 } 669 } 670 } 671 672 // parseBytesCopy is to benchmark not using unsafe. 673 func parseBytesCopy(b []byte) (UUID, error) { 674 return Parse(string(b)) 675 } 676 677 func BenchmarkParseBytesCopy(b *testing.B) { 678 for i := 0; i < b.N; i++ { 679 _, err := parseBytesCopy(asBytes) 680 if err != nil { 681 b.Fatal(err) 682 } 683 } 684 } 685 686 func BenchmarkNew(b *testing.B) { 687 for i := 0; i < b.N; i++ { 688 NewV4() 689 } 690 } 691 692 func BenchmarkUUID_String(b *testing.B) { 693 uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 694 if err != nil { 695 b.Fatal(err) 696 } 697 for i := 0; i < b.N; i++ { 698 if uuid.String() == "" { 699 b.Fatal("invalid uuid") 700 } 701 } 702 } 703 704 func BenchmarkUUID_URN(b *testing.B) { 705 uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 706 if err != nil { 707 b.Fatal(err) 708 } 709 for i := 0; i < b.N; i++ { 710 if uuid.URN() == "" { 711 b.Fatal("invalid uuid") 712 } 713 } 714 } 715 716 func BenchmarkParseBadLength(b *testing.B) { 717 short := asString[:10] 718 for i := 0; i < b.N; i++ { 719 _, err := Parse(short) 720 if err == nil { 721 b.Fatalf("expected ‘%s’ was invalid", short) 722 } 723 } 724 } 725 726 func BenchmarkParseLen32Truncated(b *testing.B) { 727 partial := asString[:len(asString)-4] 728 for i := 0; i < b.N; i++ { 729 _, err := Parse(partial) 730 if err == nil { 731 b.Fatalf("expected ‘%s’ was invalid", partial) 732 } 733 } 734 } 735 736 func BenchmarkParseLen36Corrupted(b *testing.B) { 737 wrong := asString[:len(asString)-1] + "x" 738 for i := 0; i < b.N; i++ { 739 _, err := Parse(wrong) 740 if err == nil { 741 b.Fatalf("expected ‘%s’ was invalid", wrong) 742 } 743 } 744 } 745 746 func BenchmarkUUID_New(b *testing.B) { 747 b.RunParallel(func(pb *testing.PB) { 748 for pb.Next() { 749 _, err := newRandom() 750 if err != nil { 751 b.Fatal(err) 752 } 753 } 754 }) 755 } 756 757 func BenchmarkUUID_NewPooled(b *testing.B) { 758 EnableRandPool() 759 b.RunParallel(func(pb *testing.PB) { 760 for pb.Next() { 761 _, err := newRandom() 762 if err != nil { 763 b.Fatal(err) 764 } 765 } 766 }) 767 } 768 769 func BenchmarkUUIDs_Strings(b *testing.B) { 770 uuid1, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 771 if err != nil { 772 b.Fatal(err) 773 } 774 uuid2, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") 775 if err != nil { 776 b.Fatal(err) 777 } 778 uuids := UUIDs{uuid1, uuid2} 779 for i := 0; i < b.N; i++ { 780 uuids.Strings() 781 } 782 } 783 784 func TestVersion6(t *testing.T) { 785 uuid1, err := NewV6() 786 if err != nil { 787 t.Fatalf("could not create UUID: %v", err) 788 } 789 uuid2, err := NewV6() 790 if err != nil { 791 t.Fatalf("could not create UUID: %v", err) 792 } 793 794 if uuid1 == uuid2 { 795 t.Errorf("%s:duplicate uuid", uuid1) 796 } 797 if v := uuid1.Version(); v != 6 { 798 t.Errorf("%s: version %s expected 6", uuid1, v) 799 } 800 if v := uuid2.Version(); v != 6 { 801 t.Errorf("%s: version %s expected 6", uuid2, v) 802 } 803 n1 := uuid1.NodeID() 804 n2 := uuid2.NodeID() 805 if !bytes.Equal(n1, n2) { 806 t.Errorf("Different nodes %x != %x", n1, n2) 807 } 808 t1 := uuid1.Time() 809 t2 := uuid2.Time() 810 q1 := uuid1.ClockSequence() 811 q2 := uuid2.ClockSequence() 812 813 switch { 814 case t1 == t2 && q1 == q2: 815 t.Error("time stopped") 816 case t1 > t2 && q1 == q2: 817 t.Error("time reversed") 818 case t1 < t2 && q1 != q2: 819 t.Error("clock sequence changed unexpectedly") 820 } 821 } 822 823 // uuid v7 time is only unix milliseconds, so 824 // uuid1.Time() == uuid2.Time() is right, but uuid1 must != uuid2 825 func TestVersion7(t *testing.T) { 826 SetRand(nil) 827 m := make(map[string]bool) 828 for x := 1; x < 128; x++ { 829 uuid := NewV7() 830 // if err != nil { 831 // t.Fatalf("could not create UUID: %v", err) 832 // } 833 s := uuid.String() 834 if m[s] { 835 t.Errorf("NewV7 returned duplicated UUID %s", s) 836 } 837 m[s] = true 838 if v := uuid.Version(); v != 7 { 839 t.Errorf("UUID of version %s", v) 840 } 841 if uuid.Variant() != RFC4122 { 842 t.Errorf("UUID is variant %d", uuid.Variant()) 843 } 844 } 845 } 846 847 // uuid v7 time is only unix milliseconds, so 848 // uuid1.Time() == uuid2.Time() is right, but uuid1 must != uuid2 849 func TestVersion7_pooled(t *testing.T) { 850 SetRand(nil) 851 EnableRandPool() 852 defer DisableRandPool() 853 854 m := make(map[string]bool) 855 for x := 1; x < 128; x++ { 856 uuid := NewV7() 857 // if err != nil { 858 // t.Fatalf("could not create UUID: %v", err) 859 // } 860 s := uuid.String() 861 if m[s] { 862 t.Errorf("NewV7 returned duplicated UUID %s", s) 863 } 864 m[s] = true 865 if v := uuid.Version(); v != 7 { 866 t.Errorf("UUID of version %s", v) 867 } 868 if uuid.Variant() != RFC4122 { 869 t.Errorf("UUID is variant %d", uuid.Variant()) 870 } 871 } 872 } 873 874 func TestVersion7FromReader(t *testing.T) { 875 myString := "8059ddhdle77cb52" 876 r := bytes.NewReader([]byte(myString)) 877 _, err := NewV7FromReader(r) 878 if err != nil { 879 t.Errorf("failed generating UUID from a reader") 880 } 881 _, err = NewV7FromReader(r) 882 if err == nil { 883 t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewV7FromReader may not be using the provided reader") 884 } 885 } 886 887 func TestVersion7Monotonicity(t *testing.T) { 888 length := 10000 889 u1 := NewV7().String() 890 for i := 0; i < length; i++ { 891 u2 := NewV7().String() 892 if u2 <= u1 { 893 t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1) 894 break 895 } 896 u1 = u2 897 } 898 } 899 900 type fakeRand struct{} 901 902 func (g fakeRand) Read(bs []byte) (int, error) { 903 for i, _ := range bs { 904 bs[i] = 0x88 905 } 906 return len(bs), nil 907 } 908 909 func TestVersion7MonotonicityStrict(t *testing.T) { 910 timeNow = func() time.Time { 911 return time.Date(2008, 8, 8, 8, 8, 8, 8, time.UTC) 912 } 913 defer func() { 914 timeNow = time.Now 915 }() 916 917 SetRand(fakeRand{}) 918 defer SetRand(nil) 919 920 length := 100000 // > 3906 921 u1 := NewV7().String() 922 for i := 0; i < length; i++ { 923 u2 := NewV7().String() 924 if u2 <= u1 { 925 t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1) 926 break 927 } 928 u1 = u2 929 } 930 } 931 932 func TestEqual(t *testing.T) { 933 zero := Nil 934 someUuid := NewV4() 935 936 for range 100 { 937 uuid := NewV4() 938 if uuid.Equal(uuid) == false { 939 t.Fatalf("%s should be equal to %s", uuid.String(), uuid.String()) 940 } 941 942 if uuid.Equal(zero) { 943 t.Fatalf("%s should be different than %s", uuid.String(), zero.String()) 944 } 945 946 if uuid.Equal(someUuid) { 947 t.Fatalf("%s should be different than %s", uuid.String(), someUuid.String()) 948 } 949 } 950 951 }