1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package thrift
21
22import (
23	"fmt"
24	"testing"
25	"testing/quick"
26)
27
28func TestHexToByte(t *testing.T) {
29	for _, c := range []struct {
30		s    string
31		b    byte
32		fail bool
33	}{
34		{
35			s: "ff",
36			b: 0xff,
37		},
38		{
39			s: "FF",
40			b: 0xff,
41		},
42		{
43			s: "00",
44			b: 0,
45		},
46		{
47			s: "77",
48			b: 0x77,
49		},
50		{
51			s: "aC",
52			b: 0xac,
53		},
54		{
55			s:    "xx",
56			fail: true,
57		},
58		{
59			s:    "x0",
60			fail: true,
61		},
62		{
63			s:    "fx",
64			fail: true,
65		},
66	} {
67		t.Run(c.s, func(t *testing.T) {
68			b, ok := hexToByte(c.s[0], c.s[1])
69			if ok != !c.fail {
70				t.Errorf("Want failure, got %x, %v", b, ok)
71			}
72			if !c.fail && b != c.b {
73				t.Errorf("Want %x, got %x", c.b, b)
74			}
75		})
76	}
77}
78
79func TestUUIDString(t *testing.T) {
80	for _, c := range []struct {
81		uuid Tuuid
82		want string
83	}{
84		{
85			uuid: Tuuid{},
86			want: "00000000-0000-0000-0000-000000000000",
87		},
88		{
89			uuid: Tuuid{
90				0x6b, 0xa7, 0xb8, 0x10,
91				0x9d, 0xad,
92				0x11, 0xd1,
93				0x80, 0xb4,
94				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
95			},
96			want: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
97		},
98		{
99			uuid: Tuuid{
100				0x6b, 0xa7, 0xB8, 0x11,
101				0x9d, 0xAd,
102				0x11, 0xd1,
103				0x80, 0xb4,
104				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
105			},
106			want: "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
107		},
108		{
109			uuid: Tuuid{
110				0x6b, 0xa7, 0xb8, 0x12,
111				0x9d, 0xad,
112				0x11, 0xd1,
113				0x80, 0xb4,
114				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
115			},
116			want: "6ba7b812-9dad-11d1-80b4-00c04fd430c8",
117		},
118		{
119			uuid: Tuuid{
120				0x6b, 0xa7, 0xb8, 0x14,
121				0x9d, 0xad,
122				0x11, 0xd1,
123				0x80, 0xb4,
124				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
125			},
126			want: "6ba7b814-9dad-11d1-80b4-00c04fd430c8",
127		},
128	} {
129		t.Run(fmt.Sprintf("% 02x", c.uuid[:]), func(t *testing.T) {
130			got := c.uuid.String()
131			if got != c.want {
132				t.Errorf("got %q, want %q", got, c.want)
133			}
134		})
135	}
136}
137
138func TestUUIDParse(t *testing.T) {
139	for _, c := range []struct {
140		uuid string
141		want Tuuid
142		err  bool
143	}{
144		{
145			uuid: "00000000-0000-0000-0000-000000000000",
146			want: Tuuid{
147				0x00, 0x00, 0x00, 0x00,
148				0x00, 0x00,
149				0x00, 0x00,
150				0x00, 0x00,
151				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152			},
153		},
154		{
155			uuid: "6BA7B810-9DAD-11D1-80B4-00C04FD430C8",
156			want: Tuuid{
157				0x6B, 0xA7, 0xB8, 0x10,
158				0x9D, 0xAD,
159				0x11, 0xD1,
160				0x80, 0xB4,
161				0x00, 0xC0, 0x4F, 0xD4, 0x30, 0xC8,
162			},
163		},
164		{
165			uuid: "6ba7B811-9dAd-11d1-80b4-00c04fd430c8",
166			want: Tuuid{
167				0x6b, 0xa7, 0xB8, 0x11,
168				0x9d, 0xAd,
169				0x11, 0xd1,
170				0x80, 0xb4,
171				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
172			},
173		},
174		{
175			uuid: "6ba7b812-9dad-11d1-80b4-00c04fd430c8",
176			want: Tuuid{
177				0x6b, 0xa7, 0xb8, 0x12,
178				0x9d, 0xad,
179				0x11, 0xd1,
180				0x80, 0xb4,
181				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
182			},
183		},
184		{
185			uuid: "6ba7b814-9dad-11d1-80b4-00c04fd430c8",
186			want: Tuuid{
187				0x6b, 0xa7, 0xb8, 0x14,
188				0x9d, 0xad,
189				0x11, 0xd1,
190				0x80, 0xb4,
191				0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
192			},
193		},
194		{
195			uuid: "00000000000000000000000000000000",
196			err:  true, // not in canonical form
197		},
198		{
199			uuid: "6ba7b810-9d-ad11d1-80b4-00c04fd430c8",
200			err:  true, // wrong position of hyphens
201		},
202		{
203			uuid: "urn:uuid:6ba7b811-9dad-11d1-80b4-00c04fd430c8",
204			err:  true, // urn form is not supported
205		},
206		{
207			uuid: "{6ba7b812-9dad-11d1-80b4-00c04fd430c8}",
208			err:  true, // guid with braces form is not supported
209		},
210		{
211			uuid: "6xa7b814-9dad-11d1-80b4-00c04fd430c8",
212			err:  true, // non-hex numbers
213		},
214	} {
215		t.Run(c.uuid, func(t *testing.T) {
216			uuid, err := ParseTuuid(c.uuid)
217			if c.err {
218				if err == nil {
219					t.Errorf("Got %v, want error", uuid)
220				}
221			} else {
222				if err != nil {
223					t.Errorf("Failed to parse: %v", err)
224				}
225				if uuid != c.want {
226					t.Errorf("Got %v, want %v", uuid, c.want)
227				}
228			}
229		})
230	}
231}
232
233func TestUUIDQuick(t *testing.T) {
234	f := func(u Tuuid) bool {
235		s := u.String()
236		parsed, err := ParseTuuid(s)
237		if err != nil {
238			t.Error(err)
239		}
240		if parsed != u {
241			t.Errorf("Parsed %v want %v", parsed, u)
242		}
243		return !t.Failed()
244	}
245	if err := quick.Check(f, nil); err != nil {
246		t.Error(err)
247	}
248}
249
250func BenchmarkUUIDParse(b *testing.B) {
251	for _, s := range []string{
252		"00000000-0000-0000-0000-000000000000",
253		"6ba7b810-9dad-11d1-80b4-00c04fd430c8",
254		"6ba7b811-9dad-11d1-80b4-00c04fd430c8",
255		"6ba7b812-9dad-11d1-80b4-00c04fd430c8",
256		"6ba7b814-9dad-11d1-80b4-00c04fd430c8",
257	} {
258		b.Run(s, func(b *testing.B) {
259			b.ReportAllocs()
260			if _, err := ParseTuuid(s); err != nil {
261				b.Fatalf("Unable to parse %q: %v", s, err)
262			}
263			b.ResetTimer()
264			b.RunParallel(func(pb *testing.PB) {
265				for pb.Next() {
266					ParseTuuid(s)
267				}
268			})
269		})
270	}
271}
272
273func BenchmarkUUIDString(b *testing.B) {
274	for _, u := range []Tuuid{
275		{},
276		Must(ParseTuuid("6ba7b810-9dad-11d1-80b4-00c04fd430c8")),
277		Must(ParseTuuid("6ba7b811-9dad-11d1-80b4-00c04fd430c8")),
278		Must(ParseTuuid("6ba7b812-9dad-11d1-80b4-00c04fd430c8")),
279		Must(ParseTuuid("6ba7b814-9dad-11d1-80b4-00c04fd430c8")),
280	} {
281		b.Run(u.String(), func(b *testing.B) {
282			b.ReportAllocs()
283			b.RunParallel(func(pb *testing.PB) {
284				for pb.Next() {
285					_ = u.String()
286				}
287			})
288		})
289	}
290}
291