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