chromium/device/bluetooth/test/bluetooth_test_win.cc

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "device/bluetooth/test/bluetooth_test_win.h"

#include <windows.devices.bluetooth.h>
#include <windows.devices.radios.h>
#include <wrl/client.h>
#include <wrl/implements.h>

#include <algorithm>
#include <memory>
#include <utility>
#include <vector>

#include "base/containers/circular_deque.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/test_pending_task.h"
#include "base/time/time.h"
#include "base/win/vector.h"
#include "base/win/windows_version.h"
#include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_win.h"
#include "device/bluetooth/bluetooth_adapter_winrt.h"
#include "device/bluetooth/bluetooth_advertisement_winrt.h"
#include "device/bluetooth/bluetooth_device_winrt.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor_winrt.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "device/bluetooth/test/fake_bluetooth_adapter_winrt.h"
#include "device/bluetooth/test/fake_bluetooth_le_advertisement_publisher_winrt.h"
#include "device/bluetooth/test/fake_bluetooth_le_advertisement_watcher_winrt.h"
#include "device/bluetooth/test/fake_bluetooth_le_advertisement_winrt.h"
#include "device/bluetooth/test/fake_bluetooth_le_device_winrt.h"
#include "device/bluetooth/test/fake_bluetooth_le_manufacturer_data_winrt.h"
#include "device/bluetooth/test/fake_device_information_winrt.h"
#include "device/bluetooth/test/fake_device_watcher_winrt.h"
#include "device/bluetooth/test/fake_gatt_characteristic_winrt.h"
#include "device/bluetooth/test/fake_gatt_descriptor_winrt.h"
#include "device/bluetooth/test/fake_gatt_session_winrt.h"
#include "device/bluetooth/test/fake_radio_winrt.h"

// Note: As UWP does not provide int specializations for IObservableVector and
// VectorChangedEventHandler we need to supply our own. UUIDs were generated
// using `uuidgen`.
namespace ABI::Windows::Foundation::Collections {

template <>
struct __declspec(uuid("2736c37e-4218-496f-a46a-92d5d9e610a9"))
    IObservableVector<GUID> : IObservableVector_impl<GUID> {};

template <>
struct __declspec(uuid("94844fba-ddf9-475c-be6e-ebb87039cef6"))
    VectorChangedEventHandler<GUID> : VectorChangedEventHandler_impl<GUID> {};

}  // namespace ABI::Windows::Foundation::Collections

namespace device {

namespace {

using ABI::Windows::Devices::Bluetooth::IBluetoothAdapter;
using ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
using ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics;
using ABI::Windows::Devices::Bluetooth::Advertisement::
    IBluetoothLEAdvertisement;
using ABI::Windows::Devices::Bluetooth::Advertisement::
    IBluetoothLEAdvertisementPublisherFactory;
using ABI::Windows::Devices::Bluetooth::Advertisement::
    IBluetoothLEAdvertisementWatcher;
using ABI::Windows::Devices::Bluetooth::Advertisement::
    IBluetoothLEManufacturerDataFactory;
using ABI::Windows::Devices::Enumeration::DevicePairingKinds;
using ABI::Windows::Devices::Enumeration::IDeviceInformation;
using ABI::Windows::Devices::Enumeration::IDeviceInformationStatics;
using ABI::Windows::Devices::Radios::IRadioStatics;
using Microsoft::WRL::ComPtr;
using Microsoft::WRL::Make;

class TestBluetoothAdvertisementWinrt : public BluetoothAdvertisementWinrt {
 public:
  TestBluetoothAdvertisementWinrt() = default;

 protected:
  ~TestBluetoothAdvertisementWinrt() override = default;

  HRESULT
  GetBluetoothLEAdvertisementPublisherActivationFactory(
      IBluetoothLEAdvertisementPublisherFactory** factory) const override {
    return Make<FakeBluetoothLEAdvertisementPublisherFactoryWinrt>().CopyTo(
        factory);
  }

  HRESULT ActivateBluetoothLEAdvertisementInstance(
      IBluetoothLEAdvertisement** instance) const override {
    return Make<FakeBluetoothLEAdvertisementWinrt>().CopyTo(instance);
  }

