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

Unified Diff: pkg/scheduled_test/lib/src/schedule.dart

Issue 12288061: Support nested tasks in scheduled_test. (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 side-by-side diff with in-line comments
Download patch
Index: pkg/scheduled_test/lib/src/schedule.dart
diff --git a/pkg/scheduled_test/lib/src/schedule.dart b/pkg/scheduled_test/lib/src/schedule.dart
index 58a14871418f67a2c4e3742d34b5cd49a23f1740..3ff53ac901741a85c8be5f07fe988239e364a48e 100644
--- a/pkg/scheduled_test/lib/src/schedule.dart
+++ b/pkg/scheduled_test/lib/src/schedule.dart
@@ -127,19 +127,20 @@ class Schedule {
try {
setUp();
} catch (e, stackTrace) {
+ _state = ScheduleState.RUNNING;
Bob Nystrom 2013/02/19 23:15:04 Document why you're setting this state even though
nweiz 2013/02/20 00:23:12 Done.
throw new ScheduleError.from(this, e, stackTrace: stackTrace);
}
_state = ScheduleState.RUNNING;
return tasks._run();
}).catchError((e) {
- errors.add(e);
+ _addError(e);
return onException._run().catchError((innerError) {
// If an error occurs in a task in the onException queue, make sure it's
// registered in the error list and re-throw it. We could also re-throw
// `e`; ultimately, all the errors will be shown to the user if any
// ScheduleError is thrown.
- errors.add(innerError);
+ _addError(innerError);
throw innerError;
}).then((_) {
// If there are no errors in the onException queue, re-throw the
@@ -150,7 +151,7 @@ class Schedule {
return onComplete._run().catchError((e) {
// If an error occurs in a task in the onComplete queue, make sure it's
// registered in the error list and re-throw it.
- errors.add(e);
+ _addError(e);
throw e;
});
}).whenComplete(() {
@@ -189,7 +190,7 @@ class Schedule {
void _signalPostTimeoutError(error, [stackTrace]) {
var scheduleError = new ScheduleError.from(this, error,
stackTrace: stackTrace);
- errors.add(scheduleError);
+ _addError(scheduleError);
if (_state == ScheduleState.DONE) {
throw new StateError(
"An out-of-band error was caught after the test timed out.\n"
@@ -203,7 +204,7 @@ class Schedule {
/// out-of-band callbacks are properly handled by the scheduled test.
///
/// The top-level `wrapAsync` function should usually be used in preference to
- /// this.
+ /// this in test code.
Function wrapAsync(fn(arg)) {
if (_state == ScheduleState.DONE) {
throw new StateError("wrapAsync called after the schedule has finished "
@@ -237,6 +238,35 @@ class Schedule {
};
}
+ /// Like [wrapAsync], this ensures that the current task queue waits for
+ /// out-of-band asynchronous code, and that errors raised in that code are
+ /// handled correctly. However, [wrapFuture] wraps a [Future] chain rather
+ /// than a single callback.
+ ///
+ /// The returned [Future] completes to the same value or error as [future].
+ ///
+ /// The top-level `wrapFuture` function should usually be used in preference
+ /// to this in test code.
+ Future wrapFuture(Future future) {
+ var doneCb = wrapAsync((_) => null);
Bob Nystrom 2013/02/19 23:15:04 Cb -> Callback Or just inline this function in th
nweiz 2013/02/20 00:23:12 Done.
+ done() => new Future.immediate(null).then(doneCb);
+
+ future = future.then((result) {
+ done();
+ return result;
+ }).catchError((e) {
+ signalError(e);
+ done();
+ throw e;
+ });
+
+ // Don't top-level the error, since it's already been signaled to the
+ // schedule.
+ future.catchError((_) => null);
+
+ return future;
+ }
+
/// Returns a string representation of all errors registered on this schedule.
String errorString() {
if (errors.isEmpty) return "The schedule had no errors.";
@@ -285,6 +315,14 @@ class Schedule {
if (_noPendingCallbacks == null) _noPendingCallbacks = new Completer();
return _noPendingCallbacks.future;
}
+
+ /// Register an error in the schedule's error list. This ensures that there
+ /// are no duplicate errors, and that all errors are wrapped in
+ /// [ScheduleError].
+ void _addError(error) {
+ if (errors.contains(error)) return;
+ errors.add(new ScheduleError.from(this, error));
+ }
}
/// An enum of states for a [Schedule].
@@ -333,6 +371,10 @@ class TaskQueue {
TaskQueue._(this.name, this._schedule);
+ /// Whether this queue is currently running.
+ bool get isRunning => _schedule.state == ScheduleState.RUNNING &&
+ _schedule.currentQueue == this;
Bob Nystrom 2013/02/19 23:15:04 Indent +2.
nweiz 2013/02/20 00:23:12 Done.
+
/// Schedules a task, [fn], to run asynchronously as part of this queue. Tasks
/// will be run in the order they're scheduled. In [fn] returns a [Future],
/// tasks after it won't be run until that [Future] completes.
@@ -343,8 +385,21 @@ class TaskQueue {
///
/// If [description] is passed, it's used to describe the task for debugging
/// purposes when an error occurs.
+ ///
+ /// If this is called when this queue is currently running, it will run [fn]
+ /// on the next event loop iteration rather than adding it to a queue. The
+ /// current task will not complete until [fn] (and any [Future] it returns)
+ /// has finished running. Any errors in [fn] will automatically be handled.
Future schedule(fn(), [String description]) {
- var task = new Task(fn, this, description);
+ if (isRunning) {
+ var task = _schedule.currentTask;
+ var wrappedFn = () => _schedule.wrapFuture(
+ new Future.immediate(null).then((_) => fn()));
+ if (task == null) return wrappedFn();
+ return task.runChild(wrappedFn, description);
+ }
+
+ var task = new Task(fn, description, this);
_contents.add(task);
return task.result;
}
@@ -362,7 +417,7 @@ class TaskQueue {
_taskFuture = null;
_schedule.heartbeat();
}).catchError((e) {
- if (_error != null) _schedule.errors.add(_error);
+ if (_error != null) _schedule._addError(_error);
throw new ScheduleError.from(_schedule, e);
});
}).whenComplete(() {
@@ -379,7 +434,7 @@ class TaskQueue {
void _signalError(ScheduleError error) {
// If multiple errors are detected while a task is running, make sure the
// earlier ones are recorded in the schedule.
- if (_error != null) _schedule.errors.add(_error);
+ if (_error != null) _schedule._addError(_error);
_error = error;
}

Powered by Google App Engine
This is Rietveld 408576698