chromium/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl_unittest.cc

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

#include "ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl.h"

#include <cstdint>
#include <iomanip>
#include <memory>
#include <sstream>
#include <vector>

#include "ash/quick_pair/common/constants.h"
#include "ash/quick_pair/common/device.h"
#include "ash/quick_pair/common/fast_pair/fast_pair_service_data_creator.h"
#include "ash/quick_pair/common/pair_failure.h"
#include "ash/quick_pair/proto/fastpair.pb.h"
#include "ash/quick_pair/repository/fake_fast_pair_repository.h"
#include "ash/quick_pair/repository/fast_pair/device_metadata.h"
#include "ash/quick_pair/repository/fast_pair/pairing_metadata.h"
#include "ash/quick_pair/scanning/fast_pair/fake_fast_pair_scanner.h"
#include "ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/services/quick_pair/fast_pair_data_parser.h"
#include "chromeos/ash/services/quick_pair/mock_quick_pair_process_manager.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process_manager.h"
#include "chromeos/ash/services/quick_pair/quick_pair_process_manager_impl.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

constexpr int kNotDiscoverableAdvHeader = 0b00000110;
constexpr int kAccountKeyFilterHeader = 0b01100000;
constexpr int kAccountKeyFilterNoNotificationHeader = 0b01100010;
constexpr int kBatteryHeader = 0b00110011;
constexpr int kSaltHeader = 0b00010001;
constexpr long kModelIdLong = 7441431;
const std::string kModelIdString = "718c17";
const std::string kAccountKeyFilter = "112233445566";
const std::string kSalt = "01";
const std::string kBattery = "01048F";
const std::string kInvalidBattery = "F1F48F";
const std::string kBatteryUnknownValue = "3FFFFF";
const std::string kModelId = "112233";
const std::string kAddress = "test_address";

}  // namespace

namespace ash {
namespace quick_pair {

class FastPairNotDiscoverableScannerImplTest : public testing::Test {
 public:
  void SetUp() override {
    repository_ = std::make_unique<FakeFastPairRepository>();

    scanner_ = base::MakeRefCounted<FakeFastPairScanner>();

    data_parser_ = std::make_unique<ash::quick_pair::FastPairDataParser>(
        fast_pair_data_parser_.InitWithNewPipeAndPassReceiver());

    data_parser_remote_.Bind(std::move(fast_pair_data_parser_),
                             task_enviornment_.GetMainThreadTaskRunner());

    process_manager_ = std::make_unique<MockQuickPairProcessManager>();
    quick_pair_process::SetProcessManager(process_manager_.get());

    adapter_ =
        base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();

    not_discoverable_scanner_ =
        std::make_unique<FastPairNotDiscoverableScannerImpl>(
            scanner_, adapter_, found_device_callback_.Get(),
            lost_device_callback_.Get());
  }

 protected:
  std::vector<uint8_t> GetDiscoverableAdvServicedata() {
    std::vector<uint8_t> model_id_bytes;
    base::HexStringToBytes(kModelIdString, &model_id_bytes);
    return model_id_bytes;
  }

  std::vector<uint8_t> GetAdvNoUiServicedata() {
    return FastPairServiceDataCreator::Builder()
        .SetHeader(kNotDiscoverableAdvHeader)
        .SetModelId(kModelIdString)
        .AddExtraFieldHeader(kAccountKeyFilterNoNotificationHeader)
        .AddExtraField(kAccountKeyFilter)
        .AddExtraFieldHeader(kSaltHeader)
        .AddExtraField(kSalt)
        .Build()
        ->CreateServiceData();
  }

  std::vector<uint8_t> GetAdvServicedata() {
    return FastPairServiceDataCreator::Builder()
        .SetHeader(kNotDiscoverableAdvHeader)
        .SetModelId(kModelIdString)
        .AddExtraFieldHeader(kAccountKeyFilterHeader)
        .AddExtraField(kAccountKeyFilter)
        .AddExtraFieldHeader(kSaltHeader)
        .AddExtraField(kSalt)
        .Build()
        ->CreateServiceData();
  }

