// 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/stl_util.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 < base::size(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(),
            base::size(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