  HRESULT GetBluetoothLEManufacturerDataFactory(
      IBluetoothLEManufacturerDataFactory** factory) const override {
    return Make<FakeBluetoothLEManufacturerDataFactory>().CopyTo(factory);
  }
};

class TestBluetoothDeviceWinrt : public BluetoothDeviceWinrt {
 public:
  TestBluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
                           uint64_t raw_address,
                           BluetoothTestWinrt* bluetooth_test_winrt)
      : BluetoothDeviceWinrt(adapter, raw_address),
        bluetooth_test_winrt_(bluetooth_test_winrt) {}

  HRESULT GetBluetoothLEDeviceStaticsActivationFactory(
      IBluetoothLEDeviceStatics** statics) const override {
    auto device_statics =
        Make<FakeBluetoothLEDeviceStaticsWinrt>(bluetooth_test_winrt_);
    return device_statics.CopyTo(statics);
  }

  HRESULT GetGattSessionStaticsActivationFactory(
      ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
          IGattSessionStatics** statics) const override {
    auto gatt_session_statics =
        Make<FakeGattSessionStaticsWinrt>(bluetooth_test_winrt_);
    return gatt_session_statics.CopyTo(statics);
  }

  FakeBluetoothLEDeviceWinrt* ble_device() {
    return static_cast<FakeBluetoothLEDeviceWinrt*>(ble_device_.Get());
  }

  FakeGattSessionWinrt* gatt_session() {
    return static_cast<FakeGattSessionWinrt*>(gatt_session_.Get());
  }

 private:
  raw_ptr<BluetoothTestWinrt> bluetooth_test_winrt_ = nullptr;
};

class TestBluetoothAdapterWinrt : public BluetoothAdapterWinrt {
 public:
  TestBluetoothAdapterWinrt(ComPtr<IBluetoothAdapter> adapter,
                            ComPtr<IDeviceInformation> device_information,
                            ComPtr<IRadioStatics> radio_statics,
                            base::OnceClosure init_cb,
                            BluetoothTestWinrt* bluetooth_test_winrt)
      : adapter_(std::move(adapter)),
        device_information_(std::move(device_information)),
        watcher_(Make<FakeBluetoothLEAdvertisementWatcherWinrt>()),
        bluetooth_test_winrt_(bluetooth_test_winrt) {
    ComPtr<IBluetoothAdapterStatics> bluetooth_adapter_statics;
    Make<FakeBluetoothAdapterStaticsWinrt>(adapter_).CopyTo(
        (IBluetoothAdapterStatics**)&bluetooth_adapter_statics);
    ComPtr<IDeviceInformationStatics> device_information_statics;
    Make<FakeDeviceInformationStaticsWinrt>(device_information_)
        .CopyTo((IDeviceInformationStatics**)&device_information_statics);
    InitForTests(std::move(init_cb), std::move(bluetooth_adapter_statics),
                 std::move(device_information_statics),
                 std::move(radio_statics));
  }

  FakeBluetoothLEAdvertisementWatcherWinrt* watcher() { return watcher_.Get(); }

 protected:
  ~TestBluetoothAdapterWinrt() override = default;

  HRESULT GetTestBluetoothAdapterStaticsActivationFactory(
      IBluetoothAdapterStatics** statics) const {
    auto adapter_statics = Make<FakeBluetoothAdapterStaticsWinrt>(adapter_);
    return adapter_statics.CopyTo(statics);
  }

  HRESULT
  GetTestDeviceInformationStaticsActivationFactory(
      IDeviceInformationStatics** statics) const {
    auto device_information_statics =
        Make<FakeDeviceInformationStaticsWinrt>(device_information_);
    return device_information_statics.CopyTo(statics);
  }

  HRESULT ActivateBluetoothAdvertisementLEWatcherInstance(
      IBluetoothLEAdvertisementWatcher** instance) const override {
    return watcher_.CopyTo(instance);
  }

  scoped_refptr<BluetoothAdvertisementWinrt> CreateAdvertisement()
      const override {
    return base::MakeRefCounted<TestBluetoothAdvertisementWinrt>();
  }

