chromium/ash/quick_pair/ui/ui_broker_impl_unittest.cc

// Copyright 2022 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/ui/ui_broker_impl.h"

#include "ash/constants/ash_features.h"
#include "ash/quick_pair/common/constants.h"
#include "ash/quick_pair/common/device.h"
#include "ash/quick_pair/ui/fast_pair/fast_pair_presenter.h"
#include "ash/quick_pair/ui/fast_pair/fast_pair_presenter_impl.h"
#include "ash/quick_pair/ui/ui_broker.h"
#include "ash/test/ash_test_base.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/message_center.h"

namespace {

constexpr char kTestDeviceAddress[] = "11:12:13:14:15:16";
constexpr char kValidModelId[] = "718c17";

class FakeFastPairPresenter : public ash::quick_pair::FastPairPresenter {
 public:
  FakeFastPairPresenter(message_center::MessageCenter* message_center) {}

  ~FakeFastPairPresenter() override = default;

  void ShowDiscovery(scoped_refptr<ash::quick_pair::Device> device,
                     ash::quick_pair::DiscoveryCallback callback) override {
    callback.Run(ash::quick_pair::DiscoveryAction::kPairToDevice);
  }

  void ShowPairing(scoped_refptr<ash::quick_pair::Device> device) override {
    show_pairing_ = true;
  }

  bool show_pairing() { return show_pairing_; }

  void ShowPairingFailed(
      scoped_refptr<ash::quick_pair::Device> device,
      ash::quick_pair::PairingFailedCallback callback) override {
    callback.Run(ash::quick_pair::PairingFailedAction::kNavigateToSettings);
    show_pairing_failed_ = true;
  }

  bool show_pairing_failed() { return show_pairing_failed_; }

  void ShowAssociateAccount(
      scoped_refptr<ash::quick_pair::Device> device,
      ash::quick_pair::AssociateAccountCallback callback) override {
    callback.Run(ash::quick_pair::AssociateAccountAction::kLearnMore);
  }

  void ShowInstallCompanionApp(
      scoped_refptr<ash::quick_pair::Device> device,
      ash::quick_pair::CompanionAppCallback callback) override {
    callback.Run(ash::quick_pair::CompanionAppAction::kDownloadAndLaunchApp);
  }

  void ShowLaunchCompanionApp(
      scoped_refptr<ash::quick_pair::Device> device,
      ash::quick_pair::CompanionAppCallback callback) override {
    callback.Run(ash::quick_pair::CompanionAppAction::kLaunchApp);
  }

  void RemoveNotifications() override { removed_ = true; }

  void ExtendNotification() override { notification_extended_ = true; }

  bool removed() { return removed_; }

  bool notification_extended() { return notification_extended_; }

 private:
  bool show_pairing_ = false;
  bool removed_ = false;
  bool show_pairing_failed_ = false;
  bool notification_extended_ = false;
};

class FakeFastPairPresenterFactory
    : public ash::quick_pair::FastPairPresenterImpl::Factory {
 public:
  std::unique_ptr<ash::quick_pair::FastPairPresenter> CreateInstance(
      message_center::MessageCenter* message_center) override {
    auto fake_fast_pair_presenter =
        std::make_unique<FakeFastPairPresenter>(message_center);
    fake_fast_pair_presenter_ = fake_fast_pair_presenter.get();
    return fake_fast_pair_presenter;
  }

  ~FakeFastPairPresenterFactory() override = default;

  FakeFastPairPresenter* fake_fast_pair_presenter() {
    return fake_fast_pair_presenter_;
  }

 protected:
  raw_ptr<FakeFastPairPresenter, DanglingUntriaged> fake_fast_pair_presenter_ =
      nullptr;
};

}  // namespace

namespace ash {
namespace quick_pair {

class UIBrokerImplTest : public AshTestBase, public UIBroker::Observer {
 public:
  void SetUp() override {
    presenter_factory_ = std::make_unique<FakeFastPairPresenterFactory>();
    FastPairPresenterImpl::Factory::SetFactoryForTesting(
        presenter_factory_.get());

    // We need to make sure that we register the test factory before calling
    // `AshTestBase::SetUp()`, since the test setup will create the presenter
    // behind the scenes.
    AshTestBase::SetUp();

    ui_broker_ = std::make_unique<UIBrokerImpl>();
    ui_broker_->AddObserver(this);
  }