  std::vector<uint8_t> GetAdvBatteryServicedata() {
    return FastPairServiceDataCreator::Builder()
        .SetHeader(kNotDiscoverableAdvHeader)
        .SetModelId(kModelId)
        .AddExtraFieldHeader(kAccountKeyFilterHeader)
        .AddExtraField(kAccountKeyFilter)
        .AddExtraFieldHeader(kSaltHeader)
        .AddExtraField(kSalt)
        .AddExtraFieldHeader(kBatteryHeader)
        .AddExtraField(kBattery)
        .Build()
        ->CreateServiceData();
  }

  std::vector<uint8_t> GetAdvInvalidBatteryServicedata() {
    return FastPairServiceDataCreator::Builder()
        .SetHeader(kNotDiscoverableAdvHeader)
        .SetModelId(kModelId)
        .AddExtraFieldHeader(kAccountKeyFilterHeader)
        .AddExtraField(kAccountKeyFilter)
        .AddExtraFieldHeader(kSaltHeader)
        .AddExtraField(kSalt)
        .AddExtraFieldHeader(kBatteryHeader)
        .AddExtraField(kInvalidBattery)
        .Build()
        ->CreateServiceData();
  }

  std::vector<uint8_t> GetAdvUnknownBatteryServicedata() {
    return FastPairServiceDataCreator::Builder()
        .SetHeader(kNotDiscoverableAdvHeader)
        .SetModelId(kModelId)
        .AddExtraFieldHeader(kAccountKeyFilterHeader)
        .AddExtraField(kAccountKeyFilter)
        .AddExtraFieldHeader(kSaltHeader)
        .AddExtraField(kSalt)
        .AddExtraFieldHeader(kBatteryHeader)
        .AddExtraField(kBatteryUnknownValue)
        .Build()
        ->CreateServiceData();
  }

  device::BluetoothDevice* GetDevice(const std::vector<uint8_t>& service_data,
                                     bool is_paired = false) {
    auto device = std::make_unique<device::MockBluetoothDevice>(
        adapter_.get(), 0, "test_name", kAddress, /*paired=*/is_paired,
        /*connected=*/false);
    device::BluetoothDevice* device_ptr = device.get();

    device->SetServiceDataForUUID(kFastPairBluetoothUuid, service_data);

    adapter_->AddMockDevice(std::move(device));
    ON_CALL(*adapter_, GetDevice(kAddress))
        .WillByDefault(testing::Return(device_ptr));

    return device_ptr;
  }

