root/base/timer/timer_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. delay_ms_
  2. Start
  3. Run
  4. timer_
  5. Start
  6. Run
  7. delay_
  8. Start
  9. Run
  10. RunTest_OneShotTimer
  11. RunTest_OneShotTimer_Cancel
  12. RunTest_OneShotSelfDeletingTimer
  13. RunTest_RepeatingTimer
  14. RunTest_RepeatingTimer_Cancel
  15. signaled
  16. Signal
  17. RunTest_DelayTimer_NoCall
  18. RunTest_DelayTimer_OneCall
  19. RunTest_DelayTimer_Reset
  20. Signal
  21. RunTest_DelayTimer_Deleted
  22. TEST
  23. TEST
  24. TEST
  25. TEST
  26. TEST
  27. TEST
  28. TEST
  29. TEST
  30. TEST
  31. TEST
  32. TEST
  33. TEST
  34. TimerTestCallback
  35. TEST
  36. TEST
  37. TEST
  38. TEST
  39. ClearAllCallbackHappened
  40. SetCallbackHappened1
  41. SetCallbackHappened2
  42. TEST
  43. TEST

// Copyright (c) 2012 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 "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/timer/timer.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::TimeDelta;

namespace {

// The message loops on which each timer should be tested.
const base::MessageLoop::Type testing_message_loops[] = {
  base::MessageLoop::TYPE_DEFAULT,
  base::MessageLoop::TYPE_IO,
#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
  base::MessageLoop::TYPE_UI,
#endif
};

const int kNumTestingMessageLoops = arraysize(testing_message_loops);

class OneShotTimerTester {
 public:
  explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10)
      : did_run_(did_run),
        delay_ms_(milliseconds) {
  }
  void Start() {
    timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this,
                 &OneShotTimerTester::Run);
  }
 private:
  void Run() {
    *did_run_ = true;
    base::MessageLoop::current()->QuitWhenIdle();
  }
  bool* did_run_;
  base::OneShotTimer<OneShotTimerTester> timer_;
  const unsigned delay_ms_;
};

class OneShotSelfDeletingTimerTester {
 public:
  explicit OneShotSelfDeletingTimerTester(bool* did_run) :
      did_run_(did_run),
      timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
  }
  void Start() {
    timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
                  &OneShotSelfDeletingTimerTester::Run);
  }
 private:
  void Run() {
    *did_run_ = true;
    timer_.reset();
    base::MessageLoop::current()->QuitWhenIdle();
  }
  bool* did_run_;
  scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
};

class RepeatingTimerTester {
 public:
  explicit RepeatingTimerTester(bool* did_run, const TimeDelta& delay)
      : did_run_(did_run), counter_(10), delay_(delay) {
  }

  void Start() {
    timer_.Start(FROM_HERE, delay_, this, &RepeatingTimerTester::Run);
  }
 private:
  void Run() {
    if (--counter_ == 0) {
      *did_run_ = true;
      timer_.Stop();
      base::MessageLoop::current()->QuitWhenIdle();
    }
  }
  bool* did_run_;
  int counter_;
  TimeDelta delay_;
  base::RepeatingTimer<RepeatingTimerTester> timer_;
};

void RunTest_OneShotTimer(base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  bool did_run = false;
  OneShotTimerTester f(&did_run);
  f.Start();

  base::MessageLoop::current()->Run();

  EXPECT_TRUE(did_run);
}

void RunTest_OneShotTimer_Cancel(base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  bool did_run_a = false;
  OneShotTimerTester* a = new OneShotTimerTester(&did_run_a);

  // This should run before the timer expires.
  base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);

  // Now start the timer.
  a->Start();

  bool did_run_b = false;
  OneShotTimerTester b(&did_run_b);
  b.Start();

  base::MessageLoop::current()->Run();

  EXPECT_FALSE(did_run_a);
  EXPECT_TRUE(did_run_b);
}

void RunTest_OneShotSelfDeletingTimer(
    base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  bool did_run = false;
  OneShotSelfDeletingTimerTester f(&did_run);
  f.Start();

  base::MessageLoop::current()->Run();

  EXPECT_TRUE(did_run);
}

void RunTest_RepeatingTimer(base::MessageLoop::Type message_loop_type,
                            const TimeDelta& delay) {
  base::MessageLoop loop(message_loop_type);

  bool did_run = false;
  RepeatingTimerTester f(&did_run, delay);
  f.Start();

  base::MessageLoop::current()->Run();

  EXPECT_TRUE(did_run);
}