  void TearDown() override {
    ui_broker_->RemoveObserver(this);
    ui_broker_.reset();
    ClearLogin();
    AshTestBase::TearDown();
    FastPairPresenterImpl::Factory::SetFactoryForTesting(nullptr);
  }

  void OnDiscoveryAction(scoped_refptr<Device> device,
                         DiscoveryAction action) override {
    discovery_action_ = action;
  }

  void OnCompanionAppAction(scoped_refptr<Device> device,
                            CompanionAppAction action) override {
    companion_app_action_ = action;
  }

  void OnPairingFailureAction(scoped_refptr<Device> device,
                              PairingFailedAction action) override {
    pairing_failed_action_ = action;
  }

  void OnAssociateAccountAction(scoped_refptr<Device> device,
                                AssociateAccountAction action) override {
    associate_account_action_ = action;
  }

 protected:
  DiscoveryAction discovery_action_;
  PairingFailedAction pairing_failed_action_;
  AssociateAccountAction associate_account_action_;
  CompanionAppAction companion_app_action_;
  std::unique_ptr<FakeFastPairPresenterFactory> presenter_factory_;
  std::unique_ptr<UIBroker> ui_broker_;
};

TEST_F(UIBrokerImplTest, ShowDiscovery_Initial) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ShowDiscovery(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(discovery_action_, DiscoveryAction::kPairToDevice);
}

TEST_F(UIBrokerImplTest, ShowDiscovery_Subsequent) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  ui_broker_->ShowDiscovery(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(discovery_action_, DiscoveryAction::kPairToDevice);
}

TEST_F(UIBrokerImplTest, ShowPairing_Initial) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ShowPairing(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(presenter_factory_->fake_fast_pair_presenter()->show_pairing());
}

TEST_F(UIBrokerImplTest, ShowPairing_Subsequent) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  ui_broker_->ShowPairing(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(presenter_factory_->fake_fast_pair_presenter()->show_pairing());
}

TEST_F(UIBrokerImplTest, ShowPairingFailed_Initial) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ShowPairingFailed(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(pairing_failed_action_, PairingFailedAction::kNavigateToSettings);
}

TEST_F(UIBrokerImplTest, ShowPairingFailed_Subsequent) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  ui_broker_->ShowPairingFailed(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(pairing_failed_action_, PairingFailedAction::kNavigateToSettings);
}

TEST_F(UIBrokerImplTest, ShowPairingFailed_Retroactive) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  ui_broker_->ShowPairingFailed(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_FALSE(
      presenter_factory_->fake_fast_pair_presenter()->show_pairing_failed());
}

TEST_F(UIBrokerImplTest, ShowAssociateAccount_Initial) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ShowAssociateAccount(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(associate_account_action_, AssociateAccountAction::kLearnMore);
}

TEST_F(UIBrokerImplTest, ShowAssociateAccount_Retroactive) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  ui_broker_->ShowAssociateAccount(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(associate_account_action_, AssociateAccountAction::kLearnMore);
}

TEST_F(UIBrokerImplTest, ShowInstallCompanionApp_Initial_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      /*enabled_features=*/{},
      /*disabled_features=*/{ash::features::kFastPairPwaCompanion});

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  EXPECT_DEATH_IF_SUPPORTED({ ui_broker_->ShowInstallCompanionApp(device); },
                            "");
}

TEST_F(UIBrokerImplTest, ShowInstallCompanionApp_Initial_Enabled) {
  base::test::ScopedFeatureList feature_list{
      ash::features::kFastPairPwaCompanion};

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ShowInstallCompanionApp(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(companion_app_action_, CompanionAppAction::kDownloadAndLaunchApp);
}

TEST_F(UIBrokerImplTest, ShowInstallCompanionApp_Subsequent_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      /*enabled_features=*/{},
      /*disabled_features=*/{ash::features::kFastPairPwaCompanion});

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  EXPECT_DEATH_IF_SUPPORTED({ ui_broker_->ShowInstallCompanionApp(device); },
                            "");
}

TEST_F(UIBrokerImplTest, ShowInstallCompanionApp_Subsequent_Enabled) {
  base::test::ScopedFeatureList feature_list{
      ash::features::kFastPairPwaCompanion};

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  ui_broker_->ShowInstallCompanionApp(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(companion_app_action_, CompanionAppAction::kDownloadAndLaunchApp);
}

TEST_F(UIBrokerImplTest, ShowInstallCompanionApp_Retroactive_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      /*enabled_features=*/{},
      /*disabled_features=*/{ash::features::kFastPairPwaCompanion});

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  EXPECT_DEATH_IF_SUPPORTED({ ui_broker_->ShowInstallCompanionApp(device); },
                            "");
}

TEST_F(UIBrokerImplTest, ShowInstallCompanionApp_Retroactive_Enabled) {
  base::test::ScopedFeatureList feature_list{
      ash::features::kFastPairPwaCompanion};

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  ui_broker_->ShowInstallCompanionApp(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(companion_app_action_, CompanionAppAction::kDownloadAndLaunchApp);
}

TEST_F(UIBrokerImplTest, ShowLaunchCompanionApp_Initial_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      /*enabled_features=*/{},
      /*disabled_features=*/{ash::features::kFastPairPwaCompanion});

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  EXPECT_DEATH_IF_SUPPORTED({ ui_broker_->ShowLaunchCompanionApp(device); },
                            "");
}

TEST_F(UIBrokerImplTest, ShowLaunchCompanionApp_Initial_Enabled) {
  base::test::ScopedFeatureList feature_list{
      ash::features::kFastPairPwaCompanion};

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ShowLaunchCompanionApp(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(companion_app_action_, CompanionAppAction::kLaunchApp);
}

TEST_F(UIBrokerImplTest, ShowLaunchCompanionApp_Subsequent_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      /*enabled_features=*/{},
      /*disabled_features=*/{ash::features::kFastPairPwaCompanion});

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  EXPECT_DEATH_IF_SUPPORTED({ ui_broker_->ShowLaunchCompanionApp(device); },
                            "");
}

TEST_F(UIBrokerImplTest, ShowLaunchCompanionApp_Subsequent_Enabled) {
  base::test::ScopedFeatureList feature_list{
      ash::features::kFastPairPwaCompanion};

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  ui_broker_->ShowLaunchCompanionApp(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(companion_app_action_, CompanionAppAction::kLaunchApp);
}

TEST_F(UIBrokerImplTest, ShowLaunchCompanionApp_Retroactive_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      /*enabled_features=*/{},
      /*disabled_features=*/{ash::features::kFastPairPwaCompanion});

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  EXPECT_DEATH_IF_SUPPORTED({ ui_broker_->ShowLaunchCompanionApp(device); },
                            "");
}

TEST_F(UIBrokerImplTest, ShowLaunchCompanionApp_Retroactive_Enabled) {
  base::test::ScopedFeatureList feature_list{
      ash::features::kFastPairPwaCompanion};

  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  ui_broker_->ShowLaunchCompanionApp(device);
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(companion_app_action_, CompanionAppAction::kLaunchApp);
}

TEST_F(UIBrokerImplTest, RemoveNotifications_Initial) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->RemoveNotifications();
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(presenter_factory_->fake_fast_pair_presenter()->removed());
}

TEST_F(UIBrokerImplTest, RemoveNotifications_Subsequent) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairSubsequent);
  ui_broker_->RemoveNotifications();
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(presenter_factory_->fake_fast_pair_presenter()->removed());
}

TEST_F(UIBrokerImplTest, RemoveNotifications_Retroactive) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairRetroactive);
  ui_broker_->RemoveNotifications();
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(presenter_factory_->fake_fast_pair_presenter()->removed());
}

TEST_F(UIBrokerImplTest, ExtendNotifications) {
  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestDeviceAddress,
                                             Protocol::kFastPairInitial);
  ui_broker_->ExtendNotification();
  base::RunLoop().RunUntilIdle();

  EXPECT_TRUE(
      presenter_factory_->fake_fast_pair_presenter()->notification_extended());
}

}  // namespace quick_pair
}  // namespace ash