  base::test::SingleThreadTaskEnvironment task_enviornment_;
  scoped_refptr<FakeFastPairScanner> scanner_;
  std::unique_ptr<FakeFastPairRepository> repository_;
  std::unique_ptr<FastPairNotDiscoverableScanner> not_discoverable_scanner_;
  scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> adapter_;
  std::unique_ptr<MockQuickPairProcessManager> process_manager_;
  mojo::SharedRemote<mojom::FastPairDataParser> data_parser_remote_;
  mojo::PendingRemote<mojom::FastPairDataParser> fast_pair_data_parser_;
  std::unique_ptr<FastPairDataParser> data_parser_;
  base::MockCallback<DeviceCallback> found_device_callback_;
  base::MockCallback<DeviceCallback> lost_device_callback_;
};

// TODO(crbug.com/40822900) flaky on ASan + LSan bots
#if defined(ADDRESS_SANITIZER) && defined(LEAK_SANITIZER)
#define MAYBE_UtilityProcessStopped_FailedAllRetryAttempts \
  DISABLED_UtilityProcessStopped_FailedAllRetryAttempts
#else
#define MAYBE_UtilityProcessStopped_FailedAllRetryAttempts \
  UtilityProcessStopped_FailedAllRetryAttempts
#endif
TEST_F(FastPairNotDiscoverableScannerImplTest,
       MAYBE_UtilityProcessStopped_FailedAllRetryAttempts) {
  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());
  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            std::move(callback).Run(
                QuickPairProcessManager::ShutdownReason::kCrash);
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  scanner_->NotifyDeviceFound(device);
}

// TODO(crbug.com/40822900) flaky on ASan + LSan bots
#if defined(ADDRESS_SANITIZER) && defined(LEAK_SANITIZER)
#define MAYBE_UtilityProcessStopped_DeviceLost \
  DISABLED_UtilityProcessStopped_DeviceLost
#else
#define MAYBE_UtilityProcessStopped_DeviceLost \
  UtilityProcessStopped_DeviceLost
#endif
TEST_F(FastPairNotDiscoverableScannerImplTest,
       MAYBE_UtilityProcessStopped_DeviceLost) {
  auto device = std::make_unique<device::MockBluetoothDevice>(
      adapter_.get(), 0, "test_name", kAddress, /*paired=*/false,
      /*connected=*/false);
  device->SetServiceDataForUUID(kFastPairBluetoothUuid, {1, 2, 3});

  device::BluetoothDevice* device_ptr = device.get();

  adapter_->AddMockDevice(std::move(device));
  ON_CALL(*adapter_, GetDevice(kAddress))
      .WillByDefault(testing::Return(nullptr));

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            std::move(callback).Run(
                QuickPairProcessManager::ShutdownReason::kCrash);
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  scanner_->NotifyDeviceFound(device_ptr);
}

// TODO(crbug.com/40822900) flaky on ASan + LSan bots
#if defined(ADDRESS_SANITIZER) && defined(LEAK_SANITIZER)
#define MAYBE_UtilityProcessStopped_FastPairServiceDataLost \
  DISABLED_UtilityProcessStopped_FastPairServiceDataLost
#else
#define MAYBE_UtilityProcessStopped_FastPairServiceDataLost \
  UtilityProcessStopped_FastPairServiceDataLost
#endif
TEST_F(FastPairNotDiscoverableScannerImplTest,
       MAYBE_UtilityProcessStopped_FastPairServiceDataLost) {
  auto device = std::make_unique<device::MockBluetoothDevice>(
      adapter_.get(), 0, "test_name", kAddress, /*paired=*/false,
      /*connected=*/false);
  device::BluetoothDevice* device_ptr = device.get();

  auto* mock_device = static_cast<device::MockBluetoothDevice*>(device_ptr);

  device->SetServiceDataForUUID(kFastPairBluetoothUuid, GetAdvServicedata());

  adapter_->AddMockDevice(std::move(device));
  ON_CALL(*adapter_, GetDevice(kAddress))
      .WillByDefault(testing::Return(device_ptr));

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            std::move(callback).Run(
                QuickPairProcessManager::ShutdownReason::kCrash);
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  scanner_->NotifyDeviceFound(device_ptr);
  mock_device->SetServiceDataForUUID(kFastPairBluetoothUuid, {});
}

TEST_F(FastPairNotDiscoverableScannerImplTest, NoServiceData) {
  EXPECT_CALL(found_device_callback_, Run).Times(0);
  std::unique_ptr<device::BluetoothDevice> device =
      base::WrapUnique(static_cast<device::BluetoothDevice*>(
          new testing::NiceMock<device::MockBluetoothDevice>(
              adapter_.get(), 0, "test_name", "test_address",
              /*paired=*/false,
              /*connected=*/false)));

  scanner_->NotifyDeviceFound(device.get());
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotDiscoverableScannerImplTest, NoParsedAdvertisement) {
  EXPECT_CALL(found_device_callback_, Run).Times(0);
  device::BluetoothDevice* device = GetDevice(GetDiscoverableAdvServicedata());
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotDiscoverableScannerImplTest, DontShowUI) {
  EXPECT_CALL(found_device_callback_, Run).Times(0);
  device::BluetoothDevice* device = GetDevice(GetAdvNoUiServicedata());
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotDiscoverableScannerImplTest, NoMetadata) {
  EXPECT_CALL(found_device_callback_, Run).Times(0);
  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotDiscoverableScannerImplTest, DeviceLostDuringParsing) {
  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  EXPECT_CALL(found_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceFound(device);
  scanner_->NotifyDeviceLost(device);

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

TEST_F(FastPairNotDiscoverableScannerImplTest, NoModelId) {
  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceFound(device);

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

TEST_F(FastPairNotDiscoverableScannerImplTest, InvokesLostCallbackAfterFound) {
  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  EXPECT_CALL(found_device_callback_, Run).Times(1);
  scanner_->NotifyDeviceFound(device);

  base::RunLoop().RunUntilIdle();

  EXPECT_CALL(lost_device_callback_, Run).Times(1);
  scanner_->NotifyDeviceLost(device);

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

TEST_F(FastPairNotDiscoverableScannerImplTest, AlreadySavedToChromebook) {
  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(true);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  EXPECT_CALL(lost_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceFound(device);

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

TEST_F(FastPairNotDiscoverableScannerImplTest, FactoryCreate) {
  not_discoverable_scanner_.reset();
  std::unique_ptr<FastPairNotDiscoverableScanner>
      discoverable_scanner_from_factory =
          FastPairNotDiscoverableScannerImpl::Factory::Create(
              scanner_, adapter_, found_device_callback_.Get(),
              lost_device_callback_.Get());

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  EXPECT_CALL(found_device_callback_, Run).Times(1);

  device::BluetoothDevice* device = GetDevice(GetAdvBatteryServicedata());
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotDiscoverableScannerImplTest,
       DoesntInvokeLostCallbackIfDidntInvokeFound) {
  EXPECT_CALL(found_device_callback_, Run).Times(0);
  EXPECT_CALL(lost_device_callback_, Run).Times(0);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });
  device::BluetoothDevice* device = GetDevice(std::vector<uint8_t>());
  scanner_->NotifyDeviceLost(device);
  base::RunLoop().RunUntilIdle();
}

TEST_F(FastPairNotDiscoverableScannerImplTest, SetBatteryInfo) {
  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(1);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  device::BluetoothDevice* device = GetDevice(GetAdvBatteryServicedata());
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(std::nullopt, device->GetBatteryInfo(
                              device::BluetoothDevice::BatteryType::kDefault));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kLeftBudTrueWireless));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kRightBudTrueWireless));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kCaseTrueWireless));
}

