text: // Copyright 2016 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "components/arc/bluetooth/bluetooth_struct_traits.h"
  
  #include <string>
  #include <utility>
  
  #include "base/macros.h"
  #include "device/bluetooth/bluetooth_uuid.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace {
  
  constexpr char kUuidStr[] = "12345678-1234-5678-9abc-def123456789";
  constexpr uint8_t kUuidArray[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34,
                                    0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1,
                                    0x23, 0x45, 0x67, 0x89};
  constexpr size_t kUuidSize = 16;
  
  constexpr char kUuid16Str[] = "1234";
  constexpr uint16_t kUuid16 = 0x1234;
  constexpr uint8_t kServiceData[] = {0x11, 0x22, 0x33, 0x44, 0x55};
  constexpr uint8_t kManufacturerData[] = {0x00, 0xe0};
  
  template <typename MojoType, typename UserType>
  mojo::StructPtr<MojoType> ConvertToMojo(UserType* input) {
    std::vector<uint8_t> data = MojoType::Serialize(input);
    mojo::StructPtr<MojoType> output;
    MojoType::Deserialize(std::move(data), &output);
    return output;
  }
  
  template <typename MojoType, typename UserType>
  bool ConvertFromMojo(mojo::StructPtr<MojoType> input, UserType* output) {
    std::vector<uint8_t> data = MojoType::Serialize(&input);
    return MojoType::Deserialize(std::move(data), output);
  }
  
  }  // namespace
  
  namespace mojo {
  
  TEST(BluetoothStructTraitsTest, SerializeBluetoothUUID) {
    device::BluetoothUUID uuid_device(kUuidStr);
    arc::mojom::BluetoothUUIDPtr uuid_mojo =
        ConvertToMojo<arc::mojom::BluetoothUUID>(&uuid_device);
    EXPECT_EQ(kUuidSize, uuid_mojo->uuid.size());
    for (size_t i = 0; i < kUuidSize; i++) {
      EXPECT_EQ(kUuidArray[i], uuid_mojo->uuid[i]);
    }
  }
  
  TEST(BluetoothStructTraitsTest, DeserializeBluetoothUUID) {
    arc::mojom::BluetoothUUIDPtr uuid_mojo = arc::mojom::BluetoothUUID::New();
    for (size_t i = 0; i < kUuidSize; i++) {
      uuid_mojo->uuid.push_back(kUuidArray[i]);
    }
    uuid_mojo->uuid =
        std::vector<uint8_t>(std::begin(kUuidArray), std::end(kUuidArray));
    device::BluetoothUUID uuid_device;
    EXPECT_TRUE(ConvertFromMojo(std::move(uuid_mojo), &uuid_device));
    EXPECT_EQ(std::string(kUuidStr), uuid_device.canonical_value());
  
    // Size checks are performed in serialization code. UUIDs with a length
    // other than 16 bytes will not make it through the mojo deserialization
    // code since arc::mojom::BluetoothUUID::uuid is defined as
    // array<uint8, 16>.
  }
  
  TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisement) {
    arc::mojom::BluetoothAdvertisementPtr advertisement_mojo =
        arc::mojom::BluetoothAdvertisement::New();
    std::vector<arc::mojom::BluetoothAdvertisingDataPtr> adv_data;
  
    // Create 16bit service UUIDs.
    arc::mojom::BluetoothAdvertisingDataPtr data =
        arc::mojom::BluetoothAdvertisingData::New();
    data->set_service_uuids_16({kUuid16});
    adv_data.push_back(std::move(data));
  
    // Create service UUIDs.
    data = arc::mojom::BluetoothAdvertisingData::New();
    std::vector<device::BluetoothUUID> service_uuids;
    service_uuids.push_back((device::BluetoothUUID(kUuidStr)));
    data->set_service_uuids(service_uuids);
    adv_data.push_back(std::move(data));
  
    // Create service data.
    data = arc::mojom::BluetoothAdvertisingData::New();
    arc::mojom::BluetoothServiceDataPtr service_data =
        arc::mojom::BluetoothServiceData::New();
    service_data->uuid_16bit = kUuid16;
    service_data->data =
        std::vector<uint8_t>(std::begin(kServiceData), std::end(kServiceData));
    data->set_service_data(std::move(service_data));
    adv_data.push_back(std::move(data));
  
    // Create manufacturer data.
    data = arc::mojom::BluetoothAdvertisingData::New();
    data->set_manufacturer_data(std::vector<uint8_t>(
        std::begin(kManufacturerData), std::end(kManufacturerData)));
    adv_data.push_back(std::move(data));
  
    advertisement_mojo->type =
        arc::mojom::BluetoothAdvertisementType::ADV_TYPE_CONNECTABLE;
    advertisement_mojo->data = std::move(adv_data);
  
    std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement;
    EXPECT_TRUE(ConvertFromMojo(std::move(advertisement_mojo), &advertisement));
  
    EXPECT_EQ(advertisement->type(),
              device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_PERIPHERAL);
  
    std::unique_ptr<device::BluetoothAdvertisement::UUIDList> converted_uuids =
        advertisement->service_uuids();
    EXPECT_EQ(converted_uuids->size(), 2U);
    EXPECT_EQ(converted_uuids->at(0), kUuid16Str);
    EXPECT_EQ(converted_uuids->at(1), kUuidStr);
  
    std::unique_ptr<device::BluetoothAdvertisement::ServiceData>
        converted_service = advertisement->service_data();
    EXPECT_EQ(converted_service->size(), 1U);
    EXPECT_EQ(converted_service->begin()->first, kUuid16Str);
    for (size_t i = 0; i < arraysize(kServiceData); i++) {
      EXPECT_EQ(kServiceData[i], converted_service->begin()->second[i]);
    }
  
    std::unique_ptr<device::BluetoothAdvertisement::ManufacturerData>
        converted_manufacturer = advertisement->manufacturer_data();
    EXPECT_EQ(converted_manufacturer->size(), 1U);
    uint16_t cic = converted_manufacturer->begin()->first;
    EXPECT_EQ(cic & 0xff, kManufacturerData[0]);
    EXPECT_EQ((cic >> 8) & 0xff, kManufacturerData[1]);
    EXPECT_EQ(converted_manufacturer->begin()->second.size(),
              arraysize(kManufacturerData) - sizeof(uint16_t));
  }
  
  TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisementFailure) {
    arc::mojom::BluetoothAdvertisementPtr advertisement_mojo =
        arc::mojom::BluetoothAdvertisement::New();
    std::vector<arc::mojom::BluetoothAdvertisingDataPtr> adv_data;
  
    // Create empty manufacturer data. Manufacturer data must include the CIC
    // which is 2 bytes long.
    arc::mojom::BluetoothAdvertisingDataPtr data =
        arc::mojom::BluetoothAdvertisingData::New();
    data->set_manufacturer_data(std::vector<uint8_t>());
    adv_data.push_back(std::move(data));
  
    advertisement_mojo->type =
        arc::mojom::BluetoothAdvertisementType::ADV_TYPE_CONNECTABLE;
    advertisement_mojo->data = std::move(adv_data);
  
    std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement;
    EXPECT_FALSE(ConvertFromMojo(std::move(advertisement_mojo), &advertisement));
  }
  
  }  // namespace mojo
  