xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/common/advertising_data_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/common/advertising_data.h"
16 
17 #include <cpp-string/string_printf.h>
18 
19 #include <limits>
20 #include <string>
21 #include <variant>
22 
23 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
26 #include "pw_bluetooth_sapphire/internal/host/common/to_string.h"
27 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
28 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
29 #include "pw_unit_test/framework.h"
30 
31 namespace bt {
32 namespace {
33 
34 constexpr uint16_t kGattUuid = 0x1801;
35 constexpr uint16_t kEddystoneUuid = 0xFEAA;
36 constexpr uint16_t kHeartRateServiceUuid = 0x180D;
37 
38 constexpr uint16_t kId1As16 = 0x0212;
39 constexpr uint16_t kId2As16 = 0x1122;
40 
41 constexpr size_t kRandomDataSize = 100;
42 
TEST(AdvertisingDataTest,MakeEmpty)43 TEST(AdvertisingDataTest, MakeEmpty) {
44   AdvertisingData data;
45 
46   EXPECT_EQ(0u, data.CalculateBlockSize());
47 }
48 
TEST(AdvertisingDataTest,CopyLeavesNoRemnants)49 TEST(AdvertisingDataTest, CopyLeavesNoRemnants) {
50   AdvertisingData data;
51   data.SetFlags(0x4);
52   data.SetTxPower(4);
53   data.SetAppearance(0x4567);
54   EXPECT_TRUE(data.SetLocalName("fuchsia"));
55   EXPECT_TRUE(data.AddUri("http://fuchsia.cl"));
56 
57   StaticByteBuffer bytes(0x01, 0x02, 0x03);
58   EXPECT_TRUE(data.SetManufacturerData(0x0123, bytes.view()));
59 
60   auto service_uuid = UUID(kId1As16);
61   EXPECT_TRUE(data.AddServiceUuid(service_uuid));
62 
63   StaticByteBuffer service_bytes(0x01, 0x02);
64   EXPECT_TRUE(data.SetServiceData(service_uuid, service_bytes.view()));
65 
66   AdvertisingData new_data;
67   new_data.SetTxPower(1);
68   new_data.Copy(&data);
69 
70   EXPECT_EQ(1, data.tx_power().value());
71   EXPECT_FALSE(data.appearance().has_value());
72   EXPECT_FALSE(data.local_name().has_value());
73   EXPECT_FALSE(data.flags().has_value());
74   EXPECT_EQ(0u, data.uris().size());
75   EXPECT_EQ(0u, data.manufacturer_data_ids().size());
76   EXPECT_EQ(0u, data.service_uuids().size());
77   EXPECT_EQ(0u, data.service_data_uuids().size());
78 }
79 
TEST(AdvertisingDataTest,EncodeKnownURI)80 TEST(AdvertisingDataTest, EncodeKnownURI) {
81   AdvertisingData data;
82   EXPECT_TRUE(data.AddUri("https://abc.xyz"));
83 
84   StaticByteBuffer bytes(
85       0x0B, 0x24, 0x17, '/', '/', 'a', 'b', 'c', '.', 'x', 'y', 'z');
86 
87   EXPECT_EQ(bytes.size(), data.CalculateBlockSize());
88   DynamicByteBuffer block(data.CalculateBlockSize());
89   data.WriteBlock(&block, std::nullopt);
90   EXPECT_TRUE(ContainersEqual(bytes, block));
91 }
92 
TEST(AdvertisingDataTest,EncodeUnknownURI)93 TEST(AdvertisingDataTest, EncodeUnknownURI) {
94   AdvertisingData data;
95   EXPECT_TRUE(data.AddUri("flubs:xyz"));
96 
97   StaticByteBuffer bytes(
98       0x0B, 0x24, 0x01, 'f', 'l', 'u', 'b', 's', ':', 'x', 'y', 'z');
99 
100   size_t block_size = data.CalculateBlockSize();
101   EXPECT_EQ(bytes.size(), block_size);
102   DynamicByteBuffer block(block_size);
103   data.WriteBlock(&block, std::nullopt);
104   EXPECT_TRUE(ContainersEqual(bytes, block));
105 }
106 
TEST(AdvertisingDataTest,CompressServiceUUIDs)107 TEST(AdvertisingDataTest, CompressServiceUUIDs) {
108   AdvertisingData data;
109   std::unordered_set<UUID> uuids{UUID(kId1As16), UUID(kId2As16)};
110   for (auto& uuid : uuids) {
111     SCOPED_TRACE(bt_str(uuid));
112     EXPECT_TRUE(data.AddServiceUuid(uuid));
113   }
114 
115   uint8_t expected_block_size = 1                          // length byte
116                                 + 1                        // type byte
117                                 + (sizeof(uint16_t) * 2);  // 2 16-bit UUIDs
118   EXPECT_EQ(expected_block_size, data.CalculateBlockSize());
119 
120   StaticByteBuffer expected_header{expected_block_size - 1,
121                                    DataType::kIncomplete16BitServiceUuids};
122 
123   DynamicByteBuffer block(expected_block_size);
124   data.WriteBlock(&block, std::nullopt);
125 
126   EXPECT_TRUE(
127       ContainersEqual(expected_header, block.view(/*pos=*/0, /*size=*/2)));
128   auto to_uuid = [](const ByteBuffer& b, size_t pos) {
129     return UUID(b.view(pos, /*size=*/2).To<uint16_t>());
130   };
131   EXPECT_TRUE(uuids.find(to_uuid(block, 2)) != uuids.end());
132   EXPECT_TRUE(uuids.find(to_uuid(block, 4)) != uuids.end());
133 }
134 
TEST(AdvertisingDataTest,ParseBlock)135 TEST(AdvertisingDataTest, ParseBlock) {
136   StaticByteBuffer bytes(
137       // Complete 16-bit UUIDs
138       0x05,
139       0x03,
140       0x12,
141       0x02,
142       0x22,
143       0x11,
144       // Incomplete list of 32-bit UUIDs
145       0x05,
146       0x04,
147       0x34,
148       0x12,
149       0x34,
150       0x12,
151       // Local name
152       0x09,
153       0x09,
154       'T',
155       'e',
156       's',
157       't',
158       0xF0,
159       0x9F,
160       0x92,
161       0x96,
162       // TX Power
163       0x02,
164       0x0A,
165       0x8F);
166 
167   AdvertisingData::ParseResult data = AdvertisingData::FromBytes(bytes);
168   ASSERT_EQ(fit::ok(), data);
169 
170   EXPECT_EQ(3u, data->service_uuids().size());
171   EXPECT_TRUE(data->local_name());
172   EXPECT_EQ("Test��", data->local_name()->name);
173   EXPECT_TRUE(data->tx_power());
174   EXPECT_EQ(-113, *(data->tx_power()));
175 }
176 
TEST(AdvertisingDataTest,ParseBlockUnknownDataType)177 TEST(AdvertisingDataTest, ParseBlockUnknownDataType) {
178   AdvertisingData expected_ad;
179   constexpr uint8_t lower_byte = 0x12, upper_byte = 0x22;
180   constexpr uint16_t uuid_value = (upper_byte << 8) + lower_byte;
181   // The only field present in the expected AD is one complete 16-bit UUID.
182   EXPECT_TRUE(expected_ad.AddServiceUuid(UUID(uuid_value)));
183 
184   StaticByteBuffer bytes{// Complete 16-bit UUIDs
185                          0x03,
186                          0x03,
187                          lower_byte,
188                          upper_byte,
189                          // 0x40, the second octet, is not a recognized DataType
190                          // (see common/supplement_data.h).
191                          0x05,
192                          0x40,
193                          0x34,
194                          0x12,
195                          0x34,
196                          0x12};
197   AdvertisingData::ParseResult data = AdvertisingData::FromBytes(bytes);
198   ASSERT_EQ(fit::ok(), data);
199 
200   // The second field of `bytes` was valid (in that its length byte matched its
201   // length), but its Data Type was unknown, so it should be ignored (i.e. the
202   // only field in the `data` should be the single 16-bit UUID, matching
203   // expected AD).
204   EXPECT_EQ(expected_ad, *data);
205 }
206 
TEST(AdvertisingDataTest,ParseBlockNameTooLong)207 TEST(AdvertisingDataTest, ParseBlockNameTooLong) {
208   // A block with a name of exactly kMaxNameLength (==248) bytes should be
209   // parsed correctly.
210   {
211     StaticByteBuffer<2> leading_bytes{kMaxNameLength + 1,
212                                       DataType::kCompleteLocalName};
213     auto bytes = DynamicByteBuffer(kMaxNameLength + 2);
214     bytes.Write(leading_bytes);
215     DynamicByteBuffer name(kMaxNameLength);
216     name.Fill('a');
217     bytes.Write(name, /*pos=*/2);
218     AdvertisingData::ParseResult result = AdvertisingData::FromBytes(bytes);
219     ASSERT_EQ(fit::ok(), result);
220     EXPECT_EQ(result->local_name()->name, std::string(kMaxNameLength, 'a'));
221   }
222   // Repeat previous test with shortened name.
223   {
224     auto leading_bytes =
225         StaticByteBuffer<2>{kMaxNameLength + 1, DataType::kShortenedLocalName};
226     auto bytes = DynamicByteBuffer(kMaxNameLength + 2);
227     bytes.Write(leading_bytes);
228     DynamicByteBuffer name(kMaxNameLength);
229     name.Fill('a');
230     bytes.Write(name, /*pos=*/2);
231     AdvertisingData::ParseResult result = AdvertisingData::FromBytes(bytes);
232     ASSERT_EQ(fit::ok(), result);
233     EXPECT_EQ(result->local_name()->name, std::string(kMaxNameLength, 'a'));
234   }
235   // A block with a name of kMaxNameLength+1 (==249) bytes should be rejected.
236   {
237     StaticByteBuffer<2> leading_bytes{kMaxNameLength + 2,
238                                       DataType::kCompleteLocalName};
239     auto bytes = DynamicByteBuffer(kMaxNameLength + 3);
240     bytes.Write(leading_bytes);
241     DynamicByteBuffer name(kMaxNameLength + 1);
242     name.Fill('a');
243     bytes.Write(name, /*pos=*/2);
244     AdvertisingData::ParseResult result = AdvertisingData::FromBytes(bytes);
245     ASSERT_TRUE(result.is_error());
246     EXPECT_EQ(AdvertisingData::ParseError::kLocalNameTooLong,
247               result.error_value());
248   }
249   // Repeat previous test with shortened name.
250   {
251     auto leading_bytes =
252         StaticByteBuffer<2>{kMaxNameLength + 2, DataType::kShortenedLocalName};
253     auto bytes = DynamicByteBuffer(kMaxNameLength + 3);
254     bytes.Write(leading_bytes);
255     DynamicByteBuffer name(kMaxNameLength + 1);
256     name.Fill('a');
257     bytes.Write(name, /*pos=*/2);
258     AdvertisingData::ParseResult result = AdvertisingData::FromBytes(bytes);
259     ASSERT_TRUE(result.is_error());
260     EXPECT_EQ(AdvertisingData::ParseError::kLocalNameTooLong,
261               result.error_value());
262   }
263 }
264 
TEST(AdvertisingDataTest,ManufacturerZeroLength)265 TEST(AdvertisingDataTest, ManufacturerZeroLength) {
266   StaticByteBuffer bytes(
267       // Complete 16-bit UUIDs
268       0x05,
269       0x03,
270       0x12,
271       0x02,
272       0x22,
273       0x11,
274       // Manufacturer Data with no data
275       0x03,
276       0xFF,
277       0x34,
278       0x12);
279 
280   EXPECT_EQ(0u, AdvertisingData().manufacturer_data_ids().size());
281 
282   AdvertisingData::ParseResult data = AdvertisingData::FromBytes(bytes);
283   ASSERT_EQ(fit::ok(), data);
284 
285   EXPECT_EQ(1u, data->manufacturer_data_ids().count(0x1234));
286   EXPECT_EQ(0u, data->manufacturer_data(0x1234).size());
287 }
288 
TEST(AdvertisingDataTest,ServiceData)289 TEST(AdvertisingDataTest, ServiceData) {
290   // A typical Eddystone-URL beacon advertisement
291   // to "https://fuchsia.cl"
292   StaticByteBuffer bytes(
293       // Complete 16-bit UUIDs, 0xFEAA
294       0x03,
295       0x03,
296       0xAA,
297       0xFE,
298       // Eddystone Service (0xFEAA) Data:
299       0x10,
300       0x16,
301       0xAA,
302       0xFE,
303       0x10,  // Eddystone-Uri type
304       0xEE,  // TX Power level -18dBm
305       0x03,  // "https://"
306       'f',
307       'u',
308       'c',
309       'h',
310       's',
311       'i',
312       'a',
313       '.',
314       'c',
315       'l');
316 
317   EXPECT_EQ(0u, AdvertisingData().service_data_uuids().size());
318 
319   AdvertisingData::ParseResult data = AdvertisingData::FromBytes(bytes);
320   ASSERT_EQ(fit::ok(), data);
321 
322   UUID eddystone(uint16_t{0xFEAA});
323 
324   EXPECT_EQ(1u, data->service_data_uuids().size());
325   EXPECT_EQ(13u, data->service_data(eddystone).size());
326 
327   EXPECT_TRUE(ContainersEqual(bytes.view(8), data->service_data(eddystone)));
328 }
329 
330 // Per CSS v9 Part A 1.1.1, "A packet or data block shall not contain more than
331 // one instance for each Service UUID data size". We enforce this by failing to
332 // parse AdvertisingData with UUIDs of a particular size which exceed the amount
333 // that can fit in one TLV field.
TEST(AdvertisingDataTest,TooManyUuidsOfSizeRejected)334 TEST(AdvertisingDataTest, TooManyUuidsOfSizeRejected) {
335   // Space for the maximum # of 16 bit UUIDs + length + type fields.
336   const uint64_t kMaxAllowed16BitUuidsSize =
337       (2 + kMax16BitUuids * UUIDElemSize::k16Bit);
338   // Space for one more UUID + type and length fields
339   const uint64_t kExpectedBuffSize =
340       kMaxAllowed16BitUuidsSize + (2 + UUIDElemSize::k16Bit);
341 
342   DynamicByteBuffer bytes(kExpectedBuffSize);
343   uint64_t offset = 0;
344   // Write first TLV field with maximum # of UUIDs
345   bytes.Write(StaticByteBuffer{
346       kMax16BitUuids * UUIDElemSize::k16Bit + 1,                  // Size byte
347       static_cast<uint8_t>(DataType::kComplete16BitServiceUuids)  // Type byte
348   });
349   offset += 2;
350   for (uint16_t i = 0; i < kMax16BitUuids; ++i) {
351     UUID uuid(static_cast<uint16_t>(i + 'a'));
352     bytes.Write(uuid.CompactView(), offset);
353     offset += uuid.CompactSize();
354   }
355   // Verify that we successfully parse an AD with the maximum amount of 16 bit
356   // UUIDs
357   AdvertisingData::ParseResult adv_result = AdvertisingData::FromBytes(
358       bytes.view(/*pos=*/0, /*size=*/kMaxAllowed16BitUuidsSize));
359   ASSERT_EQ(fit::ok(), adv_result);
360   EXPECT_EQ(kMax16BitUuids, adv_result->service_uuids().size());
361   // Write second Complete 16 bit Service UUIDs TLV field with one more UUID
362   bytes.Write(
363       StaticByteBuffer{
364           UUIDElemSize::k16Bit + 1,  // Size byte
365           static_cast<uint8_t>(
366               DataType::kComplete16BitServiceUuids)  // Type byte
367       },
368       offset);
369   offset += 2;
370   UUID uuid(static_cast<uint16_t>(kMax16BitUuids + 'a'));
371   bytes.Write(uuid.CompactView(), offset);
372 
373   adv_result = AdvertisingData::FromBytes(bytes);
374   ASSERT_TRUE(adv_result.is_error());
375   EXPECT_EQ(AdvertisingData::ParseError::kUuidsMalformed,
376             adv_result.error_value());
377 }
378 
TEST(AdvertisingDataTest,Missing)379 TEST(AdvertisingDataTest, Missing) {
380   AdvertisingData::ParseResult result =
381       AdvertisingData::FromBytes(DynamicByteBuffer());
382   ASSERT_TRUE(result.is_error());
383   EXPECT_EQ(AdvertisingData::ParseError::kMissing, result.error_value());
384 }
385 
TEST(AdvertisingDataTest,InvalidTlvFormat)386 TEST(AdvertisingDataTest, InvalidTlvFormat) {
387   AdvertisingData::ParseResult result =
388       AdvertisingData::FromBytes(StaticByteBuffer(0x03));
389   ASSERT_TRUE(result.is_error());
390   EXPECT_EQ(AdvertisingData::ParseError::kInvalidTlvFormat,
391             result.error_value());
392 }
393 
TEST(AdvertisingDataTest,TxPowerLevelMalformed)394 TEST(AdvertisingDataTest, TxPowerLevelMalformed) {
395   StaticByteBuffer service_data{/*length=*/0x01,
396                                 static_cast<uint8_t>(DataType::kTxPowerLevel)};
397   AdvertisingData::ParseResult result =
398       AdvertisingData::FromBytes(service_data);
399   ASSERT_TRUE(result.is_error());
400   EXPECT_EQ(AdvertisingData::ParseError::kTxPowerLevelMalformed,
401             result.error_value());
402 }
403 
TEST(AdvertisingDataTest,UuidsMalformed)404 TEST(AdvertisingDataTest, UuidsMalformed) {
405   StaticByteBuffer service_data{
406       0x02,  // Length
407       static_cast<uint8_t>(DataType::kComplete16BitServiceUuids),
408       0x12  // The length of a valid 16-bit UUID byte array be a multiple of 2
409             // (and 1 % 2 == 1).
410   };
411   AdvertisingData::ParseResult result =
412       AdvertisingData::FromBytes(service_data);
413   ASSERT_TRUE(result.is_error());
414   EXPECT_EQ(AdvertisingData::ParseError::kUuidsMalformed, result.error_value());
415 }
416 
TEST(AdvertisingDataTest,ManufacturerSpecificDataTooSmall)417 TEST(AdvertisingDataTest, ManufacturerSpecificDataTooSmall) {
418   StaticByteBuffer service_data{
419       0x02,  // Length
420       static_cast<uint8_t>(DataType::kManufacturerSpecificData),
421       0x12  // Manufacturer-specific data must be at least 2 bytes
422   };
423   AdvertisingData::ParseResult result =
424       AdvertisingData::FromBytes(service_data);
425   ASSERT_TRUE(result.is_error());
426   EXPECT_EQ(AdvertisingData::ParseError::kManufacturerSpecificDataTooSmall,
427             result.error_value());
428 }
429 
TEST(AdvertisingDataTest,DecodeServiceDataWithIncompleteUuid)430 TEST(AdvertisingDataTest, DecodeServiceDataWithIncompleteUuid) {
431   StaticByteBuffer service_data(
432       0x02,                                               // Length
433       static_cast<uint8_t>(DataType::kServiceData16Bit),  // Data type
434       0xAA  // First byte of incomplete UUID
435   );
436 
437   AdvertisingData::ParseResult result =
438       AdvertisingData::FromBytes(service_data);
439   ASSERT_TRUE(result.is_error());
440   EXPECT_EQ(AdvertisingData::ParseError::kServiceDataTooSmall,
441             result.error_value());
442 }
443 
TEST(AdvertisingDataTest,AppearanceMalformed)444 TEST(AdvertisingDataTest, AppearanceMalformed) {
445   StaticByteBuffer service_data{
446       0x02,  // Length
447       static_cast<uint8_t>(DataType::kAppearance),
448       0x12  // Appearance is supposed to be 2 bytes
449   };
450   AdvertisingData::ParseResult result =
451       AdvertisingData::FromBytes(service_data);
452   ASSERT_TRUE(result.is_error());
453   EXPECT_EQ(AdvertisingData::ParseError::kAppearanceMalformed,
454             result.error_value());
455 }
TEST(AdvertisingDataTest,Equality)456 TEST(AdvertisingDataTest, Equality) {
457   AdvertisingData one, two;
458 
459   UUID gatt(kGattUuid);
460   UUID eddy(kEddystoneUuid);
461 
462   // Service UUIDs
463   EXPECT_EQ(two, one);
464   EXPECT_TRUE(one.AddServiceUuid(gatt));
465   EXPECT_NE(two, one);
466   EXPECT_TRUE(two.AddServiceUuid(gatt));
467   EXPECT_EQ(two, one);
468 
469   // Even when the bytes are the same but from different places
470   StaticByteBuffer bytes(0x01, 0x02, 0x03, 0x04);
471   StaticByteBuffer same(0x01, 0x02, 0x03, 0x04);
472   EXPECT_TRUE(two.SetManufacturerData(0x0123, bytes.view()));
473   EXPECT_NE(two, one);
474   EXPECT_TRUE(one.SetManufacturerData(0x0123, same.view()));
475   EXPECT_EQ(two, one);
476 
477   // When TX Power is different
478   two.SetTxPower(-34);
479   EXPECT_NE(two, one);
480   one.SetTxPower(-30);
481   EXPECT_NE(two, one);
482   one.SetTxPower(-34);
483   EXPECT_EQ(two, one);
484 
485   // Even if the fields were added in different orders
486   AdvertisingData three, four;
487   EXPECT_TRUE(three.AddServiceUuid(eddy));
488   EXPECT_TRUE(three.AddServiceUuid(gatt));
489   EXPECT_NE(three, four);
490 
491   EXPECT_TRUE(four.AddServiceUuid(gatt));
492   EXPECT_TRUE(four.AddServiceUuid(eddy));
493   EXPECT_EQ(three, four);
494 }
495 
TEST(AdvertisingDataTest,ToString)496 TEST(AdvertisingDataTest, ToString) {
497   AdvertisingData data;
498 
499   AdvFlags flags = kLEGeneralDiscoverableMode | kBREDRNotSupported;
500   data.SetFlags(flags);
501   data.SetTxPower(-18);
502   data.SetAppearance(0x4567);
503   EXPECT_TRUE(data.SetLocalName("fuchsia"));
504   EXPECT_TRUE(data.AddUri("http://fuchsia.cl"));
505 
506   uint32_t service_uuid_32 = 0x12345678;
507   UUID service_uuid_32bit = UUID(service_uuid_32);
508   UUID service_uuid_16bit = UUID(kId1As16);
509   EXPECT_TRUE(data.AddServiceUuid(service_uuid_32bit));
510   EXPECT_TRUE(data.AddServiceUuid(service_uuid_16bit));
511 
512   StaticByteBuffer service_bytes(0x01, 0x02);
513   EXPECT_TRUE(data.SetServiceData(service_uuid_16bit, service_bytes.view()));
514 
515   StaticByteBuffer bytes(0x01, 0x02, 0x03);
516   EXPECT_TRUE(data.SetManufacturerData(0x0123, bytes.view()));
517 
518   EXPECT_EQ(
519       "Advertising Data { Complete Name: fuchsia, TX Power: -18, Appearance: "
520       "0x4567, URIs: { http://fuchsia.cl, }, Flags: { LE General Discoverable "
521       "Mode, BR/EDR Not Supported, }, Service UUIDs: { "
522       "00000212-0000-1000-8000-00805f9b34fb, "
523       "12345678-0000-1000-8000-00805f9b34fb, }, Service Data: { { "
524       "UUID:00000212-0000-1000-8000-00805f9b34fb, Data: {01 02} }, }, "
525       "Manufacturer Data: { { Company ID: 0x0123, Data: {01 02 03} }, }, }",
526       data.ToString());
527 }
528 
TEST(AdvertisingDataTest,ToStringHasEmptyFields)529 TEST(AdvertisingDataTest, ToStringHasEmptyFields) {
530   AdvertisingData data;
531 
532   EXPECT_EQ("Advertising Data { }", data.ToString());
533 }
534 
TEST(AdvertisingDataTest,Copy)535 TEST(AdvertisingDataTest, Copy) {
536   UUID gatt(kGattUuid);
537   UUID eddy(kEddystoneUuid);
538   StaticByteBuffer<kRandomDataSize> rand_data;
539   random_generator()->Get(rand_data.mutable_subspan());
540 
541   AdvertisingData source;
542   EXPECT_TRUE(source.AddUri("http://fuchsia.cl"));
543   EXPECT_TRUE(source.AddUri("https://ru.st"));
544   EXPECT_TRUE(source.SetManufacturerData(0x0123, rand_data.view()));
545   EXPECT_TRUE(source.AddServiceUuid(gatt));
546   EXPECT_TRUE(source.AddServiceUuid(eddy));
547 
548   AdvertisingData dest;
549   source.Copy(&dest);
550 
551   EXPECT_EQ(source, dest);
552 
553   // Modifying the source shouldn't mess with the copy
554   EXPECT_TRUE(source.SetLocalName("fuchsia"));
555   EXPECT_FALSE(dest.local_name());
556 
557   StaticByteBuffer bytes(0x01, 0x02, 0x03);
558   EXPECT_TRUE(source.SetManufacturerData(0x0123, bytes.view()));
559   EXPECT_TRUE(ContainersEqual(rand_data, dest.manufacturer_data(0x0123)));
560 }
561 
TEST(AdvertisingDataTest,Move)562 TEST(AdvertisingDataTest, Move) {
563   UUID gatt(kGattUuid);
564   UUID eddy(kEddystoneUuid);
565   StaticByteBuffer<kRandomDataSize> rand_data;
566   random_generator()->Get(rand_data.mutable_subspan());
567 
568   UUID heart_rate_uuid(kHeartRateServiceUuid);
569   int8_t tx_power = 18;          // arbitrary TX power
570   uint16_t appearance = 0x4567;  // arbitrary appearance value
571   uint8_t flags = 0x48;          // arbitrary flags value
572   AdvertisingData source;
573   EXPECT_TRUE(source.SetLocalName("test"));
574   source.SetFlags(flags);
575   source.SetTxPower(tx_power);
576   source.SetAppearance(appearance);
577   EXPECT_TRUE(source.AddUri("http://fuchsia.cl"));
578   EXPECT_TRUE(source.AddUri("https://ru.st"));
579   EXPECT_TRUE(source.SetManufacturerData(0x0123, rand_data.view()));
580   EXPECT_TRUE(source.AddServiceUuid(gatt));
581   EXPECT_TRUE(source.AddServiceUuid(eddy));
582   EXPECT_TRUE(source.SetServiceData(heart_rate_uuid, rand_data.view()));
583 
584   auto verify_advertising_data = [&](const AdvertisingData& dest,
585                                      const char* type) {
586     SCOPED_TRACE(type);
587     // Dest should have the data we set.
588     EXPECT_EQ("test", dest.local_name()->name);
589     EXPECT_EQ(tx_power, dest.tx_power().value());
590     EXPECT_EQ(appearance, dest.appearance().value());
591     EXPECT_EQ(
592         std::unordered_set<std::string>({"http://fuchsia.cl", "https://ru.st"}),
593         dest.uris());
594     EXPECT_TRUE(ContainersEqual(rand_data, dest.manufacturer_data(0x0123)));
595     EXPECT_EQ(std::unordered_set<UUID>({gatt, eddy}), dest.service_uuids());
596     EXPECT_TRUE(ContainersEqual(rand_data, dest.service_data(heart_rate_uuid)));
597     EXPECT_EQ(flags, dest.flags().value());
598   };
599 
600   AdvertisingData move_constructed(std::move(source));
601 
602   // source should be empty.
603   EXPECT_EQ(AdvertisingData(), source);
604   verify_advertising_data(move_constructed, "move_constructed");
605 
606   AdvertisingData move_assigned{};
607   move_assigned = std::move(move_constructed);
608   EXPECT_EQ(AdvertisingData(), move_constructed);
609   verify_advertising_data(move_assigned, "move_assigned");
610 }
611 
TEST(AdvertisingDataTest,Flags)612 TEST(AdvertisingDataTest, Flags) {
613   // A zero-byte flags is allowed, and sets the flags field to zeroes.
614   StaticByteBuffer flags_empty(0x01, DataType::kFlags);
615   // Extra bytes are accepted but ignored.
616   StaticByteBuffer flags_extra(0x04, DataType::kFlags, 0x03, 0x42, 0x49);
617 
618   AdvertisingData::ParseResult data = AdvertisingData::FromBytes(flags_empty);
619   ASSERT_EQ(fit::ok(), data);
620   ASSERT_TRUE(data->flags().has_value());
621   ASSERT_EQ(0x00, data->flags().value());
622 
623   data = AdvertisingData::FromBytes(flags_extra);
624   ASSERT_EQ(fit::ok(), data);
625   ASSERT_TRUE(data->flags().has_value());
626   ASSERT_EQ(0x03, data->flags().value());
627 }
628 
TEST(AdvertisingDataTest,Uris)629 TEST(AdvertisingDataTest, Uris) {
630   // The encoding scheme is represented by the first UTF-8 code-point in the URI
631   // string. Per
632   // https://www.bluetooth.com/specifications/assigned-numbers/uri-scheme-name-string-mapping/,
633   // 0xBA is the highest code point corresponding to an encoding scheme.
634   // However, 0xBA > 0x7F, so representing too-large encoding schemes (i.e.
635   // code-points > 0xBA) in UTF-8 requires two bytes.
636   const uint8_t kLargestKnownSchemeByte1 = 0xC2,
637                 kLargestKnownSchemeByte2 = 0xBA;
638   // These bytes represent the (valid) UTF-8 code point for the (unknown
639   // encoding scheme) U+00BB.
640   const uint8_t kUnknownSchemeByte1 = 0xC2, kUnknownSchemeByte2 = 0xBB;
641   StaticByteBuffer bytes(
642       // Uri: "https://abc.xyz"
643       0x0B,
644       DataType::kURI,
645       0x17,
646       '/',
647       '/',
648       'a',
649       'b',
650       'c',
651       '.',
652       'x',
653       'y',
654       'z',
655       // Empty URI should be ignored:
656       0x01,
657       DataType::kURI,
658       // Uri: "flubs:abc"
659       0x0B,
660       DataType::kURI,
661       0x01,
662       'f',
663       'l',
664       'u',
665       'b',
666       's',
667       ':',
668       'a',
669       'b',
670       'c',
671       // Uri: "ms-settings-cloudstorage:flub"
672       0x07,
673       DataType::kURI,
674       kLargestKnownSchemeByte1,
675       kLargestKnownSchemeByte2,
676       'f',
677       'l',
678       'u',
679       'b',
680       // Invalid URI should be ignored - UTF-8 U+00BB doesn't correspond to an
681       // encoding scheme.
682       0x07,
683       DataType::kURI,
684       kUnknownSchemeByte1,
685       kUnknownSchemeByte2,
686       'f',
687       'l',
688       'u',
689       'b',
690       // Invalid URI should be ignored - UTF-8 U+0000 doesn't correspond to an
691       // encoding scheme.
692       0x03,
693       DataType::kURI,
694       0x00,
695       0x00);
696 
697   AdvertisingData::ParseResult data = AdvertisingData::FromBytes(bytes);
698   ASSERT_EQ(fit::ok(), data);
699 
700   auto uris = data->uris();
701   EXPECT_EQ(3u, uris.size());
702 
703   EXPECT_TRUE(std::find(uris.begin(), uris.end(), "https://abc.xyz") !=
704               uris.end());
705   EXPECT_TRUE(std::find(uris.begin(), uris.end(), "flubs:abc") != uris.end());
706   EXPECT_TRUE(std::find(uris.begin(),
707                         uris.end(),
708                         "ms-settings-cloudstorage:flub") != uris.end());
709 }
710 
711 // Tests writing a fully populated |AdvertisingData| to
712 // an output buffer succeeds.
TEST(AdvertisingDataTest,WriteBlockSuccess)713 TEST(AdvertisingDataTest, WriteBlockSuccess) {
714   AdvertisingData data;
715 
716   data.SetTxPower(4);
717   data.SetAppearance(0x4567);
718   EXPECT_TRUE(data.SetLocalName("fuchsia"));
719 
720   StaticByteBuffer bytes(0x01, 0x02, 0x03);
721   EXPECT_TRUE(data.SetManufacturerData(0x0123, bytes.view()));
722 
723   auto service_uuid = UUID(kId1As16);
724   StaticByteBuffer service_bytes(0x01, 0x02);
725   EXPECT_TRUE(data.AddServiceUuid(service_uuid));
726   EXPECT_TRUE(data.SetServiceData(service_uuid, service_bytes.view()));
727 
728   EXPECT_TRUE(data.AddUri("http://fuchsia.cl"));
729 
730   DynamicByteBuffer write_buf(data.CalculateBlockSize());
731   EXPECT_TRUE(data.WriteBlock(&write_buf, std::nullopt));
732 
733   StaticByteBuffer expected_buf(0x02,
734                                 0x0a,
735                                 0x04,  // tx_power_level_: 4
736                                 0x03,
737                                 0x19,
738                                 0x67,
739                                 0x45,  // appearance_: 0x4567
740                                 0x08,
741                                 0x09,
742                                 0x66,
743                                 0x75,
744                                 0x63,
745                                 0x68,
746                                 0x73,
747                                 0x69,
748                                 0x61,  // local_name_: "fuchsia"
749                                 0x06,
750                                 0xff,
751                                 0x23,
752                                 0x01,
753                                 0x01,
754                                 0x02,
755                                 0x03,  // manufacturer_data_
756                                 0x05,
757                                 0x16,
758                                 0x12,
759                                 0x02,
760                                 0x01,
761                                 0x02,  // service_data_
762                                 0x0e,
763                                 0x24,
764                                 0x16,
765                                 0x2f,
766                                 0x2f,
767                                 0x66,
768                                 0x75,
769                                 0x63,
770                                 0x68,
771                                 0x73,
772                                 0x69,
773                                 0x61,
774                                 0x2e,
775                                 0x63,
776                                 0x6c,
777                                 0x03,
778                                 0x02,
779                                 0x12,
780                                 0x02);  // uris_
781   EXPECT_TRUE(ContainersEqual(expected_buf, write_buf));
782 }
783 
784 // Tests writing |AdvertisingData| to an output buffer that
785 // is too small fails gracefully and returns early.
TEST(AdvertisingDataTest,WriteBlockSmallBufError)786 TEST(AdvertisingDataTest, WriteBlockSmallBufError) {
787   AdvertisingData data;
788 
789   data.SetTxPower(4);
790   data.SetAppearance(0x4567);
791   EXPECT_TRUE(data.SetLocalName("fuchsia"));
792 
793   DynamicByteBuffer write_buf(data.CalculateBlockSize() - 1);
794   // The buffer is too small. No write should occur, and should return false.
795   EXPECT_FALSE(data.WriteBlock(&write_buf, std::nullopt));
796 }
797 
798 // Tests writing a fully populated |AdvertisingData| with provided flags to
799 // an output buffer succeeds.
TEST(AdvertisingDataTest,WriteBlockWithFlagsSuccess)800 TEST(AdvertisingDataTest, WriteBlockWithFlagsSuccess) {
801   AdvertisingData data;
802 
803   data.SetTxPower(4);
804   data.SetAppearance(0x4567);
805   EXPECT_TRUE(data.SetLocalName("fuchsia"));
806 
807   StaticByteBuffer bytes(0x01, 0x02, 0x03);
808   EXPECT_TRUE(data.SetManufacturerData(0x0123, bytes.view()));
809 
810   auto service_uuid = UUID(kId1As16);
811   StaticByteBuffer service_bytes(0x01, 0x02);
812   EXPECT_TRUE(data.AddServiceUuid(service_uuid));
813   EXPECT_TRUE(data.SetServiceData(service_uuid, service_bytes.view()));
814 
815   EXPECT_TRUE(data.AddUri("http://fuchsia.cl"));
816 
817   DynamicByteBuffer write_buf(data.CalculateBlockSize(/*include_flags=*/true));
818   EXPECT_TRUE(data.WriteBlock(&write_buf, AdvFlag::kLEGeneralDiscoverableMode));
819 
820   StaticByteBuffer expected_buf(0x02,
821                                 0x01,
822                                 0x02,  // flags: 2
823                                 0x02,
824                                 0x0a,
825                                 0x04,  // tx_power_level_: 4
826                                 0x03,
827                                 0x19,
828                                 0x67,
829                                 0x45,  // appearance_: 0x4567
830                                 0x08,
831                                 0x09,
832                                 0x66,
833                                 0x75,
834                                 0x63,
835                                 0x68,
836                                 0x73,
837                                 0x69,
838                                 0x61,  // local_name_: "fuchsia"
839                                 0x06,
840                                 0xff,
841                                 0x23,
842                                 0x01,
843                                 0x01,
844                                 0x02,
845                                 0x03,  // manufacturer_data_
846                                 0x05,
847                                 0x16,
848                                 0x12,
849                                 0x02,
850                                 0x01,
851                                 0x02,  // service_data_
852                                 0x0e,
853                                 0x24,
854                                 0x16,
855                                 0x2f,
856                                 0x2f,
857                                 0x66,
858                                 0x75,
859                                 0x63,
860                                 0x68,
861                                 0x73,
862                                 0x69,
863                                 0x61,
864                                 0x2e,
865                                 0x63,
866                                 0x6c,
867                                 0x03,
868                                 0x02,
869                                 0x12,
870                                 0x02);  // uris_
871   EXPECT_TRUE(ContainersEqual(expected_buf, write_buf));
872 }
873 
TEST(AdvertisingDataTest,WriteBlockWithFlagsBufError)874 TEST(AdvertisingDataTest, WriteBlockWithFlagsBufError) {
875   AdvertisingData data;
876 
877   data.SetTxPower(6);
878   EXPECT_TRUE(data.SetLocalName("Fuchsia"));
879   data.SetAppearance(0x1234);
880 
881   DynamicByteBuffer write_buf(data.CalculateBlockSize(/*include_flags=*/true) -
882                               1);
883   EXPECT_FALSE(
884       data.WriteBlock(&write_buf, AdvFlag::kLEGeneralDiscoverableMode));
885 }
886 
887 // Adds `n_(consecutively_increasing)_uuids` to `input` and returns the "next"
888 // UUID in the sequence. UUIDs may wrap around - this is OK, as we only care
889 // that they are all distinct.
AddNDistinctUuids(AdvertisingData & input,std::variant<uint16_t,uint32_t,UInt128> starting_uuid,uint8_t n_uuids)890 UUID AddNDistinctUuids(AdvertisingData& input,
891                        std::variant<uint16_t, uint32_t, UInt128> starting_uuid,
892                        uint8_t n_uuids) {
893   UUID next;
894   for (uint8_t i = 0; true; ++i) {
895     std::visit(
896         [&](auto arg) {
897           using T = std::decay_t<decltype(arg)>;
898           if constexpr (std::is_same_v<T, UInt128>) {
899             arg[0] += i;
900             next = UUID(arg);
901           } else {
902             next = UUID(static_cast<T>(arg + i));
903           }
904         },
905         starting_uuid);
906     SCOPED_TRACE(
907         bt_lib_cpp_string::StringPrintf("i: %du UUID: %s", i, bt_str(next)));
908     if (i >= n_uuids) {
909       return next;
910     }
911     EXPECT_TRUE(input.AddServiceUuid(next));
912   }
913 }
914 
TEST(AdvertisingDataTest,SetFieldsWithTooLongParameters)915 TEST(AdvertisingDataTest, SetFieldsWithTooLongParameters) {
916   AdvertisingData data;
917   {
918     // Use the https URI encoding scheme. This prefix will be compressed to one
919     // byte when encoded.
920     std::string uri = "https:";
921     uri += std::string(kMaxEncodedUriLength - 1, '.');
922     EXPECT_TRUE(data.AddUri(uri));
923     uri += '.';
924     EXPECT_FALSE(data.AddUri(uri));
925   }
926   // Attempt to set slightly too long service data.
927   {
928     UUID two_byte_uuid{kHeartRateServiceUuid};
929     DynamicByteBuffer long_data(kMaxEncodedServiceDataLength - 1);
930     long_data.Fill(0xAB);
931     EXPECT_FALSE(data.SetServiceData(two_byte_uuid, long_data));
932     // An empty DynamicByteBuffer represents unset service data per the header.
933     EXPECT_TRUE(
934         ContainersEqual(DynamicByteBuffer(), data.service_data(two_byte_uuid)));
935     // Now use a view that is just small enough to fit when encoded
936     BufferView view = long_data.view(/*pos=*/0, /*size=*/long_data.size() - 1);
937     EXPECT_TRUE(data.SetServiceData(two_byte_uuid, view));
938     EXPECT_TRUE(ContainersEqual(view, data.service_data(two_byte_uuid)));
939   }
940   // Attempt to set slightly too long manufacturer data.
941   {
942     uint16_t manufacturer_id{0xABBA};
943     DynamicByteBuffer long_data(kMaxManufacturerDataLength + 1);
944     long_data.Fill(0xAB);
945     EXPECT_FALSE(data.SetManufacturerData(manufacturer_id, long_data.view()));
946     // An empty DynamicByteBuffer represents unset service data per the header.
947     EXPECT_TRUE(ContainersEqual(DynamicByteBuffer(),
948                                 data.manufacturer_data(manufacturer_id)));
949     // Now use a view that is just small enough to fit when encoded
950     BufferView view = long_data.view(/*pos=*/0, /*size=*/long_data.size() - 1);
951     EXPECT_TRUE(data.SetManufacturerData(manufacturer_id, view));
952     EXPECT_TRUE(ContainersEqual(view, data.manufacturer_data(manufacturer_id)));
953   }
954   // Ensure that service UUIDs are truncated when they do not fit.
955   {
956     uint16_t starting_16bit_uuid = 0x0001;
957     UUID should_fail = AddNDistinctUuids(
958         data,
959         std::variant<uint16_t, uint32_t, UInt128>{starting_16bit_uuid},
960         kMax16BitUuids);
961     EXPECT_FALSE(data.AddServiceUuid(should_fail));
962     EXPECT_TRUE(data.service_uuids().find(should_fail) ==
963                 data.service_uuids().end());
964 
965     // This value must not fit in a 16 bit number in order to count as a "32
966     // bit" UUID
967     uint32_t starting_32bit_uuid = std::numeric_limits<uint16_t>::max() + 1;
968     should_fail = AddNDistinctUuids(
969         data,
970         std::variant<uint16_t, uint32_t, UInt128>{starting_32bit_uuid},
971         kMax32BitUuids);
972     EXPECT_FALSE(data.AddServiceUuid(should_fail));
973     EXPECT_TRUE(data.service_uuids().find(should_fail) ==
974                 data.service_uuids().end());
975 
976     UInt128 starting_128bit_uuid = {0xAB,
977                                     0xAB,
978                                     0xAB,
979                                     0xAB,
980                                     0xAB,
981                                     0xAB,
982                                     0xAB,
983                                     0xAB,
984                                     0xAB,
985                                     0xAB,
986                                     0xAB,
987                                     0xAB,
988                                     0xAB,
989                                     0xAB,
990                                     0xAB,
991                                     0xAB};
992     should_fail = AddNDistinctUuids(
993         data,
994         std::variant<uint16_t, uint32_t, UInt128>{starting_128bit_uuid},
995         kMax128BitUuids);
996     EXPECT_FALSE(data.AddServiceUuid(should_fail));
997     EXPECT_TRUE(data.service_uuids().find(should_fail) ==
998                 data.service_uuids().end());
999   }
1000   // Ensures names exceeding kMaxNameLength are rejected.
1001   {
1002     std::string name_that_fits(kMaxNameLength, 'a');
1003     std::string too_long_name(kMaxNameLength + 1, 'b');
1004     EXPECT_TRUE(data.SetLocalName(name_that_fits));
1005     EXPECT_EQ(name_that_fits, data.local_name()->name);
1006     EXPECT_FALSE(data.SetLocalName(too_long_name));
1007     EXPECT_EQ(name_that_fits, data.local_name()->name);
1008   }
1009   // Write the data out to ensure no assertions are triggered
1010   DynamicByteBuffer block(data.CalculateBlockSize());
1011   EXPECT_TRUE(data.WriteBlock(&block, std::nullopt));
1012 }
1013 
1014 // Tests that setting a complete local name overwrites an existing shortened
1015 // local name and that setting a shortened local name has no effect if a
1016 // complete local name is currently stored.
TEST(AdvertisingDataTest,CompleteLocalNameFavored)1017 TEST(AdvertisingDataTest, CompleteLocalNameFavored) {
1018   AdvertisingData data;
1019   std::string short_name = "short";
1020   std::string complete_name = "complete";
1021 
1022   EXPECT_TRUE(data.SetLocalName(short_name, /*is_complete=*/false));
1023   EXPECT_EQ(short_name, data.local_name()->name);
1024   EXPECT_TRUE(data.SetLocalName(complete_name, /*is_complete=*/true));
1025   EXPECT_EQ(complete_name, data.local_name()->name);
1026 
1027   EXPECT_FALSE(data.SetLocalName(short_name, /*is_complete=*/false));
1028   EXPECT_EQ(complete_name, data.local_name()->name);
1029 }
1030 
1031 // Tests that even when the maximum number of distinct UUIDs for a certain size
1032 // have been added to an AD, we do not reject additional UUIDs that are
1033 // duplicates of already-added UUIDs.
TEST(AdvertisingDataTest,AddDuplicateServiceUuidsWhenFullSucceeds)1034 TEST(AdvertisingDataTest, AddDuplicateServiceUuidsWhenFullSucceeds) {
1035   AdvertisingData data;
1036   uint16_t starting_16bit_uuid = 0x0001;
1037   UUID should_fail = AddNDistinctUuids(
1038       data,
1039       std::variant<uint16_t, uint32_t, UInt128>{starting_16bit_uuid},
1040       kMax16BitUuids);
1041   // Verify that adding another distinct UUID fails - i.e. we are at the limit.
1042   EXPECT_FALSE(data.AddServiceUuid(should_fail));
1043   EXPECT_TRUE(data.service_uuids().find(should_fail) ==
1044               data.service_uuids().end());
1045   // Verify that we are notified of success when adding an existing UUID
1046   EXPECT_TRUE(data.AddServiceUuid(UUID(starting_16bit_uuid)));
1047 }
1048 
TEST(AdvertisingDataTest,ResolvableSetIdentifierRoundTrip)1049 TEST(AdvertisingDataTest, ResolvableSetIdentifierRoundTrip) {
1050   AdvertisingData data;
1051   std::array<uint8_t, 6> identifier = {0x01, 0x01, 0x4f, 0x96, 0x02, 0x03};
1052 
1053   data.SetResolvableSetIdentifier(identifier);
1054   data.SetAppearance(0x4567);
1055 
1056   DynamicByteBuffer write_buf(data.CalculateBlockSize(/*include_flags=*/true));
1057   EXPECT_TRUE(data.WriteBlock(&write_buf, AdvFlag::kLEGeneralDiscoverableMode));
1058 
1059   StaticByteBuffer expected_buf(0x02,
1060                                 0x01,
1061                                 0x02,  // flags: 2
1062                                 0x03,
1063                                 0x19,
1064                                 0x67,
1065                                 0x45,  // appearance_: 0x4567
1066                                 0x07,
1067                                 0x2E,
1068                                 0x01,
1069                                 0x01,
1070                                 0x4F,
1071                                 0x96,
1072                                 0x02,
1073                                 0x03);  // resolvable_set_identifier_
1074   EXPECT_TRUE(ContainersEqual(expected_buf, write_buf));
1075 
1076   AdvertisingData::ParseResult result = AdvertisingData::FromBytes(write_buf);
1077   EXPECT_TRUE(result.is_ok());
1078   const AdvertisingData& parsed = result.value();
1079   ASSERT_TRUE(parsed.appearance());
1080   ASSERT_TRUE(parsed.resolvable_set_identifier());
1081   EXPECT_TRUE(ContainersEqual(*parsed.resolvable_set_identifier(), identifier));
1082 }
1083 
TEST(AdvertisingDataTest,BroadcastNameRoundTrip)1084 TEST(AdvertisingDataTest, BroadcastNameRoundTrip) {
1085   AdvertisingData data;
1086 
1087   std::string name = "Sapphire ��";
1088 
1089   data.SetBroadcastName(name);
1090   data.SetAppearance(0x4567);
1091 
1092   DynamicByteBuffer write_buf(data.CalculateBlockSize(/*include_flags=*/true));
1093   EXPECT_TRUE(data.WriteBlock(&write_buf, AdvFlag::kLEGeneralDiscoverableMode));
1094 
1095   StaticByteBuffer expected_buf(0x02,
1096                                 0x01,
1097                                 0x02,  // flags: 2
1098                                 0x03,
1099                                 0x19,
1100                                 0x67,
1101                                 0x45,  // appearance_: 0x4567
1102                                 0x0e,
1103                                 0x30,
1104                                 'S',
1105                                 'a',
1106                                 'p',
1107                                 'p',
1108                                 'h',
1109                                 'i',
1110                                 'r',
1111                                 'e',
1112                                 ' ',
1113                                 0xf0,
1114                                 0x9f,
1115                                 0x92,
1116                                 0x96);  // broadcast_name_
1117   EXPECT_TRUE(ContainersEqual(expected_buf, write_buf));
1118 
1119   AdvertisingData::ParseResult result = AdvertisingData::FromBytes(write_buf);
1120   EXPECT_TRUE(result.is_ok());
1121   const AdvertisingData& parsed = result.value();
1122   ASSERT_TRUE(parsed.broadcast_name());
1123   EXPECT_EQ(name, *parsed.broadcast_name());
1124 }
1125 
1126 }  // namespace
1127 }  // namespace bt
1128