  std::unique_ptr<BluetoothDeviceWinrt> CreateDevice(
      uint64_t raw_address) override {
    return std::make_unique<TestBluetoothDeviceWinrt>(this, raw_address,
                                                      bluetooth_test_winrt_);
  }

 private:
  ComPtr<IBluetoothAdapter> adapter_;
  ComPtr<IDeviceInformation> device_information_;
  ComPtr<FakeBluetoothLEAdvertisementWatcherWinrt> watcher_;
  raw_ptr<BluetoothTestWinrt> bluetooth_test_winrt_ = nullptr;
};

BLUETOOTH_ADDRESS
CanonicalStringToBLUETOOTH_ADDRESS(std::string device_address) {
  BLUETOOTH_ADDRESS win_addr;
  unsigned int data[6];
  int result =
      sscanf_s(device_address.c_str(), "%02X:%02X:%02X:%02X:%02X:%02X",
               &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]);
  CHECK_EQ(6, result);
  for (int i = 0; i < 6; i++) {
    win_addr.rgBytes[i] = data[i];
  }
  return win_addr;
}

}  // namespace

BluetoothTestWin::BluetoothTestWin()
    : ui_task_runner_(new base::TestSimpleTaskRunner()),
      bluetooth_task_runner_(new base::TestSimpleTaskRunner()) {}

BluetoothTestWin::~BluetoothTestWin() = default;

bool BluetoothTestWin::PlatformSupportsLowEnergy() {
  return false;
}

void BluetoothTestWin::InitWithDefaultAdapter() {
  auto adapter = base::WrapRefCounted(new BluetoothAdapterWin());
  base::RunLoop run_loop;
  adapter->Initialize(run_loop.QuitClosure());
  run_loop.Run();
  adapter_ = std::move(adapter);
}

void BluetoothTestWin::InitWithoutDefaultAdapter() {
  auto adapter = base::WrapRefCounted(new BluetoothAdapterWin());
  adapter->InitForTest(base::DoNothing(), nullptr, ui_task_runner_,
                       bluetooth_task_runner_);
  adapter_ = std::move(adapter);
}

void BluetoothTestWin::InitWithFakeAdapter() {
  auto fake_bt_classic_wrapper =
      std::make_unique<win::BluetoothClassicWrapperFake>();
  fake_bt_classic_wrapper->SimulateARadio(
      base::UTF8ToUTF16(kTestAdapterName),
      CanonicalStringToBLUETOOTH_ADDRESS(kTestAdapterAddress));

  auto adapter = base::WrapRefCounted(new BluetoothAdapterWin());
  base::RunLoop run_loop;
  adapter->InitForTest(run_loop.QuitClosure(),
                       std::move(fake_bt_classic_wrapper), nullptr,
                       bluetooth_task_runner_);
  adapter_ = std::move(adapter);
  FinishPendingTasks();
  run_loop.Run();
}

bool BluetoothTestWin::DenyPermission() {
  return false;
}

void BluetoothTestWin::StartLowEnergyDiscoverySession() {
  __super::StartLowEnergyDiscoverySession();
  FinishPendingTasks();
}

BluetoothDevice* BluetoothTestWin::SimulateLowEnergyDevice(int device_ordinal) {
  NOTREACHED();
}

std::optional<BluetoothUUID> BluetoothTestWin::GetTargetGattService(
    BluetoothDevice* device) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  return ble_device->GetTargetGattService();
}

void BluetoothTestWin::SimulateGattConnection(BluetoothDevice* device) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateStatusChangeToDisconnect(
    BluetoothDevice* device) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattServicesDiscovered(
    BluetoothDevice* device,
    const std::vector<std::string>& uuids,
    const std::vector<std::string>& blocked_uuids) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattServiceRemoved(
    BluetoothRemoteGattService* service) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristic(
    BluetoothRemoteGattService* service,
    const std::string& uuid,
    int properties) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristicRemoved(
    BluetoothRemoteGattService* service,
    BluetoothRemoteGattCharacteristic* characteristic) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristicRead(
    BluetoothRemoteGattCharacteristic* characteristic,
    const std::vector<uint8_t>& value) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristicReadError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristicWrite(
    BluetoothRemoteGattCharacteristic* characteristic) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristicWriteError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::DeleteDevice(BluetoothDevice* device) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattDescriptor(
    BluetoothRemoteGattCharacteristic* characteristic,
    const std::string& uuid) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattNotifySessionStarted(
    BluetoothRemoteGattCharacteristic* characteristic) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattNotifySessionStartError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::SimulateGattCharacteristicChanged(
    BluetoothRemoteGattCharacteristic* characteristic,
    const std::vector<uint8_t>& value) {
  NOTREACHED_IN_MIGRATION();
}

