chromium/chromecast/device/bluetooth/le/le_scan_result_test.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/device/bluetooth/le/le_scan_result.h"

#include "base/containers/contains.h"
#include "chromecast/device/bluetooth/bluetooth_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromecast {
namespace bluetooth {

TEST(LeScanResultTest, SetAdvData) {
  static const uint8_t kBadData[] = {0x3, 0x2};

  LeScanResult scan_result;

  // Setting invalid data should not change the object.
  EXPECT_FALSE(scan_result.SetAdvData({kBadData}));
  EXPECT_TRUE(scan_result.adv_data.empty());
  EXPECT_TRUE(scan_result.type_to_data.empty());

  const std::vector<uint8_t> kFlags = {0x47};
  const std::vector<uint8_t> kName = {0x41, 0x42, 0x43};
  const std::vector<uint8_t> kService = {0x12, 0x34};

  std::vector<uint8_t> adv_data;
  adv_data.push_back(kFlags.size() + 1);
  adv_data.push_back(LeScanResult::kGapFlags);
  adv_data.insert(adv_data.end(), kFlags.begin(), kFlags.end());
  adv_data.push_back(kName.size() + 1);
  adv_data.push_back(LeScanResult::kGapCompleteName);
  adv_data.insert(adv_data.end(), kName.begin(), kName.end());
  adv_data.push_back(kService.size() + 1);
  adv_data.push_back(LeScanResult::kGapComplete16BitServiceUuids);
  adv_data.insert(adv_data.end(), kService.begin(), kService.end());

  EXPECT_TRUE(scan_result.SetAdvData(adv_data));
  EXPECT_EQ(adv_data, scan_result.adv_data);
  ASSERT_EQ(1ul, scan_result.type_to_data[LeScanResult::kGapFlags].size());
  EXPECT_EQ(kFlags, scan_result.type_to_data[LeScanResult::kGapFlags][0]);
  ASSERT_EQ(1ul,
            scan_result.type_to_data[LeScanResult::kGapCompleteName].size());
  EXPECT_EQ(kName, scan_result.type_to_data[LeScanResult::kGapCompleteName][0]);
  ASSERT_EQ(
      1ul, scan_result.type_to_data[LeScanResult::kGapComplete16BitServiceUuids]
               .size());
  EXPECT_EQ(
      kService,
      scan_result.type_to_data[LeScanResult::kGapComplete16BitServiceUuids][0]);
}

TEST(LeScanResultTest, Name) {
  LeScanResult scan_result;
  EXPECT_FALSE(scan_result.Name());

  static const char kName1[] = "foo";
  static const char kName2[] = "foobar";

  scan_result.type_to_data[LeScanResult::kGapShortName].push_back(
      std::vector<uint8_t>(
          reinterpret_cast<const uint8_t*>(kName1),
          reinterpret_cast<const uint8_t*>(kName1) + strlen(kName1)));
  std::optional<std::string> name = scan_result.Name();
  ASSERT_TRUE(name);
  EXPECT_EQ(kName1, *name);

  scan_result.type_to_data[LeScanResult::kGapCompleteName].push_back(
      std::vector<uint8_t>(
          reinterpret_cast<const uint8_t*>(kName2),
          reinterpret_cast<const uint8_t*>(kName2) + strlen(kName2)));

  name = scan_result.Name();
  ASSERT_TRUE(name);
  EXPECT_EQ(kName2, *name);
}

TEST(LeScanResultTest, Flags) {
  static const uint8_t kFlags = 0x42;

  LeScanResult scan_result;
  EXPECT_FALSE(scan_result.Flags());
  scan_result.type_to_data[LeScanResult::kGapFlags].push_back({kFlags});
  auto flags = scan_result.Flags();
  ASSERT_TRUE(flags);
  EXPECT_EQ(kFlags, *flags);
}

TEST(LeScanResultTest, AllUuids) {
  static const uint16_t kIncompleteUuid16 = 0x1234;
  const std::vector<uint8_t> kIncompleteUuid16Bytes = {0x34, 0x12};
  static const uint16_t kCompleteUuid16 = 0x5678;
  const std::vector<uint8_t> kCompleteUuid16Bytes = {0x78, 0x56};
  static const uint32_t kIncompleteUuid32 = 0x12345678;
  const std::vector<uint8_t> kIncompleteUuid32Bytes = {0x78, 0x56, 0x34, 0x12};
  static const uint32_t kCompleteUuid32 = 0xabcdef01;
  const std::vector<uint8_t> kCompleteUuid32Bytes = {0x1, 0xef, 0xcd, 0xab};
  static const bluetooth_v2_shlib::Uuid kIncompleteUuid128 = {
      {0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66,
       0x55, 0x44, 0x00, 0x00}};
  static const bluetooth_v2_shlib::Uuid kCompleteUuid128 = {
      {0xa8, 0x22, 0xc8, 0x85, 0xaf, 0x02, 0xc7, 0x80, 0x9d, 0x4d, 0xbd, 0x9a,
       0x1f, 0xa0, 0x6d, 0x93}};
  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapIncomplete16BitServiceUuids]
      .push_back(kIncompleteUuid16Bytes);
  scan_result.type_to_data[LeScanResult::kGapComplete16BitServiceUuids]
      .push_back(kCompleteUuid16Bytes);
  scan_result.type_to_data[LeScanResult::kGapIncomplete32BitServiceUuids]
      .push_back(kIncompleteUuid32Bytes);
  scan_result.type_to_data[LeScanResult::kGapComplete32BitServiceUuids]
      .push_back(kCompleteUuid32Bytes);
  scan_result.type_to_data[LeScanResult::kGapIncomplete128BitServiceUuids]
      .emplace_back(kIncompleteUuid128.rbegin(), kIncompleteUuid128.rend());
  scan_result.type_to_data[LeScanResult::kGapComplete128BitServiceUuids]
      .emplace_back(kCompleteUuid128.rbegin(), kCompleteUuid128.rend());

