blob: 96967c2b3ef5da21b69b260da223b0b617c3043e [file] [log] [blame]
// 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