void BluetoothTestWin::FinishPendingTasks() {
  bluetooth_task_runner_->RunPendingTasks();
  base::RunLoop().RunUntilIdle();
}

BluetoothTestWinrt::BluetoothTestWinrt() {
  std::vector<base::test::FeatureRef> enabled;
  std::vector<base::test::FeatureRef> disabled;
  if (GetParam().new_gatt_session_handling_enabled) {
    enabled.push_back(kNewBLEGattSessionHandling);
  } else {
    disabled.push_back(kNewBLEGattSessionHandling);
  }
  // TODO(crbug.com/40847175): Remove once `kWebBluetoothConfirmPairingSupport`
  // is enabled by default.
  enabled.push_back(features::kWebBluetoothConfirmPairingSupport);
  scoped_feature_list_.InitWithFeatures(enabled, disabled);
}

BluetoothTestWinrt::~BluetoothTestWinrt() {
  // The callbacks run by |notify_sessions_| may end up calling back into
  // |this|, so run them early to prevent a use-after-free.
  notify_sessions_.clear();
}

bool BluetoothTestWinrt::UsesNewGattSessionHandling() const {
  return GetParam().new_gatt_session_handling_enabled &&
         base::win::GetVersion() >= base::win::Version::WIN10_RS3;
}

bool BluetoothTestWinrt::PlatformSupportsLowEnergy() {
  return true;
}

void BluetoothTestWinrt::InitWithDefaultAdapter() {
  base::RunLoop run_loop;
  auto adapter = base::WrapRefCounted(new BluetoothAdapterWinrt());
  adapter->Initialize(run_loop.QuitClosure());
  adapter_ = std::move(adapter);
  run_loop.Run();
}

void BluetoothTestWinrt::InitWithoutDefaultAdapter() {
  base::RunLoop run_loop;
  adapter_ = base::MakeRefCounted<TestBluetoothAdapterWinrt>(
      /*adapter=*/nullptr, /*device_information=*/nullptr,
      Make<FakeRadioStaticsWinrt>(), run_loop.QuitClosure(), this);
  run_loop.Run();
}

void BluetoothTestWinrt::InitWithFakeAdapter() {
  base::RunLoop run_loop;
  adapter_ = base::MakeRefCounted<TestBluetoothAdapterWinrt>(
      Make<FakeBluetoothAdapterWinrt>(kTestAdapterAddress,
                                      Make<FakeRadioWinrt>()),
      Make<FakeDeviceInformationWinrt>(kTestAdapterName),
      Make<FakeRadioStaticsWinrt>(), run_loop.QuitClosure(), this);
  run_loop.Run();
}

void BluetoothTestWinrt::InitFakeAdapterWithoutRadio() {
  base::RunLoop run_loop;
  adapter_ = base::MakeRefCounted<TestBluetoothAdapterWinrt>(
      Make<FakeBluetoothAdapterWinrt>(kTestAdapterAddress, /*radio=*/nullptr),
      Make<FakeDeviceInformationWinrt>(kTestAdapterName),
      Make<FakeRadioStaticsWinrt>(), run_loop.QuitClosure(), this);
  run_loop.Run();
}

void BluetoothTestWinrt::InitFakeAdapterWithRadioAccessDenied() {
  // Simulate "allow apps to control radio access" toggled off in
  // Windows 10 Privacy settings.
  base::RunLoop run_loop;
  auto radio_statics = Make<FakeRadioStaticsWinrt>();
  radio_statics->SimulateRequestAccessAsyncError(
      ABI::Windows::Devices::Radios::RadioAccessStatus_DeniedByUser);
  adapter_ = base::MakeRefCounted<TestBluetoothAdapterWinrt>(
      Make<FakeBluetoothAdapterWinrt>(kTestAdapterAddress,
                                      Make<FakeRadioWinrt>()),
      Make<FakeDeviceInformationWinrt>(kTestAdapterName),
      std::move(radio_statics), run_loop.QuitClosure(), this);
  run_loop.Run();
}

