chromium/chromeos/ash/components/phonehub/do_not_disturb_controller_impl_unittest.cc

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

#include "chromeos/ash/components/phonehub/do_not_disturb_controller_impl.h"

#include <memory>

#include "chromeos/ash/components/phonehub/fake_message_sender.h"
#include "chromeos/ash/components/phonehub/fake_user_action_recorder.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace phonehub {
namespace {

class FakeObserver : public DoNotDisturbController::Observer {
 public:
  FakeObserver() = default;
  ~FakeObserver() override = default;

  size_t num_calls() const { return num_calls_; }

  // DoNotDisturbController::Observer:
  void OnDndStateChanged() override { ++num_calls_; }

 private:
  size_t num_calls_ = 0;
};

}  // namespace

class DoNotDisturbControllerImplTest : public testing::Test {
 protected:
  DoNotDisturbControllerImplTest() = default;
  DoNotDisturbControllerImplTest(const DoNotDisturbControllerImplTest&) =
      delete;
  DoNotDisturbControllerImplTest& operator=(
      const DoNotDisturbControllerImplTest&) = delete;
  ~DoNotDisturbControllerImplTest() override = default;

  // testing::Test:
  void SetUp() override {
    controller_ = std::make_unique<DoNotDisturbControllerImpl>(
        &fake_message_sender_, &fake_user_action_recorder_);
    controller_->AddObserver(&fake_observer_);
  }

  void TearDown() override { controller_->RemoveObserver(&fake_observer_); }

  bool IsDndEnabled() const { return controller_->IsDndEnabled(); }

  bool CanRequestNewDndState() const {
    return controller_->CanRequestNewDndState();
  }

  void SetDoNotDisturbInternal(bool is_dnd_enabled,
                               bool can_request_new_dnd_state) {
    controller_->SetDoNotDisturbStateInternal(is_dnd_enabled,
                                              can_request_new_dnd_state);
  }

  void RequestNewDoNotDisturbState(bool enabled) {
    controller_->RequestNewDoNotDisturbState(enabled);
  }

  bool GetRecentUpdateNotificationModeRequest() {
    return fake_message_sender_.GetRecentUpdateNotificationModeRequest();
  }

  size_t GetUpdateNotificationModeRequestCallCount() {
    return fake_message_sender_.GetUpdateNotificationModeRequestCallCount();
  }

  size_t GetNumObserverCalls() const { return fake_observer_.num_calls(); }

  FakeUserActionRecorder fake_user_action_recorder_;

 private:
  FakeObserver fake_observer_;

  FakeMessageSender fake_message_sender_;

  std::unique_ptr<DoNotDisturbControllerImpl> controller_;
};

TEST_F(DoNotDisturbControllerImplTest, SetInternalStatesWithObservers) {
  EXPECT_FALSE(IsDndEnabled());

  SetDoNotDisturbInternal(/*is_dnd_enabled=*/true,
                          /*can_request_new_dnd_state=*/true);
  EXPECT_TRUE(IsDndEnabled());
  EXPECT_TRUE(CanRequestNewDndState());
  EXPECT_EQ(1u, GetNumObserverCalls());

  SetDoNotDisturbInternal(/*is_dnd_enabled=*/false,
                          /*can_request_new_dnd_state=*/true);
  EXPECT_FALSE(IsDndEnabled());
  EXPECT_TRUE(CanRequestNewDndState());
  EXPECT_EQ(2u, GetNumObserverCalls());

  // Setting internal dnd state with the same previous state will not trigger an
  // observer event.
  SetDoNotDisturbInternal(/*is_dnd_enabled=*/false,
                          /*can_request_new_dnd_state=*/true);
  EXPECT_FALSE(IsDndEnabled());
  EXPECT_TRUE(CanRequestNewDndState());
  EXPECT_EQ(2u, GetNumObserverCalls());

  // Changing |can_request_new_dnd_state| should also trigger an observer event.
  SetDoNotDisturbInternal(/*is_dnd_enabled=*/false,
                          /*can_request_new_dnd_state=*/false);
  EXPECT_FALSE(IsDndEnabled());
  EXPECT_FALSE(CanRequestNewDndState());
  EXPECT_EQ(3u, GetNumObserverCalls());

  // No new changes, expect no observer call.
  SetDoNotDisturbInternal(/*is_dnd_enabled=*/false,
                          /*can_request_new_dnd_state=*/false);
  EXPECT_FALSE(IsDndEnabled());
  EXPECT_FALSE(CanRequestNewDndState());
  EXPECT_EQ(3u, GetNumObserverCalls());

  // Both states are changed, expect an observer call.
  SetDoNotDisturbInternal(/*is_dnd_enabled=*/true,
                          /*can_request_new_dnd_state=*/true);
  EXPECT_TRUE(IsDndEnabled());
  EXPECT_TRUE(CanRequestNewDndState());
  EXPECT_EQ(4u, GetNumObserverCalls());
}

TEST_F(DoNotDisturbControllerImplTest, RequestNewDoNotDisturbState) {
  RequestNewDoNotDisturbState(/*enabled=*/true);
  EXPECT_EQ(1u, fake_user_action_recorder_.num_dnd_attempts());
  EXPECT_TRUE(GetRecentUpdateNotificationModeRequest());
  EXPECT_EQ(1u, GetUpdateNotificationModeRequestCallCount());
  // Simulate receiving a response and setting the internal value.
  SetDoNotDisturbInternal(/*is_dnd_enabled=*/true,
                          /*can_request_new_dnd_state=*/true);

  RequestNewDoNotDisturbState(/*enabled=*/false);
  EXPECT_EQ(2u, fake_user_action_recorder_.num_dnd_attempts());
  EXPECT_FALSE(GetRecentUpdateNotificationModeRequest());
  EXPECT_EQ(2u, GetUpdateNotificationModeRequestCallCount());
  // Simulate receiving a response and setting the internal value.
  SetDoNotDisturbInternal(/*is_dnd_enabled=*/false,
                          /*can_request_new_dnd_state=*/true);

  // Requesting for a the same state as the currently set state is a no-op.
  RequestNewDoNotDisturbState(/*enabled=*/false);
  EXPECT_EQ(2u, fake_user_action_recorder_.num_dnd_attempts());
  EXPECT_FALSE(GetRecentUpdateNotificationModeRequest());
  EXPECT_EQ(2u, GetUpdateNotificationModeRequestCallCount());
}

}  // namespace phonehub
}  // namespace ash