chromium/ash/system/power/adaptive_charging_notification_controller_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/system/power/adaptive_charging_notification_controller.h"

#include <string>

#include "ash/constants/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/containers/contains.h"
#include "base/i18n/rtl.h"
#include "base/run_loop.h"
#include "base/test/icu_test_util.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "ui/message_center/message_center.h"

namespace ash {

namespace {

constexpr base::Time::Exploded kTestDateTimeExploded = {.year = 2022,
                                                        .month = 4,
                                                        .day_of_week = 5,
                                                        .day_of_month = 29,
                                                        .hour = 2,
                                                        .minute = 42,
                                                        .second = 7};

// Enables or disables the user pref for the entire feature.
void SetAdaptiveChargingPref(bool enabled) {
  Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
      prefs::kPowerAdaptiveChargingEnabled, enabled);
  base::RunLoop().RunUntilIdle();
}

// Returns the number of (popup or non-popup) notifications that are currently
// visible in the message center queue.
size_t VisibleNotificationCount() {
  return message_center::MessageCenter::Get()->GetVisibleNotifications().size();
}

}  // namespace

class AdaptiveChargingNotificationControllerTest : public AshTestBase {
 public:
  AdaptiveChargingNotificationControllerTest() = default;
  AdaptiveChargingNotificationControllerTest(
      const AdaptiveChargingNotificationControllerTest&) = delete;
  AdaptiveChargingNotificationControllerTest& operator=(
      const AdaptiveChargingNotificationControllerTest&) = delete;
  ~AdaptiveChargingNotificationControllerTest() override = default;

  // AshTestBase:
  void SetUp() override {
    AshTestBase::SetUp();
    controller_ = std::make_unique<AdaptiveChargingNotificationController>();
  }

  AdaptiveChargingNotificationController* GetController() {
    return controller_.get();
  }

  void SimulateClick(int button_index) {
    message_center::Notification* notification =
        message_center::MessageCenter::Get()->FindVisibleNotificationById(
            /*id=*/"adaptive-charging-notify-info");
    notification->delegate()->Click(button_index, std::nullopt);
  }

 private:
  std::unique_ptr<AdaptiveChargingNotificationController> controller_;
};

TEST_F(AdaptiveChargingNotificationControllerTest, ShouldntShowNotification) {
  SetAdaptiveChargingPref(false);

  GetController()->ShowAdaptiveChargingNotification();
  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));

  EXPECT_EQ(VisibleNotificationCount(), 0u);
}

TEST_F(AdaptiveChargingNotificationControllerTest, ShowNotificationWithHour) {
  SetAdaptiveChargingPref(true);
  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));

  EXPECT_EQ(VisibleNotificationCount(), 1u);
}

TEST_F(AdaptiveChargingNotificationControllerTest,
       ShowNotificationWithoutHour) {
  SetAdaptiveChargingPref(true);
  GetController()->ShowAdaptiveChargingNotification();

  EXPECT_EQ(VisibleNotificationCount(), 1u);
}

TEST_F(AdaptiveChargingNotificationControllerTest, HaveTimeInNotification) {
  // Set default locale.
  base::test::ScopedRestoreICUDefaultLocale restore_locale;
  base::i18n::SetICUDefaultLocale("en_AU");
  base::test::ScopedRestoreDefaultTimezone sydney_time("Australia/Sydney");

  // Override time for testing.
  base::subtle::ScopedTimeClockOverrides time_override(
      []() {
        base::Time time;
        EXPECT_TRUE(base::Time::FromUTCExploded(kTestDateTimeExploded, &time));
        return time;
      },
      /*time_ticks_override=*/nullptr,
      /*thread_ticks_override=*/nullptr);

  SetAdaptiveChargingPref(true);
  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));

  const message_center::Notification* notification =
      message_center::MessageCenter::Get()->FindPopupNotificationById(
          "adaptive-charging-notify-info");

  ASSERT_TRUE(notification);

  // Current local time is 12:42 pm, so 5 hours after should be 5:30pm (rounding
  // from 5:42pm).
  EXPECT_TRUE(base::Contains(notification->message(), u"5:30\u202fpm"));
}

TEST_F(AdaptiveChargingNotificationControllerTest, TimeRoundingUpTest) {
  // Set default locale.
  base::test::ScopedRestoreICUDefaultLocale restore_locale;
  base::i18n::SetICUDefaultLocale("en_AU");
  base::test::ScopedRestoreDefaultTimezone sydney_time("Australia/Sydney");

  // Override time for testing.
  base::subtle::ScopedTimeClockOverrides time_override(
      []() {
        base::Time time;
        EXPECT_TRUE(base::Time::FromUTCExploded(kTestDateTimeExploded, &time));
        return time + base::Minutes(2);  // Local time is 12:44pm.
      },
      /*time_ticks_override=*/nullptr,
      /*thread_ticks_override=*/nullptr);

  SetAdaptiveChargingPref(true);
  GetController()->ShowAdaptiveChargingNotification(
      base::Seconds(5 * 3600 + 120));

  const message_center::Notification* notification =
      message_center::MessageCenter::Get()->FindPopupNotificationById(
          "adaptive-charging-notify-info");

  ASSERT_TRUE(notification);

  // Current local time is 12:44 pm, so 5 hours 2 mins after should be 6:00pm
  // (rounding from 5:46pm).
  EXPECT_TRUE(base::Contains(notification->message(), u"6:00\u202fpm"));
}

TEST_F(AdaptiveChargingNotificationControllerTest,
       ClickButtonMakesNotificationDisappear) {
  SetAdaptiveChargingPref(true);
  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));
  EXPECT_EQ(VisibleNotificationCount(), 1u);

  // Notification should disappear after click.
  SimulateClick(/*button_index=*/0);
  EXPECT_EQ(VisibleNotificationCount(), 0u);
}

}  // namespace ash