xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/sdp/data_element_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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