chromium/device/bluetooth/bluetooth_device_unittest.cc

// Copyright 2014 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/bluetooth_device.h"

#include <stddef.h>

#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/test_future.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_remote_gatt_service.h"
#include "device/bluetooth/public/cpp/bluetooth_address.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "device/bluetooth/test/mock_pairing_delegate.h"
#include "device/bluetooth/test/test_bluetooth_adapter_observer.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_ANDROID)
#include "device/bluetooth/test/bluetooth_test_android.h"
#elif BUILDFLAG(IS_APPLE)
#include "device/bluetooth/test/bluetooth_test_mac.h"
#elif BUILDFLAG(IS_WIN)
#include "device/bluetooth/test/bluetooth_test_win.h"
#elif defined(USE_CAST_BLUETOOTH_ADAPTER)
#include "device/bluetooth/test/bluetooth_test_cast.h"
#elif BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
#elif BUILDFLAG(IS_FUCHSIA)
#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif

namespace device {


namespace {

_;
Return;
StrictMock;

int8_t ToInt8(BluetoothTest::TestRSSI rssi) {}

int8_t ToInt8(BluetoothTest::TestTxPower tx_power) {}

#if BUILDFLAG(IS_WIN)
void ScheduleAsynchronousCancelPairing(BluetoothDevice* device) {
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&BluetoothDevice::CancelPairing,
                                base::Unretained(device)));
}

void ScheduleAsynchronousRejectPairing(BluetoothDevice* device) {
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&BluetoothDevice::RejectPairing,
                                base::Unretained(device)));
}
#endif  // BUILDFLAG(IS_WIN)

}  // namespace


UUIDSet;
ServiceDataMap;
ManufacturerDataMap;

TEST(BluetoothDeviceTest, CanonicalizeAddressFormat_AcceptsAllValidFormats) {}

TEST(BluetoothDeviceTest,
     CanonicalizeAddressFormat_AcceptsAllValidFormatsBytes) {}

TEST(BluetoothDeviceTest, CanonicalizeAddressFormat_RejectsInvalidFormats) {}

TEST(BluetoothDeviceTest, GattConnectionErrorReentrancy) {}

#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, DeviceIsPaired) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();
  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  // By default a device should not be paired.
  EXPECT_FALSE(device->IsPaired());

  // Connect to the device and simulate a paired state.
  ASSERT_TRUE(ConnectGatt(device));
  SimulateDevicePaired(device, true);
  EXPECT_TRUE(device->IsPaired());

  SimulateDevicePaired(device, false);
  EXPECT_FALSE(device->IsPaired());
}

// Tests that providing a correct pin code results in a paired device.
TEST_P(BluetoothTestWinrt, DevicePairRequestPinCodeCorrect) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();
  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());

  SimulatePairingPinCode(device, "123456");
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, RequestPinCode)
      .WillOnce([](BluetoothDevice* device) {
        ASSERT_NE(device, nullptr);
        device->SetPinCode("123456");
      });

  base::RunLoop run_loop;
  device->Pair(
      &pairing_delegate,
      base::BindLambdaForTesting(
          [&](std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
            EXPECT_FALSE(error_code.has_value());
            run_loop.Quit();
          }));
  run_loop.Run();

  EXPECT_TRUE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());
}

// Tests that providing a wrong pin code does not result in a paired device.
TEST_P(BluetoothTestWinrt, DevicePairRequestPinCodeWrong) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();
  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());

  SimulatePairingPinCode(device, "123456");
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, RequestPinCode)
      .WillOnce([](BluetoothDevice* device) {
        ASSERT_NE(device, nullptr);
        device->SetPinCode("000000");
      });
  base::RunLoop run_loop;
  device->Pair(
      &pairing_delegate,
      base::BindLambdaForTesting(
          [&](std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
            EXPECT_EQ(BluetoothDevice::ERROR_FAILED, error_code);
            run_loop.Quit();
          }));
  run_loop.Run();

  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());
}

// Tests that rejecting the pairing does not result in a paired device.
TEST_P(BluetoothTestWinrt, DevicePairRequestPinCodeRejectPairing) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();
  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());

  SimulatePairingPinCode(device, "123456");
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, RequestPinCode)
      .WillOnce([](BluetoothDevice* device) {
        ASSERT_NE(device, nullptr);
        ScheduleAsynchronousRejectPairing(device);
      });

  base::RunLoop run_loop;
  device->Pair(
      &pairing_delegate,
      base::BindLambdaForTesting(
          [&](std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
            EXPECT_EQ(BluetoothDevice::ERROR_AUTH_REJECTED, error_code);
            run_loop.Quit();
          }));
  run_loop.Run();

  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());
}

