1// Copyright (C) 2013, 2015 by Maxim Bublis <b@codemonkey.ru>
2//
3// Permission is hereby granted, free of charge, to any person obtaining
4// a copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to
8// permit persons to whom the Software is furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be
12// included in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22package uuid
23
24import (
25	"bytes"
26	"testing"
27)
28
29func TestBytes(t *testing.T) {
30	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
31
32	bytes1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
33
34	if !bytes.Equal(u.Bytes(), bytes1) {
35		t.Errorf("Incorrect bytes representation for UUID: %s", u)
36	}
37}
38
39func TestString(t *testing.T) {
40	if NamespaceDNS.String() != "6ba7b810-9dad-11d1-80b4-00c04fd430c8" {
41		t.Errorf("Incorrect string representation for UUID: %s", NamespaceDNS.String())
42	}
43}
44
45func TestEqual(t *testing.T) {
46	if !Equal(NamespaceDNS, NamespaceDNS) {
47		t.Errorf("Incorrect comparison of %s and %s", NamespaceDNS, NamespaceDNS)
48	}
49
50	if Equal(NamespaceDNS, NamespaceURL) {
51		t.Errorf("Incorrect comparison of %s and %s", NamespaceDNS, NamespaceURL)
52	}
53}
54
55func TestOr(t *testing.T) {
56	u1 := UUID{0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff}
57	u2 := UUID{0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00}
58
59	u := UUID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
60
61	if !Equal(u, Or(u1, u2)) {
62		t.Errorf("Incorrect bitwise OR result %s", Or(u1, u2))
63	}
64}
65
66func TestAnd(t *testing.T) {
67	u1 := UUID{0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff}
68	u2 := UUID{0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00}
69
70	u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
71
72	if !Equal(u, And(u1, u2)) {
73		t.Errorf("Incorrect bitwise AND result %s", And(u1, u2))
74	}
75}
76
77func TestVersion(t *testing.T) {
78	u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
79
80	if u.Version() != 1 {
81		t.Errorf("Incorrect version for UUID: %d", u.Version())
82	}
83}
84
85func TestSetVersion(t *testing.T) {
86	u := UUID{}
87	u.SetVersion(4)
88
89	if u.Version() != 4 {
90		t.Errorf("Incorrect version for UUID after u.setVersion(4): %d", u.Version())
91	}
92}
93
94func TestVariant(t *testing.T) {
95	u1 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
96
97	if u1.Variant() != VariantNCS {
98		t.Errorf("Incorrect variant for UUID variant %d: %d", VariantNCS, u1.Variant())
99	}
100
101	u2 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
102
103	if u2.Variant() != VariantRFC4122 {
104		t.Errorf("Incorrect variant for UUID variant %d: %d", VariantRFC4122, u2.Variant())
105	}
106
107	u3 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
108
109	if u3.Variant() != VariantMicrosoft {
110		t.Errorf("Incorrect variant for UUID variant %d: %d", VariantMicrosoft, u3.Variant())
111	}
112
113	u4 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
114
115	if u4.Variant() != VariantFuture {
116		t.Errorf("Incorrect variant for UUID variant %d: %d", VariantFuture, u4.Variant())
117	}
118}
119
120func TestSetVariant(t *testing.T) {
121	u := new(UUID)
122	u.SetVariant()
123
124	if u.Variant() != VariantRFC4122 {
125		t.Errorf("Incorrect variant for UUID after u.setVariant(): %d", u.Variant())
126	}
127}
128
129func TestFromBytes(t *testing.T) {
130	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
131	b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
132
133	u1, err := FromBytes(b1)
134	if err != nil {
135		t.Errorf("Error parsing UUID from bytes: %s", err)
136	}
137
138	if !Equal(u, u1) {
139		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
140	}
141
142	b2 := []byte{}
143
144	_, err = FromBytes(b2)
145	if err == nil {
146		t.Errorf("Should return error parsing from empty byte slice, got %s", err)
147	}
148}
149
150func TestMarshalBinary(t *testing.T) {
151	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
152	b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
153
154	b2, err := u.MarshalBinary()
155	if err != nil {
156		t.Errorf("Error marshaling UUID: %s", err)
157	}
158
159	if !bytes.Equal(b1, b2) {
160		t.Errorf("Marshaled UUID should be %s, got %s", b1, b2)
161	}
162}
163
164func TestUnmarshalBinary(t *testing.T) {
165	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
166	b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
167
168	u1 := UUID{}
169	err := u1.UnmarshalBinary(b1)
170	if err != nil {
171		t.Errorf("Error unmarshaling UUID: %s", err)
172	}
173
174	if !Equal(u, u1) {
175		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
176	}
177
178	b2 := []byte{}
179	u2 := UUID{}
180
181	err = u2.UnmarshalBinary(b2)
182	if err == nil {
183		t.Errorf("Should return error unmarshalling from empty byte slice, got %s", err)
184	}
185}
186
187func TestFromString(t *testing.T) {
188	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
189
190	s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
191	s2 := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
192	s3 := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
193
194	_, err := FromString("")
195	if err == nil {
196		t.Errorf("Should return error trying to parse empty string, got %s", err)
197	}
198
199	u1, err := FromString(s1)
200	if err != nil {
201		t.Errorf("Error parsing UUID from string: %s", err)
202	}
203
204	if !Equal(u, u1) {
205		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
206	}
207
208	u2, err := FromString(s2)
209	if err != nil {
210		t.Errorf("Error parsing UUID from string: %s", err)
211	}
212
213	if !Equal(u, u2) {
214		t.Errorf("UUIDs should be equal: %s and %s", u, u2)
215	}
216
217	u3, err := FromString(s3)
218	if err != nil {
219		t.Errorf("Error parsing UUID from string: %s", err)
220	}
221
222	if !Equal(u, u3) {
223		t.Errorf("UUIDs should be equal: %s and %s", u, u3)
224	}
225}
226
227func TestFromStringOrNil(t *testing.T) {
228	u := FromStringOrNil("")
229	if u != Nil {
230		t.Errorf("Should return Nil UUID on parse failure, got %s", u)
231	}
232}
233
234func TestFromBytesOrNil(t *testing.T) {
235	b := []byte{}
236	u := FromBytesOrNil(b)
237	if u != Nil {
238		t.Errorf("Should return Nil UUID on parse failure, got %s", u)
239	}
240}
241
242func TestMarshalText(t *testing.T) {
243	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
244	b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
245
246	b2, err := u.MarshalText()
247	if err != nil {
248		t.Errorf("Error marshaling UUID: %s", err)
249	}
250
251	if !bytes.Equal(b1, b2) {
252		t.Errorf("Marshaled UUID should be %s, got %s", b1, b2)
253	}
254}
255
256func TestUnmarshalText(t *testing.T) {
257	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
258	b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
259
260	u1 := UUID{}
261	err := u1.UnmarshalText(b1)
262	if err != nil {
263		t.Errorf("Error unmarshaling UUID: %s", err)
264	}
265
266	if !Equal(u, u1) {
267		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
268	}
269
270	b2 := []byte("")
271	u2 := UUID{}
272
273	err = u2.UnmarshalText(b2)
274	if err == nil {
275		t.Errorf("Should return error trying to unmarshal from empty string")
276	}
277}
278
279func TestValue(t *testing.T) {
280	u, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
281	if err != nil {
282		t.Errorf("Error parsing UUID from string: %s", err)
283	}
284
285	val, err := u.Value()
286	if err != nil {
287		t.Errorf("Error getting UUID value: %s", err)
288	}
289
290	if val != u.String() {
291		t.Errorf("Wrong value returned, should be equal: %s and %s", val, u)
292	}
293}
294
295func TestScanBinary(t *testing.T) {
296	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
297	b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
298
299	u1 := UUID{}
300	err := u1.Scan(b1)
301	if err != nil {
302		t.Errorf("Error unmarshaling UUID: %s", err)
303	}
304
305	if !Equal(u, u1) {
306		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
307	}
308
309	b2 := []byte{}
310	u2 := UUID{}
311
312	err = u2.Scan(b2)
313	if err == nil {
314		t.Errorf("Should return error unmarshalling from empty byte slice, got %s", err)
315	}
316}
317
318func TestScanString(t *testing.T) {
319	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
320	s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
321
322	u1 := UUID{}
323	err := u1.Scan(s1)
324	if err != nil {
325		t.Errorf("Error unmarshaling UUID: %s", err)
326	}
327
328	if !Equal(u, u1) {
329		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
330	}
331
332	s2 := ""
333	u2 := UUID{}
334
335	err = u2.Scan(s2)
336	if err == nil {
337		t.Errorf("Should return error trying to unmarshal from empty string")
338	}
339}
340
341func TestScanText(t *testing.T) {
342	u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
343	b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
344
345	u1 := UUID{}
346	err := u1.Scan(b1)
347	if err != nil {
348		t.Errorf("Error unmarshaling UUID: %s", err)
349	}
350
351	if !Equal(u, u1) {
352		t.Errorf("UUIDs should be equal: %s and %s", u, u1)
353	}
354
355	b2 := []byte("")
356	u2 := UUID{}
357
358	err = u2.Scan(b2)
359	if err == nil {
360		t.Errorf("Should return error trying to unmarshal from empty string")
361	}
362}
363
364func TestScanUnsupported(t *testing.T) {
365	u := UUID{}
366
367	err := u.Scan(true)
368	if err == nil {
369		t.Errorf("Should return error trying to unmarshal from bool")
370	}
371}
372
373func TestNewV1(t *testing.T) {
374	u := NewV1()
375
376	if u.Version() != 1 {
377		t.Errorf("UUIDv1 generated with incorrect version: %d", u.Version())
378	}
379
380	if u.Variant() != VariantRFC4122 {
381		t.Errorf("UUIDv1 generated with incorrect variant: %d", u.Variant())
382	}
383
384	u1 := NewV1()
385	u2 := NewV1()
386
387	if Equal(u1, u2) {
388		t.Errorf("UUIDv1 generated two equal UUIDs: %s and %s", u1, u2)
389	}
390
391	oldFunc := epochFunc
392	epochFunc = func() uint64 { return 0 }
393
394	u3 := NewV1()
395	u4 := NewV1()
396
397	if Equal(u3, u4) {
398		t.Errorf("UUIDv1 generated two equal UUIDs: %s and %s", u3, u4)
399	}
400
401	epochFunc = oldFunc
402}
403
404func TestNewV2(t *testing.T) {
405	u1 := NewV2(DomainPerson)
406
407	if u1.Version() != 2 {
408		t.Errorf("UUIDv2 generated with incorrect version: %d", u1.Version())
409	}
410
411	if u1.Variant() != VariantRFC4122 {
412		t.Errorf("UUIDv2 generated with incorrect variant: %d", u1.Variant())
413	}
414
415	u2 := NewV2(DomainGroup)
416
417	if u2.Version() != 2 {
418		t.Errorf("UUIDv2 generated with incorrect version: %d", u2.Version())
419	}
420
421	if u2.Variant() != VariantRFC4122 {
422		t.Errorf("UUIDv2 generated with incorrect variant: %d", u2.Variant())
423	}
424}
425
426func TestNewV3(t *testing.T) {
427	u := NewV3(NamespaceDNS, "www.example.com")
428
429	if u.Version() != 3 {
430		t.Errorf("UUIDv3 generated with incorrect version: %d", u.Version())
431	}
432
433	if u.Variant() != VariantRFC4122 {
434		t.Errorf("UUIDv3 generated with incorrect variant: %d", u.Variant())
435	}
436
437	if u.String() != "5df41881-3aed-3515-88a7-2f4a814cf09e" {
438		t.Errorf("UUIDv3 generated incorrectly: %s", u.String())
439	}
440
441	u = NewV3(NamespaceDNS, "python.org")
442
443	if u.String() != "6fa459ea-ee8a-3ca4-894e-db77e160355e" {
444		t.Errorf("UUIDv3 generated incorrectly: %s", u.String())
445	}
446
447	u1 := NewV3(NamespaceDNS, "golang.org")
448	u2 := NewV3(NamespaceDNS, "golang.org")
449	if !Equal(u1, u2) {
450		t.Errorf("UUIDv3 generated different UUIDs for same namespace and name: %s and %s", u1, u2)
451	}
452
453	u3 := NewV3(NamespaceDNS, "example.com")
454	if Equal(u1, u3) {
455		t.Errorf("UUIDv3 generated same UUIDs for different names in same namespace: %s and %s", u1, u2)
456	}
457
458	u4 := NewV3(NamespaceURL, "golang.org")
459	if Equal(u1, u4) {
460		t.Errorf("UUIDv3 generated same UUIDs for sane names in different namespaces: %s and %s", u1, u4)
461	}
462}
463
464func TestNewV4(t *testing.T) {
465	u := NewV4()
466
467	if u.Version() != 4 {
468		t.Errorf("UUIDv4 generated with incorrect version: %d", u.Version())
469	}
470
471	if u.Variant() != VariantRFC4122 {
472		t.Errorf("UUIDv4 generated with incorrect variant: %d", u.Variant())
473	}
474}
475
476func TestNewV5(t *testing.T) {
477	u := NewV5(NamespaceDNS, "www.example.com")
478
479	if u.Version() != 5 {
480		t.Errorf("UUIDv5 generated with incorrect version: %d", u.Version())
481	}
482
483	if u.Variant() != VariantRFC4122 {
484		t.Errorf("UUIDv5 generated with incorrect variant: %d", u.Variant())
485	}
486
487	u = NewV5(NamespaceDNS, "python.org")
488
489	if u.String() != "886313e1-3b8a-5372-9b90-0c9aee199e5d" {
490		t.Errorf("UUIDv5 generated incorrectly: %s", u.String())
491	}
492
493	u1 := NewV5(NamespaceDNS, "golang.org")
494	u2 := NewV5(NamespaceDNS, "golang.org")
495	if !Equal(u1, u2) {
496		t.Errorf("UUIDv5 generated different UUIDs for same namespace and name: %s and %s", u1, u2)
497	}
498
499	u3 := NewV5(NamespaceDNS, "example.com")
500	if Equal(u1, u3) {
501		t.Errorf("UUIDv5 generated same UUIDs for different names in same namespace: %s and %s", u1, u2)
502	}
503
504	u4 := NewV5(NamespaceURL, "golang.org")
505	if Equal(u1, u4) {
506		t.Errorf("UUIDv3 generated same UUIDs for sane names in different namespaces: %s and %s", u1, u4)
507	}
508}
509