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 5package uuid 6 7import ( 8 "bytes" 9 "fmt" 10 "os" 11 "runtime" 12 "strings" 13 "testing" 14 "time" 15 "unsafe" 16) 17 18type test struct { 19 in string 20 version Version 21 variant Variant 22 isuuid bool 23} 24 25var tests = []test{ 26 {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, 27 {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, 28 {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, 29 {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, 30 {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, 31 {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, 32 {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, 33 {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, 34 {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, 35 {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, 36 {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, 37 {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, 38 {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, 39 {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, 40 {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, 41 {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, 42 43 {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 44 {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 45 {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, 46 {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, 47 {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, 48 {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, 49 {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, 50 {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, 51 {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, 52 {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, 53 {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, 54 {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, 55 {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, 56 {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, 57 {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, 58 {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, 59 {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, 60 {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, 61 62 {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, 63 {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, 64 {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, 65 {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, 66 {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, 67 {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, 68 69 {"{f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, RFC4122, true}, 70 {"{f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, Invalid, false}, 71 {"f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, Invalid, false}, 72 73 {"f47ac10b58cc037285670e02b2c3d479", 0, RFC4122, true}, 74 {"f47ac10b58cc037285670e02b2c3d4790", 0, Invalid, false}, 75 {"f47ac10b58cc037285670e02b2c3d47", 0, Invalid, false}, 76} 77 78var constants = []struct { 79 c interface{} 80 name string 81}{ 82 {Person, "Person"}, 83 {Group, "Group"}, 84 {Org, "Org"}, 85 {Invalid, "Invalid"}, 86 {RFC4122, "RFC4122"}, 87 {Reserved, "Reserved"}, 88 {Microsoft, "Microsoft"}, 89 {Future, "Future"}, 90 {Domain(17), "Domain17"}, 91 {Variant(42), "BadVariant42"}, 92} 93 94func testTest(t *testing.T, in string, tt test) { 95 uuid, err := Parse(in) 96 if ok := (err == nil); ok != tt.isuuid { 97 t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) 98 } 99 if err != nil { 100 return 101 } 102 103 if v := uuid.Variant(); v != tt.variant { 104 t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) 105 } 106 if v := uuid.Version(); v != tt.version { 107 t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) 108 } 109} 110 111func testBytes(t *testing.T, in []byte, tt test) { 112 uuid, err := ParseBytes(in) 113 if ok := (err == nil); ok != tt.isuuid { 114 t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid) 115 } 116 if err != nil { 117 return 118 } 119 suuid, _ := Parse(string(in)) 120 if uuid != suuid { 121 t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid) 122 } 123} 124 125func TestUUID(t *testing.T) { 126 for _, tt := range tests { 127 testTest(t, tt.in, tt) 128 testTest(t, strings.ToUpper(tt.in), tt) 129 testBytes(t, []byte(tt.in), tt) 130 } 131} 132 133func TestFromBytes(t *testing.T) { 134 b := []byte{ 135 0x7d, 0x44, 0x48, 0x40, 136 0x9d, 0xc0, 137 0x11, 0xd1, 138 0xb2, 0x45, 139 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 140 } 141 uuid, err := FromBytes(b) 142 if err != nil { 143 t.Fatalf("%s", err) 144 } 145 for i := 0; i < len(uuid); i++ { 146 if b[i] != uuid[i] { 147 t.Fatalf("FromBytes() got %v expected %v\b", uuid[:], b) 148 } 149 } 150} 151 152func TestConstants(t *testing.T) { 153 for x, tt := range constants { 154 v, ok := tt.c.(fmt.Stringer) 155 if !ok { 156 t.Errorf("%x: %v: not a stringer", x, v) 157 } else if s := v.String(); s != tt.name { 158 v, _ := tt.c.(int) 159 t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name) 160 } 161 } 162} 163 164func TestRandomUUID(t *testing.T) { 165 m := make(map[string]bool) 166 for x := 1; x < 32; x++ { 167 uuid := New() 168 s := uuid.String() 169 if m[s] { 170 t.Errorf("NewRandom returned duplicated UUID %s", s) 171 } 172 m[s] = true 173 if v := uuid.Version(); v != 4 { 174 t.Errorf("Random UUID of version %s", v) 175 } 176 if uuid.Variant() != RFC4122 { 177 t.Errorf("Random UUID is variant %d", uuid.Variant()) 178 } 179 } 180} 181 182func TestNew(t *testing.T) { 183 m := make(map[UUID]bool) 184 for x := 1; x < 32; x++ { 185 s := New() 186 if m[s] { 187 t.Errorf("New returned duplicated UUID %s", s) 188 } 189 m[s] = true 190 uuid, err := Parse(s.String()) 191 if err != nil { 192 t.Errorf("New.String() returned %q which does not decode", s) 193 continue 194 } 195 if v := uuid.Version(); v != 4 { 196 t.Errorf("Random UUID of version %s", v) 197 } 198 if uuid.Variant() != RFC4122 { 199 t.Errorf("Random UUID is variant %d", uuid.Variant()) 200 } 201 } 202} 203 204func TestClockSeq(t *testing.T) { 205 // Fake time.Now for this test to return a monotonically advancing time; restore it at end. 206 defer func(orig func() time.Time) { timeNow = orig }(timeNow) 207 monTime := time.Now() 208 timeNow = func() time.Time { 209 monTime = monTime.Add(1 * time.Second) 210 return monTime 211 } 212 213 SetClockSequence(-1) 214 uuid1, err := NewUUID() 215 if err != nil { 216 t.Fatalf("could not create UUID: %v", err) 217 } 218 uuid2, err := NewUUID() 219 if err != nil { 220 t.Fatalf("could not create UUID: %v", err) 221 } 222 223 if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 { 224 t.Errorf("clock sequence %d != %d", s1, s2) 225 } 226 227 SetClockSequence(-1) 228 uuid2, err = NewUUID() 229 if err != nil { 230 t.Fatalf("could not create UUID: %v", err) 231 } 232 233 // Just on the very off chance we generated the same sequence 234 // two times we try again. 235 if uuid1.ClockSequence() == uuid2.ClockSequence() { 236 SetClockSequence(-1) 237 uuid2, err = NewUUID() 238 if err != nil { 239 t.Fatalf("could not create UUID: %v", err) 240 } 241 } 242 if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 { 243 t.Errorf("Duplicate clock sequence %d", s1) 244 } 245 246 SetClockSequence(0x1234) 247 uuid1, err = NewUUID() 248 if err != nil { 249 t.Fatalf("could not create UUID: %v", err) 250 } 251 if seq := uuid1.ClockSequence(); seq != 0x1234 { 252 t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq) 253 } 254} 255 256func TestCoding(t *testing.T) { 257 text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" 258 urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" 259 data := UUID{ 260 0x7d, 0x44, 0x48, 0x40, 261 0x9d, 0xc0, 262 0x11, 0xd1, 263 0xb2, 0x45, 264 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, 265 } 266 if v := data.String(); v != text { 267 t.Errorf("%x: encoded to %s, expected %s", data, v, text) 268 } 269 if v := data.URN(); v != urn { 270 t.Errorf("%x: urn is %s, expected %s", data, v, urn) 271 } 272 273 uuid, err := Parse(text) 274 if err != nil { 275 t.Errorf("Parse returned unexpected error %v", err) 276 } 277 if data != uuid { 278 t.Errorf("%s: decoded to %s, expected %s", text, uuid, data) 279 } 280} 281 282func TestVersion1(t *testing.T) { 283 uuid1, err := NewUUID() 284 if err != nil { 285 t.Fatalf("could not create UUID: %v", err) 286 } 287 uuid2, err := NewUUID() 288 if err != nil { 289 t.Fatalf("could not create UUID: %v", err) 290 } 291 292 if uuid1 == uuid2 { 293 t.Errorf("%s:duplicate uuid", uuid1) 294 } 295 if v := uuid1.Version(); v != 1 { 296 t.Errorf("%s: version %s expected 1", uuid1, v) 297 } 298 if v := uuid2.Version(); v != 1 { 299 t.Errorf("%s: version %s expected 1", uuid2, v) 300 } 301 n1 := uuid1.NodeID() 302 n2 := uuid2.NodeID() 303 if !bytes.Equal(n1, n2) { 304 t.Errorf("Different nodes %x != %x", n1, n2) 305 } 306 t1 := uuid1.Time() 307 t2 := uuid2.Time() 308 q1 := uuid1.ClockSequence() 309 q2 := uuid2.ClockSequence() 310 311 switch { 312 case t1 == t2 && q1 == q2: 313 t.Error("time stopped") 314 case t1 > t2 && q1 == q2: 315 t.Error("time reversed") 316 case t1 < t2 && q1 != q2: 317 t.Error("clock sequence changed unexpectedly") 318 } 319} 320 321func TestNode(t *testing.T) { 322 // This test is mostly to make sure we don't leave nodeMu locked. 323 ifname = "" 324 if ni := NodeInterface(); ni != "" { 325 t.Errorf("NodeInterface got %q, want %q", ni, "") 326 } 327 if SetNodeInterface("xyzzy") { 328 t.Error("SetNodeInterface succeeded on a bad interface name") 329 } 330 if !SetNodeInterface("") { 331 t.Error("SetNodeInterface failed") 332 } 333 if runtime.GOARCH != "js" { 334 if ni := NodeInterface(); ni == "" { 335 t.Error("NodeInterface returned an empty string") 336 } 337 } 338 339 ni := NodeID() 340 if len(ni) != 6 { 341 t.Errorf("ni got %d bytes, want 6", len(ni)) 342 } 343 hasData := false 344 for _, b := range ni { 345 if b != 0 { 346 hasData = true 347 } 348 } 349 if !hasData { 350 t.Error("nodeid is all zeros") 351 } 352 353 id := []byte{1, 2, 3, 4, 5, 6, 7, 8} 354 SetNodeID(id) 355 ni = NodeID() 356 if !bytes.Equal(ni, id[:6]) { 357 t.Errorf("got nodeid %v, want %v", ni, id[:6]) 358 } 359 360 if ni := NodeInterface(); ni != "user" { 361 t.Errorf("got interface %q, want %q", ni, "user") 362 } 363} 364 365func TestNodeAndTime(t *testing.T) { 366 // Time is February 5, 1998 12:30:23.136364800 AM GMT 367 368 uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") 369 if err != nil { 370 t.Fatalf("Parser returned unexpected error %v", err) 371 } 372 node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} 373 374 ts := uuid.Time() 375 c := time.Unix(ts.UnixTime()) 376 want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) 377 if !c.Equal(want) { 378 t.Errorf("Got time %v, want %v", c, want) 379 } 380 if !bytes.Equal(node, uuid.NodeID()) { 381 t.Errorf("Expected node %v got %v", node, uuid.NodeID()) 382 } 383} 384 385func TestMD5(t *testing.T) { 386 uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String() 387 want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" 388 if uuid != want { 389 t.Errorf("MD5: got %q expected %q", uuid, want) 390 } 391} 392 393func TestSHA1(t *testing.T) { 394 uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String() 395 want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" 396 if uuid != want { 397 t.Errorf("SHA1: got %q expected %q", uuid, want) 398 } 399} 400 401func TestNodeID(t *testing.T) { 402 nid := []byte{1, 2, 3, 4, 5, 6} 403 SetNodeInterface("") 404 s := NodeInterface() 405 if runtime.GOARCH != "js" { 406 if s == "" || s == "user" { 407 t.Errorf("NodeInterface %q after SetInterface", s) 408 } 409 } 410 node1 := NodeID() 411 if node1 == nil { 412 t.Error("NodeID nil after SetNodeInterface", s) 413 } 414 SetNodeID(nid) 415 s = NodeInterface() 416 if s != "user" { 417 t.Errorf("Expected NodeInterface %q got %q", "user", s) 418 } 419 node2 := NodeID() 420 if node2 == nil { 421 t.Error("NodeID nil after SetNodeID", s) 422 } 423 if bytes.Equal(node1, node2) { 424 t.Error("NodeID not changed after SetNodeID", s) 425 } else if !bytes.Equal(nid, node2) { 426 t.Errorf("NodeID is %x, expected %x", node2, nid) 427 } 428} 429 430func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) { 431 if err != nil { 432 t.Errorf("%s failed: %v", name, err) 433 return 434 } 435 if v := uuid.Version(); v != 2 { 436 t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v) 437 return 438 } 439 if v := uuid.Domain(); v != domain { 440 t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v) 441 } 442 if v := uuid.ID(); v != id { 443 t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v) 444 } 445} 446 447func TestDCE(t *testing.T) { 448 uuid, err := NewDCESecurity(42, 12345678) 449 testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678) 450 uuid, err = NewDCEPerson() 451 testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid())) 452 uuid, err = NewDCEGroup() 453 testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid())) 454} 455 456type badRand struct{} 457 458func (r badRand) Read(buf []byte) (int, error) { 459 for i := range buf { 460 buf[i] = byte(i) 461 } 462 return len(buf), nil 463} 464 465func TestBadRand(t *testing.T) { 466 SetRand(badRand{}) 467 uuid1 := New() 468 uuid2 := New() 469 if uuid1 != uuid2 { 470 t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2) 471 } 472 SetRand(nil) 473 uuid1 = New() 474 uuid2 = New() 475 if uuid1 == uuid2 { 476 t.Errorf("unexpected duplicates, got %q", uuid1) 477 } 478} 479 480func TestSetRand(t *testing.T) { 481 myString := "805-9dd6-1a877cb526c678e71d38-7122-44c0-9b7c-04e7001cc78783ac3e82-47a3-4cc3-9951-13f3339d88088f5d685a-11f7-4078-ada9-de44ad2daeb7" 482 483 SetRand(strings.NewReader(myString)) 484 uuid1 := New() 485 uuid2 := New() 486 487 SetRand(strings.NewReader(myString)) 488 uuid3 := New() 489 uuid4 := New() 490 491 if uuid1 != uuid3 { 492 t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) 493 } 494 if uuid2 != uuid4 { 495 t.Errorf("expected duplicates, got %q and %q", uuid2, uuid4) 496 } 497} 498 499func TestRandomFromReader(t *testing.T) { 500 myString := "8059ddhdle77cb52" 501 r := bytes.NewReader([]byte(myString)) 502 r2 := bytes.NewReader([]byte(myString)) 503 uuid1, err := NewRandomFromReader(r) 504 if err != nil { 505 t.Errorf("failed generating UUID from a reader") 506 } 507 _, err = NewRandomFromReader(r) 508 if err == nil { 509 t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewRandomFromReader may not be using the provided reader") 510 } 511 uuid3, err := NewRandomFromReader(r2) 512 if err != nil { 513 t.Errorf("failed generating UUID from a reader") 514 } 515 if uuid1 != uuid3 { 516 t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3) 517 } 518} 519 520func TestWrongLength(t *testing.T) { 521 _, err := Parse("12345") 522 if err == nil { 523 t.Errorf("expected ‘12345’ was invalid") 524 } else if err.Error() != "invalid UUID length: 5" { 525 t.Errorf("expected a different error message for an invalid length") 526 } 527} 528 529var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479" 530var asBytes = []byte(asString) 531 532func BenchmarkParse(b *testing.B) { 533 for i := 0; i < b.N; i++ { 534 _, err := Parse(asString) 535 if err != nil { 536 b.Fatal(err) 537 } 538 } 539} 540 541func BenchmarkParseBytes(b *testing.B) { 542 for i := 0; i < b.N; i++ { 543 _, err := ParseBytes(asBytes) 544 if err != nil { 545 b.Fatal(err) 546 } 547 } 548} 549 550// parseBytesUnsafe is to benchmark using unsafe. 551func parseBytesUnsafe(b []byte) (UUID, error) { 552 return Parse(*(*string)(unsafe.Pointer(&b))) 553} 554 555func BenchmarkParseBytesUnsafe(b *testing.B) { 556 for i := 0; i < b.N; i++ { 557 _, err := parseBytesUnsafe(asBytes) 558 if err != nil { 559 b.Fatal(err) 560 } 561 } 562} 563 564// parseBytesCopy is to benchmark not using unsafe. 565func parseBytesCopy(b []byte) (UUID, error) { 566 return Parse(string(b)) 567} 568 569func BenchmarkParseBytesCopy(b *testing.B) { 570 for i := 0; i < b.N; i++ { 571 _, err := parseBytesCopy(asBytes) 572 if err != nil { 573 b.Fatal(err) 574 } 575 } 576} 577 578func BenchmarkNew(b *testing.B) { 579 for i := 0; i < b.N; i++ { 580 New() 581 } 582} 583 584func BenchmarkUUID_String(b *testing.B) { 585 uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 586 if err != nil { 587 b.Fatal(err) 588 } 589 for i := 0; i < b.N; i++ { 590 if uuid.String() == "" { 591 b.Fatal("invalid uuid") 592 } 593 } 594} 595 596func BenchmarkUUID_URN(b *testing.B) { 597 uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") 598 if err != nil { 599 b.Fatal(err) 600 } 601 for i := 0; i < b.N; i++ { 602 if uuid.URN() == "" { 603 b.Fatal("invalid uuid") 604 } 605 } 606} 607 608func BenchmarkParseBadLength(b *testing.B) { 609 short := asString[:10] 610 for i := 0; i < b.N; i++ { 611 _, err := Parse(short) 612 if err == nil { 613 b.Fatalf("expected ‘%s’ was invalid", short) 614 } 615 } 616} 617 618func BenchmarkParseLen32Truncated(b *testing.B) { 619 partial := asString[:len(asString)-4] 620 for i := 0; i < b.N; i++ { 621 _, err := Parse(partial) 622 if err == nil { 623 b.Fatalf("expected ‘%s’ was invalid", partial) 624 } 625 } 626} 627 628func BenchmarkParseLen36Corrupted(b *testing.B) { 629 wrong := asString[:len(asString)-1] + "x" 630 for i := 0; i < b.N; i++ { 631 _, err := Parse(wrong) 632 if err == nil { 633 b.Fatalf("expected ‘%s’ was invalid", wrong) 634 } 635 } 636} 637