  auto all_uuids = scan_result.AllServiceUuids();
  ASSERT_TRUE(all_uuids);
  ASSERT_EQ(6ul, all_uuids->size());

  auto exists = [&all_uuids](const bluetooth_v2_shlib::Uuid& uuid) {
    return base::Contains(*all_uuids, uuid);
  };

  EXPECT_TRUE(exists(util::UuidFromInt16(kIncompleteUuid16)));
  EXPECT_TRUE(exists(util::UuidFromInt16(kCompleteUuid16)));
  EXPECT_TRUE(exists(util::UuidFromInt32(kIncompleteUuid32)));
  EXPECT_TRUE(exists(util::UuidFromInt32(kCompleteUuid32)));
  EXPECT_TRUE(exists(kIncompleteUuid128));
  EXPECT_TRUE(exists(kCompleteUuid128));
}

TEST(LeScanResultTest, IncompleteListOf16BitServiceUuid) {
  static const uint16_t kUuid1 = 0x1234;
  const std::vector<uint8_t> kUuid1Bytes = {0x34, 0x12};

  static const uint16_t kUuid2 = 0x5678;
  const std::vector<uint8_t> kUuid2Bytes = {0x78, 0x56};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapIncomplete16BitServiceUuids]
      .push_back(kUuid1Bytes);
  scan_result.type_to_data[LeScanResult::kGapIncomplete16BitServiceUuids]
      .push_back(kUuid2Bytes);

  auto uuids = scan_result.IncompleteListOf16BitServiceUuids();
  ASSERT_TRUE(uuids);
  ASSERT_EQ(2ul, uuids->size());
  EXPECT_EQ(util::UuidFromInt16(kUuid1), (*uuids)[0]);
  EXPECT_EQ(util::UuidFromInt16(kUuid2), (*uuids)[1]);
}

TEST(LeScanResultTest, CompleteListOf16BitServiceUuid) {
  static const uint16_t kUuid1 = 0x1234;
  const std::vector<uint8_t> kUuid1Bytes = {0x34, 0x12};

  static const uint16_t kUuid2 = 0x5678;
  const std::vector<uint8_t> kUuid2Bytes = {0x78, 0x56};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapComplete16BitServiceUuids]
      .push_back(kUuid1Bytes);
  scan_result.type_to_data[LeScanResult::kGapComplete16BitServiceUuids]
      .push_back(kUuid2Bytes);

  auto uuids = scan_result.CompleteListOf16BitServiceUuids();
  ASSERT_TRUE(uuids);
  ASSERT_EQ(2ul, uuids->size());
  EXPECT_EQ(util::UuidFromInt16(kUuid1), (*uuids)[0]);
  EXPECT_EQ(util::UuidFromInt16(kUuid2), (*uuids)[1]);
}