TEST_F(FastPairNotDiscoverableScannerImplTest, SetUnknownBatteryInfo) {
  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(1);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  device::BluetoothDevice* device =
      GetDevice(GetAdvUnknownBatteryServicedata());
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(std::nullopt, device->GetBatteryInfo(
                              device::BluetoothDevice::BatteryType::kDefault));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kLeftBudTrueWireless));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kRightBudTrueWireless));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kCaseTrueWireless));
}

TEST_F(FastPairNotDiscoverableScannerImplTest, SetInvalidPercentBatteryInfo) {
  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  repository_->set_is_account_key_paired_locally(false);

  EXPECT_CALL(found_device_callback_, Run).Times(1);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  device::BluetoothDevice* device =
      GetDevice(GetAdvInvalidBatteryServicedata());
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(std::nullopt, device->GetBatteryInfo(
                              device::BluetoothDevice::BatteryType::kDefault));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kLeftBudTrueWireless));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kRightBudTrueWireless));
  EXPECT_NE(std::nullopt,
            device->GetBatteryInfo(
                device::BluetoothDevice::BatteryType::kCaseTrueWireless));
}

TEST_F(FastPairNotDiscoverableScannerImplTest, AlreadyInitialPaired) {
  device::BluetoothDevice* device =
      GetDevice(GetAdvServicedata(), /*is_paired=*/true);

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  // After initial pairing, we'll save the account key locally.
  repository_->set_is_account_key_paired_locally(true);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_CALL(lost_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceLost(device);

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

// TODO(b/242891006): Re-enable this test after the bug is fixed.
TEST_F(FastPairNotDiscoverableScannerImplTest, DISABLED_AlreadyClassicPaired) {
  device::BluetoothDevice* device =
      GetDevice(GetAdvServicedata(), /*is_paired=*/true);

  nearby::fastpair::GetObservedDeviceResponse response;
  response.mutable_device()->set_id(kModelIdLong);
  response.mutable_device()->set_trigger_distance(2);

  auto device_metadata =
      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
  PairingMetadata pairing_metadata(device_metadata.get(),
                                   std::vector<uint8_t>());
  repository_->SetCheckAccountKeysResult(pairing_metadata);
  // When classic pairing, the user elects to not save their account key.
  repository_->set_is_account_key_paired_locally(false);
  EXPECT_CALL(*process_manager_, GetProcessReference)
      .WillRepeatedly(
          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
            return std::make_unique<
                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
                data_parser_remote_, base::DoNothing());
          });

  EXPECT_CALL(found_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceFound(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_CALL(lost_device_callback_, Run).Times(0);
  scanner_->NotifyDeviceLost(device);

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

}  // namespace quick_pair
}  // namespace ash