// Tests that cancelling the pairing does not result in a paired device.
TEST_P(BluetoothTestWinrt, DevicePairRequestPinCodeCancelPairing) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();
  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());

  SimulatePairingPinCode(device, "123456");
  StrictMock<MockPairingDelegate> pairing_delegate;

  EXPECT_CALL(pairing_delegate, RequestPinCode)
      .WillOnce([](BluetoothDevice* device) {
        ASSERT_NE(device, nullptr);
        ScheduleAsynchronousCancelPairing(device);
      });

  base::RunLoop run_loop;
  device->Pair(
      &pairing_delegate,
      base::BindLambdaForTesting(
          [&](std::optional<BluetoothDevice::ConnectErrorCode> error_code) {
            EXPECT_EQ(BluetoothDevice::ERROR_AUTH_CANCELED, error_code);
            run_loop.Quit();
          }));
  run_loop.Run();

  EXPECT_FALSE(device->IsPaired());
  EXPECT_FALSE(device->ExpectingPinCode());
}

TEST_P(BluetoothTestWinrt, DevicePairRequestConfirmOnlyAccept) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();

  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());

  SimulateConfirmOnly(device);
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, AuthorizePairing)
      .WillOnce([](BluetoothDevice* device) {
        ASSERT_NE(device, nullptr);
        device->ConfirmPairing();
      });

  base::test::TestFuture<std::optional<BluetoothDevice::ConnectErrorCode>>
      error_code_future;
  device->Pair(&pairing_delegate, error_code_future.GetCallback());

  EXPECT_FALSE(error_code_future.Get().has_value());
  EXPECT_TRUE(device->IsPaired());
}

TEST_P(BluetoothTestWinrt, DevicePairRequestConfirmOnlyCancel) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();

  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());

  SimulateConfirmOnly(device);
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, AuthorizePairing)
      .WillOnce([](BluetoothDevice* device) {
        ASSERT_NE(device, nullptr);
        ScheduleAsynchronousCancelPairing(device);
      });

  base::test::TestFuture<std::optional<BluetoothDevice::ConnectErrorCode>>
      error_code_future;
  device->Pair(&pairing_delegate, error_code_future.GetCallback());

  EXPECT_EQ(error_code_future.Get(), BluetoothDevice::ERROR_AUTH_CANCELED);
  EXPECT_FALSE(device->IsPaired());
}

TEST_P(BluetoothTestWinrt, DevicePairRequestConfirmPinAccept) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();

  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());

  SimulateDisplayPin(device, "123456");
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, ConfirmPasskey)
      .WillOnce([](BluetoothDevice* device, uint32_t passkey) {
        ASSERT_NE(device, nullptr);
        ASSERT_EQ(passkey, 123456u);
        device->ConfirmPairing();
      });

  base::test::TestFuture<std::optional<BluetoothDevice::ConnectErrorCode>>
      error_code_future;
  device->Pair(&pairing_delegate, error_code_future.GetCallback());

  EXPECT_FALSE(error_code_future.Get().has_value());
  EXPECT_TRUE(device->IsPaired());
}

TEST_P(BluetoothTestWinrt, DevicePairRequestConfirmPinCancel) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();

  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());

  SimulateDisplayPin(device, "123456");
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, ConfirmPasskey)
      .WillOnce([](BluetoothDevice* device, uint32_t passkey) {
        ASSERT_NE(device, nullptr);
        ASSERT_EQ(passkey, 123456u);
        ScheduleAsynchronousCancelPairing(device);
      });

  base::test::TestFuture<std::optional<BluetoothDevice::ConnectErrorCode>>
      error_code_future;
  device->Pair(&pairing_delegate, error_code_future.GetCallback());

  EXPECT_EQ(error_code_future.Get(), BluetoothDevice::ERROR_AUTH_CANCELED);
  EXPECT_FALSE(device->IsPaired());
}

TEST_P(BluetoothTestWinrt, DevicePairRequestConfirmPinLeadingZeroAccept) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();

  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());

  SimulateDisplayPin(device, "000001");
  StrictMock<MockPairingDelegate> pairing_delegate;
  EXPECT_CALL(pairing_delegate, ConfirmPasskey)
      .WillOnce([](BluetoothDevice* device, uint32_t passkey) {
        ASSERT_NE(device, nullptr);
        ASSERT_EQ(passkey, 1u);
        device->ConfirmPairing();
      });

  base::test::TestFuture<std::optional<BluetoothDevice::ConnectErrorCode>>
      error_code_future;
  device->Pair(&pairing_delegate, error_code_future.GetCallback());

  EXPECT_FALSE(error_code_future.Get().has_value());
  EXPECT_TRUE(device->IsPaired());
}

TEST_P(BluetoothTestWinrt, DevicePairRequestConfirmPinInvalid) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();

  BluetoothDevice* device = SimulateLowEnergyDevice(1);

  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_FALSE(device->IsPaired());

  SimulateDisplayPin(device, "1000000");
  StrictMock<MockPairingDelegate> pairing_delegate;

  EXPECT_CALL(pairing_delegate, ConfirmPasskey).Times(0);

  base::test::TestFuture<std::optional<BluetoothDevice::ConnectErrorCode>>
      error_code_future;
  device->Pair(&pairing_delegate, error_code_future.GetCallback());

  EXPECT_EQ(error_code_future.Get(), BluetoothDevice::ERROR_AUTH_FAILED);
  EXPECT_FALSE(device->IsPaired());
}
#endif  // BUILDFLAG(IS_WIN)

// Verifies basic device properties, e.g. GetAddress, GetName, ...
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, LowEnergyDeviceProperties) {
#else
TEST_F(BluetoothTest, LowEnergyDeviceProperties) {}

// Verifies that the device name can be populated by later advertisement
// packets and is persistent.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, LowEnergyDeviceNameDelayed) {
#else
// This test does not yet pass on any other platform.
TEST_F(BluetoothTest, DISABLED_LowEnergyDeviceNameDelayed) {}

// Device with no advertised Service UUIDs.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, LowEnergyDeviceNoUUIDs) {
#else
TEST_F(BluetoothTest, LowEnergyDeviceNoUUIDs) {}

#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_ANDROID)
#define MAYBE_GetServiceDataUUIDs_GetServiceDataForUUID
#else
#define MAYBE_GetServiceDataUUIDs_GetServiceDataForUUID
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetServiceDataUUIDs_GetServiceDataForUUID) {
#else
TEST_F(BluetoothTest, MAYBE_GetServiceDataUUIDs_GetServiceDataForUUID) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_AdvertisementData_Discovery
#else
#define MAYBE_AdvertisementData_Discovery
#endif
// Tests that the Advertisement Data fields are correctly updated during
// discovery.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, AdvertisementData_Discovery) {
#else
TEST_F(BluetoothTest, MAYBE_AdvertisementData_Discovery) {}

// TODO(dougt) As I turn on new platforms for WebBluetooth Scanning,
// I will relax this #ifdef
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
#define MAYBE_DeviceAdvertisementReceived
#else
#define MAYBE_DeviceAdvertisementReceived
#endif
// Tests that the Bluetooth adapter observer is notified when a device
// advertisement is received.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, DeviceAdvertisementReceived) {
#else
TEST_F(BluetoothTest, MAYBE_DeviceAdvertisementReceived) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetUUIDs_Connection
#else
#define MAYBE_GetUUIDs_Connection
#endif
// Tests Advertisement Data is updated correctly during a connection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetUUIDs_Connection) {
#else
TEST_F(BluetoothTest, MAYBE_GetUUIDs_Connection) {}

#if BUILDFLAG(IS_APPLE)
// Tests that receiving 2 notifications in a row from macOS that services has
// changed is handled correctly. Each notification should generate a
// notification that the gatt device has changed, and each notification should
// ask to macOS to scan for services. Only after the second service scan is
// received, the device changed notification should be sent and the
// characteristic discovery procedure should be started.
// Android: This test doesn't apply to Android because there is no services
// changed event that could arrive during a discovery procedure.
TEST_F(BluetoothTest, TwoPendingServiceDiscoveryRequests) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }

  InitWithFakeAdapter();
  TestBluetoothAdapterObserver observer(adapter_);

  BluetoothDevice* device = SimulateLowEnergyDevice(1);
  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_EQ(1, observer.device_changed_count());
  EXPECT_FALSE(device->IsGattServicesDiscoveryComplete());

  observer.Reset();
  SimulateGattServicesChanged(device);
  EXPECT_EQ(1, observer.device_changed_count());
  EXPECT_FALSE(device->IsGattServicesDiscoveryComplete());

  // First system call to
  // -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:] using
  // SimulateDidDiscoverServicesMac().
  observer.Reset();
  AddServicesToDeviceMac(device, {kTestUUIDHeartRate});
  SimulateDidDiscoverServicesMac(device);
  EXPECT_EQ(0, observer.device_changed_count());
  EXPECT_FALSE(device->IsGattServicesDiscoveryComplete());
  EXPECT_EQ(gatt_characteristic_discovery_attempts_, 0);

  // Second system call to
  // -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:] using the
  // generic call to SimulateGattServicesDiscovered(). This method triggers
  // the full discovery cycles (services, characteristics and descriptors),
  // which includes -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:].
  SimulateGattServicesDiscovered(
      device, std::vector<std::string>({kTestUUIDImmediateAlert}));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, observer.device_changed_count());
  EXPECT_TRUE(device->IsGattServicesDiscoveryComplete());
  // Characteristics are discovered once for each service.
  EXPECT_EQ(gatt_characteristic_discovery_attempts_, 2);

  EXPECT_EQ(2u, device->GetGattServices().size());
}

// Simulate an unexpected call to -[id<CBPeripheralDelegate>
// peripheral:didDiscoverServices:]. This should not happen, but if it does
// (buggy device?), a discovery cycle should be done.
TEST_F(BluetoothTest, ExtraDidDiscoverServicesCall) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }

  InitWithFakeAdapter();
  TestBluetoothAdapterObserver observer(adapter_);

  BluetoothDevice* device = SimulateLowEnergyDevice(1);
  ASSERT_TRUE(ConnectGatt(device));
  EXPECT_EQ(1, observer.device_changed_count());
  EXPECT_FALSE(device->IsGattServicesDiscoveryComplete());

  // Legitimate system call to
  // -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:].
  observer.Reset();
  SimulateGattServicesDiscovered(
      device, std::vector<std::string>({kTestUUIDHeartRate}));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, observer.device_changed_count());
  EXPECT_TRUE(device->IsGattServicesDiscoveryComplete());
  EXPECT_EQ(gatt_characteristic_discovery_attempts_, 1);
  EXPECT_EQ(1u, device->GetGattServices().size());

  // Unexpected system call to
  // -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:]:
  // This system call is expected only once after -[CBCentralManager
  // discoverServices:]. The call to -[CBCentralManager discoverServices:] and
  // its answer with -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:]
  // is done with SimulateGattServicesDiscovered(). So a second system call to
  // -[id<CBPeripheralDelegate> peripheral:didDiscoverServices:] is not expected
  // and should be ignored.
  AddServicesToDeviceMac(device, {kTestUUIDImmediateAlert});
  SimulateDidDiscoverServicesMac(device);
  EXPECT_EQ(1, observer.device_changed_count());
  EXPECT_TRUE(device->IsGattServicesDiscoveryComplete());

  EXPECT_EQ(1u, device->GetGattServices().size());
}
#endif

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_AdvertisementData_DiscoveryDuringConnection
#else
#define MAYBE_AdvertisementData_DiscoveryDuringConnection
#endif
// Tests Advertisement Data is updated correctly when we start discovery
// during a connection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, AdvertisementData_DiscoveryDuringConnection) {
#else
TEST_F(BluetoothTest, MAYBE_AdvertisementData_DiscoveryDuringConnection) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_AdvertisementData_ConnectionDuringDiscovery
#else
#define MAYBE_AdvertisementData_ConnectionDuringDiscovery
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, AdvertisementData_ConnectionDuringDiscovery) {
#else
TEST_F(BluetoothTest, MAYBE_AdvertisementData_ConnectionDuringDiscovery) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE) || \
    BUILDFLAG(IS_LINUX)