TEST(LeScanResultTest, IncompleteListOf32BitServiceUuid) {
  static const uint32_t kUuid1 = 0x12345678;
  const std::vector<uint8_t> kUuid1Bytes = {0x78, 0x56, 0x34, 0x12};

  static const uint32_t kUuid2 = 0xabcdef01;
  const std::vector<uint8_t> kUuid2Bytes = {0x1, 0xef, 0xcd, 0xab};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapIncomplete32BitServiceUuids]
      .push_back(kUuid1Bytes);
  scan_result.type_to_data[LeScanResult::kGapIncomplete32BitServiceUuids]
      .push_back(kUuid2Bytes);

  auto uuids = scan_result.IncompleteListOf32BitServiceUuids();
  ASSERT_TRUE(uuids);
  ASSERT_EQ(2ul, uuids->size());
  EXPECT_EQ(util::UuidFromInt32(kUuid1), (*uuids)[0]);
  EXPECT_EQ(util::UuidFromInt32(kUuid2), (*uuids)[1]);
}

TEST(LeScanResultTest, CompleteListOf32BitServiceUuid) {
  static const uint32_t kUuid1 = 0x12345678;
  const std::vector<uint8_t> kUuid1Bytes = {0x78, 0x56, 0x34, 0x12};

  static const uint32_t kUuid2 = 0xabcdef01;
  const std::vector<uint8_t> kUuid2Bytes = {0x1, 0xef, 0xcd, 0xab};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapComplete32BitServiceUuids]
      .push_back(kUuid1Bytes);
  scan_result.type_to_data[LeScanResult::kGapComplete32BitServiceUuids]
      .push_back(kUuid2Bytes);

  auto uuids = scan_result.CompleteListOf32BitServiceUuids();
  ASSERT_TRUE(uuids);
  ASSERT_EQ(2ul, uuids->size());
  EXPECT_EQ(util::UuidFromInt32(kUuid1), (*uuids)[0]);
  EXPECT_EQ(util::UuidFromInt32(kUuid2), (*uuids)[1]);
}

TEST(LeScanResultTest, IncompleteListOf128BitServiceUuid) {
  static const bluetooth_v2_shlib::Uuid kUuid1 = {
      {0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66,
       0x55, 0x44, 0x00, 0x00}};
  static const bluetooth_v2_shlib::Uuid kUuid2 = {
      {0xa8, 0x22, 0xc8, 0x85, 0xaf, 0x02, 0xc7, 0x80, 0x9d, 0x4d, 0xbd, 0x9a,
       0x1f, 0xa0, 0x6d, 0x93}};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapIncomplete128BitServiceUuids]
      .emplace_back(kUuid1.rbegin(), kUuid1.rend());
  scan_result.type_to_data[LeScanResult::kGapIncomplete128BitServiceUuids]
      .emplace_back(kUuid2.rbegin(), kUuid2.rend());

  auto uuids = scan_result.IncompleteListOf128BitServiceUuids();
  ASSERT_TRUE(uuids);
  ASSERT_EQ(2ul, uuids->size());
  EXPECT_EQ(kUuid1, (*uuids)[0]);
  EXPECT_EQ(kUuid2, (*uuids)[1]);
}