void RunTest_RepeatingTimer_Cancel(base::MessageLoop::Type message_loop_type,
                                   const TimeDelta& delay) {
  base::MessageLoop loop(message_loop_type);

  bool did_run_a = false;
  RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a, delay);

  // This should run before the timer expires.
  base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);

  // Now start the timer.
  a->Start();

  bool did_run_b = false;
  RepeatingTimerTester b(&did_run_b, delay);
  b.Start();

  base::MessageLoop::current()->Run();

  EXPECT_FALSE(did_run_a);
  EXPECT_TRUE(did_run_b);
}

class DelayTimerTarget {
 public:
  DelayTimerTarget()
      : signaled_(false) {
  }

  bool signaled() const { return signaled_; }

  void Signal() {
    ASSERT_FALSE(signaled_);
    signaled_ = true;
  }

 private:
  bool signaled_;
};

void RunTest_DelayTimer_NoCall(base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  // If Delay is never called, the timer shouldn't go off.
  DelayTimerTarget target;
  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);

  bool did_run = false;
  OneShotTimerTester tester(&did_run);
  tester.Start();
  base::MessageLoop::current()->Run();

  ASSERT_FALSE(target.signaled());
}

void RunTest_DelayTimer_OneCall(base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  DelayTimerTarget target;
  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
  timer.Reset();

  bool did_run = false;
  OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
  tester.Start();
  base::MessageLoop::current()->Run();

  ASSERT_TRUE(target.signaled());
}

struct ResetHelper {
  ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
              DelayTimerTarget* target)
      : timer_(timer),
        target_(target) {
  }

  void Reset() {
    ASSERT_FALSE(target_->signaled());
    timer_->Reset();
  }

 private:
  base::DelayTimer<DelayTimerTarget> *const timer_;
  DelayTimerTarget *const target_;
};

void RunTest_DelayTimer_Reset(base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  // If Delay is never called, the timer shouldn't go off.
  DelayTimerTarget target;
  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
      TimeDelta::FromMilliseconds(50), &target, &DelayTimerTarget::Signal);
  timer.Reset();

  ResetHelper reset_helper(&timer, &target);

  base::OneShotTimer<ResetHelper> timers[20];
  for (size_t i = 0; i < arraysize(timers); ++i) {
    timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10),
                    &reset_helper, &ResetHelper::Reset);
  }

  bool did_run = false;
  OneShotTimerTester tester(&did_run, 300);
  tester.Start();
  base::MessageLoop::current()->Run();

  ASSERT_TRUE(target.signaled());
}

class DelayTimerFatalTarget {
 public:
  void Signal() {
    ASSERT_TRUE(false);
  }
};


void RunTest_DelayTimer_Deleted(base::MessageLoop::Type message_loop_type) {
  base::MessageLoop loop(message_loop_type);

  DelayTimerFatalTarget target;

  {
    base::DelayTimer<DelayTimerFatalTarget> timer(
        FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
        &DelayTimerFatalTarget::Signal);
    timer.Reset();
  }

  // When the timer is deleted, the DelayTimerFatalTarget should never be
  // called.
  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
}

}  // namespace

//-----------------------------------------------------------------------------
// Each test is run against each type of MessageLoop.  That way we are sure
// that timers work properly in all configurations.

TEST(TimerTest, OneShotTimer) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_OneShotTimer(testing_message_loops[i]);
  }
}

TEST(TimerTest, OneShotTimer_Cancel) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_OneShotTimer_Cancel(testing_message_loops[i]);
  }
}

// If underline timer does not handle properly, we will crash or fail
// in full page heap environment.
TEST(TimerTest, OneShotSelfDeletingTimer) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_OneShotSelfDeletingTimer(testing_message_loops[i]);
  }
}

TEST(TimerTest, RepeatingTimer) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_RepeatingTimer(testing_message_loops[i],
                           TimeDelta::FromMilliseconds(10));
  }
}

TEST(TimerTest, RepeatingTimer_Cancel) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_RepeatingTimer_Cancel(testing_message_loops[i],
                                  TimeDelta::FromMilliseconds(10));
  }
}

TEST(TimerTest, RepeatingTimerZeroDelay) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_RepeatingTimer(testing_message_loops[i],
                           TimeDelta::FromMilliseconds(0));
  }
}

TEST(TimerTest, RepeatingTimerZeroDelay_Cancel) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_RepeatingTimer_Cancel(testing_message_loops[i],
                                  TimeDelta::FromMilliseconds(0));
  }
}

