| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/power/power_status.h" |
| |
| #include <memory> |
| |
| #include "ash/resources/vector_icons/vector_icons.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| using power_manager::PowerSupplyProperties; |
| |
| namespace ash { |
| namespace { |
| |
| class TestObserver : public PowerStatus::Observer { |
| public: |
| TestObserver() : power_changed_count_(0) {} |
| ~TestObserver() override {} |
| |
| int power_changed_count() const { return power_changed_count_; } |
| |
| // PowerStatus::Observer overrides: |
| void OnPowerStatusChanged() override { ++power_changed_count_; } |
| |
| private: |
| int power_changed_count_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestObserver); |
| }; |
| |
| } // namespace |
| |
| class PowerStatusTest : public testing::Test { |
| public: |
| PowerStatusTest() |
| : scoped_task_environment_( |
| base::test::ScopedTaskEnvironment::MainThreadType::UI), |
| power_status_(NULL) {} |
| ~PowerStatusTest() override {} |
| |
| void SetUp() override { |
| chromeos::DBusThreadManager::Initialize(); |
| PowerStatus::Initialize(); |
| power_status_ = PowerStatus::Get(); |
| test_observer_.reset(new TestObserver); |
| power_status_->AddObserver(test_observer_.get()); |
| } |
| |
| void TearDown() override { |
| power_status_->RemoveObserver(test_observer_.get()); |
| test_observer_.reset(); |
| PowerStatus::Shutdown(); |
| chromeos::DBusThreadManager::Shutdown(); |
| } |
| |
| protected: |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| PowerStatus* power_status_; // Not owned. |
| std::unique_ptr<TestObserver> test_observer_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(PowerStatusTest); |
| }; |
| |
| TEST_F(PowerStatusTest, InitializeAndUpdate) { |
| // Test that the initial power supply state should be acquired after |
| // PowerStatus is instantiated. This depends on |
| // PowerManagerClientStubImpl, which responds to power status update |
| // requests, pretends there is a battery present, and generates some valid |
| // power supply status data. |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1, test_observer_->power_changed_count()); |
| |
| // Test RequestUpdate, test_obsever_ should be notified for power suuply |
| // status change. |
| power_status_->RequestStatusUpdate(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(2, test_observer_->power_changed_count()); |
| } |
| |
| TEST_F(PowerStatusTest, ShouldDisplayBatteryTime) { |
| EXPECT_FALSE( |
| PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(-1))); |
| EXPECT_FALSE( |
| PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(0))); |
| EXPECT_FALSE( |
| PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(59))); |
| EXPECT_TRUE( |
| PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(60))); |
| EXPECT_TRUE( |
| PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(600))); |
| EXPECT_TRUE(PowerStatus::ShouldDisplayBatteryTime( |
| base::TimeDelta::FromSeconds(3600))); |
| EXPECT_TRUE(PowerStatus::ShouldDisplayBatteryTime( |
| base::TimeDelta::FromSeconds(PowerStatus::kMaxBatteryTimeToDisplaySec))); |
| EXPECT_FALSE( |
| PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds( |
| PowerStatus::kMaxBatteryTimeToDisplaySec + 1))); |
| } |
| |
| TEST_F(PowerStatusTest, SplitTimeIntoHoursAndMinutes) { |
| int hours = 0, minutes = 0; |
| PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(0), |
| &hours, &minutes); |
| EXPECT_EQ(0, hours); |
| EXPECT_EQ(0, minutes); |
| |
| PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(60), |
| &hours, &minutes); |
| EXPECT_EQ(0, hours); |
| EXPECT_EQ(1, minutes); |
| |
| PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(3600), |
| &hours, &minutes); |
| EXPECT_EQ(1, hours); |
| EXPECT_EQ(0, minutes); |
| |
| PowerStatus::SplitTimeIntoHoursAndMinutes( |
| base::TimeDelta::FromSeconds(3600 + 60), &hours, &minutes); |
| EXPECT_EQ(1, hours); |
| EXPECT_EQ(1, minutes); |
| |
| PowerStatus::SplitTimeIntoHoursAndMinutes( |
| base::TimeDelta::FromSeconds(7 * 3600 + 23 * 60), &hours, &minutes); |
| EXPECT_EQ(7, hours); |
| EXPECT_EQ(23, minutes); |
| |
| // Check that minutes are rounded. |
| PowerStatus::SplitTimeIntoHoursAndMinutes( |
| base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 30), &hours, &minutes); |
| EXPECT_EQ(2, hours); |
| EXPECT_EQ(4, minutes); |
| |
| PowerStatus::SplitTimeIntoHoursAndMinutes( |
| base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 29), &hours, &minutes); |
| EXPECT_EQ(2, hours); |
| EXPECT_EQ(3, minutes); |
| |
| // Check that times close to hour boundaries aren't incorrectly rounded such |
| // that they display 60 minutes: http://crbug.com/368261 |
| PowerStatus::SplitTimeIntoHoursAndMinutes( |
| base::TimeDelta::FromSecondsD(3599.9), &hours, &minutes); |
| EXPECT_EQ(1, hours); |
| EXPECT_EQ(0, minutes); |
| |
| PowerStatus::SplitTimeIntoHoursAndMinutes( |
| base::TimeDelta::FromSecondsD(3600.1), &hours, &minutes); |
| EXPECT_EQ(1, hours); |
| EXPECT_EQ(0, minutes); |
| } |
| |
| TEST_F(PowerStatusTest, GetBatteryImageInfo) { |
| PowerSupplyProperties prop; |
| prop.set_external_power(PowerSupplyProperties::AC); |
| prop.set_battery_state(PowerSupplyProperties::CHARGING); |
| prop.set_battery_percent(98.0); |
| power_status_->SetProtoForTesting(prop); |
| const PowerStatus::BatteryImageInfo info_charging_98 = |
| power_status_->GetBatteryImageInfo(); |
| |
| // 99% should use the same icon as 98%. |
| prop.set_battery_percent(99.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(info_charging_98, power_status_->GetBatteryImageInfo()); |
| |
| // A different icon should be used when the battery is full. |
| prop.set_battery_state(PowerSupplyProperties::FULL); |
| prop.set_battery_percent(100.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_NE(info_charging_98, power_status_->GetBatteryImageInfo()); |
| |
| // A much-lower battery level should use a different icon. |
| prop.set_battery_state(PowerSupplyProperties::CHARGING); |
| prop.set_battery_percent(20.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_NE(info_charging_98, power_status_->GetBatteryImageInfo()); |
| |
| // Ditto for 98%, but on USB instead of AC. |
| prop.set_external_power(PowerSupplyProperties::USB); |
| prop.set_battery_percent(98.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_NE(info_charging_98, power_status_->GetBatteryImageInfo()); |
| } |
| |
| // Tests that the |icon_badge| member of BatteryImageInfo is set correctly |
| // with various power supply property values. |
| TEST_F(PowerStatusTest, BatteryImageInfoIconBadge) { |
| PowerSupplyProperties prop; |
| |
| // A charging battery connected to AC power should have a bolt badge. |
| prop.set_external_power(PowerSupplyProperties::AC); |
| prop.set_battery_state(PowerSupplyProperties::CHARGING); |
| prop.set_battery_percent(98.0); |
| power_status_->SetProtoForTesting(prop); |
| const gfx::VectorIcon* bolt_icon = |
| power_status_->GetBatteryImageInfo().icon_badge; |
| EXPECT_TRUE(bolt_icon); |
| |
| // A discharging battery connected to AC should also have a bolt badge. |
| prop.set_battery_state(PowerSupplyProperties::DISCHARGING); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(bolt_icon, power_status_->GetBatteryImageInfo().icon_badge); |
| |
| // A charging battery connected to USB power should have an |
| // unreliable badge. |
| prop.set_external_power(PowerSupplyProperties::USB); |
| prop.set_battery_state(PowerSupplyProperties::CHARGING); |
| power_status_->SetProtoForTesting(prop); |
| const gfx::VectorIcon* unreliable_icon = |
| power_status_->GetBatteryImageInfo().icon_badge; |
| EXPECT_NE(unreliable_icon, bolt_icon); |
| EXPECT_TRUE(unreliable_icon); |
| |
| // A discharging battery connected to USB power should also have an |
| // unreliable badge. |
| prop.set_battery_state(PowerSupplyProperties::DISCHARGING); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(unreliable_icon, power_status_->GetBatteryImageInfo().icon_badge); |
| |
| // Show the right icon when no battery is present. |
| prop.set_external_power(PowerSupplyProperties::DISCONNECTED); |
| prop.set_battery_state(PowerSupplyProperties::NOT_PRESENT); |
| power_status_->SetProtoForTesting(prop); |
| const gfx::VectorIcon* x_icon = |
| power_status_->GetBatteryImageInfo().icon_badge; |
| EXPECT_TRUE(x_icon); |
| EXPECT_NE(bolt_icon, x_icon); |
| EXPECT_NE(unreliable_icon, x_icon); |
| |
| // Do not show a badge when the battery is discharging. |
| prop.set_battery_state(PowerSupplyProperties::DISCHARGING); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_FALSE(power_status_->GetBatteryImageInfo().icon_badge); |
| |
| // Show the right icon for a discharging battery when it falls below |
| // a charge level of PowerStatus::kCriticalBatteryChargePercentage. |
| prop.set_battery_percent(PowerStatus::kCriticalBatteryChargePercentage); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_FALSE(power_status_->GetBatteryImageInfo().icon_badge); |
| prop.set_battery_percent(PowerStatus::kCriticalBatteryChargePercentage - 1); |
| power_status_->SetProtoForTesting(prop); |
| const gfx::VectorIcon* alert_icon = |
| power_status_->GetBatteryImageInfo().icon_badge; |
| EXPECT_TRUE(alert_icon); |
| EXPECT_NE(bolt_icon, alert_icon); |
| EXPECT_NE(unreliable_icon, alert_icon); |
| EXPECT_NE(x_icon, alert_icon); |
| } |
| |
| // Tests that the |charge_level| member of BatteryImageInfo is set correctly |
| // with various power supply property values. |
| TEST_F(PowerStatusTest, BatteryImageInfoChargeLevel) { |
| PowerSupplyProperties prop; |
| |
| // No charge level is drawn when the battery is not present. |
| prop.set_external_power(PowerSupplyProperties::DISCONNECTED); |
| prop.set_battery_state(PowerSupplyProperties::NOT_PRESENT); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(0, power_status_->GetBatteryImageInfo().charge_level); |
| |
| // A charge level of 0 when the battery is 0% full. |
| prop.set_external_power(PowerSupplyProperties::AC); |
| prop.set_battery_state(PowerSupplyProperties::CHARGING); |
| prop.set_battery_percent(0.0); |
| EXPECT_EQ(0, power_status_->GetBatteryImageInfo().charge_level); |
| |
| // A charge level of 1 when the battery is up to 16% full, and a level of 2 |
| // for 17% full. |
| prop.set_battery_percent(16.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(1, power_status_->GetBatteryImageInfo().charge_level); |
| prop.set_battery_percent(17.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(2, power_status_->GetBatteryImageInfo().charge_level); |
| |
| // A charge level of 6 when the battery is 50% full. |
| prop.set_battery_percent(50.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(6, power_status_->GetBatteryImageInfo().charge_level); |
| |
| // A charge level of 11 when the battery is 99% full, and a level of 12 when |
| // the battery is 100% full. |
| prop.set_battery_percent(99.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(11, power_status_->GetBatteryImageInfo().charge_level); |
| prop.set_battery_percent(100.0); |
| power_status_->SetProtoForTesting(prop); |
| EXPECT_EQ(12, power_status_->GetBatteryImageInfo().charge_level); |
| } |
| |
| } // namespace ash |