TEST(LeScanResultTest, CompleteListOf128BitServiceUuid) {
  static const bluetooth_v2_shlib::Uuid kUuid1 = {
      {0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66,
       0x55, 0x44, 0x00, 0x00}};
  static const bluetooth_v2_shlib::Uuid kUuid2 = {
      {0xa8, 0x22, 0xc8, 0x85, 0xaf, 0x02, 0xc7, 0x80, 0x9d, 0x4d, 0xbd, 0x9a,
       0x1f, 0xa0, 0x6d, 0x93}};
  static const bluetooth_v2_shlib::Uuid kUuid3 = {
      {0xaa, 0x22, 0xc8, 0x85, 0xaf, 0x02, 0xc7, 0x80, 0x9d, 0x4d, 0xbd, 0x9a,
       0x1f, 0xa0, 0x6d, 0x93}};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapComplete128BitServiceUuids]
      .emplace_back(kUuid1.rbegin(), kUuid1.rend());
  scan_result.type_to_data[LeScanResult::kGapComplete128BitServiceUuids]
      .emplace_back(kUuid2.rbegin(), kUuid2.rend());
  auto& end =
      scan_result.type_to_data[LeScanResult::kGapComplete128BitServiceUuids]
          .back();
  end.insert(end.end(), kUuid3.rbegin(), kUuid3.rend());

  auto uuids = scan_result.CompleteListOf128BitServiceUuids();
  ASSERT_TRUE(uuids);
  ASSERT_EQ(3ul, uuids->size());
  EXPECT_EQ(kUuid1, (*uuids)[0]);
  EXPECT_EQ(kUuid2, (*uuids)[1]);
  EXPECT_EQ(kUuid3, (*uuids)[2]);
}

TEST(LeScanResultTest, AllServiceData) {
  static const uint16_t kUuid16 = 0x1234;
  const std::vector<uint8_t> kUuid16Bytes = {0x34, 0x12, 0xab, 0xcd, 0xef};

  static const uint32_t kUuid32 = 0x12345678;
  const std::vector<uint8_t> kUuid32Bytes = {0x78, 0x56, 0x34, 0x12,
                                             0xab, 0xcd, 0xef};

  static const bluetooth_v2_shlib::Uuid kUuid128 = {
      {0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66,
       0x55, 0x44, 0x00, 0x00}};
  const std::vector<uint8_t> kUuid128Data = {0x78, 0x56, 0x34, 0x12,
                                             0xab, 0xcd, 0xef};
  std::vector<uint8_t> uuid128_bytes(kUuid128.rbegin(), kUuid128.rend());
  uuid128_bytes.insert(uuid128_bytes.end(), kUuid128Data.begin(),
                       kUuid128Data.end());

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapServicesData16bit].push_back(
      kUuid16Bytes);
  scan_result.type_to_data[LeScanResult::kGapServicesData32bit].push_back(
      kUuid32Bytes);
  scan_result.type_to_data[LeScanResult::kGapServicesData128bit].push_back(
      uuid128_bytes);

  auto sd = scan_result.AllServiceData();
  EXPECT_EQ(3ul, sd.size());
  EXPECT_EQ(sd[util::UuidFromInt16(kUuid16)],
            std::vector<uint8_t>(kUuid16Bytes.begin() + sizeof(kUuid16),
                                 kUuid16Bytes.end()));
  EXPECT_EQ(sd[util::UuidFromInt32(kUuid32)],
            std::vector<uint8_t>(kUuid32Bytes.begin() + sizeof(kUuid32),
                                 kUuid32Bytes.end()));
  EXPECT_EQ(sd[kUuid128], kUuid128Data);
}

TEST(LeScanResultTest, ServiceData16Bit) {
  static const uint16_t kUuid1 = 0x1234;
  const std::vector<uint8_t> kUuid1Bytes = {0x34, 0x12, 0xab, 0xcd, 0xef};

  static const uint16_t kUuid2 = 0x5678;
  const std::vector<uint8_t> kUuid2Bytes = {0x78, 0x56, 0xa1, 0x0d, 0xe1};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapServicesData16bit].push_back(
      kUuid1Bytes);
  scan_result.type_to_data[LeScanResult::kGapServicesData16bit].push_back(
      kUuid2Bytes);

  auto sd = scan_result.ServiceData16Bit();
  ASSERT_EQ(2ul, sd.size());
  EXPECT_EQ(sd[util::UuidFromInt16(kUuid1)],
            std::vector<uint8_t>(kUuid1Bytes.begin() + sizeof(kUuid1),
                                 kUuid1Bytes.end()));
  EXPECT_EQ(sd[util::UuidFromInt16(kUuid2)],
            std::vector<uint8_t>(kUuid2Bytes.begin() + sizeof(kUuid2),
                                 kUuid2Bytes.end()));
}

