Files
sdk/tests/lib/async/zone_error_callback_test.dart
T
Lasse R.H. Nielsen f8086c81ae Collect all test-related files in package:expect.
Collects files from `package:async_helper` and `tests/language`
that are generally useful, so that all test-related helpers are
in `package:expect`.

Moves the two libraries from `package:async_helper` into `package:expect`,
and the `tests/language/static_type_helper.dart` file too.

Deprecates `async_minitest.dart`, to follow `minitest.dart`,
expecting the Flutter use of it to have been fixed to not break
on deprecation (I believe Flutter no longer breaks builds on deprecations at all).

Patch 1 is the actual change.
Patch 2+4+8 is changing all existing references to the files.
Patch 6 ignores deprecation in files still using `async_minitest.dart`.

3+5+7+9 are updating this text to make the numbers match.
Then it's just test-expectations and small tweaks from there.

Change-Id: I1b665135b5fef9b9a0c3b340ffe9daf874d0174c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/373120
Reviewed-by: Nate Bosch <nbosch@google.com>
Reviewed-by: Devon Carew <devoncarew@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
2024-10-11 16:53:52 +00:00

350 lines
9.0 KiB
Dart

// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/async_helper.dart';
import 'package:expect/expect.dart';
import 'dart:async';
main() {
asyncStart();
testNoChange();
testWithReplacement();
asyncEnd();
}
class MockStack implements StackTrace {
final int id;
const MockStack(this.id);
String toString() => "MocKStack($id)";
}
const stack1 = const MockStack(1);
const stack2 = const MockStack(2);
class SomeError implements Error {
final int id;
const SomeError(this.id);
StackTrace get stackTrace => stack2;
String toString() => "SomeError($id)";
}
const error1 = const SomeError(1);
const error2 = const SomeError(2);
Null expectError(e, s) {
// Remember one asyncStart per use of this callback.
Expect.identical(error1, e);
Expect.identical(stack1, s);
asyncEnd();
return null;
}
Null expectErrorOnly(e, s) {
// Remember one asyncStart per use of this callback.
Expect.identical(error1, e);
asyncEnd();
return null;
}
AsyncError? replace(self, parent, zone, e, s) {
if (identical(error1, e)) {
// Give parent chance to replace your replacements.
return parent.errorCallback(zone, error2, stack2) ??
AsyncError(error2, stack2);
}
return parent.errorCallback(zone, e, s);
}
var replaceZoneSpec = new ZoneSpecification(errorCallback: replace);
// Expectation after replacing.
Null expectReplaced(e, s) {
Expect.identical(error2, e);
Expect.identical(stack2, s);
asyncEnd();
return null;
}
void testProgrammaticErrors(expectError) {
{
asyncStart();
Completer c = new Completer();
c.future.catchError(expectError);
c.completeError(error1, stack1);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream.listen(null, onError: expectError, cancelOnError: true);
controller.addError(error1, stack1);
}
{
asyncStart();
StreamController controller = new StreamController(sync: true);
controller.stream.listen(null, onError: expectError, cancelOnError: true);
controller.addError(error1, stack1);
}
{
asyncStart();
StreamController controller = new StreamController.broadcast();
controller.stream.listen(null, onError: expectError, cancelOnError: true);
controller.addError(error1, stack1);
}
{
asyncStart();
StreamController controller = new StreamController.broadcast(sync: true);
controller.stream.listen(null, onError: expectError, cancelOnError: true);
controller.addError(error1, stack1);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.asBroadcastStream()
.listen(null, onError: expectError, cancelOnError: true);
controller.addError(error1, stack1);
}
{
asyncStart();
StreamController controller = new StreamController(sync: true);
controller.stream
.asBroadcastStream()
.listen(null, onError: expectError, cancelOnError: true);
controller.addError(error1, stack1);
}
{
asyncStart();
Future f = new Future.error(error1, stack1);
f.catchError(expectError);
}
}
void testThrownErrors(expectErrorOnly) {
// Throw error in non-registered callback.
{
asyncStart();
Future f = new Future(() => throw error1);
f.catchError(expectErrorOnly);
}
{
asyncStart();
Future f = new Future.microtask(() => throw error1);
f.catchError(expectErrorOnly);
}
{
asyncStart();
Future f = new Future.sync(() => throw error1);
f.catchError(expectErrorOnly);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.map((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.where((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream.forEach((x) => throw error1).catchError(expectErrorOnly);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.expand((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.asyncMap((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.asyncExpand((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.handleError((e, s) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.addError("ignore", null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.skipWhile((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.takeWhile((x) => throw error1)
.listen(null, onError: expectErrorOnly, cancelOnError: true);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
Future<bool?>.value(controller.stream.every((x) => throw error1))
.catchError(expectErrorOnly);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
Future<bool?>.value(controller.stream.any((x) => throw error1))
.catchError(expectErrorOnly);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.firstWhere((x) => throw error1)
.catchError(expectErrorOnly);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.lastWhere((x) => throw error1)
.catchError(expectErrorOnly);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.singleWhere((x) => throw error1)
.catchError(expectErrorOnly);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.reduce((x, y) => throw error1)
.catchError(expectErrorOnly);
controller.add(null);
controller.add(null);
}
{
asyncStart();
StreamController controller = new StreamController();
controller.stream
.fold(null, (x, y) => throw error1)
.catchError(expectErrorOnly);
controller.add(null);
}
}
testNoChange() {
void testTransparent() {
testProgrammaticErrors(expectError);
testThrownErrors(expectErrorOnly);
}
// Run directly.
testTransparent();
// Run in a zone that doesn't change callback.
runZoned(testTransparent,
zoneSpecification:
new ZoneSpecification(handleUncaughtError: (s, p, z, e, t) {}));
// Run in zone that delegates to root zone
runZoned(testTransparent,
zoneSpecification: new ZoneSpecification(
errorCallback: (s, p, z, e, t) => p.errorCallback(z, e, t)));
// Run in a zone that returns null from the callback.
runZoned(testTransparent,
zoneSpecification:
new ZoneSpecification(errorCallback: (s, p, z, e, t) => null));
// Run in zone that returns same values.
runZoned(testTransparent,
zoneSpecification: new ZoneSpecification(
errorCallback: (s, p, z, e, t) => new AsyncError(e, t)));
// Run in zone that returns null, inside zone that does replacement.
runZoned(() {
runZoned(testTransparent,
zoneSpecification:
new ZoneSpecification(errorCallback: (s, p, z, e, t) => null));
}, zoneSpecification: replaceZoneSpec);
}
void testWithReplacement() {
void testReplaced() {
testProgrammaticErrors(expectReplaced);
testThrownErrors(expectReplaced);
}
// Zone which replaces errors.
runZoned(testReplaced, zoneSpecification: replaceZoneSpec);
// Nested zone, only innermost gets to act.
runZoned(() {
runZoned(testReplaced, zoneSpecification: replaceZoneSpec);
}, zoneSpecification: replaceZoneSpec);
// Use delegation to parent which replaces.
runZoned(() {
runZoned(testReplaced,
zoneSpecification: new ZoneSpecification(
errorCallback: (s, p, z, e, t) => p.errorCallback(z, e, t)));
}, zoneSpecification: replaceZoneSpec);
}