Unverified Commit 5a52ad6d authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[framework] Remove danger zone (#100246)

parent 0adf9671
...@@ -435,38 +435,21 @@ abstract class ImageProvider<T extends Object> { ...@@ -435,38 +435,21 @@ abstract class ImageProvider<T extends Object> {
didError = true; didError = true;
} }
// If an error is added to a synchronous completer before a listener has been Future<T> key;
// added, it can throw an error both into the zone and up the stack. Thus, it try {
// looks like the error has been caught, but it is in fact also bubbling to the key = obtainKey(configuration);
// zone. Since we cannot prevent all usage of Completer.sync here, or rather } catch (error, stackTrace) {
// that changing them would be too breaking, we instead hook into the same handleError(error, stackTrace);
// zone mechanism to intercept the uncaught error and deliver it to the return;
// image stream's error handler. Note that these errors may be duplicated, }
// hence the need for the `didError` flag. key.then<void>((T key) {
final Zone dangerZone = Zone.current.fork( obtainedKey = key;
specification: ZoneSpecification(
handleUncaughtError: (Zone zone, ZoneDelegate delegate, Zone parent, Object error, StackTrace stackTrace) {
handleError(error, stackTrace);
},
),
);
dangerZone.runGuarded(() {
Future<T> key;
try { try {
key = obtainKey(configuration); successCallback(key, handleError);
} catch (error, stackTrace) { } catch (error, stackTrace) {
handleError(error, stackTrace); handleError(error, stackTrace);
return;
} }
key.then<void>((T key) { }).catchError(handleError);
obtainedKey = key;
try {
successCallback(key, handleError);
} catch (error, stackTrace) {
handleError(error, stackTrace);
}
}).catchError(handleError);
});
} }
/// Called by [resolve] with the key returned by [obtainKey]. /// Called by [resolve] with the key returned by [obtainKey].
......
...@@ -57,55 +57,6 @@ void main() { ...@@ -57,55 +57,6 @@ void main() {
expect(await caughtError.future, true); expect(await caughtError.future, true);
}); });
test('resolve sync errors will be caught', () async {
bool uncaught = false;
final Zone testZone = Zone.current.fork(specification: ZoneSpecification(
handleUncaughtError: (Zone zone, ZoneDelegate zoneDelegate, Zone parent, Object error, StackTrace stackTrace) {
uncaught = true;
},
));
await testZone.run(() async {
final ImageProvider imageProvider = LoadErrorImageProvider();
final Completer<bool> caughtError = Completer<bool>();
FlutterError.onError = (FlutterErrorDetails details) {
throw Error();
};
final ImageStream result = imageProvider.resolve(ImageConfiguration.empty);
result.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {
}, onError: (dynamic error, StackTrace? stackTrace) {
caughtError.complete(true);
}));
expect(await caughtError.future, true);
});
expect(uncaught, false);
});
test('resolve errors in the completer will be caught', () async {
bool uncaught = false;
final Zone testZone = Zone.current.fork(specification: ZoneSpecification(
handleUncaughtError: (Zone zone, ZoneDelegate zoneDelegate, Zone parent, Object error, StackTrace stackTrace) {
uncaught = true;
},
));
await testZone.run(() async {
final ImageProvider imageProvider = LoadErrorCompleterImageProvider();
final Completer<bool> caughtError = Completer<bool>();
final Completer<bool> onErrorCompleter = Completer<bool>();
FlutterError.onError = (FlutterErrorDetails details) {
onErrorCompleter.complete(true);
throw Error();
};
final ImageStream result = imageProvider.resolve(ImageConfiguration.empty);
result.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {
}, onError: (dynamic error, StackTrace? stackTrace) {
caughtError.complete(true);
}));
expect(await caughtError.future, true);
expect(await onErrorCompleter.future, true);
});
expect(uncaught, false);
});
test('File image with empty file throws expected error and evicts from cache', () async { test('File image with empty file throws expected error and evicts from cache', () async {
final Completer<StateError> error = Completer<StateError>(); final Completer<StateError> error = Completer<StateError>();
FlutterError.onError = (FlutterErrorDetails details) { FlutterError.onError = (FlutterErrorDetails details) {
......
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