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