1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
18 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
19 #include "pw_unit_test/framework.h"
20
21 namespace bt {
22 namespace {
23
24 // Variants of 16-bit ID 180d
25 constexpr uint16_t kId1As16 = 0x180d;
26 constexpr uint32_t kId1As32 = 0x0000180d;
27 constexpr UInt128 kId1As128 = {{0xFB,
28 0x34,
29 0x9B,
30 0x5F,
31 0x80,
32 0x00,
33 0x00,
34 0x80,
35 0x00,
36 0x10,
37 0x00,
38 0x00,
39 0x0d,
40 0x18,
41 0x00,
42 0x00}};
43 constexpr char kId1AsString[] = "0000180d-0000-1000-8000-00805f9b34fb";
44
45 // 16-bit ID for comparison
46 constexpr uint16_t kOther16BitId = 0x1800;
47
48 // Variants of 32-bit ID 0xdeadbeef
49 constexpr uint32_t kId2As32 = 0xdeadbeef;
50 constexpr UInt128 kId2As128 = {{0xFB,
51 0x34,
52 0x9B,
53 0x5F,
54 0x80,
55 0x00,
56 0x00,
57 0x80,
58 0x00,
59 0x10,
60 0x00,
61 0x00,
62 0xef,
63 0xbe,
64 0xad,
65 0xde}};
66 constexpr char kId2AsString[] = "deadbeef-0000-1000-8000-00805f9b34fb";
67
68 constexpr UInt128 kId3As128 = {
69 {0x00,
70 0x01,
71 0x02,
72 0x03,
73 0x04,
74 0x05,
75 0x06,
76 0x07,
77 0x08,
78 0x09,
79 0x0A,
80 0x0B,
81
82 // Make this part be the same as kId1* for the sake of testing.
83 0x0d,
84 0x18,
85 0x00,
86 0x00}};
87 constexpr char kId3AsString[] = "0000180d-0b0a-0908-0706-050403020100";
88
89 TEST(UUIDTest, 16Bit) {
90 constexpr UUID uuid(kId1As16);
91
92 // We perform each comparison twice, swapping the lhs and rhs, to test the
93 // top-level equality operators.
94
95 // Direct comparison with uint16_t.
96 EXPECT_EQ(uuid, kId1As16);
97 EXPECT_NE(uuid, kOther16BitId);
98 EXPECT_EQ(kId1As16, uuid);
99 EXPECT_NE(kOther16BitId, uuid);
100
101 // Direct comparison with uint32_t.
102 EXPECT_EQ(uuid, kId1As32);
103 EXPECT_NE(uuid, kId2As32);
104 EXPECT_EQ(kId1As32, uuid);
105 EXPECT_NE(kId2As32, uuid);
106
107 // Direct comparison with UInt128.
108 EXPECT_EQ(kId1As128, uuid);
109 EXPECT_NE(kId2As128, uuid);
110
111 // Direct comparison with UUID.
112 EXPECT_EQ(UUID(kId1As16), uuid);
113 EXPECT_EQ(UUID(kId1As32), uuid);
114 EXPECT_EQ(UUID(static_cast<uint16_t>(kId1As32)), uuid);
115 EXPECT_EQ(UUID(kId1As128), uuid);
116 EXPECT_NE(UUID(kOther16BitId), uuid);
117 EXPECT_NE(UUID(kId2As32), uuid);
118 EXPECT_NE(UUID(kId2As128), uuid);
119
120 auto as16 = uuid.As16Bit();
121 EXPECT_TRUE(as16);
122 EXPECT_EQ(kId1As16, *as16);
123 }
124
125 TEST(UUIDTest, 32Bit) {
126 constexpr UUID uuid(kId2As32);
127
128 // Direct comparison with uint32_t.
129 EXPECT_EQ(uuid, kId2As32);
130 EXPECT_EQ(kId2As32, uuid);
131 EXPECT_NE(uuid, kId1As32);
132 EXPECT_NE(kId1As32, uuid);
133
134 // Direct comparison with UInt128.
135 EXPECT_EQ(kId2As128, uuid);
136 EXPECT_NE(kId1As128, uuid);
137
138 // Direct comparison with UUID.
139 EXPECT_EQ(UUID(kId2As32), uuid);
140 EXPECT_EQ(UUID(kId2As128), uuid);
141 EXPECT_NE(UUID(kId1As16), uuid);
142 EXPECT_NE(UUID(kId1As32), uuid);
143 EXPECT_NE(UUID(kId1As128), uuid);
144
145 EXPECT_FALSE(uuid.As16Bit());
146 }
147
148 TEST(UUIDTest, 128Bit) {
149 constexpr UUID uuid(kId3As128);
150
151 EXPECT_EQ(kId3As128, uuid);
152
153 // 16-bit and 32-bit comparison should fail as the base-UUID portions do not
154 // match.
155 EXPECT_NE(kId1As16, uuid);
156 EXPECT_NE(kId1As32, uuid);
157
158 EXPECT_EQ(UUID(kId3As128), uuid);
159 EXPECT_NE(UUID(kId1As128), uuid);
160
161 EXPECT_FALSE(uuid.As16Bit());
162 }
163
TEST(UUIDTest,CompareBytes)164 TEST(UUIDTest, CompareBytes) {
165 StaticByteBuffer kUuid16Bytes(0x0d, 0x18);
166 StaticByteBuffer kUuid32Bytes(0x0d, 0x18, 0x00, 0x00);
167 StaticByteBuffer kUuid128Bytes(0xFB,
168 0x34,
169 0x9B,
170 0x5F,
171 0x80,
172 0x00,
173 0x00,
174 0x80,
175 0x00,
176 0x10,
177 0x00,
178 0x00,
179 0x0d,
180 0x18,
181 0x00,
182 0x00);
183
184 constexpr UUID uuid(kId1As16);
185 EXPECT_TRUE(uuid.CompareBytes(kUuid16Bytes));
186 EXPECT_TRUE(uuid.CompareBytes(kUuid32Bytes));
187 EXPECT_TRUE(uuid.CompareBytes(kUuid128Bytes));
188
189 BufferView empty;
190 EXPECT_FALSE(uuid.CompareBytes(empty));
191 }
192
TEST(UUIDTest,ToString)193 TEST(UUIDTest, ToString) {
194 EXPECT_EQ(kId1AsString, UUID(kId1As16).ToString());
195 EXPECT_EQ(kId1AsString, UUID(kId1As32).ToString());
196 EXPECT_EQ(kId1AsString, UUID(kId1As128).ToString());
197
198 EXPECT_EQ(kId2AsString, UUID(kId2As32).ToString());
199 EXPECT_EQ(kId2AsString, UUID(kId2As128).ToString());
200
201 EXPECT_EQ(kId3AsString, UUID(kId3As128).ToString());
202 }
203
TEST(UUIDTest,IsStringValidUuid)204 TEST(UUIDTest, IsStringValidUuid) {
205 EXPECT_FALSE(IsStringValidUuid("0000180d00001000800000805f9b34fb"));
206 EXPECT_FALSE(IsStringValidUuid("0000180d-0000-1000-8000000805f9b34fb"));
207 EXPECT_FALSE(IsStringValidUuid("0000180d-0000-100008000-00805f9b34fb"));
208 EXPECT_FALSE(IsStringValidUuid("0000180d-000001000-8000-00805f9b34fb"));
209 EXPECT_FALSE(IsStringValidUuid("0000180d00000-1000-8000-00805f9b34fb"));
210 EXPECT_FALSE(IsStringValidUuid("0000180d-0000-1000-8000-00805g9b34fb"));
211 EXPECT_FALSE(IsStringValidUuid("000-180d-0000-1000-8000-00805f9b34fb"));
212
213 // Combinations of lower and upper case characters should work.
214 EXPECT_TRUE(IsStringValidUuid("0000180d-0000-1000-8000-00805f9b34fb"));
215 EXPECT_TRUE(IsStringValidUuid("0000180D-0000-1000-8000-00805F9B34FB"));
216 EXPECT_TRUE(IsStringValidUuid("0000180d-0000-1000-8000-00805F9b34fB"));
217 EXPECT_TRUE(IsStringValidUuid(kId2AsString));
218 EXPECT_TRUE(IsStringValidUuid(kId3AsString));
219 }
220
TEST(UUIDTest,StringToUuid)221 TEST(UUIDTest, StringToUuid) {
222 UUID uuid;
223
224 EXPECT_FALSE(StringToUuid("0000180d00001000800000805f9b34fb", &uuid));
225 EXPECT_FALSE(StringToUuid("0000180d-0000-1000-8000000805f9b34fb", &uuid));
226 EXPECT_FALSE(StringToUuid("0000180d-0000-100008000-00805f9b34fb", &uuid));
227 EXPECT_FALSE(StringToUuid("0000180d-000001000-8000-00805f9b34fb", &uuid));
228 EXPECT_FALSE(StringToUuid("0000180d00000-1000-8000-00805f9b34fb", &uuid));
229 EXPECT_FALSE(StringToUuid("0000180d-0000-1000-8000-00805g9b34fb", &uuid));
230 EXPECT_FALSE(StringToUuid("000-180d-0000-1000-8000-00805f9b34fb", &uuid));
231
232 // Combinations of lower and upper case characters should work.
233 EXPECT_TRUE(StringToUuid("0000180d-0000-1000-8000-00805f9b34fb", &uuid));
234 EXPECT_EQ(kId1As16, uuid);
235 EXPECT_TRUE(StringToUuid("0000180D-0000-1000-8000-00805F9B34FB", &uuid));
236 EXPECT_EQ(kId1As16, uuid);
237 EXPECT_TRUE(StringToUuid("0000180d-0000-1000-8000-00805F9b34fB", &uuid));
238 EXPECT_EQ(kId1As16, uuid);
239
240 EXPECT_TRUE(StringToUuid(kId2AsString, &uuid));
241 EXPECT_EQ(kId2As32, uuid);
242
243 EXPECT_TRUE(StringToUuid(kId3AsString, &uuid));
244 EXPECT_EQ(kId3As128, uuid.value());
245 }
246
TEST(UUIDTest,StringToUuid16)247 TEST(UUIDTest, StringToUuid16) {
248 UUID uuid;
249
250 EXPECT_FALSE(StringToUuid("0180d", &uuid));
251 EXPECT_FALSE(StringToUuid("0000180d", &uuid));
252 EXPECT_FALSE(StringToUuid("why", &uuid));
253 EXPECT_FALSE(StringToUuid("d", &uuid));
254 EXPECT_FALSE(StringToUuid("0x180d", &uuid));
255
256 // Combinations of lower and upper case characters should work.
257 EXPECT_TRUE(StringToUuid("180d", &uuid));
258 EXPECT_EQ(kId1As16, uuid);
259 EXPECT_TRUE(StringToUuid("180D", &uuid));
260 EXPECT_EQ(kId1As16, uuid);
261 }
262
TEST(UUIDTest,FromBytes)263 TEST(UUIDTest, FromBytes) {
264 StaticByteBuffer kUuid16Bytes(0x0d, 0x18);
265 StaticByteBuffer kUuid32Bytes(0x0d, 0x18, 0x00, 0x00);
266 StaticByteBuffer kUuid128Bytes(0xFB,
267 0x34,
268 0x9B,
269 0x5F,
270 0x80,
271 0x00,
272 0x00,
273 0x80,
274 0x00,
275 0x10,
276 0x00,
277 0x00,
278 0x0d,
279 0x18,
280 0x00,
281 0x00);
282
283 StaticByteBuffer kInvalid0(0x0d);
284 StaticByteBuffer kInvalid1(0x0d, 0x18, 0x00);
285 BufferView kInvalid2;
286
287 UUID uuid;
288
289 EXPECT_FALSE(UUID::FromBytes(kInvalid0, &uuid));
290 EXPECT_FALSE(UUID::FromBytes(kInvalid1, &uuid));
291 EXPECT_FALSE(UUID::FromBytes(kInvalid2, &uuid));
292
293 EXPECT_TRUE(UUID::FromBytes(kUuid16Bytes, &uuid));
294 EXPECT_EQ(kId1As16, uuid);
295 EXPECT_TRUE(UUID::FromBytes(kUuid32Bytes, &uuid));
296 EXPECT_EQ(kId1As16, uuid);
297 EXPECT_TRUE(UUID::FromBytes(kUuid128Bytes, &uuid));
298 EXPECT_EQ(kId1As16, uuid);
299 }
300
TEST(UUIDTest,ByteConstructor)301 TEST(UUIDTest, ByteConstructor) {
302 const StaticByteBuffer kUuid16(0x0d, 0x18);
303 UUID uuid(kUuid16);
304 EXPECT_EQ(kId1As16, uuid);
305 }
306
TEST(UUIDTest,ByteConstructorAssertsOnInvalidInput)307 TEST(UUIDTest, ByteConstructorAssertsOnInvalidInput) {
308 const StaticByteBuffer kInvalidUuid(0x0d);
309 EXPECT_DEATH_IF_SUPPORTED((UUID(kInvalidUuid)), ".*");
310 }
311
TEST(UUIDTest,CompactSize)312 TEST(UUIDTest, CompactSize) {
313 UUID direct(kId1As16);
314 UUID fromstring;
315
316 StringToUuid(kId1AsString, &fromstring);
317
318 EXPECT_EQ(2u, direct.CompactSize());
319 EXPECT_EQ(2u, fromstring.CompactSize());
320
321 direct = UUID(kId2As32);
322 StringToUuid(kId2AsString, &fromstring);
323
324 EXPECT_EQ(4u, direct.CompactSize());
325 EXPECT_EQ(4u, fromstring.CompactSize());
326 EXPECT_EQ(16u, direct.CompactSize(/*allow_32bit=*/false));
327 EXPECT_EQ(16u, fromstring.CompactSize(/*allow_32bit=*/false));
328
329 direct = UUID(kId3As128);
330 StringToUuid(kId3AsString, &fromstring);
331
332 EXPECT_EQ(16u, direct.CompactSize());
333 EXPECT_EQ(16u, fromstring.CompactSize());
334 }
335
TEST(UUIDTest,ToBytes16)336 TEST(UUIDTest, ToBytes16) {
337 StaticByteBuffer kUuid16Bytes(0x0d, 0x18);
338
339 UUID uuid(kId1As16);
340 DynamicByteBuffer bytes(uuid.CompactSize());
341
342 EXPECT_EQ(bytes.size(), uuid.ToBytes(&bytes));
343 EXPECT_TRUE(ContainersEqual(kUuid16Bytes, bytes));
344
345 uuid = UUID(kId1As32);
346
347 EXPECT_EQ(bytes.size(), uuid.ToBytes(&bytes));
348 EXPECT_TRUE(ContainersEqual(kUuid16Bytes, bytes));
349 }
350
TEST(UUIDTest,ToBytes32)351 TEST(UUIDTest, ToBytes32) {
352 StaticByteBuffer kUuid32Bytes(0xef, 0xbe, 0xad, 0xde);
353
354 UUID uuid(kId2As32);
355 DynamicByteBuffer bytes(uuid.CompactSize());
356
357 EXPECT_EQ(bytes.size(), uuid.ToBytes(&bytes));
358 EXPECT_TRUE(ContainersEqual(kUuid32Bytes, bytes));
359
360 StaticByteBuffer<16> bytes128;
361 EXPECT_EQ(bytes128.size(), uuid.ToBytes(&bytes128, /*allow_32bit=*/false));
362 EXPECT_TRUE(ContainersEqual(kId2As128, bytes128));
363 }
364
TEST(UUIDTest,CompactView16)365 TEST(UUIDTest, CompactView16) {
366 StaticByteBuffer kUuid16Bytes(0x0d, 0x18);
367
368 UUID uuid(kId1As16);
369
370 BufferView view = uuid.CompactView();
371 EXPECT_TRUE(ContainersEqual(kUuid16Bytes, view));
372
373 uuid = UUID(kId1As32);
374 view = uuid.CompactView();
375 EXPECT_TRUE(ContainersEqual(kUuid16Bytes, view));
376 }
377
TEST(UUIDTest,CompactView32)378 TEST(UUIDTest, CompactView32) {
379 StaticByteBuffer kUuid32Bytes(0xef, 0xbe, 0xad, 0xde);
380
381 UUID uuid(kId2As32);
382
383 BufferView view = uuid.CompactView();
384 EXPECT_TRUE(ContainersEqual(kUuid32Bytes, view));
385
386 view = uuid.CompactView(/*allow_32bit=*/false);
387 EXPECT_TRUE(ContainersEqual(kId2As128, view));
388 }
389
TEST(UUIDTest,Hash)390 TEST(UUIDTest, Hash) {
391 constexpr UUID uuid1(kId3As128);
392 constexpr UUID uuid2(kId3As128);
393
394 EXPECT_EQ(uuid1, uuid2);
395 EXPECT_EQ(uuid1.Hash(), uuid2.Hash());
396 }
397
TEST(UUIDTest,Generate)398 TEST(UUIDTest, Generate) {
399 for (int i = 0; i < 50; i++) {
400 UUID uuid = UUID::Generate();
401 EXPECT_EQ(uuid.value()[6] & 0b1111'0000, 0b0100'0000);
402 EXPECT_EQ(uuid.value()[8] & 0b1100'0000, 0b1000'0000);
403 }
404 }
405
406 } // namespace
407 } // namespace bt
408