Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /// A library that wraps [Timer] in a way that can be mocked out in test code. | |
| 6 /// Application code only needs to use [getTimer] to get an instance of [Timer]. | |
| 7 /// Then test code can call [mock] to mock out all new [Timer] instances so that | |
| 8 /// they're controllable by a returned [Clock] object. | |
| 9 library mock_clock; | |
| 10 | |
| 11 import 'dart:async'; | |
| 12 | |
| 13 import 'utils.dart'; | |
| 14 | |
| 15 /// The mock clock object. New [Timer]s will be mocked if and only if this is | |
| 16 /// non-`null`. | |
| 17 Clock _clock; | |
| 18 | |
| 19 /// Whether or not mocking is active. | |
| 20 bool get _mocked => _clock != null; | |
| 21 | |
| 22 /// Causes all future calls to [getTimer] to return mock [Timer] objects that | |
| 23 /// are controlled by the returned [Clock]. This may only be called once. | |
| 24 Clock mock() { | |
| 25 if (_mocked) { | |
| 26 throw new StateError("mock_clock.mock() has already been called."); | |
| 27 } | |
| 28 | |
| 29 _clock = new Clock._(); | |
| 30 return _clock; | |
| 31 } | |
| 32 | |
| 33 typedef void TimerCallback(Timer timer); | |
| 34 | |
| 35 /// Returns a new (possibly mocked) [Timer]. Works the same as [new Timer]. | |
| 36 Timer getTimer(int ms, TimerCallback callback) => | |
|
Bob Nystrom
2013/02/13 01:42:28
"get" -> "create" or "new"
nweiz
2013/02/13 02:03:26
Done.
| |
| 37 _mocked ? new _MockTimer(ms, callback) : new Timer(ms, callback); | |
| 38 | |
| 39 /// A clock that controls when mocked [Timer]s move forward in time. It starts | |
| 40 /// at time 0 and advances forward millisecond-by-millisecond, broadcasting each | |
| 41 /// tick on the [onTick] stream. | |
| 42 class Clock { | |
| 43 /// The current time of the clock, in milliseconds. Starts at 0. | |
| 44 int get time => _time; | |
| 45 int _time = 0; | |
| 46 | |
| 47 /// The stream of millisecond ticks of the clock. | |
| 48 Stream<int> get onTick => _onTickController.stream; | |
| 49 final _onTickController = new StreamController<int>.broadcast(); | |
| 50 | |
| 51 Clock._(); | |
| 52 | |
| 53 /// Advances the clock forward by [milliseconds]. This works like synchronous | |
| 54 /// code that takes [milliseconds] to execute; any [Timer]s that are scheduled | |
| 55 /// to fire during the interval will do so asynchronously once control returns | |
| 56 /// to the event loop. | |
| 57 void tick([int milliseconds=1]) { | |
| 58 for (var i = 0; i < milliseconds; i++) { | |
| 59 var tickTime = ++_time; | |
| 60 new Future.immediate(null).then((_) => _onTickController.add(tickTime)); | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 /// Automatically progresses forward in time as long as there are still | |
| 65 /// subscribers to [onTick] (that is, [Timer]s waiting to fire). After each | |
| 66 /// tick, this pumps the event loop repeatedly so that all non-clock-dependent | |
| 67 /// code runs before the next tick. | |
| 68 void run() { | |
| 69 pumpEventQueue().then((_) { | |
| 70 if (!_onTickController.hasSubscribers) { | |
| 71 return; | |
| 72 } | |
|
Bob Nystrom
2013/02/13 01:42:28
Can ditch the {} here if you want.
nweiz
2013/02/13 02:03:26
Done.
| |
| 73 | |
| 74 tick(); | |
| 75 return run(); | |
| 76 }); | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 /// A mock implementation of [Timer] that uses [Clock] to keep time, rather than | |
| 81 /// the system clock. | |
| 82 class _MockTimer implements Timer { | |
| 83 /// The time at which the timer should fire. | |
| 84 final int _time; | |
| 85 | |
| 86 /// The callback to run when the timer fires. | |
| 87 final TimerCallback _callback; | |
| 88 | |
| 89 /// The subscription to the [Clock.onTick] stream. | |
| 90 StreamSubscription _subscription; | |
| 91 | |
| 92 // TODO(nweiz): Remove this when issue 8512 is fixed. | |
| 93 var _cancelled = false; | |
| 94 | |
| 95 _MockTimer(int milliseconds, this._callback) | |
| 96 : _time = _clock.time + milliseconds { | |
| 97 _subscription = _clock.onTick.listen((time) { | |
| 98 if (_cancelled || time < _time) return; | |
| 99 _subscription.cancel(); | |
| 100 _callback(this); | |
| 101 }); | |
| 102 } | |
| 103 | |
| 104 void cancel() { | |
| 105 _cancelled = true; | |
| 106 _subscription.cancel(); | |
| 107 } | |
| 108 } | |
| OLD | NEW |