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