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