TEST(TimerTest, DelayTimer_NoCall) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_DelayTimer_NoCall(testing_message_loops[i]);
  }
}

TEST(TimerTest, DelayTimer_OneCall) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_DelayTimer_OneCall(testing_message_loops[i]);
  }
}

// It's flaky on the buildbot, http://crbug.com/25038.
TEST(TimerTest, DISABLED_DelayTimer_Reset) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_DelayTimer_Reset(testing_message_loops[i]);
  }
}

TEST(TimerTest, DelayTimer_Deleted) {
  for (int i = 0; i < kNumTestingMessageLoops; i++) {
    RunTest_DelayTimer_Deleted(testing_message_loops[i]);
  }
}

TEST(TimerTest, MessageLoopShutdown) {
  // 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.
  bool did_run = false;
  {
    OneShotTimerTester a(&did_run);
    OneShotTimerTester b(&did_run);
    OneShotTimerTester c(&did_run);
    OneShotTimerTester d(&did_run);
    {
      base::MessageLoop loop;
      a.Start();
      b.Start();
    }  // MessageLoop destructs by falling out of scope.
  }  // OneShotTimers destruct.  SHOULD NOT CRASH, of course.

  EXPECT_FALSE(did_run);
}

void TimerTestCallback() {
}

TEST(TimerTest, NonRepeatIsRunning) {
  {
    base::MessageLoop loop;
    base::Timer timer(false, false);
    EXPECT_FALSE(timer.IsRunning());
    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
                base::Bind(&TimerTestCallback));
    EXPECT_TRUE(timer.IsRunning());
    timer.Stop();
    EXPECT_FALSE(timer.IsRunning());
    EXPECT_TRUE(timer.user_task().is_null());
  }

  {
    base::Timer timer(true, false);
    base::MessageLoop loop;
    EXPECT_FALSE(timer.IsRunning());
    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
                base::Bind(&TimerTestCallback));
    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, NonRepeatMessageLoopDeath) {
  base::Timer timer(false, false);
  {
    base::MessageLoop loop;
    EXPECT_FALSE(timer.IsRunning());
    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
                base::Bind(&TimerTestCallback));
    EXPECT_TRUE(timer.IsRunning());
  }
  EXPECT_FALSE(timer.IsRunning());
  EXPECT_TRUE(timer.user_task().is_null());
}

TEST(TimerTest, RetainRepeatIsRunning) {
  base::MessageLoop loop;
  base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
                    base::Bind(&TimerTestCallback), true);
  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) {
  base::MessageLoop loop;
  base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
                    base::Bind(&TimerTestCallback), false);
  EXPECT_FALSE(timer.IsRunning());
  timer.Reset();
  EXPECT_TRUE(timer.IsRunning());
  timer.Stop();
  EXPECT_FALSE(timer.IsRunning());
  timer.Reset();
  EXPECT_TRUE(timer.IsRunning());
}

namespace {

bool g_callback_happened1 = false;
bool g_callback_happened2 = false;

void ClearAllCallbackHappened() {
  g_callback_happened1 = false;
  g_callback_happened2 = false;
}

void SetCallbackHappened1() {
  g_callback_happened1 = true;
  base::MessageLoop::current()->QuitWhenIdle();
}

void SetCallbackHappened2() {
  g_callback_happened2 = true;
  base::MessageLoop::current()->QuitWhenIdle();
}

TEST(TimerTest, ContinuationStopStart) {
  {
    ClearAllCallbackHappened();
    base::MessageLoop loop;
    base::Timer timer(false, false);
    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
                base::Bind(&SetCallbackHappened1));
    timer.Stop();
    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(40),
                base::Bind(&SetCallbackHappened2));
    base::MessageLoop::current()->Run();
    EXPECT_FALSE(g_callback_happened1);
    EXPECT_TRUE(g_callback_happened2);
  }
}

TEST(TimerTest, ContinuationReset) {
  {
    ClearAllCallbackHappened();
    base::MessageLoop loop;
    base::Timer timer(false, false);
    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
                base::Bind(&SetCallbackHappened1));
    timer.Reset();
    // Since Reset happened before task ran, the user_task must not be cleared:
    ASSERT_FALSE(timer.user_task().is_null());
    base::MessageLoop::current()->Run();
    EXPECT_TRUE(g_callback_happened1);
  }
}

}  // namespace

/* [<][>][^][v][top][bottom][index][help] */