chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.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 "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_remote_gatt_service.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 {

class BluetoothRemoteGattDescriptorTest :
#if BUILDFLAG(IS_WIN)
    public BluetoothTestWinrt {};

#if BUILDFLAG(IS_WIN)
using BluetoothRemoteGattDescriptorTestWinrt =
    BluetoothRemoteGattDescriptorTest;
#endif

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetIdentifier
#else
#define MAYBE_GetIdentifier
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, GetIdentifier) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetIdentifier) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_GetUUID
#else
#define MAYBE_GetUUID
#endif
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, GetUUID) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_GetUUID) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadRemoteDescriptor_Empty
#else
#define MAYBE_ReadRemoteDescriptor_Empty
#endif
// Tests ReadRemoteDescriptor and GetValue with empty value buffer.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, ReadRemoteDescriptor_Empty) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_ReadRemoteDescriptor_Empty) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteRemoteDescriptor_Empty
#else
#define MAYBE_WriteRemoteDescriptor_Empty
#endif
// Tests WriteRemoteDescriptor with empty value buffer.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, WriteRemoteDescriptor_Empty) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_WriteRemoteDescriptor_Empty) {}

#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ReadRemoteDescriptor_AfterDeleted
#else
#define MAYBE_ReadRemoteDescriptor_AfterDeleted
#endif
// Tests ReadRemoteDescriptor completing after Chrome objects are deleted.
// macOS: Not applicable: This can never happen if CBPeripheral delegate is set
// to nil.
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_ReadRemoteDescriptor_AfterDeleted) {}

#if BUILDFLAG(IS_ANDROID)
#define MAYBE_WriteRemoteDescriptor_AfterDeleted
#else
#define MAYBE_WriteRemoteDescriptor_AfterDeleted
#endif
// Tests WriteRemoteDescriptor completing after Chrome objects are deleted.
// macOS: Not applicable: This can never happen if CBPeripheral delegate is set
// to nil.
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_WriteRemoteDescriptor_AfterDeleted) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadRemoteDescriptor
#else
#define MAYBE_ReadRemoteDescriptor
#endif
// Tests ReadRemoteDescriptor and GetValue with non-empty value buffer.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, ReadRemoteDescriptor) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_ReadRemoteDescriptor) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteRemoteDescriptor
#else
#define MAYBE_WriteRemoteDescriptor
#endif
// Tests WriteRemoteDescriptor with non-empty value buffer.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, WriteRemoteDescriptor) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_WriteRemoteDescriptor) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadRemoteDescriptor_Twice
#else
#define MAYBE_ReadRemoteDescriptor_Twice
#endif
// Tests ReadRemoteDescriptor and GetValue multiple times.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, ReadRemoteDescriptor_Twice) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_ReadRemoteDescriptor_Twice) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteRemoteDescriptor_Twice
#else
#define MAYBE_WriteRemoteDescriptor_Twice
#endif
// Tests WriteRemoteDescriptor multiple times.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, WriteRemoteDescriptor_Twice) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_WriteRemoteDescriptor_Twice) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadRemoteDescriptor_MultipleDescriptors
#else
#define MAYBE_ReadRemoteDescriptor_MultipleDescriptors
#endif
// Tests ReadRemoteDescriptor on two descriptors.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt,
       ReadRemoteDescriptor_MultipleDescriptors) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_ReadRemoteDescriptor_MultipleDescriptors) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteRemoteDescriptor_MultipleDescriptors
#else
#define MAYBE_WriteRemoteDescriptor_MultipleDescriptors
#endif
// Tests WriteRemoteDescriptor on two descriptors.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt,
       WriteRemoteDescriptor_MultipleDescriptors) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_WriteRemoteDescriptor_MultipleDescriptors) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadError
#else
#define MAYBE_ReadError
#endif
// Tests ReadRemoteDescriptor asynchronous error.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, ReadError) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_ReadError) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteError
#else
#define MAYBE_WriteError
#endif
// Tests WriteRemoteDescriptor asynchronous error.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt, WriteError) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_WriteError) {}

#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ReadSynchronousError
#else
#define MAYBE_ReadSynchronousError
#endif
// Tests ReadRemoteDescriptor synchronous error.
// Test not relevant for macOS since descriptor read cannot generate
// synchronous error.
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_ReadSynchronousError) {}

