Commit 7cf362fc authored by Nate Bosch's avatar Nate Bosch Committed by Jonah Williams

Handle onError callback with optional argument (#43436)

Check for a binary callback first since a function with an optional
second argument will match both typedefs.

Remove documentation around a synchronous error following some other
error or value - a synchronous error can never follow a value or an
asynchronous error. If there is a synchronous error it will _always_ be
the first thing to happen.

Add a test for a unary error handler and an error handler with an
optional stack trace argument.
parent 0dc5ea4a
......@@ -26,8 +26,7 @@ import 'dart:async';
/// completed with its result when passed the error object and stack trace.
///
/// After the returned [Future] is completed, whether it be with a value or an
/// error, all further errors resulting from the execution of [fn] both
/// synchronous and asynchronous are ignored.
/// error, all further errors resulting from the execution of [fn] are ignored.
///
/// Rationale:
///
......@@ -100,10 +99,10 @@ Future<T> asyncGuard<T>(
completer.completeError(e, s);
return;
}
if (onError is _UnaryOnError) {
completer.complete(onError(e));
} else if (onError is _BinaryOnError) {
if (onError is _BinaryOnError) {
completer.complete(onError(e, s));
} else if (onError is _UnaryOnError) {
completer.complete(onError(e));
}
}
......
......@@ -181,7 +181,7 @@ void main() {
expect(caughtByCatchError, true);
});
test('asyncError is propagated correctly with onError callback', () async {
test('asyncError is propagated with binary onError', () async {
bool caughtByZone = false;
bool caughtByHandler = false;
bool caughtByOnError = false;
......@@ -218,4 +218,83 @@ void main() {
expect(caughtByHandler, false);
expect(caughtByOnError, true);
});
test('asyncError is propagated with unary onError', () async {
bool caughtByZone = false;
bool caughtByHandler = false;
bool caughtByOnError = false;
final Completer<void> completer = Completer<void>();
await FakeAsync().run((FakeAsync time) {
unawaited(runZoned(() async {
final Future<void> f = asyncGuard<void>(
() => delayedThrow(time),
onError: (Object e) {
caughtByOnError = true;
},
);
try {
await f;
} catch (e) {
caughtByHandler = true;
}
if (!completer.isCompleted) {
completer.complete(null);
}
}, onError: (Object e, StackTrace s) {
caughtByZone = true;
if (!completer.isCompleted) {
completer.complete(null);
}
}));
time.elapse(const Duration(seconds: 1));
time.flushMicrotasks();
return completer.future;
});
expect(caughtByZone, false);
expect(caughtByHandler, false);
expect(caughtByOnError, true);
});
test('asyncError is propagated with optional stack trace', () async {
bool caughtByZone = false;
bool caughtByHandler = false;
bool caughtByOnError = false;
bool nonNullStackTrace = false;
final Completer<void> completer = Completer<void>();
await FakeAsync().run((FakeAsync time) {
unawaited(runZoned(() async {
final Future<void> f = asyncGuard<void>(
() => delayedThrow(time),
onError: (Object e, [StackTrace s]) {
caughtByOnError = true;
nonNullStackTrace = s != null;
},
);
try {
await f;
} catch (e) {
caughtByHandler = true;
}
if (!completer.isCompleted) {
completer.complete(null);
}
}, onError: (Object e, StackTrace s) {
caughtByZone = true;
if (!completer.isCompleted) {
completer.complete(null);
}
}));
time.elapse(const Duration(seconds: 1));
time.flushMicrotasks();
return completer.future;
});
expect(caughtByZone, false);
expect(caughtByHandler, false);
expect(caughtByOnError, true);
expect(nonNullStackTrace, true);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment