#include "base/timer/wall_clock_timer.h"
#include <memory>
#include <utility>
#include "base/test/mock_callback.h"
#include "base/test/power_monitor_test.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
class WallClockTimerTest : public ::testing::Test {
protected:
void FastForwardBy(base::TimeDelta delay, bool with_power = true) {
if (!with_power) {
fake_power_monitor_source_.Suspend();
}
clock_.Advance(delay);
if (with_power) {
task_environment_.FastForwardBy(delay);
} else {
fake_power_monitor_source_.Resume();
task_environment_.RunUntilIdle();
}
}
base::test::ScopedPowerMonitorTestSource fake_power_monitor_source_;
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::SimpleTestClock clock_;
};
TEST_F(WallClockTimerTest, PowerResume) {
::testing::StrictMock<base::MockOnceClosure> callback;
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
constexpr auto delay = base::Minutes(1);
const auto start_time = base::Time::Now();
const auto run_time = start_time + delay;
clock_.SetNow(start_time);
wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
constexpr auto past_time = base::Seconds(30);
FastForwardBy(past_time, false);
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
EXPECT_CALL(callback, Run());
FastForwardBy(delay - past_time);
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_FALSE(wall_clock_timer.IsRunning());
}
TEST_F(WallClockTimerTest, UseTimerTwiceInRow) {
::testing::StrictMock<base::MockOnceClosure> first_callback;
::testing::StrictMock<base::MockOnceClosure> second_callback;
const auto start_time = base::Time::Now();
clock_.SetNow(start_time);
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
constexpr auto delay = base::Minutes(1);
wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
EXPECT_CALL(first_callback, Run())
.WillOnce(::testing::InvokeWithoutArgs(
[this, &wall_clock_timer, &second_callback, delay] {
wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
second_callback.Get());
}));
FastForwardBy(delay);
::testing::Mock::VerifyAndClearExpectations(&first_callback);
::testing::Mock::VerifyAndClearExpectations(&second_callback);
constexpr auto past_time = base::Seconds(30);
FastForwardBy(past_time, false);
::testing::Mock::VerifyAndClearExpectations(&second_callback);
EXPECT_CALL(second_callback, Run());
FastForwardBy(delay - past_time);
::testing::Mock::VerifyAndClearExpectations(&second_callback);
}
TEST_F(WallClockTimerTest, Stop) {
::testing::StrictMock<base::MockOnceClosure> callback;
clock_.SetNow(base::Time::Now());
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
constexpr auto delay = base::Minutes(1);
wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
constexpr auto past_time = base::Seconds(20);
FastForwardBy(past_time);
EXPECT_TRUE(wall_clock_timer.IsRunning());
wall_clock_timer.Stop();
EXPECT_FALSE(wall_clock_timer.IsRunning());
FastForwardBy(past_time, false);
EXPECT_FALSE(wall_clock_timer.IsRunning());
FastForwardBy(delay - past_time * 2);
::testing::Mock::VerifyAndClearExpectations(&callback);
}
TEST_F(WallClockTimerTest, RestartRunningTimer) {
::testing::StrictMock<base::MockOnceClosure> first_callback;
::testing::StrictMock<base::MockOnceClosure> second_callback;
constexpr auto delay = base::Minutes(1);
clock_.SetNow(base::Time::Now());
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
constexpr auto past_time = delay / 2;
FastForwardBy(past_time);
wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
second_callback.Get());
FastForwardBy(past_time);
::testing::Mock::VerifyAndClearExpectations(&first_callback);
::testing::Mock::VerifyAndClearExpectations(&second_callback);
EXPECT_CALL(second_callback, Run());
FastForwardBy(past_time);
::testing::Mock::VerifyAndClearExpectations(&first_callback);
::testing::Mock::VerifyAndClearExpectations(&second_callback);
}
TEST_F(WallClockTimerTest, DoubleStop) {
::testing::StrictMock<base::MockOnceClosure> callback;
clock_.SetNow(base::Time::Now());
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
constexpr auto delay = base::Minutes(1);
wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
constexpr auto past_time = delay / 4;
FastForwardBy(past_time);
EXPECT_TRUE(wall_clock_timer.IsRunning());
wall_clock_timer.Stop();
EXPECT_FALSE(wall_clock_timer.IsRunning());
FastForwardBy(past_time);
EXPECT_FALSE(wall_clock_timer.IsRunning());
wall_clock_timer.Stop();
EXPECT_FALSE(wall_clock_timer.IsRunning());
FastForwardBy(past_time, false);
FastForwardBy(delay - past_time * 3);
::testing::Mock::VerifyAndClearExpectations(&callback);
}
TEST_F(WallClockTimerTest, NonStopTickClock) {
::testing::StrictMock<base::MockOnceClosure> callback;
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
constexpr auto delay = base::Minutes(1);
const auto start_time = base::Time::Now();
const auto run_time = start_time + delay;
clock_.SetNow(start_time);
wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
constexpr auto past_time = base::Seconds(30);
fake_power_monitor_source_.Suspend();
clock_.SetNow(clock_.Now() + past_time);
task_environment_.FastForwardBy(past_time);
fake_power_monitor_source_.Resume();
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
EXPECT_CALL(callback, Run());
FastForwardBy(delay - past_time);
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_FALSE(wall_clock_timer.IsRunning());
}
TEST_F(WallClockTimerTest, NonStopTickClockWithLongPause) {
::testing::StrictMock<base::MockOnceClosure> callback;
WallClockTimer wall_clock_timer(&clock_,
task_environment_.GetMockTickClock());
constexpr auto delay = base::Minutes(1);
const auto start_time = base::Time::Now();
const auto run_time = start_time + delay;
clock_.SetNow(start_time);
wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
constexpr auto past_time = base::Seconds(60);
EXPECT_CALL(callback, Run());
fake_power_monitor_source_.Suspend();
clock_.SetNow(clock_.Now() + past_time);
task_environment_.FastForwardBy(past_time);
fake_power_monitor_source_.Resume();
::testing::Mock::VerifyAndClearExpectations(&callback);
EXPECT_FALSE(wall_clock_timer.IsRunning());
}
}