#if BUILDFLAG(IS_ANDROID)
#define MAYBE_WriteSynchronousError
#else
#define MAYBE_WriteSynchronousError
#endif
// Tests WriteRemoteDescriptor synchronous error.
// Test not relevant for macOS since descriptor write cannot generate
// synchronous error.
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_WriteSynchronousError) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadRemoteDescriptor_ReadPending
#else
#define MAYBE_ReadRemoteDescriptor_ReadPending
#endif
// Tests ReadRemoteDescriptor error with a pending read operation.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt,
       ReadRemoteDescriptor_ReadPending) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_ReadRemoteDescriptor_ReadPending) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteRemoteDescriptor_WritePending
#else
#define MAYBE_WriteRemoteDescriptor_WritePending
#endif
// Tests WriteRemoteDescriptor error with a pending write operation.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt,
       WriteRemoteDescriptor_WritePending) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_WriteRemoteDescriptor_WritePending) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_ReadRemoteDescriptor_WritePending
#else
#define MAYBE_ReadRemoteDescriptor_WritePending
#endif
// Tests ReadRemoteDescriptor error with a pending write operation.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt,
       ReadRemoteDescriptor_WritePending) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_ReadRemoteDescriptor_WritePending) {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
#define MAYBE_WriteRemoteDescriptor_ReadPending
#else
#define MAYBE_WriteRemoteDescriptor_ReadPending
#endif
// Tests WriteRemoteDescriptor error with a pending Read operation.
#if BUILDFLAG(IS_WIN)
TEST_P(BluetoothRemoteGattDescriptorTestWinrt,
       WriteRemoteDescriptor_ReadPending) {
#else
TEST_F(BluetoothRemoteGattDescriptorTest,
       MAYBE_WriteRemoteDescriptor_ReadPending) {}

#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ReadDuringDisconnect
#else
#define MAYBE_ReadDuringDisconnect
#endif
// Tests that read requests after a device disconnects but before the
// disconnect task runs do not result in a crash.
// macOS: Does not apply. All events arrive on the UI Thread.
// TODO(crbug.com/41303035): Enable this test on Windows.
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_ReadDuringDisconnect) {}

#if BUILDFLAG(IS_ANDROID)
#define MAYBE_WriteDuringDisconnect
#else
#define MAYBE_WriteDuringDisconnect
#endif
// Tests that write requests after a device disconnects but before the
// disconnect task runs do not result in a crash.
// macOS: Does not apply. All events arrive on the UI Thread.
// TODO(crbug.com/41303035): Enable this test on Windows.
TEST_F(BluetoothRemoteGattDescriptorTest, MAYBE_WriteDuringDisconnect) {}

#if BUILDFLAG(IS_APPLE)
// Tests NSString for descriptor value for macOS.
// https://developer.apple.com/reference/corebluetooth/cbdescriptor
TEST_F(BluetoothRemoteGattDescriptorTest, ReadRemoteDescriptor_NSString) {
  ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());

  descriptor1_->ReadRemoteDescriptor(
      GetReadValueCallback(Call::EXPECTED, Result::SUCCESS));
  EXPECT_EQ(1, gatt_read_descriptor_attempts_);

  std::string test_string = "Hello";
  SimulateGattDescriptorReadNSStringMac(descriptor1_, test_string);
  base::RunLoop().RunUntilIdle();

  std::vector<uint8_t> test_vector(test_string.begin(), test_string.end());
  EXPECT_EQ(test_vector, last_read_value_);
  EXPECT_EQ(test_vector, descriptor1_->GetValue());
}

// Tests NSNumber for descriptor value for macOS.
// https://developer.apple.com/reference/corebluetooth/cbdescriptor
TEST_F(BluetoothRemoteGattDescriptorTest, ReadRemoteDescriptor_NSNumber) {
  ASSERT_NO_FATAL_FAILURE(FakeDescriptorBoilerplate());

  descriptor1_->ReadRemoteDescriptor(
      GetReadValueCallback(Call::EXPECTED, Result::SUCCESS));
  EXPECT_EQ(1, gatt_read_descriptor_attempts_);

  const short test_number = 0x1234;
  SimulateGattDescriptorReadNSNumberMac(descriptor1_, test_number);
  base::RunLoop().RunUntilIdle();

  uint8_t values[] = {0x34, 0x12};
  std::vector<uint8_t> test_vector(values, values + std::size(values));
  EXPECT_EQ(test_vector, last_read_value_);
  EXPECT_EQ(test_vector, descriptor1_->GetValue());
}
#endif  // BUILDFLAG(IS_APPLE)

#if BUILDFLAG(IS_WIN)
INSTANTIATE_TEST_SUITE_P(All,
                         BluetoothRemoteGattDescriptorTestWinrt,
                         ::testing::ValuesIn(kBluetoothTestWinrtParam));
#endif  // BUILDFLAG(IS_WIN)

}  // namespace device