| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/timer/timer.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/run_loop.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/task_environment.h" |
| #include "base/test/test_simple_task_runner.h" |
| #include "base/time/tick_clock.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| |
| namespace { |
| |
| constexpr TimeDelta kTestDelay = Seconds(10); |
| constexpr TimeDelta kLongTestDelay = Minutes(10); |
| |
| // The main thread types on which each timer should be tested. |
| const test::TaskEnvironment::MainThreadType testing_main_threads[] = { |
| test::TaskEnvironment::MainThreadType::DEFAULT, |
| test::TaskEnvironment::MainThreadType::IO, |
| #if !BUILDFLAG(IS_IOS) // iOS does not allow direct running of the UI loop. |
| test::TaskEnvironment::MainThreadType::UI, |
| #endif |
| }; |
| |
| class Receiver { |
| public: |
| Receiver() : count_(0) {} |
| void OnCalled() { count_++; } |
| bool WasCalled() { return count_ > 0; } |
| int TimesCalled() { return count_; } |
| |
| private: |
| int count_; |
| }; |
| |
| // Basic test with same setup as RunTest_OneShotTimers_Cancel below to confirm |
| // that |timer| would be fired in that test if it wasn't for the deletion. |
| void RunTest_OneShotTimers( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| OneShotTimer timer; |
| timer.Start(FROM_HERE, kTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver))); |
| |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_TRUE(receiver.WasCalled()); |
| EXPECT_FALSE(timer.IsRunning()); |
| } |
| |
| void RunTest_OneShotTimers_Cancel( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| auto timer = std::make_unique<OneShotTimer>(); |
| auto* timer_ptr = timer.get(); |
| |
| // This should run before the timer expires. |
| SequencedTaskRunner::GetCurrentDefault()->DeleteSoon(FROM_HERE, |
| std::move(timer)); |
| |
| timer_ptr->Start(FROM_HERE, kTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver))); |
| |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_FALSE(receiver.WasCalled()); |
| } |
| |
| void RunTest_OneShotSelfDeletingTimer( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| auto timer = std::make_unique<OneShotTimer>(); |
| auto* timer_ptr = timer.get(); |
| |
| timer_ptr->Start( |
| FROM_HERE, kTestDelay, |
| BindLambdaForTesting([&receiver, timer = std::move(timer)]() mutable { |
| receiver.OnCalled(); |
| EXPECT_FALSE(timer->IsRunning()); |
| timer.reset(); |
| })); |
| |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_TRUE(receiver.WasCalled()); |
| } |
| |
| void RunTest_RepeatingTimer( |
| test::TaskEnvironment::MainThreadType main_thread_type, |
| const TimeDelta& delay) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| RepeatingTimer timer; |
| timer.Start(FROM_HERE, kTestDelay, |
| BindRepeating(&Receiver::OnCalled, Unretained(&receiver))); |
| |
| task_environment.FastForwardBy(20 * kTestDelay); |
| EXPECT_EQ(receiver.TimesCalled(), 20); |
| EXPECT_TRUE(timer.IsRunning()); |
| } |
| |
| void RunTest_RepeatingTimer_Cancel( |
| test::TaskEnvironment::MainThreadType main_thread_type, |
| const TimeDelta& delay) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| auto timer = std::make_unique<RepeatingTimer>(); |
| auto* timer_ptr = timer.get(); |
| |
| // This should run before the timer expires. |
| SequencedTaskRunner::GetCurrentDefault()->DeleteSoon(FROM_HERE, |
| std::move(timer)); |
| |
| timer_ptr->Start(FROM_HERE, delay, |
| BindRepeating(&Receiver::OnCalled, Unretained(&receiver))); |
| |
| task_environment.FastForwardBy(delay); |
| EXPECT_FALSE(receiver.WasCalled()); |
| } |
| |
| void RunTest_DelayTimer_NoCall( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled); |
| |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_FALSE(receiver.WasCalled()); |
| } |
| |
| void RunTest_DelayTimer_OneCall( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled); |
| timer.Reset(); |
| |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_TRUE(receiver.WasCalled()); |
| } |
| |
| void RunTest_DelayTimer_Reset( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled); |
| timer.Reset(); |
| |
| // Fast-forward by a delay smaller than the timer delay. The timer will not |
| // fire. |
| task_environment.FastForwardBy(kTestDelay / 2); |
| EXPECT_FALSE(receiver.WasCalled()); |
| |
| // Postpone the fire time. |
| timer.Reset(); |
| |
| // Verify that the timer does not fire at its original fire time. |
| task_environment.FastForwardBy(kTestDelay / 2); |
| EXPECT_FALSE(receiver.WasCalled()); |
| |
| // Fast-forward by the timer delay. The timer will fire. |
| task_environment.FastForwardBy(kTestDelay / 2); |
| EXPECT_TRUE(receiver.WasCalled()); |
| } |
| |
| void RunTest_DelayTimer_Deleted( |
| test::TaskEnvironment::MainThreadType main_thread_type) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME, main_thread_type); |
| |
| Receiver receiver; |
| |
| { |
| DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled); |
| timer.Reset(); |
| } |
| |
| // Because the timer was deleted, it will never fire. |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_FALSE(receiver.WasCalled()); |
| } |
| |
| } // namespace |
| |
| //----------------------------------------------------------------------------- |
| // Each test is run against each type of main thread. That way we are sure |
| // that timers work properly in all configurations. |
| |
| class TimerTestWithThreadType |
| : public testing::TestWithParam<test::TaskEnvironment::MainThreadType> {}; |
| |
| TEST_P(TimerTestWithThreadType, OneShotTimers) { |
| RunTest_OneShotTimers(GetParam()); |
| } |
| |
| TEST_P(TimerTestWithThreadType, OneShotTimers_Cancel) { |
| RunTest_OneShotTimers_Cancel(GetParam()); |
| } |
| |
| // If underline timer does not handle properly, we will crash or fail |
| // in full page heap environment. |
| TEST_P(TimerTestWithThreadType, OneShotSelfDeletingTimer) { |
| RunTest_OneShotSelfDeletingTimer(GetParam()); |
| } |
| |
| TEST(TimerTest, OneShotTimer_CustomTaskRunner) { |
| auto task_runner = base::MakeRefCounted<TestSimpleTaskRunner>(); |
| |
| OneShotTimer timer; |
| |
| bool task_ran = false; |
| |
| // The timer will use the TestSimpleTaskRunner to schedule its delays. |
| timer.SetTaskRunner(task_runner); |
| timer.Start(FROM_HERE, Days(1), |
| BindLambdaForTesting([&]() { task_ran = true; })); |
| |
| EXPECT_FALSE(task_ran); |
| EXPECT_TRUE(task_runner->HasPendingTask()); |
| |
| task_runner->RunPendingTasks(); |
| |
| EXPECT_TRUE(task_ran); |
| } |
| |
| TEST(TimerTest, OneShotTimerWithTickClock) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| Receiver receiver; |
| OneShotTimer timer(task_environment.GetMockTickClock()); |
| timer.Start(FROM_HERE, kTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver))); |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_TRUE(receiver.WasCalled()); |
| EXPECT_FALSE(timer.IsRunning()); |
| } |
| |
| TEST_P(TimerTestWithThreadType, RepeatingTimer) { |
| RunTest_RepeatingTimer(GetParam(), kTestDelay); |
| } |
| |
| TEST_P(TimerTestWithThreadType, RepeatingTimer_Cancel) { |
| RunTest_RepeatingTimer_Cancel(GetParam(), kTestDelay); |
| } |
| |
| TEST_P(TimerTestWithThreadType, RepeatingTimerZeroDelay) { |
| RunTest_RepeatingTimer(GetParam(), Seconds(0)); |
| } |
| |
| TEST_P(TimerTestWithThreadType, RepeatingTimerZeroDelay_Cancel) { |
| RunTest_RepeatingTimer_Cancel(GetParam(), Seconds(0)); |
| } |
| |
| TEST(TimerTest, RepeatingTimerWithTickClock) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| Receiver receiver; |
| const int expected_times_called = 10; |
| RepeatingTimer timer(task_environment.GetMockTickClock()); |
| timer.Start(FROM_HERE, kTestDelay, |
| BindRepeating(&Receiver::OnCalled, Unretained(&receiver))); |
| task_environment.FastForwardBy(expected_times_called * kTestDelay); |
| timer.Stop(); |
| EXPECT_EQ(expected_times_called, receiver.TimesCalled()); |
| } |
| |
| TEST_P(TimerTestWithThreadType, DelayTimer_NoCall) { |
| RunTest_DelayTimer_NoCall(GetParam()); |
| } |
| |
| TEST_P(TimerTestWithThreadType, DelayTimer_OneCall) { |
| RunTest_DelayTimer_OneCall(GetParam()); |
| } |
| |
| TEST_P(TimerTestWithThreadType, DelayTimer_Reset) { |
| RunTest_DelayTimer_Reset(GetParam()); |
| } |
| |
| TEST_P(TimerTestWithThreadType, DelayTimer_Deleted) { |
| RunTest_DelayTimer_Deleted(GetParam()); |
| } |
| |
| TEST(TimerTest, DelayTimerWithTickClock) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| Receiver receiver; |
| DelayTimer timer(FROM_HERE, kTestDelay, &receiver, &Receiver::OnCalled, |
| task_environment.GetMockTickClock()); |
| task_environment.FastForwardBy(kTestDelay - Microseconds(1)); |
| EXPECT_FALSE(receiver.WasCalled()); |
| timer.Reset(); |
| task_environment.FastForwardBy(kTestDelay - Microseconds(1)); |
| EXPECT_FALSE(receiver.WasCalled()); |
| timer.Reset(); |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_TRUE(receiver.WasCalled()); |
| } |
| |
| TEST(TimerTest, TaskEnvironmentShutdown) { |
| // This test is designed to verify that shutdown of the |
| // message loop does not cause crashes if there were pending |
| // timers not yet fired. It may only trigger exceptions |
| // if debug heap checking is enabled. |
| Receiver receiver; |
| OneShotTimer timer; |
| |
| { |
| test::TaskEnvironment task_environment; |
| timer.Start(FROM_HERE, kTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver))); |
| } // Task environment destructs by falling out of scope. |
| |
| EXPECT_FALSE(receiver.WasCalled()); |
| // Timer destruct. SHOULD NOT CRASH, of course. |
| } |
| |
| TEST(TimerTest, TaskEnvironmentSelfOwningTimer) { |
| // This test verifies that a timer does not cause crashes if |
| // |Timer::user_task_| owns the timer. The test may only trigger exceptions if |
| // debug heap checking is enabled. |
| |
| auto timer = std::make_unique<OneShotTimer>(); |
| auto* timer_ptr = timer.get(); |
| |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| |
| timer_ptr->Start(FROM_HERE, kTestDelay, |
| BindLambdaForTesting([timer = std::move(timer)]() {})); |
| // |Timer::user_task_| owns sole reference to |timer|. Both will be destroyed |
| // once the task ran. SHOULD NOT CRASH. |
| task_environment.FastForwardUntilNoTasksRemain(); |
| } |
| |
| TEST(TimerTest, TaskEnvironmentSelfOwningTimerStopped) { |
| // This test verifies that a timer does not cause crashes when stopped if |
| // |Timer::user_task_| owns the timer. The test may only trigger exceptions if |
| // debug heap checking is enabled. |
| |
| auto timer = std::make_unique<OneShotTimer>(); |
| auto* timer_ptr = timer.get(); |
| |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| |
| timer_ptr->Start(FROM_HERE, kTestDelay, |
| BindLambdaForTesting([timer = std::move(timer)]() { |
| // Stop destroys |Timer::user_task_| which owns sole |
| // reference to |timer|. SHOULD NOT CRASH. |
| timer->Stop(); |
| })); |
| task_environment.FastForwardUntilNoTasksRemain(); |
| } |
| |
| TEST(TimerTest, NonRepeatIsRunning) { |
| { |
| test::TaskEnvironment task_environment; |
| OneShotTimer timer; |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Start(FROM_HERE, kTestDelay, DoNothing()); |
| EXPECT_TRUE(timer.IsRunning()); |
| timer.Stop(); |
| EXPECT_FALSE(timer.IsRunning()); |
| } |
| |
| { |
| RetainingOneShotTimer timer; |
| test::TaskEnvironment task_environment; |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Start(FROM_HERE, kTestDelay, DoNothing()); |
| EXPECT_TRUE(timer.IsRunning()); |
| timer.Stop(); |
| EXPECT_FALSE(timer.IsRunning()); |
| ASSERT_FALSE(timer.user_task().is_null()); |
| timer.Reset(); |
| EXPECT_TRUE(timer.IsRunning()); |
| } |
| } |
| |
| TEST(TimerTest, NonRepeatTaskEnvironmentDeath) { |
| OneShotTimer timer; |
| { |
| test::TaskEnvironment task_environment; |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Start(FROM_HERE, kTestDelay, DoNothing()); |
| EXPECT_TRUE(timer.IsRunning()); |
| } |
| EXPECT_FALSE(timer.IsRunning()); |
| } |
| |
| TEST(TimerTest, RetainRepeatIsRunning) { |
| test::TaskEnvironment task_environment; |
| RepeatingTimer timer(FROM_HERE, kTestDelay, DoNothing()); |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Reset(); |
| EXPECT_TRUE(timer.IsRunning()); |
| timer.Stop(); |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Reset(); |
| EXPECT_TRUE(timer.IsRunning()); |
| } |
| |
| TEST(TimerTest, RetainNonRepeatIsRunning) { |
| test::TaskEnvironment task_environment; |
| RetainingOneShotTimer timer(FROM_HERE, kTestDelay, DoNothing()); |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Reset(); |
| EXPECT_TRUE(timer.IsRunning()); |
| timer.Stop(); |
| EXPECT_FALSE(timer.IsRunning()); |
| timer.Reset(); |
| EXPECT_TRUE(timer.IsRunning()); |
| } |
| |
| //----------------------------------------------------------------------------- |
| |
| TEST(TimerTest, ContinuationStopStart) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| |
| Receiver receiver1; |
| Receiver receiver2; |
| OneShotTimer timer; |
| timer.Start(FROM_HERE, kTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver1))); |
| timer.Stop(); |
| timer.Start(FROM_HERE, kLongTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver2))); |
| task_environment.FastForwardBy(kLongTestDelay); |
| EXPECT_FALSE(receiver1.WasCalled()); |
| EXPECT_TRUE(receiver2.WasCalled()); |
| } |
| |
| TEST(TimerTest, ContinuationReset) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| |
| Receiver receiver; |
| OneShotTimer timer; |
| timer.Start(FROM_HERE, kTestDelay, |
| BindOnce(&Receiver::OnCalled, Unretained(&receiver))); |
| timer.Reset(); |
| // // Since Reset happened before task ran, the user_task must not be |
| // cleared: ASSERT_FALSE(timer.user_task().is_null()); |
| task_environment.FastForwardBy(kTestDelay); |
| EXPECT_TRUE(receiver.WasCalled()); |
| } |
| |
| TEST(TimerTest, AbandonedTaskIsCancelled) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| OneShotTimer timer; |
| |
| // Start a timer. There will be a pending task on the current sequence. |
| timer.Start(FROM_HERE, kTestDelay, base::DoNothing()); |
| EXPECT_EQ(1u, task_environment.GetPendingMainThreadTaskCount()); |
| |
| // After AbandonAndStop(), the task is correctly treated as cancelled. |
| timer.AbandonAndStop(); |
| EXPECT_EQ(0u, task_environment.GetPendingMainThreadTaskCount()); |
| EXPECT_FALSE(timer.IsRunning()); |
| } |
| |
| TEST(TimerTest, DeadlineTimer) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| RunLoop run_loop; |
| DeadlineTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| timer.Start(FROM_HERE, start + Seconds(5), run_loop.QuitClosure()); |
| run_loop.Run(); |
| EXPECT_EQ(start + Seconds(5), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, DeadlineTimerCancel) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| RunLoop run_loop; |
| DeadlineTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| MockRepeatingCallback<void()> callback; |
| timer.Start(FROM_HERE, start + Seconds(5), callback.Get()); |
| |
| EXPECT_CALL(callback, Run()).Times(0); |
| timer.Stop(); |
| task_environment.FastForwardBy(Seconds(5)); |
| EXPECT_EQ(start + Seconds(5), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, DeadlineTimerTaskDestructed) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| RunLoop run_loop; |
| DeadlineTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| MockRepeatingCallback<void()> destructed; |
| ScopedClosureRunner scoped_closure(destructed.Get()); |
| timer.Start(FROM_HERE, start + Seconds(5), |
| BindOnce([](ScopedClosureRunner) {}, std::move(scoped_closure))); |
| |
| EXPECT_CALL(destructed, Run()); |
| timer.Stop(); |
| testing::Mock::VerifyAndClearExpectations(&destructed); |
| } |
| |
| TEST(TimerTest, DeadlineTimerStartTwice) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| DeadlineTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| RunLoop run_loop; |
| timer.Start(FROM_HERE, start + Seconds(5), run_loop.QuitClosure()); |
| timer.Start(FROM_HERE, start + Seconds(10), run_loop.QuitClosure()); |
| run_loop.Run(); |
| EXPECT_EQ(start + Seconds(10), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, MetronomeTimer) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| MetronomeTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| // Ensure the run_loop.Run() below doesn't straddle over multiple ticks. |
| task_environment.AdvanceClock( |
| start.SnappedToNextTick(TimeTicks(), Seconds(5)) - start); |
| start = TimeTicks::Now(); |
| |
| RunLoop run_loop; |
| timer.Start(FROM_HERE, Seconds(5), run_loop.QuitClosure()); |
| run_loop.Run(); |
| EXPECT_EQ(start + Seconds(5), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, MetronomeTimerCustomPhase) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| RunLoop run_loop; |
| MetronomeTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| timer.Start(FROM_HERE, Seconds(5), run_loop.QuitClosure(), start); |
| run_loop.Run(); |
| EXPECT_EQ(start + Seconds(5), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, MetronomeTimerReset) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| RunLoop run_loop; |
| TimeTicks start = TimeTicks::Now(); |
| MetronomeTimer timer(FROM_HERE, Seconds(5), run_loop.QuitClosure(), start); |
| |
| timer.Reset(); |
| run_loop.Run(); |
| EXPECT_EQ(start + Seconds(5), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, MetronomeTimerStartTwice) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| MetronomeTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| { |
| RunLoop run_loop; |
| timer.Start(FROM_HERE, Seconds(4), run_loop.QuitClosure(), start); |
| run_loop.Run(); |
| } |
| EXPECT_EQ(start + Seconds(4), TimeTicks::Now()); |
| |
| { |
| RunLoop run_loop; |
| timer.Start(FROM_HERE, Seconds(2), run_loop.QuitClosure(), start); |
| run_loop.Run(); |
| } |
| EXPECT_EQ(start + Seconds(6), TimeTicks::Now()); |
| } |
| |
| TEST(TimerTest, MetronomeTimerMultiple) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| MetronomeTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| // Ensure the subsequent FastForwardBy() don't straddle over multiple ticks. |
| task_environment.AdvanceClock( |
| start.SnappedToNextTick(TimeTicks(), Seconds(5)) - start); |
| |
| MockRepeatingCallback<void()> callback; |
| timer.Start(FROM_HERE, Seconds(5), callback.Get()); |
| |
| // The first tick is skipped because it is too close. Ticks at 5s and 10s. |
| EXPECT_CALL(callback, Run()).Times(2); |
| task_environment.FastForwardBy(Seconds(10)); |
| |
| EXPECT_CALL(callback, Run()).Times(2); |
| // Ticks at 15s and 25s, while 20s is missed. |
| task_environment.AdvanceClock(Seconds(12)); |
| task_environment.FastForwardBy(Seconds(3)); |
| } |
| |
| TEST(TimerTest, MetronomeTimerCancel) { |
| test::TaskEnvironment task_environment( |
| test::TaskEnvironment::TimeSource::MOCK_TIME); |
| RunLoop run_loop; |
| MetronomeTimer timer; |
| TimeTicks start = TimeTicks::Now(); |
| |
| MockRepeatingCallback<void()> callback; |
| timer.Start(FROM_HERE, Seconds(5), callback.Get()); |
| |
| EXPECT_CALL(callback, Run()).Times(0); |
| timer.Stop(); |
| task_environment.FastForwardBy(Seconds(5)); |
| EXPECT_EQ(start + Seconds(5), TimeTicks::Now()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| TimerTestWithThreadType, |
| testing::ValuesIn(testing_main_threads)); |
| |
| } // namespace base |