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