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