| 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 library test_utils; |
| 6 |
| 7 import 'dart:async'; |
| 8 |
| 9 import 'package:scheduled_test/src/utils.dart'; |
| 10 |
| 11 /// Wraps [input] to provide a timeout. If [input] completes before |
| 12 /// [milliseconds] have passed, then the return value completes in the same way. |
| 13 /// However, if [milliseconds] pass before [input] has completed, [onTimeout] is |
| 14 /// run and its result is passed to [input] (with chaining, if it returns a |
| 15 /// [Future]). |
| 16 /// |
| 17 /// Note that timing out will not cancel the asynchronous operation behind |
| 18 /// [input]. |
| 19 Future timeout(Future input, int milliseconds, onTimeout()) { |
| 20 bool completed = false; |
| 21 var completer = new Completer(); |
| 22 var timer = new Timer(milliseconds, (_) { |
| 23 completed = true; |
| 24 chainToCompleter(new Future.immediate(null).then((_) => onTimeout()), |
| 25 completer); |
| 26 }); |
| 27 input.then((value) { |
| 28 if (completed) return; |
| 29 timer.cancel(); |
| 30 completer.complete(value); |
| 31 }).catchError((e) { |
| 32 if (completed) return; |
| 33 timer.cancel(); |
| 34 completer.completeError(e.error, e.stackTrace); |
| 35 }); |
| 36 return completer.future; |
| 37 } |
| 38 |
| 39 /// Returns a [Future] that completes after pumping the event queue [times] |
| 40 /// times. By default, this should pump the event queue enough times to allow |
| 41 /// any code to run, as long as it's not waiting on some external event. |
| 42 Future pumpEventQueue([int times=200]) { |
| 43 if (times == 0) return new Future.immediate(null); |
| 44 return new Future.immediate(null).then((_) => pumpEventQueue(times - 1)); |
| 45 } |
| 46 |
| 47 /// A class for controlling the relative order of multiple [Future]s. This is an |
| 48 /// alternative to using [Timer]s to ensure that callbacks run in a given order. |
| 49 /// |
| 50 /// [Future]s are generated by calling [wait] with a given position. The |
| 51 /// [Future]s will complete in position order, pumping the event queue |
| 52 /// thoroughly between each completion and before the first completion. |
| 53 class Waiter { |
| 54 /// The completers for [Future]s returned by [wait]. Conceptually, this is |
| 55 /// really a priority queue, but Dart doesn't have such a data type built in. |
| 56 /// Since the number of calls to [wait] will be very small, a [Map] is fine. |
| 57 final _completers = new Map<int, Completer>(); |
| 58 |
| 59 /// Whether [_wait] is currently running. |
| 60 var _waiting = false; |
| 61 |
| 62 /// Returns a [Future] that will complete in [position] order relative to |
| 63 /// other [Future]s returned by [wait]. The order of calling [wait] doesn't |
| 64 /// matter. |
| 65 Future wait(int position) { |
| 66 if (_completers.containsKey(position)) { |
| 67 throw new StateError("Waiter already has a wait at position $position"); |
| 68 } |
| 69 |
| 70 var completer = new Completer(); |
| 71 _completers[position] = completer; |
| 72 _wait(); |
| 73 return completer.future; |
| 74 } |
| 75 |
| 76 /// Pumps the event queue, then completes the [Future] at the lowest position. |
| 77 void _wait() { |
| 78 if (_waiting) return; |
| 79 _waiting = true; |
| 80 pumpEventQueue().then((_) { |
| 81 _waiting = false; |
| 82 var completer = _completers.remove(_completers.keys.min()); |
| 83 if (!_completers.isEmpty) _wait(); |
| 84 completer.complete(); |
| 85 }); |
| 86 } |
| 87 } |
| OLD | NEW |