void BluetoothTestWinrt::SimulateSpuriousRadioStateChangedEvent() {
  static_cast<FakeRadioWinrt*>(
      static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
          ->GetRadioForTesting())
      ->SimulateSpuriousStateChangedEvent();
}

void BluetoothTestWinrt::SimulateAdapterPowerFailure() {
  static_cast<FakeRadioWinrt*>(
      static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
          ->GetRadioForTesting())
      ->SimulateAdapterPowerFailure();
}

void BluetoothTestWinrt::SimulateAdapterPoweredOn() {
  auto* radio = static_cast<FakeRadioWinrt*>(
      static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
          ->GetRadioForTesting());

  if (radio) {
    radio->SimulateAdapterPoweredOn();
    return;
  }

  // This can happen when we simulate a fake adapter without a radio.
  static_cast<FakeDeviceWatcherWinrt*>(
      static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
          ->GetPoweredRadioWatcherForTesting())
      ->SimulateAdapterPoweredOn();
}

void BluetoothTestWinrt::SimulateAdapterPoweredOff() {
  auto* radio = static_cast<FakeRadioWinrt*>(
      static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
          ->GetRadioForTesting());

  if (radio) {
    radio->SimulateAdapterPoweredOff();
    return;
  }

  // This can happen when we simulate a fake adapter without a radio.
  static_cast<FakeDeviceWatcherWinrt*>(
      static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
          ->GetPoweredRadioWatcherForTesting())
      ->SimulateAdapterPoweredOff();
}

BluetoothDevice* BluetoothTestWinrt::SimulateLowEnergyDevice(
    int device_ordinal) {
  LowEnergyDeviceData data = GetLowEnergyDeviceData(device_ordinal);
  static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
      ->watcher()
      ->SimulateLowEnergyDevice(data);

  base::RunLoop().RunUntilIdle();
  return adapter_->GetDevice(data.address);
}

void BluetoothTestWinrt::SimulateLowEnergyDiscoveryFailure() {
  static_cast<TestBluetoothAdapterWinrt*>(adapter_.get())
      ->watcher()
      ->SimulateDiscoveryError();

  // Spin until the WatcherStopped event fires.
  base::RunLoop().RunUntilIdle();
}

void BluetoothTestWinrt::SimulateDevicePaired(BluetoothDevice* device,
                                              bool is_paired) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateDevicePaired(is_paired);
}

void BluetoothTestWinrt::SimulatePairingPinCode(BluetoothDevice* device,
                                                std::string pin_code) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulatePairingPinCode(std::move(pin_code));
}

void BluetoothTestWinrt::SimulateConfirmOnly(BluetoothDevice* device) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateConfirmOnly();
}

void BluetoothTestWinrt::SimulateDisplayPin(BluetoothDevice* device,
                                            std::string_view display_pin) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateDisplayPin(display_pin);
}

void BluetoothTestWinrt::SimulateAdvertisementStarted(
    BluetoothAdvertisement* advertisement) {
  static_cast<FakeBluetoothLEAdvertisementPublisherWinrt*>(
      static_cast<BluetoothAdvertisementWinrt*>(advertisement)
          ->GetPublisherForTesting())
      ->SimulateAdvertisementStarted();
}

void BluetoothTestWinrt::SimulateAdvertisementStopped(
    BluetoothAdvertisement* advertisement) {
  static_cast<FakeBluetoothLEAdvertisementPublisherWinrt*>(
      static_cast<BluetoothAdvertisementWinrt*>(advertisement)
          ->GetPublisherForTesting())
      ->SimulateAdvertisementStopped();
}

void BluetoothTestWinrt::SimulateAdvertisementError(
    BluetoothAdvertisement* advertisement,
    BluetoothAdvertisement::ErrorCode error_code) {
  static_cast<FakeBluetoothLEAdvertisementPublisherWinrt*>(
      static_cast<BluetoothAdvertisementWinrt*>(advertisement)
          ->GetPublisherForTesting())
      ->SimulateAdvertisementError(error_code);
}