TEST(LeScanResultTest, ServiceData32Bit) {
  static const uint32_t kUuid1 = 0x12345678;
  const std::vector<uint8_t> kUuid1Bytes = {0x78, 0x56, 0x34, 0x12,
                                            0xab, 0xcd, 0xef};

  static const uint32_t kUuid2 = 0xabcdef01;
  const std::vector<uint8_t> kUuid2Bytes = {0x01, 0xef, 0xcd, 0xab,
                                            0xa1, 0x0d, 0xe1};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapServicesData32bit].push_back(
      kUuid1Bytes);
  scan_result.type_to_data[LeScanResult::kGapServicesData32bit].push_back(
      kUuid2Bytes);

  auto sd = scan_result.ServiceData32Bit();
  ASSERT_EQ(2ul, sd.size());
  EXPECT_EQ(sd[util::UuidFromInt32(kUuid1)],
            std::vector<uint8_t>(kUuid1Bytes.begin() + sizeof(kUuid1),
                                 kUuid1Bytes.end()));
  EXPECT_EQ(sd[util::UuidFromInt32(kUuid2)],
            std::vector<uint8_t>(kUuid2Bytes.begin() + sizeof(kUuid2),
                                 kUuid2Bytes.end()));
}

TEST(LeScanResultTest, ServiceData128Bit) {
  static const bluetooth_v2_shlib::Uuid kUuid1 = {
      {0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66,
       0x55, 0x44, 0x00, 0x00}};
  const std::vector<uint8_t> kUuid1Data = {0x78, 0x56, 0x34, 0x12,
                                           0xab, 0xcd, 0xef};
  std::vector<uint8_t> uuid1_bytes(kUuid1.rbegin(), kUuid1.rend());
  uuid1_bytes.insert(uuid1_bytes.end(), kUuid1Data.begin(), kUuid1Data.end());

  static const bluetooth_v2_shlib::Uuid kUuid2 = {
      {0xa8, 0x22, 0xc8, 0x85, 0xaf, 0x02, 0xc7, 0x80, 0x9d, 0x4d, 0xbd, 0x9a,
       0x1f, 0xa0, 0x6d, 0x93}};
  const std::vector<uint8_t> kUuid2Data = {0x01, 0xef, 0xcd, 0xab,
                                           0xa1, 0x0d, 0xe1};
  std::vector<uint8_t> uuid2_bytes(kUuid2.rbegin(), kUuid2.rend());
  uuid2_bytes.insert(uuid2_bytes.end(), kUuid2Data.begin(), kUuid2Data.end());

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapServicesData128bit].push_back(
      uuid1_bytes);
  scan_result.type_to_data[LeScanResult::kGapServicesData128bit].push_back(
      uuid2_bytes);

  auto sd = scan_result.ServiceData128Bit();
  ASSERT_EQ(2ul, sd.size());
  EXPECT_EQ(sd[kUuid1], kUuid1Data);
  EXPECT_EQ(sd[kUuid2], kUuid2Data);
}

TEST(LeScanResultTest, ManufacturerData) {
  static const uint16_t kManufacturer1 = 0x1234;
  const std::vector<uint8_t> kManufacturer1Bytes = {0x34, 0x12, 0xab, 0xcd,
                                                    0xef};

  static const uint16_t kManufacturer2 = 0x5678;
  const std::vector<uint8_t> kManufacturer2Bytes = {0x78, 0x56, 0xa1, 0x0d,
                                                    0xe1};

  LeScanResult scan_result;
  scan_result.type_to_data[LeScanResult::kGapManufacturerData].push_back(
      kManufacturer1Bytes);
  scan_result.type_to_data[LeScanResult::kGapManufacturerData].push_back(
      kManufacturer2Bytes);

  auto md = scan_result.ManufacturerData();
  ASSERT_EQ(2ul, md.size());
  EXPECT_EQ(
      md[kManufacturer1],
      std::vector<uint8_t>(kManufacturer1Bytes.begin() + sizeof(kManufacturer1),
                           kManufacturer1Bytes.end()));
  EXPECT_EQ(
      md[kManufacturer2],
      std::vector<uint8_t>(kManufacturer2Bytes.begin() + sizeof(kManufacturer2),
                           kManufacturer2Bytes.end()));
}

}  // namespace bluetooth
}  // namespace chromecast