Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(346)

Side by Side Diff: pkg/scheduled_test/lib/src/schedule.dart

Issue 12208116: Roll back r18349. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library schedule; 5 library schedule;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:unittest/unittest.dart' as unittest; 10 import 'package:unittest/unittest.dart' as unittest;
11 11
12 import 'schedule_error.dart'; 12 import 'schedule_error.dart';
13 import 'task.dart'; 13 import 'task.dart';
14 14
15 /// The schedule of tasks to run for a single test. This has three separate task 15 /// The schedule of tasks to run for a single test. This has three separate task
16 /// queues: [tasks], [onComplete], and [onException]. It also provides 16 /// queues: [tasks], [onComplete], and [onException]. It also provides
17 /// visibility into the current state of the schedule. 17 /// visibility into the current state of the schedule.
18 class Schedule { 18 class Schedule {
19 /// The main task queue for the schedule. These tasks are run before the other 19 /// The main task queue for the schedule. These tasks are run before the other
20 /// queues and generally constitute the main test body. 20 /// queues and generally constitute the main test body.
21 TaskQueue get tasks => _tasks; 21 TaskQueue get tasks => _tasks;
22 TaskQueue _tasks; 22 TaskQueue _tasks;
23 23
24 /// The queue of tasks to run if an error is caught while running [tasks]. The 24 /// The queue of tasks to run if an error is caught while running [tasks]. The
25 /// error will be available in [errors]. These tasks won't be run if no error 25 /// error will be available via [error]. These tasks won't be run if no error
26 /// occurs. Note that expectation failures count as errors. 26 /// occurs. Note that expectation failures count as errors.
27 /// 27 ///
28 /// This queue runs before [onComplete], and errors in [onComplete] will not 28 /// This queue runs before [onComplete], and errors in [onComplete] will not
29 /// cause this queue to be run. 29 /// cause this queue to be run.
30 /// 30 ///
31 /// If an error occurs in a task in this queue, all further tasks will be 31 /// If an error occurs in a task in this queue, all further tasks will be
32 /// skipped. 32 /// skipped.
33 TaskQueue get onException => _onException; 33 TaskQueue get onException => _onException;
34 TaskQueue _onException; 34 TaskQueue _onException;
35 35
36 /// The queue of tasks to run after [tasks] and possibly [onException] have 36 /// The queue of tasks to run after [tasks] and possibly [onException] have
37 /// run. This queue will run whether or not an error occurred. If one did, it 37 /// run. This queue will run whether or not an error occurred. If one did, it
38 /// will be available in [errors]. Note that expectation failures count as 38 /// will be available via [error]. Note that expectation failures count as
39 /// errors. 39 /// errors.
40 /// 40 ///
41 /// This queue runs after [onException]. If an error occurs while running 41 /// This queue runs after [onException]. If an error occurs while running
42 /// [onException], that error will be available in [errors] after the original 42 /// [onException], that error will be available via [error] in place of the
43 /// error. 43 /// original error.
44 /// 44 ///
45 /// If an error occurs in a task in this queue, all further tasks will be 45 /// If an error occurs in a task in this queue, all further tasks will be
46 /// skipped. 46 /// skipped.
47 TaskQueue get onComplete => _onComplete; 47 TaskQueue get onComplete => _onComplete;
48 TaskQueue _onComplete; 48 TaskQueue _onComplete;
49 49
50 /// Returns the [Task] that's currently executing, or `null` if there is no 50 /// Returns the [Task] that's currently executing, or `null` if there is no
51 /// such task. This will be `null` both before the schedule starts running and 51 /// such task. This will be `null` both before the schedule starts running and
52 /// after it's finished. 52 /// after it's finished.
53 Task get currentTask => _currentTask; 53 Task get currentTask => _currentTask;
54 Task _currentTask; 54 Task _currentTask;
55 55
56 /// Whether the schedule has finished running. This is only set once 56 /// Whether the schedule has finished running. This is only set once
57 /// [onComplete] has finished running. It will be set whether or not an 57 /// [onComplete] has finished running. It will be set whether or not an
58 /// exception has occurred. 58 /// exception has occurred.
59 bool get done => _done; 59 bool get done => _done;
60 bool _done = false; 60 bool _done = false;
61 61
62 // TODO(nweiz): make this a read-only view once issue 8321 is fixed. 62 /// The error thrown by the task queue. This will only be set while running
63 63 /// [onException] and [onComplete], since an error in [tasks] will cause it to
64 /// Errors thrown by the task queues. 64 /// terminate immediately.
65 /// 65 ScheduleError get error => _error;
66 /// When running tasks in [tasks], this will always be empty. If an error 66 ScheduleError _error;
67 /// occurs in [tasks], it will be added to this list and then [onException]
68 /// will be run. If an error occurs there as well, it will be added to this
69 /// list and [onComplete] will be run. Errors thrown during [onComplete] will
70 /// also be added to this list, although no scheduled tasks will be run
71 /// afterwards.
72 ///
73 /// Any out-of-band callbacks that throw errors will also have those errors
74 /// added to this list.
75 final errors = <ScheduleError>[];
76 67
77 /// The task queue that's currently being run, or `null` if there is no such 68 /// The task queue that's currently being run, or `null` if there is no such
78 /// queue. One of [tasks], [onException], or [onComplete]. This will be `null` 69 /// queue. One of [tasks], [onException], or [onComplete]. This will be `null`
79 /// before the schedule starts running. 70 /// before the schedule starts running.
80 TaskQueue get currentQueue => _done ? null : _currentQueue; 71 TaskQueue get currentQueue => _done ? null : _currentQueue;
81 TaskQueue _currentQueue; 72 TaskQueue _currentQueue;
82 73
83 /// The number of out-of-band callbacks that have been registered with 74 /// The number of out-of-band callbacks that have been registered with
84 /// [wrapAsync] but have yet to be called. 75 /// [wrapAsync] but have yet to be called.
85 int _pendingCallbacks = 0; 76 int _pendingCallbacks = 0;
(...skipping 15 matching lines...) Expand all
101 Future run(void setUp()) { 92 Future run(void setUp()) {
102 return new Future.immediate(null).then((_) { 93 return new Future.immediate(null).then((_) {
103 try { 94 try {
104 setUp(); 95 setUp();
105 } catch (e, stackTrace) { 96 } catch (e, stackTrace) {
106 throw new ScheduleError.from(this, e, stackTrace: stackTrace); 97 throw new ScheduleError.from(this, e, stackTrace: stackTrace);
107 } 98 }
108 99
109 return tasks._run(); 100 return tasks._run();
110 }).catchError((e) { 101 }).catchError((e) {
111 errors.add(e); 102 _error = e;
112 return onException._run().catchError((innerError) { 103 return onException._run().then((_) {
113 // If an error occurs in a task in the onException queue, make sure it's
114 // registered in the error list and re-throw it. We could also re-throw
115 // `e`; ultimately, all the errors will be shown to the user if any
116 // ScheduleError is thrown.
117 errors.add(innerError);
118 throw innerError;
119 }).then((_) {
120 // If there are no errors in the onException queue, re-throw the
121 // original error that caused it to run.
122 throw e; 104 throw e;
123 }); 105 });
124 }).whenComplete(() { 106 }).whenComplete(() => onComplete._run()).whenComplete(() {
125 return onComplete._run().catchError((e) {
126 // If an error occurs in a task in the onComplete queue, make sure it's
127 // registered in the error list and re-throw it.
128 errors.add(e);
129 throw e;
130 });
131 }).whenComplete(() {
132 _done = true; 107 _done = true;
133 }); 108 });
134 } 109 }
135 110
136 /// Signals that an out-of-band error has occurred. Using [wrapAsync] along 111 /// Signals that an out-of-band error has occurred. Using [wrapAsync] along
137 /// with `throw` is usually preferable to calling this directly. 112 /// with `throw` is usually preferable to calling this directly.
138 /// 113 ///
139 /// The metadata in [AsyncError]s and [ScheduleError]s will be preserved. 114 /// The metadata in [AsyncError]s and [ScheduleError]s will be preserved.
140 void signalError(error, [stackTrace]) { 115 void signalError(error, [stackTrace]) {
141 var scheduleError = new ScheduleError.from(this, error, 116 var scheduleError = new ScheduleError.from(this, error,
142 stackTrace: stackTrace, task: currentTask); 117 stackTrace: stackTrace, task: currentTask);
143 if (_done) { 118 if (_done) {
144 errors.add(scheduleError);
145 throw new StateError( 119 throw new StateError(
146 "An out-of-band error was signaled outside of wrapAsync after the " 120 "An out-of-band error was signaled outside of wrapAsync after the "
147 "schedule finished running.\n" 121 "schedule finished running:"
148 "${errorString()}"); 122 "${prefixLines(scheduleError.toString())}");
149 } else if (currentQueue == null) { 123 } else if (currentQueue == null) {
150 // If we're not done but there's no current queue, that means we haven't 124 // If we're not done but there's no current queue, that means we haven't
151 // started yet and thus we're in setUp or the synchronous body of the 125 // started yet and thus we're in setUp or the synchronous body of the
152 // function. Throwing the error will thus pipe it into the main 126 // function. Throwing the error will thus pipe it into the main
153 // error-handling code. 127 // error-handling code.
154 throw scheduleError; 128 throw scheduleError;
155 } else { 129 } else {
156 _currentQueue._signalError(scheduleError); 130 _currentQueue._signalError(scheduleError);
157 } 131 }
158 } 132 }
(...skipping 20 matching lines...) Expand all
179 } finally { 153 } finally {
180 _pendingCallbacks--; 154 _pendingCallbacks--;
181 if (_pendingCallbacks == 0 && _noPendingCallbacks != null) { 155 if (_pendingCallbacks == 0 && _noPendingCallbacks != null) {
182 _noPendingCallbacks.complete(); 156 _noPendingCallbacks.complete();
183 _noPendingCallbacks = null; 157 _noPendingCallbacks = null;
184 } 158 }
185 } 159 }
186 }; 160 };
187 } 161 }
188 162
189 /// Returns a string representation of all errors registered on this schedule.
190 String errorString() {
191 if (errors.isEmpty) return "The schedule had no errors.";
192 if (errors.length == 1) return errors.first.toString();
193 var errorStrings = errors.map((e) => e.toString()).join("\n================"
194 "================================================================\n");
195 return "The schedule had ${errors.length} errors:\n$errorStrings";
196 }
197
198 /// Returns a [Future] that will complete once there are no pending 163 /// Returns a [Future] that will complete once there are no pending
199 /// out-of-band callbacks. 164 /// out-of-band callbacks.
200 Future _awaitNoPendingCallbacks() { 165 Future _awaitNoPendingCallbacks() {
201 if (_pendingCallbacks == 0) return new Future.immediate(null); 166 if (_pendingCallbacks == 0) return new Future.immediate(null);
202 if (_noPendingCallbacks == null) _noPendingCallbacks = new Completer(); 167 if (_noPendingCallbacks == null) _noPendingCallbacks = new Completer();
203 return _noPendingCallbacks.future; 168 return _noPendingCallbacks.future;
204 } 169 }
205 } 170 }
206 171
207 /// A queue of asynchronous tasks to execute in order. 172 /// A queue of asynchronous tasks to execute in order.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 return task.result; 205 return task.result;
241 } 206 }
242 207
243 /// Runs all the tasks in this queue in order. 208 /// Runs all the tasks in this queue in order.
244 Future _run() { 209 Future _run() {
245 _schedule._currentQueue = this; 210 _schedule._currentQueue = this;
246 return Future.forEach(_contents, (task) { 211 return Future.forEach(_contents, (task) {
247 _schedule._currentTask = task; 212 _schedule._currentTask = task;
248 if (_error != null) throw _error; 213 if (_error != null) throw _error;
249 return task.fn().catchError((e) { 214 return task.fn().catchError((e) {
250 if (_error != null) _schedule.errors.add(_error);
251 throw new ScheduleError.from(_schedule, e, task: task); 215 throw new ScheduleError.from(_schedule, e, task: task);
252 }); 216 });
253 }).whenComplete(() { 217 }).whenComplete(() {
254 _schedule._currentTask = null; 218 _schedule._currentTask = null;
255 return _schedule._awaitNoPendingCallbacks(); 219 return _schedule._awaitNoPendingCallbacks();
256 }).then((_) { 220 }).then((_) {
257 if (_error != null) throw _error; 221 if (_error != null) throw _error;
258 }); 222 });
259 } 223 }
260 224
261 /// Signals that an out-of-band error has been detected and the queue should 225 /// Signals that an out-of-band error has been detected and the queue should
262 /// stop running as soon as possible. 226 /// stop running as soon as possible.
263 void _signalError(ScheduleError error) { 227 void _signalError(ScheduleError error) {
264 // If multiple errors are detected while a task is running, make sure the
265 // earlier ones are recorded in the schedule.
266 if (_error != null) _schedule.errors.add(_error);
267 _error = error; 228 _error = error;
268 } 229 }
269 230
270 String toString() => name; 231 String toString() => name;
271 232
272 /// Returns a detailed representation of the queue as a tree of tasks. If 233 /// Returns a detailed representation of the queue as a tree of tasks. If
273 /// [highlight] is passed, that task is specially highlighted. 234 /// [highlight] is passed, that task is specially highlighted.
274 /// 235 ///
275 /// [highlight] must be a task in this queue. 236 /// [highlight] must be a task in this queue.
276 String generateTree([Task highlight]) { 237 String generateTree([Task highlight]) {
277 assert(highlight == null || highlight.queue == this); 238 assert(highlight == null || highlight.queue == this);
278 return _contents.map((task) { 239 return _contents.map((task) {
279 var lines = task.toString().split("\n"); 240 var lines = task.toString().split("\n");
280 var firstLine = task == highlight ? 241 var firstLine = task == highlight ?
281 "> ${lines.first}" : "* ${lines.first}"; 242 "> ${lines.first}" : "* ${lines.first}";
282 lines = new List.from(lines.skip(1).map((line) => "| $line")); 243 lines = new List.from(lines.skip(1).map((line) => "| $line"));
283 lines.insertRange(0, 1, firstLine); 244 lines.insertRange(0, 1, firstLine);
284 return lines.join("\n"); 245 return lines.join("\n");
285 }).join("\n"); 246 }).join("\n");
286 } 247 }
287 } 248 }
OLDNEW
« no previous file with comments | « pkg/scheduled_test/lib/scheduled_test.dart ('k') | pkg/scheduled_test/test/scheduled_test_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698