void BluetoothTestWinrt::SimulateGattConnection(BluetoothDevice* device) {
  // Spin the message loop to make sure a device instance was obtained.
  base::RunLoop().RunUntilIdle();
  FakeBluetoothLEDeviceWinrt* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  ble_device->SimulateGattConnection();

  if (UsesNewGattSessionHandling()) {
    static_cast<TestBluetoothDeviceWinrt*>(device)
        ->gatt_session()
        ->SimulateGattConnection();

    // Spin the message loop again to make sure the device received a
    // GattSessionStatus change event.
    base::RunLoop().RunUntilIdle();
  }
}

void BluetoothTestWinrt::SimulateGattNameChange(BluetoothDevice* device,
                                                const std::string& new_name) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattNameChange(new_name);
}

void BluetoothTestWinrt::SimulateStatusChangeToDisconnect(
    BluetoothDevice* device) {
  // Spin the message loop to make sure a device instance was obtained.
  base::RunLoop().RunUntilIdle();
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateStatusChangeToDisconnect();
}

void BluetoothTestWinrt::SimulateGattConnectionError(
    BluetoothDevice* device,
    BluetoothDevice::ConnectErrorCode error_code) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattConnectionError(error_code);
  if (UsesNewGattSessionHandling()) {
    static_cast<TestBluetoothDeviceWinrt*>(device)
        ->gatt_session()
        ->SimulateGattConnectionError();
  }
}

void BluetoothTestWinrt::SimulateGattDisconnection(BluetoothDevice* device) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattDisconnection();
  if (UsesNewGattSessionHandling()) {
    static_cast<TestBluetoothDeviceWinrt*>(device)
        ->gatt_session()
        ->SimulateGattDisconnection();
  }
}

void BluetoothTestWinrt::SimulateDeviceBreaksConnection(
    BluetoothDevice* device) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateDeviceBreaksConnection();
  if (UsesNewGattSessionHandling()) {
    static_cast<TestBluetoothDeviceWinrt*>(device)
        ->gatt_session()
        ->SimulateGattDisconnection();
  }
}

void BluetoothTestWinrt::SimulateGattServicesDiscovered(
    BluetoothDevice* device,
    const std::vector<std::string>& uuids,
    const std::vector<std::string>& blocked_uuids) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattServicesDiscovered(uuids, blocked_uuids);
}

void BluetoothTestWinrt::SimulateGattServicesChanged(BluetoothDevice* device) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattServicesChanged();
}

void BluetoothTestWinrt::SimulateGattServiceRemoved(
    BluetoothRemoteGattService* service) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(service->GetDevice())
          ->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattServiceRemoved(service);
}

void BluetoothTestWinrt::SimulateGattServicesDiscoveryError(
    BluetoothDevice* device) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(device)->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattServicesDiscoveryError();
}

void BluetoothTestWinrt::SimulateGattCharacteristic(
    BluetoothRemoteGattService* service,
    const std::string& uuid,
    int properties) {
  auto* const ble_device =
      static_cast<TestBluetoothDeviceWinrt*>(service->GetDevice())
          ->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattCharacteristic(service, uuid, properties);
}

void BluetoothTestWinrt::SimulateGattNotifySessionStarted(
    BluetoothRemoteGattCharacteristic* characteristic) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattNotifySessionStarted();
}

void BluetoothTestWinrt::SimulateGattNotifySessionStartError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattNotifySessionStartError(error_code);
}

void BluetoothTestWinrt::SimulateGattNotifySessionStopped(
    BluetoothRemoteGattCharacteristic* characteristic) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattNotifySessionStopped();
}

void BluetoothTestWinrt::SimulateGattNotifySessionStopError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattNotifySessionStopError(error_code);
}

void BluetoothTestWinrt::SimulateGattCharacteristicChanged(
    BluetoothRemoteGattCharacteristic* characteristic,
    const std::vector<uint8_t>& value) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattCharacteristicChanged(value);
}

void BluetoothTestWinrt::SimulateGattCharacteristicRead(
    BluetoothRemoteGattCharacteristic* characteristic,
    const std::vector<uint8_t>& value) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattCharacteristicRead(value);
}

