Index: Source/platform/Timer.h |
diff --git a/Source/platform/Timer.h b/Source/platform/Timer.h |
index 4bf89004d96fcfb407e6166329c946d56dac99f5..589708a6ad5dbecfce4a5bd27d821ba55d783f74 100644 |
--- a/Source/platform/Timer.h |
+++ b/Source/platform/Timer.h |
@@ -105,8 +105,12 @@ private: |
friend class TimerHeapReference; |
}; |
+template <typename TimerFiredClass> class MockableTimer; |
+ |
template <typename TimerFiredClass> |
-class Timer FINAL : public TimerBase { |
+class Timer : public TimerBase { |
+ friend class MockableTimer<TimerFiredClass>; |
+ |
public: |
typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*); |
@@ -120,6 +124,46 @@ private: |
TimerFiredFunction m_function; |
}; |
+// A mockable timer is useful in manually controlling timers from tests |
+// to avoid flakiness. To access a specific instance in layout tests, |
+// it has to be plumbed through internals. |
+template <typename TimerFiredClass> |
+class MockableTimer FINAL : public Timer<TimerFiredClass> { |
+public: |
+ typedef typename Timer<TimerFiredClass>::TimerFiredFunction TimerFiredFunction; |
+ |
+ MockableTimer(TimerFiredClass* o, TimerFiredFunction f) |
+ : Timer<TimerFiredClass>(o, f) |
+ , m_manualMode(false) |
+ , m_firePending(false) |
+ { |
+ } |
+ |
+ void setManualModeForTesting(bool manualMode) { m_manualMode = manualMode; } |
+ |
+ void manualFireForTesting() |
+ { |
+ ASSERT(m_manualMode); |
+ ASSERT(Timer<TimerFiredClass>::isActive() || m_firePending); |
+ Timer<TimerFiredClass>::fired(); |
+ if (!Timer<TimerFiredClass>::repeatInterval()) |
+ Timer<TimerFiredClass>::stop(); |
+ m_firePending = false; |
+ } |
+ |
+private: |
+ bool m_manualMode; |
+ bool m_firePending; |
+ |
+ virtual void fired() OVERRIDE |
+ { |
+ if (m_manualMode) |
+ m_firePending = true; |
+ else |
+ Timer<TimerFiredClass>::fired(); |
+ } |
+}; |
+ |
inline bool TimerBase::isActive() const |
{ |
ASSERT(m_thread == currentThread()); |