#define MAYBE_GetName_NullName
#else
#define MAYBE_GetName_NullName
#endif
// GetName for Device with no name.
TEST_F(BluetoothTest, MAYBE_GetName_NullName) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_CreateGattConnection
#else
#define MAYBE_CreateGattConnection
#endif
// Basic CreateGattConnection test.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, CreateGattConnection) {
#else
TEST_F(BluetoothTest, MAYBE_CreateGattConnection) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_DisconnectionNotifiesDeviceChanged
#else
#define MAYBE_DisconnectionNotifiesDeviceChanged
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, DisconnectionNotifiesDeviceChanged) {
#else
TEST_F(BluetoothTest, MAYBE_DisconnectionNotifiesDeviceChanged) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection
#else
#define MAYBE_BluetoothGattConnection
#endif
// Creates BluetoothGattConnection instances and tests that the interface
// functions even when some Disconnect and the BluetoothDevice is destroyed.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, BluetoothGattConnection) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_ConnectWithMultipleOSConnections
#else
#define MAYBE_BluetoothGattConnection_ConnectWithMultipleOSConnections
#endif
// Calls CreateGattConnection then simulates multiple connections from platform.
TEST_F(BluetoothTest,
       MAYBE_BluetoothGattConnection_ConnectWithMultipleOSConnections) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_AlreadyConnected
#else
#define MAYBE_BluetoothGattConnection_AlreadyConnected
#endif
// Calls CreateGattConnection after already connected.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, BluetoothGattConnection_AlreadyConnected) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_AlreadyConnected) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected
#else
#define MAYBE_BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected
#endif
// Creates BluetoothGattConnection after one exists that has disconnected.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt,
       BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected) {
#else
TEST_F(BluetoothTest,
       MAYBE_BluetoothGattConnection_NewConnectionLeavesPreviousDisconnected) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_DisconnectWhenObjectsDestroyed
#else
#define MAYBE_BluetoothGattConnection_DisconnectWhenObjectsDestroyed
#endif
// Deletes BluetoothGattConnection causing disconnection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt,
       BluetoothGattConnection_DisconnectWhenObjectsDestroyed) {
#else
TEST_F(BluetoothTest,
       MAYBE_BluetoothGattConnection_DisconnectWhenObjectsDestroyed) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_DisconnectInProgress
#else
#define MAYBE_BluetoothGattConnection_DisconnectInProgress
#endif
// Starts process of disconnecting and then calls BluetoothGattConnection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, BluetoothGattConnection_DisconnectInProgress) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_DisconnectInProgress) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_SimulateDisconnect
#else
#define MAYBE_BluetoothGattConnection_SimulateDisconnect
#endif
// Calls CreateGattConnection but receives notice that the device disconnected
// before it ever connects.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, BluetoothGattConnection_SimulateDisconnect) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_SimulateDisconnect) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateConnect
#else
#define MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateConnect
#endif
// Calls CreateGattConnection & DisconnectGatt, then simulates connection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt,
       BluetoothGattConnection_DisconnectGatt_SimulateConnect) {
#else
TEST_F(BluetoothTest,
       MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateConnect) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateDisconnect
#else
#define MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateDisconnect
#endif
// Calls CreateGattConnection & DisconnectGatt, then simulates disconnection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt,
       BluetoothGattConnection_DisconnectGatt_SimulateDisconnect) {
#else
TEST_F(BluetoothTest,
       MAYBE_BluetoothGattConnection_DisconnectGatt_SimulateDisconnect) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_DisconnectGatt_Cleanup
#else
#define MAYBE_BluetoothGattConnection_DisconnectGatt_Cleanup
#endif
// Calls CreateGattConnection & DisconnectGatt, then checks that gatt services
// have been cleaned up.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, BluetoothGattConnection_DisconnectGatt_Cleanup) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_DisconnectGatt_Cleanup) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_BluetoothGattConnection_ErrorAfterConnection
#else
#define MAYBE_BluetoothGattConnection_ErrorAfterConnection
#endif
// Calls CreateGattConnection, but simulate errors connecting. Also, verifies
// multiple errors should only invoke callbacks once.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, BluetoothGattConnection_ErrorAfterConnection) {
#else
TEST_F(BluetoothTest, MAYBE_BluetoothGattConnection_ErrorAfterConnection) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
#define MAYBE_GattServices_ObserversCalls
#else
#define MAYBE_GattServices_ObserversCalls
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GattServices_ObserversCalls) {
#else
TEST_F(BluetoothTest, MAYBE_GattServices_ObserversCalls) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
#define MAYBE_GattServicesDiscovered_Success
#else
#define MAYBE_GattServicesDiscovered_Success
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GattServicesDiscovered_Success) {
#else
TEST_F(BluetoothTest, MAYBE_GattServicesDiscovered_Success) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
#define MAYBE_GattServicesDiscovered_AfterDeleted
#else
#define MAYBE_GattServicesDiscovered_AfterDeleted
#endif
// macOS: Not applicable: This can never happen because when
// the device gets destroyed the CBPeripheralDelegate is also destroyed
// and no more events are dispatched.
TEST_F(BluetoothTest, MAYBE_GattServicesDiscovered_AfterDeleted) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
#define MAYBE_GattServicesDiscoveredError_AfterDeleted
#else
#define MAYBE_GattServicesDiscoveredError_AfterDeleted
#endif
// macOS: Not applicable: This can never happen because when
// the device gets destroyed the CBPeripheralDelegate is also destroyed
// and no more events are dispatched.
TEST_F(BluetoothTest, MAYBE_GattServicesDiscoveredError_AfterDeleted) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GattServicesDiscovered_AfterDisconnection
#else
#define MAYBE_GattServicesDiscovered_AfterDisconnection
#endif
// Classic Windows does not support disconnection.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GattServicesDiscovered_AfterDisconnection) {
#else
TEST_F(BluetoothTest, MAYBE_GattServicesDiscovered_AfterDisconnection) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GattServicesDiscoveredError_AfterDisconnection
#else
#define MAYBE_GattServicesDiscoveredError_AfterDisconnection
#endif
// Windows does not support disconnecting.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GattServicesDiscoveredError_AfterDisconnection) {
#else
TEST_F(BluetoothTest, MAYBE_GattServicesDiscoveredError_AfterDisconnection) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetGattServices_and_GetGattService
#else
#define MAYBE_GetGattServices_and_GetGattService
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetGattServices_and_GetGattService) {
#else
TEST_F(BluetoothTest, MAYBE_GetGattServices_and_GetGattService) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetGattServices_FindNone
#else
#define MAYBE_GetGattServices_FindNone
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetGattServices_FindNone) {
#else
TEST_F(BluetoothTest, MAYBE_GetGattServices_FindNone) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetGattServices_DiscoveryError
#else
#define MAYBE_GetGattServices_DiscoveryError
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetGattServices_DiscoveryError) {
#else
TEST_F(BluetoothTest, MAYBE_GetGattServices_DiscoveryError) {}

#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GattServicesDiscovered_SomeServicesBlocked) {
#else
TEST_F(BluetoothTest, DISABLED_GattServicesDiscovered_SomeServicesBlocked) {}

#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
TEST_F(BluetoothTest, GetDeviceTransportType) {}
#endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetPrimaryServices
#else
#define MAYBE_GetPrimaryServices
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetPrimaryServices) {
#else
TEST_F(BluetoothTest, MAYBE_GetPrimaryServices) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetPrimaryServicesByUUID
#else
#define MAYBE_GetPrimaryServicesByUUID
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GetPrimaryServicesByUUID) {
#else
TEST_F(BluetoothTest, MAYBE_GetPrimaryServicesByUUID) {}

#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothTestWinrt, GattConnectedNameChange) {
#else
// The SimulateGattNameChange() function is not yet available on other
// platforms.
TEST_F(BluetoothTest, DISABLED_GattConnectedNameChange) {}

#if BUILDFLAG(IS_WIN)
// WinRT sometimes calls OnConnectionStatusChanged when the status is
// initialized and not when changed.
TEST_P(BluetoothTestWinrt, FalseStatusChangedTest) {
  if (!PlatformSupportsLowEnergy()) {
    GTEST_SKIP() << "Low Energy Bluetooth unavailable, skipping unit test.";
  }
  InitWithFakeAdapter();
  StartLowEnergyDiscoverySession();
  BluetoothDevice* device = SimulateLowEnergyDevice(3);
  EXPECT_FALSE(device->IsConnected());
  device->CreateGattConnection(
      GetGattConnectionCallback(Call::NOT_EXPECTED, Result::FAILURE));
  SimulateStatusChangeToDisconnect(device);

  base::RunLoop().RunUntilIdle();
}
#endif

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ServiceSpecificDiscovery
#else
#define MAYBE_ServiceSpecificDiscovery
#endif

#if !BUILDFLAG(IS_WIN)
TEST_F(BluetoothTest, MAYBE_ServiceSpecificDiscovery) {}

}  // namespace device