void BluetoothTestWinrt::SimulateGattCharacteristicReadError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattCharacteristicReadError(error_code);
}

void BluetoothTestWinrt::SimulateGattCharacteristicWrite(
    BluetoothRemoteGattCharacteristic* characteristic) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattCharacteristicWrite();
}

void BluetoothTestWinrt::SimulateGattCharacteristicWriteError(
    BluetoothRemoteGattCharacteristic* characteristic,
    BluetoothGattService::GattErrorCode error_code) {
  static_cast<FakeGattCharacteristicWinrt*>(
      static_cast<BluetoothRemoteGattCharacteristicWinrt*>(characteristic)
          ->GetCharacteristicForTesting())
      ->SimulateGattCharacteristicWriteError(error_code);
}

void BluetoothTestWinrt::SimulateGattDescriptor(
    BluetoothRemoteGattCharacteristic* characteristic,
    const std::string& uuid) {
  auto* const ble_device = static_cast<TestBluetoothDeviceWinrt*>(
                               characteristic->GetService()->GetDevice())
                               ->ble_device();
  DCHECK(ble_device);
  ble_device->SimulateGattDescriptor(characteristic, uuid);
}

void BluetoothTestWinrt::SimulateGattDescriptorRead(
    BluetoothRemoteGattDescriptor* descriptor,
    const std::vector<uint8_t>& value) {
  static_cast<FakeGattDescriptorWinrt*>(
      static_cast<BluetoothRemoteGattDescriptorWinrt*>(descriptor)
          ->GetDescriptorForTesting())
      ->SimulateGattDescriptorRead(value);
}

void BluetoothTestWinrt::SimulateGattDescriptorReadError(
    BluetoothRemoteGattDescriptor* descriptor,
    BluetoothGattService::GattErrorCode error_code) {
  static_cast<FakeGattDescriptorWinrt*>(
      static_cast<BluetoothRemoteGattDescriptorWinrt*>(descriptor)
          ->GetDescriptorForTesting())
      ->SimulateGattDescriptorReadError(error_code);
}

void BluetoothTestWinrt::SimulateGattDescriptorWrite(
    BluetoothRemoteGattDescriptor* descriptor) {
  static_cast<FakeGattDescriptorWinrt*>(
      static_cast<BluetoothRemoteGattDescriptorWinrt*>(descriptor)
          ->GetDescriptorForTesting())
      ->SimulateGattDescriptorWrite();
}

void BluetoothTestWinrt::SimulateGattDescriptorWriteError(
    BluetoothRemoteGattDescriptor* descriptor,
    BluetoothGattService::GattErrorCode error_code) {
  static_cast<FakeGattDescriptorWinrt*>(
      static_cast<BluetoothRemoteGattDescriptorWinrt*>(descriptor)
          ->GetDescriptorForTesting())
      ->SimulateGattDescriptorWriteError(error_code);
}

void BluetoothTestWinrt::DeleteDevice(BluetoothDevice* device) {
  BluetoothTestBase::DeleteDevice(device);
}

void BluetoothTestWinrt::OnFakeBluetoothDeviceConnectGattAttempt() {
  ++gatt_connection_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothDeviceGattServiceDiscoveryAttempt() {
  ++gatt_discovery_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothGattDisconnect() {
  ++gatt_disconnection_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothCharacteristicReadValue() {
  ++gatt_read_characteristic_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothCharacteristicWriteValue(
    std::vector<uint8_t> value) {
  last_write_value_ = std::move(value);
  ++gatt_write_characteristic_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothGattSetCharacteristicNotification(
    NotifyValueState state) {
  last_write_value_ = {static_cast<uint8_t>(state), 0};
  ++gatt_notify_characteristic_attempts_;
  ++gatt_write_descriptor_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothDescriptorReadValue() {
  ++gatt_read_descriptor_attempts_;
}

void BluetoothTestWinrt::OnFakeBluetoothDescriptorWriteValue(
    std::vector<uint8_t> value) {
  last_write_value_ = std::move(value);
  ++gatt_write_descriptor_attempts_;
}

}  // namespace device