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/sdp/data_element.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
18 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace bt::sdp {
23 namespace {
24
25 template <std::size_t N>
make_dynamic_byte_buffer(std::array<uint8_t,N> bytes)26 DynamicByteBuffer make_dynamic_byte_buffer(std::array<uint8_t, N> bytes) {
27 DynamicByteBuffer ret(N);
28 ret.Write(bytes.data(), N);
29 return ret;
30 }
31
TEST(DataElementTest,CreateIsNull)32 TEST(DataElementTest, CreateIsNull) {
33 DataElement elem;
34 EXPECT_EQ(DataElement::Type::kNull, elem.type());
35 EXPECT_TRUE(elem.Get<std::nullptr_t>());
36 EXPECT_EQ(nullptr, *elem.Get<std::nullptr_t>());
37
38 StaticByteBuffer expected(0x00);
39 DynamicByteBuffer buf(1);
40 EXPECT_EQ(1u, elem.Write(&buf));
41 EXPECT_TRUE(ContainersEqual(expected, buf));
42 }
43
TEST(DataElementTest,SetAndGet)44 TEST(DataElementTest, SetAndGet) {
45 DataElement elem;
46
47 elem.Set(uint8_t{5});
48
49 EXPECT_TRUE(elem.Get<uint8_t>());
50 EXPECT_EQ(5u, *elem.Get<uint8_t>());
51 EXPECT_FALSE(elem.Get<int16_t>());
52
53 elem.Set(std::string("Fuchsia"));
54
55 EXPECT_FALSE(elem.Get<uint8_t>());
56 EXPECT_TRUE(elem.Get<std::string>());
57 EXPECT_EQ(std::string("Fuchsia"), *elem.Get<std::string>());
58 }
59
TEST(DataElementTest,Read)60 TEST(DataElementTest, Read) {
61 StaticByteBuffer buf(
62 0x25, // Type (4: String) & Size (5: in an additional byte) = 0b00100 101
63 0x0B, // Bytes
64 'F',
65 'u',
66 'c',
67 'h',
68 's',
69 'i',
70 'a',
71 0xF0,
72 0x9F,
73 0x92,
74 0x96, // String
75 0xDE,
76 0xAD,
77 0xBE,
78 0xEF // Extra data (shouldn't be parsed)
79 );
80
81 DataElement elem;
82 EXPECT_EQ(13u, DataElement::Read(&elem, buf));
83
84 EXPECT_EQ(DataElement::Type::kString, elem.type());
85 EXPECT_EQ(std::string("Fuchsia"), *elem.Get<std::string>());
86
87 // Invalid - 0xDE: 0x11011 110 = 37 (invalid) + 6 (2 following byte size)
88 EXPECT_EQ(0u, DataElement::Read(&elem, buf.view(13)));
89
90 // elem shouldn't have been touched
91 EXPECT_EQ(DataElement::Type::kString, elem.type());
92 EXPECT_EQ(std::string("Fuchsia"), *elem.Get<std::string>());
93 }
94
TEST(DataElementTest,ReadInvalidType)95 TEST(DataElementTest, ReadInvalidType) {
96 StaticByteBuffer buf(
97 0xFD, // Type (Invalid) & Size (5: in an additional byte) = 0b11111 101
98 0x0B, // Bytes
99 'F',
100 'u',
101 'c',
102 'h',
103 's',
104 'i',
105 'a',
106 0xF0,
107 0x9F,
108 0x92,
109 0x96 // String
110 );
111
112 DataElement elem;
113 EXPECT_EQ(0u, DataElement::Read(&elem, buf));
114 }
115
TEST(DataElementTest,ReadUUID)116 TEST(DataElementTest, ReadUUID) {
117 StaticByteBuffer buf(
118 0x19, // Type (3: UUID) & Size (1: two bytes) = 0b00011 001
119 0x01,
120 0x00 // L2CAP
121 );
122
123 DataElement elem;
124 EXPECT_EQ(3u, DataElement::Read(&elem, buf));
125 EXPECT_EQ(DataElement::Type::kUuid, elem.type());
126 EXPECT_EQ(UUID(uint16_t{0x0100}), *elem.Get<UUID>());
127
128 StaticByteBuffer buf2(
129 0x1A, // Type (3: UUID) & Size (2: four bytes) = 0b00011 010
130 0x01,
131 0x02,
132 0x03,
133 0x04);
134
135 EXPECT_EQ(5u, DataElement::Read(&elem, buf2));
136 EXPECT_EQ(DataElement::Type::kUuid, elem.type());
137 EXPECT_EQ(UUID(uint32_t{0x01020304}), *elem.Get<UUID>());
138
139 StaticByteBuffer buf3(
140 0x1B, // Type (3: UUID) & Size (3: eight bytes) = 0b00011 011
141 0x01,
142 0x02,
143 0x03,
144 0x04,
145 0x01,
146 0x02,
147 0x03,
148 0x04,
149 0x01,
150 0x02,
151 0x03,
152 0x04,
153 0x01,
154 0x02,
155 0x03,
156 0x04);
157
158 EXPECT_EQ(0u, DataElement::Read(&elem, buf3));
159
160 StaticByteBuffer buf4(
161 0x1C, // Type (3: UUID) & Size (3: eight bytes) = 0b00011 100
162 0x01,
163 0x02,
164 0x03,
165 0x04,
166 0x05,
167 0x06,
168 0x07,
169 0x08,
170 0x09,
171 0x0A,
172 0x0B,
173 0x0C,
174 0x0D,
175 0x0E,
176 0x0F,
177 0x10);
178
179 EXPECT_EQ(17u, DataElement::Read(&elem, buf4));
180 EXPECT_EQ(DataElement::Type::kUuid, elem.type());
181 // UInt128 in UUID is little-endian
182 EXPECT_EQ(UUID({0x10,
183 0x0F,
184 0x0E,
185 0x0D,
186 0x0C,
187 0x0B,
188 0x0A,
189 0x09,
190 0x08,
191 0x07,
192 0x06,
193 0x05,
194 0x04,
195 0x03,
196 0x02,
197 0x01}),
198 *elem.Get<UUID>());
199 }
200
TEST(DataElementTest,Write)201 TEST(DataElementTest, Write) {
202 // This represents a plausible attribute_lists parameter of a
203 // SDP_ServiceSearchAttributeResponse PDU for an SPP service.
204 std::vector<DataElement> attribute_list;
205
206 // SerialPort from Assigned Numbers
207 std::vector<DataElement> service_class_list;
208 service_class_list.emplace_back(DataElement(UUID(uint16_t{0x1101})));
209 DataElement service_class_value(std::move(service_class_list));
210 attribute_list.emplace_back(DataElement(kServiceClassIdList));
211 attribute_list.emplace_back(std::move(service_class_value));
212
213 // Protocol Descriptor List
214
215 std::vector<DataElement> protocol_list_value;
216
217 // ( L2CAP, PSM=RFCOMM )
218 std::vector<DataElement> protocol_l2cap;
219 protocol_l2cap.emplace_back(DataElement(protocol::kL2CAP));
220 protocol_l2cap.emplace_back(DataElement(uint16_t{0x0003})); // RFCOMM
221
222 protocol_list_value.emplace_back(DataElement(std::move(protocol_l2cap)));
223
224 // ( RFCOMM, CHANNEL=1 )
225 std::vector<DataElement> protocol_rfcomm;
226 protocol_rfcomm.push_back(DataElement(protocol::kRFCOMM));
227 protocol_rfcomm.push_back(DataElement(uint8_t{1})); // Server Channel = 1
228
229 protocol_list_value.emplace_back(DataElement(std::move(protocol_rfcomm)));
230
231 attribute_list.emplace_back(DataElement(kProtocolDescriptorList));
232 attribute_list.emplace_back(DataElement(std::move(protocol_list_value)));
233
234 // Bluetooth Profile Descriptor List
235 std::vector<DataElement> profile_sequence_list;
236 std::vector<DataElement> spp_sequence;
237 spp_sequence.push_back(DataElement(UUID(uint16_t{0x1101})));
238 spp_sequence.push_back(DataElement(uint16_t{0x0102}));
239
240 profile_sequence_list.emplace_back(std::move(spp_sequence));
241
242 attribute_list.push_back(DataElement(kBluetoothProfileDescriptorList));
243 attribute_list.push_back((DataElement(std::move(profile_sequence_list))));
244
245 // A custom attribute that has a uint64_t in it.
246 attribute_list.emplace_back(DataElement(UUID(uint16_t(0xF00D))));
247 attribute_list.emplace_back(DataElement(uint64_t(0xB0BAC0DECAFEFACE)));
248
249 DataElement attribute_lists_elem(std::move(attribute_list));
250
251 // clang-format off
252 StaticByteBuffer expected(
253 0x35, 0x35, // Sequence uint8 41 bytes
254 0x09, // uint16_t type
255 UpperBits(kServiceClassIdList), LowerBits(kServiceClassIdList),
256 0x35, 0x03, // Sequence uint8 3 bytes
257 0x19, // UUID (16 bits)
258 0x11, 0x01, // Serial Port from assigned numbers
259 0x09, // uint16_t type
260 UpperBits(kProtocolDescriptorList), LowerBits(kProtocolDescriptorList),
261 0x35, 0x0F, // Sequence uint8 15 bytes
262 0x35, 0x06, // Sequence uint8 6 bytes
263 0x19, // Type: UUID (16 bits)
264 0x01, 0x00, // L2CAP UUID
265 0x09, // Type: uint16_t
266 0x00, 0x03, // RFCOMM PSM
267 0x35, 0x05, // Sequence uint8 5 bytes
268 0x19, // Type: UUID (16 bits)
269 0x00, 0x03, // RFCOMM UUID
270 0x08, // Type: uint8_t
271 0x01, // RFCOMM Channel 1
272 0x09, // uint16_t type
273 UpperBits(kBluetoothProfileDescriptorList),
274 LowerBits(kBluetoothProfileDescriptorList),
275 0x35, 0x08, // Sequence uint8 8 bytes
276 0x35, 0x06, // Sequence uint8 6 bytes
277 0x19, // Type: UUID (16 bits)
278 0x11, 0x01, // 0x1101 (SPP)
279 0x09, // Type: uint16_t
280 0x01, 0x02, // v1.2
281 0x19, // Type: UUID (16 bits)
282 0xF0, 0x0D, // Custom attribute ID,
283 0x0B, // uint64_t type
284 0xB0, 0xBA, 0xC0, 0xDE, 0xCA, 0xFE, 0xFA, 0xCE // Data for uint64_t
285 );
286 // clang-format on
287
288 DynamicByteBuffer block(55);
289
290 size_t written = attribute_lists_elem.Write(&block);
291
292 EXPECT_EQ(expected.size(), written);
293 EXPECT_EQ(written, attribute_lists_elem.WriteSize());
294 EXPECT_TRUE(ContainersEqual(expected, block));
295 }
296
TEST(DataElementTest,ReadSequence)297 TEST(DataElementTest, ReadSequence) {
298 // clang-format off
299 StaticByteBuffer buf(
300 0x35, 0x08, // Sequence with 1 byte length (8)
301 0x09, 0x00, 0x01, // uint16_t: 1
302 0x0A, 0x00, 0x00, 0x00, 0x02 // uint32_t: 2
303 );
304 // clang-format on
305
306 DataElement elem;
307 EXPECT_EQ(buf.size(), DataElement::Read(&elem, buf));
308 EXPECT_EQ(DataElement::Type::kSequence, elem.type());
309 auto* it = elem.At(0);
310 EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
311 EXPECT_EQ(1u, *it->Get<uint16_t>());
312
313 it = elem.At(1);
314 EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
315 EXPECT_EQ(2u, *it->Get<uint32_t>());
316 }
317
TEST(DataElementTest,ReadNestedSequence)318 TEST(DataElementTest, ReadNestedSequence) {
319 StaticByteBuffer buf(0x35,
320 0x1C, // Sequence uint8 28 bytes
321 // Sequence 0
322 0x35,
323 0x08, // Sequence uint8 8 bytes
324 0x09,
325 0x00,
326 0x00, // Element: uint16_t (0)
327 0x0A,
328 0xFE,
329 0xED,
330 0xBE,
331 0xEF, // Element: uint32_t (0xFEEDBEEF)
332 // Sequence 1
333 0x35,
334 0x10, // Sequence uint8 16 bytes
335 0x09,
336 0x00,
337 0x00, // Element: uint16_t (0)
338 0x0A,
339 0xFE,
340 0xDB,
341 0xAC,
342 0x01, // Element: uint32_t (0xFEDBAC01)
343 0x09,
344 0x00,
345 0x01, // Handle: uint16_t (1 = kServiceClassIdList)
346 0x35,
347 0x03,
348 0x19,
349 0x11,
350 0x01 // Element: Sequence (3) { UUID(0x1101) }
351 );
352
353 DataElement elem;
354 EXPECT_EQ(buf.size(), DataElement::Read(&elem, buf));
355 EXPECT_EQ(DataElement::Type::kSequence, elem.type());
356 auto* outer_it = elem.At(0);
357 EXPECT_EQ(DataElement::Type::kSequence, outer_it->type());
358
359 auto* it = outer_it->At(0);
360 EXPECT_EQ(0u, *it->Get<uint16_t>());
361
362 it = outer_it->At(1);
363 EXPECT_EQ(0xfeedbeef, *it->Get<uint32_t>());
364
365 outer_it = elem.At(1);
366 EXPECT_EQ(DataElement::Type::kSequence, outer_it->type());
367
368 it = outer_it->At(0);
369 EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
370 EXPECT_EQ(0u, *it->Get<uint16_t>());
371
372 it = outer_it->At(1);
373 EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
374 EXPECT_EQ(0xfedbac01, *it->Get<uint32_t>());
375
376 it = outer_it->At(2);
377 EXPECT_EQ(DataElement::Type::kUnsignedInt, it->type());
378 EXPECT_EQ(1u, *it->Get<uint16_t>());
379
380 it = outer_it->At(3);
381 EXPECT_EQ(DataElement::Type::kSequence, it->type());
382
383 auto inner_it = it->At(0);
384 EXPECT_EQ(DataElement::Type::kUuid, inner_it->type());
385 }
386
TEST(DataElementTest,ToString)387 TEST(DataElementTest, ToString) {
388 EXPECT_EQ("Null", DataElement().ToString());
389 EXPECT_EQ("Boolean(true)", DataElement(true).ToString());
390 EXPECT_EQ("UnsignedInt:1(27)", DataElement(uint8_t{27}).ToString());
391 EXPECT_EQ("SignedInt:4(-54321)", DataElement(int32_t{-54321}).ToString());
392 EXPECT_EQ("UUID(00000100-0000-1000-8000-00805f9b34fb)",
393 DataElement(protocol::kL2CAP).ToString());
394 EXPECT_EQ("String(fuchsia)",
395 DataElement(std::string("fuchsia")).ToString());
396 // This test and the following one print invalid unicode strings by replacing
397 // nonASCII characters
398 // with '.'. Somewhat confusingly, individual bytes of invalid unicode
399 // sequences can be valid
400 // ASCII bytes. In particular, the '\x28' in the invalid unicode sequences
401 // below is a perfectly valid '(' in ASCII, so it prints as that.
402 EXPECT_EQ(
403 "String(ABC.(XYZ)",
404 DataElement(std::string("ABC\xc3\x28XYZ")).ToString()); // Invalid UTF8.
405 EXPECT_EQ("String(ABC.(XYZ....)",
406 DataElement(std::string("ABC\xc3\x28XYZ"))
407 .ToString()); // Invalid UTF8 means the whole
408 // string must be treated as ASCII.
409 DataElement elem;
410 elem.SetUrl(std::string("http://example.com"));
411 EXPECT_EQ("Url(http://example.com)", elem.ToString());
412 std::vector<DataElement> strings;
413 strings.emplace_back(std::string("hello"));
414 strings.emplace_back(std::string("sapphire"));
415 EXPECT_EQ("Sequence { String(hello) String(sapphire) }",
416 DataElement(std::move(strings)).ToString());
417 DataElement alts;
418 strings.clear();
419 strings.emplace_back(std::string("hello"));
420 strings.emplace_back(std::string("sapphire"));
421 alts.SetAlternative(std::move(strings));
422 EXPECT_EQ("Alternatives { String(hello) String(sapphire) }",
423 alts.ToString());
424 }
425
TEST(DataElementTest,SetAndGetUrl)426 TEST(DataElementTest, SetAndGetUrl) {
427 DataElement elem;
428 elem.SetUrl(std::string("https://foobar.dev"));
429
430 EXPECT_FALSE(elem.Get<std::string>());
431 EXPECT_EQ(DataElement::Type::kUrl, elem.type());
432 EXPECT_EQ(std::string("https://foobar.dev"), *elem.GetUrl());
433 }
434
TEST(DataElementTest,SetAndGetAlt)435 TEST(DataElementTest, SetAndGetAlt) {
436 std::vector<DataElement> alternatives;
437 DataElement elem1;
438 elem1.Set<uint8_t>(5);
439 alternatives.emplace_back(std::move(elem1));
440 DataElement elem2;
441 elem2.Set(std::string("foo"));
442 alternatives.emplace_back(std::move(elem2));
443 DataElement alt_elem;
444 alt_elem.SetAlternative(std::move(alternatives));
445
446 EXPECT_EQ(DataElement::Type::kAlternative, alt_elem.type());
447 auto alt_get = alt_elem.Get<std::vector<DataElement>>();
448 EXPECT_TRUE(alt_get);
449 EXPECT_EQ(alt_get.value().size(), 2u);
450 EXPECT_EQ(alt_get.value().at(0).Get<uint8_t>().value(), 5);
451 EXPECT_EQ(alt_get.value().at(1).Get<std::string>().value(),
452 std::string("foo"));
453 }
454
TEST(DataElementTest,SetInvalidUrlStringIsNoOp)455 TEST(DataElementTest, SetInvalidUrlStringIsNoOp) {
456 DataElement elem;
457 EXPECT_EQ(DataElement::Type::kNull, elem.type());
458 elem.SetUrl(std::string("https://foobar.dev"));
459
460 EXPECT_FALSE(elem.GetUrl());
461 EXPECT_EQ(DataElement::Type::kNull, elem.type());
462 }
463
TEST(DataElementTest,ReadUrlFromBuffer)464 TEST(DataElementTest, ReadUrlFromBuffer) {
465 StaticByteBuffer buf(
466 0x45, // Type (8: URL) & Size (5: in an additional byte) = 0b01000 101
467 0x0B, // 11 Bytes
468 'F',
469 'u',
470 'c',
471 'h',
472 's',
473 'i',
474 'a',
475 '.',
476 'd',
477 'e',
478 'v', // URL String
479 0xDE,
480 0xAD,
481 0xBE,
482 0xEF // Extra data (shouldn't be parsed)
483 );
484
485 DataElement read_elem;
486 EXPECT_EQ(13u, DataElement::Read(&read_elem, buf));
487
488 EXPECT_EQ(DataElement::Type::kUrl, read_elem.type());
489 EXPECT_EQ(std::string("Fuchsia.dev"), *read_elem.GetUrl());
490 }
491
TEST(DataElementTest,WriteUrlToBuffer)492 TEST(DataElementTest, WriteUrlToBuffer) {
493 DataElement url_elem;
494 url_elem.SetUrl(std::string("Test.com"));
495
496 auto expected = StaticByteBuffer(
497 0x45, // Type (8: URL) & Size (5: in an additional byte) = 0b01000 101
498 0x08, // 8 Bytes
499 'T',
500 'e',
501 's',
502 't',
503 '.',
504 'c',
505 'o',
506 'm' // URL String
507 );
508
509 DynamicByteBuffer write_buf(10);
510
511 size_t written = url_elem.Write(&write_buf);
512
513 EXPECT_EQ(expected.size(), written);
514 EXPECT_EQ(written, url_elem.WriteSize());
515 EXPECT_TRUE(ContainersEqual(expected, write_buf));
516 }
517
TEST(DataElementTest,SetAndGetStrings)518 TEST(DataElementTest, SetAndGetStrings) {
519 auto buffer_set_string = make_dynamic_byte_buffer<10>(
520 {'s', 'e', 't', ' ', 's', 't', 'r', 'i', 'n', 'g'});
521 std::string string_set_string("set string");
522
523 auto buffer_set_buffer = make_dynamic_byte_buffer<10>(
524 {'s', 'e', 't', ' ', 'b', 'u', 'f', 'f', 'e', 'r'});
525 std::string string_set_buffer("set buffer");
526
527 DataElement elem_set_string;
528 elem_set_string.Set(string_set_string);
529
530 EXPECT_EQ(elem_set_string.Get<std::string>(), string_set_string);
531 EXPECT_EQ(elem_set_string.Get<DynamicByteBuffer>(), buffer_set_string);
532
533 DataElement elem_set_buffer;
534 elem_set_buffer.Set(string_set_buffer);
535
536 EXPECT_EQ(elem_set_buffer.Get<DynamicByteBuffer>(), buffer_set_buffer);
537 EXPECT_EQ(elem_set_buffer.Get<std::string>(), string_set_buffer);
538 }
539
540 } // namespace
541 } // namespace bt::sdp
542