From 1436635d27448ac995309692fc4f0add62182556 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 28 Feb 2024 20:36:58 +0000 Subject: [PATCH] Add more information to `ParalleWaitError.toString`. Gives the constructor optional parameters for providing more information that can be used in the `toString` message, and the `stackTrace` getter. Makes the `iterable.wait` and `record.wait` extension methods provide such information, so that the `toString` will always contain the text of *one* of the errors. (No issue, problem with logging was brought up in chat.) Change-Id: I5f9a20ad0af0c64a2e7ff3cdb56f187a5cf5a3ca Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/353080 Reviewed-by: Martin Kustermann Commit-Queue: Lasse Nielsen Reviewed-by: Stephen Adams --- CHANGELOG.md | 7 + sdk/lib/async/future_extensions.dart | 158 +++++++++++---- .../async/future_iterable_extension_test.dart | 94 ++++++++- .../async/future_record_extension_test.dart | 185 +++++++++++------- 4 files changed, 322 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa08c2c25c1..70f5aa09652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,13 @@ ### Libraries +#### `dart:async` + +- Added option for `ParallelWaitError` to get some meta-information that + it can expose in its `toString`, and the `Iterable.wait` and + `(Future,...,Future).wait` extension methods now provide that information. + Should make a `ParallelWaitError` easier to log. + #### `dart:ffi` - Added `Struct.create` and `Union.create` to create struct and union views diff --git a/sdk/lib/async/future_extensions.dart b/sdk/lib/async/future_extensions.dart index b495d4a1905..dd130b33b79 100644 --- a/sdk/lib/async/future_extensions.dart +++ b/sdk/lib/async/future_extensions.dart @@ -36,16 +36,18 @@ extension FutureIterable on Iterable> { if (errors == 0) { c.complete([for (var r in results) r.value]); } else { + var errorList = [for (var r in results) r.errorOrNull]; c.completeError(ParallelWaitError, List>( - [for (var r in results) r.valueOrNull], - [for (var r in results) r.errorOrNull], - )); + [for (var r in results) r.valueOrNull], errorList, + errorCount: errors, defaultError: errorList.firstWhere(_notNull))); } }); return c.future; } } +bool _notNull(Object? object) => object != null; + /// Parallel operations on a record of futures. /// /// {@template record-parallel-wait} @@ -81,6 +83,8 @@ extension FutureRecord2 on (Future, Future) { c.completeError(ParallelWaitError( (v1.valueOrNull, v2.valueOrNull), (v1.errorOrNull, v2.errorOrNull), + errorCount: errors, + defaultError: v1.errorOrNull ?? v2.errorOrNull )); } }); @@ -105,6 +109,8 @@ extension FutureRecord3 on (Future, Future, Future) { c.completeError(ParallelWaitError( (v1.valueOrNull, v2.valueOrNull, v3.valueOrNull), (v1.errorOrNull, v2.errorOrNull, v3.errorOrNull), + errorCount: errors, + defaultError: v1.errorOrNull ?? v2.errorOrNull ?? v3.errorOrNull, )); } }); @@ -135,6 +141,11 @@ extension FutureRecord4 on ( c.completeError(ParallelWaitError( (v1.valueOrNull, v2.valueOrNull, v3.valueOrNull, v4.valueOrNull), (v1.errorOrNull, v2.errorOrNull, v3.errorOrNull, v4.errorOrNull), + errorCount: errors, + defaultError: v1.errorOrNull ?? + v2.errorOrNull ?? + v3.errorOrNull ?? + v4.errorOrNull, )); } }); @@ -179,6 +190,12 @@ extension FutureRecord5 on ( v4.errorOrNull, v5.errorOrNull ), + errorCount: errors, + defaultError: v1.errorOrNull ?? + v2.errorOrNull ?? + v3.errorOrNull ?? + v4.errorOrNull ?? + v5.errorOrNull )); } }); @@ -227,7 +244,14 @@ extension FutureRecord6 on ( v4.errorOrNull, v5.errorOrNull, v6.errorOrNull - ), + ), + errorCount: errors, + defaultError: v1.errorOrNull ?? + v2.errorOrNull ?? + v3.errorOrNull ?? + v4.errorOrNull ?? + v5.errorOrNull ?? + v6.errorOrNull )); } }); @@ -259,16 +283,15 @@ extension FutureRecord7 on ( _FutureResult._waitAll([v1, v2, v3, v4, v5, v6, v7], (int errors) { if (errors == 0) { - c.complete( - ( - v1.value, - v2.value, - v3.value, - v4.value, - v5.value, - v6.value, - v7.value - )); + c.complete(( + v1.value, + v2.value, + v3.value, + v4.value, + v5.value, + v6.value, + v7.value + )); } else { c.completeError(ParallelWaitError( ( @@ -289,6 +312,14 @@ extension FutureRecord7 on ( v6.errorOrNull, v7.errorOrNull ), + errorCount: errors, + defaultError: v1.errorOrNull ?? + v2.errorOrNull ?? + v3.errorOrNull ?? + v4.errorOrNull ?? + v5.errorOrNull ?? + v6.errorOrNull ?? + v7.errorOrNull )); } }); @@ -322,17 +353,16 @@ extension FutureRecord8 on ( _FutureResult._waitAll([v1, v2, v3, v4, v5, v6, v7, v8], (int errors) { if (errors == 0) { - c.complete( - ( - v1.value, - v2.value, - v3.value, - v4.value, - v5.value, - v6.value, - v7.value, - v8.value - )); + c.complete(( + v1.value, + v2.value, + v3.value, + v4.value, + v5.value, + v6.value, + v7.value, + v8.value + )); } else { c.completeError(ParallelWaitError( ( @@ -355,6 +385,15 @@ extension FutureRecord8 on ( v7.errorOrNull, v8.errorOrNull ), + errorCount: errors, + defaultError: v1.errorOrNull ?? + v2.errorOrNull ?? + v3.errorOrNull ?? + v4.errorOrNull ?? + v5.errorOrNull ?? + v6.errorOrNull ?? + v7.errorOrNull ?? + v8.errorOrNull )); } }); @@ -390,18 +429,17 @@ extension FutureRecord9 on ( _FutureResult._waitAll([v1, v2, v3, v4, v5, v6, v7, v8, v9], (int errors) { if (errors == 0) { - c.complete( - ( - v1.value, - v2.value, - v3.value, - v4.value, - v5.value, - v6.value, - v7.value, - v8.value, - v9.value - )); + c.complete(( + v1.value, + v2.value, + v3.value, + v4.value, + v5.value, + v6.value, + v7.value, + v8.value, + v9.value + )); } else { c.completeError(ParallelWaitError( ( @@ -426,6 +464,16 @@ extension FutureRecord9 on ( v8.errorOrNull, v9.errorOrNull ), + errorCount: errors, + defaultError: v1.errorOrNull ?? + v2.errorOrNull ?? + v3.errorOrNull ?? + v4.errorOrNull ?? + v5.errorOrNull ?? + v6.errorOrNull ?? + v7.errorOrNull ?? + v8.errorOrNull ?? + v9.errorOrNull )); } }); @@ -464,10 +512,40 @@ class ParallelWaitError extends Error { /// future and `null` values for each successful future. final E errors; - /// Creates error with the provided [values] and [errors]. - ParallelWaitError(this.values, this.errors); + /// An error which, if present, is included in the [toString] output. + /// + /// If the default error has a stack trace, it's also reported by the + /// [stackTrace] getter, instead of where this [ParallelWaitError] was thrown. + final AsyncError? _defaultError; - String toString() => "ParallelWaitError"; + /// Number of errors, if available. + final int? _errorCount; + + /// Creates error with the provided [values] and [errors]. + /// + /// If [defaultError] is provided, its [AsyncError.error] is used in + /// the [toString] of this parallel error, and its [AsyncError.stackTrace] + /// is returned by [stackTrace]. + /// + /// If [errorCount] is provided, and it's greater than one, + /// the number is reported in the [toString]. + ParallelWaitError(this.values, this.errors, + {int? errorCount, AsyncError? defaultError}) + : _defaultError = defaultError, + _errorCount = errorCount; + + String toString() { + if (_defaultError == null) { + if (_errorCount == null || _errorCount <= 1) { + return "ParallelWaitError"; + } + return "ParallelWaitError($_errorCount errors)"; + } + return "ParallelWaitError${_errorCount != null && _errorCount > 1 // + ? "($_errorCount errors)" : ""}: ${_defaultError.error}"; + } + + StackTrace? get stackTrace => _defaultError?.stackTrace ?? super.stackTrace; } /// The result of a future, when it has completed. diff --git a/tests/lib/async/future_iterable_extension_test.dart b/tests/lib/async/future_iterable_extension_test.dart index 1ef8eafbda0..780344fd984 100644 --- a/tests/lib/async/future_iterable_extension_test.dart +++ b/tests/lib/async/future_iterable_extension_test.dart @@ -6,12 +6,14 @@ import "dart:async"; import 'package:async_helper/async_helper.dart'; import "package:expect/expect.dart"; -import '../../language/static_type_helper.dart'; void main() async { asyncStart(); var futures = [for (var i = 0; i < 5; i++) Future.value(i)]; - var errors = [for (var i = 0; i < 5; i++) Future.error("e$i")..ignore()]; + var errors = [ + for (var i = 0; i < 5; i++) + Future.error("error $i", StackTrace.fromString("stack $i"))..ignore() + ]; // Empty list. Expect.listEquals([], await >[].wait); @@ -35,9 +37,14 @@ void main() async { Expect.isNull(e.errors[0]); Expect.isNull(e.errors[1]); - Expect.equals("e2", e.errors[2]?.error); + Expect.equals("error 2", e.errors[2]?.error); Expect.isNull(e.errors[3]); Expect.isNull(e.errors[4]); + + var toString = e.toString(); + Expect.contains("ParallelWaitError:", toString); + Expect.contains("error 2", toString); + Expect.equals("stack 2", e.stackTrace.toString()); } // Multiple errors. @@ -52,10 +59,15 @@ void main() async { Expect.equals(4, e.values[4]); Expect.isNull(e.errors[0]); - Expect.equals("e1", e.errors[1]?.error); + Expect.equals("error 1", e.errors[1]?.error); Expect.isNull(e.errors[2]); - Expect.equals("e3", e.errors[3]?.error); + Expect.equals("error 3", e.errors[3]?.error); Expect.isNull(e.errors[4]); + + var toString = e.toString(); + Expect.contains("ParallelWaitError(2 errors):", toString); + Expect.containsOneOf(["error 1", "error 3"], toString); + Expect.containsOneOf(["stack 1", "stack 3"], e.stackTrace.toString()); } // All errors. @@ -69,11 +81,73 @@ void main() async { Expect.isNull(e.values[3]); Expect.isNull(e.values[4]); - Expect.equals("e0", e.errors[0]?.error); - Expect.equals("e1", e.errors[1]?.error); - Expect.equals("e2", e.errors[2]?.error); - Expect.equals("e3", e.errors[3]?.error); - Expect.equals("e4", e.errors[4]?.error); + Expect.equals("error 0", e.errors[0]?.error); + Expect.equals("error 1", e.errors[1]?.error); + Expect.equals("error 2", e.errors[2]?.error); + Expect.equals("error 3", e.errors[3]?.error); + Expect.equals("error 4", e.errors[4]?.error); + + var toString = e.toString(); + Expect.contains("ParallelWaitError(5 errors):", toString); + Expect.containsOneOf( + ["error 0", "error 1", "error 2", "error 3", "error 4"], toString); + Expect.containsOneOf( + ["stack 0", "stack 1", "stack 2", "stack 3", "stack 4"], + e.stackTrace.toString()); } + + // Direct tests of `ParallelWaitError`. + + Expect.equals("ParallelWaitError", + ParallelWaitError(null, null, errorCount: null).toString()); + Expect.equals("ParallelWaitError", + ParallelWaitError(null, null, errorCount: 0).toString()); + Expect.equals("ParallelWaitError", + ParallelWaitError(null, null, errorCount: 1).toString()); + Expect.equals("ParallelWaitError(2 errors)", + ParallelWaitError(null, null, errorCount: 2).toString()); + Expect.equals("ParallelWaitError(9999 errors)", + ParallelWaitError(null, null, errorCount: 9999).toString()); + + var defaultError = AsyncError( + StateError("default error"), StackTrace.fromString("default stack")); + final ParallelWaitError unthrownWithoutDefault = + ParallelWaitError(null, null); + final ParallelWaitError unthrownWithDefault = + ParallelWaitError(null, null, defaultError: defaultError); + final ParallelWaitError thrownWithoutDefault; + final StackTrace thrownWithoutDefaultStack; + try { + throw ParallelWaitError(null, null); + } catch (e, s) { + thrownWithoutDefault = e as ParallelWaitError; + thrownWithoutDefaultStack = s; + } + final ParallelWaitError thrownWithDefault; + try { + throw ParallelWaitError(null, null, defaultError: defaultError); + } catch (e) { + thrownWithDefault = e as ParallelWaitError; + } + + Expect.equals("ParallelWaitError", thrownWithoutDefault.toString()); + Expect.equals("ParallelWaitError", unthrownWithoutDefault.toString()); + Expect.equals( + "ParallelWaitError: ${defaultError.error}", thrownWithDefault.toString()); + Expect.equals("ParallelWaitError: ${defaultError.error}", + unthrownWithDefault.toString()); + + Expect.identical(unthrownWithDefault.stackTrace, defaultError.stackTrace); + Expect.identical(thrownWithDefault.stackTrace, defaultError.stackTrace); + Expect.equals(thrownWithoutDefault.stackTrace.toString(), + thrownWithoutDefaultStack.toString()); + Expect.isNull(unthrownWithoutDefault.stackTrace); + + // Both default and count. + Expect.equals( + "ParallelWaitError(25 errors): ${defaultError.error}", + ParallelWaitError(null, null, + errorCount: 25, defaultError: defaultError) + .toString()); asyncEnd(); } diff --git a/tests/lib/async/future_record_extension_test.dart b/tests/lib/async/future_record_extension_test.dart index 9e67d6fdb73..e8ddce9d469 100644 --- a/tests/lib/async/future_record_extension_test.dart +++ b/tests/lib/async/future_record_extension_test.dart @@ -6,17 +6,24 @@ import "dart:async"; import 'package:async_helper/async_helper.dart'; import "package:expect/expect.dart"; -import '../../language/static_type_helper.dart'; + +final fi = Future.value(2); +final fb = Future.value(true); +final fs = Future.value("s"); +final ie = StateError("ie error"); +final be = StateError("be error"); +final se = StateError("se error"); +final stie = StackTrace.fromString("ie stack"); +final stbe = StackTrace.fromString("be stack"); +final stse = StackTrace.fromString("se stack"); +final fie = Future.error(ie, stie)..ignore(); +final fbe = Future.error(be, stbe)..ignore(); +final fse = Future.error(se, stse)..ignore(); +final fsn = Completer().future; // Never completes. +final errorStackMapping = {ie: stie, be: stbe, se: stse}; void main() async { asyncStart(); - var fi = Future.value(2); - var fb = Future.value(true); - var fs = Future.value("s"); - var fie = Future.error("ie", StackTrace.empty)..ignore(); - var fbe = Future.error("be", StackTrace.empty)..ignore(); - var fse = Future.error("se", StackTrace.empty)..ignore(); - var fsn = Completer().future; // Never completes. { // 2-tuple `wait` getter. @@ -33,7 +40,8 @@ void main() async { (AsyncError?, AsyncError?)> catch (e, s) { Expect.equals((2, null), e.values); Expect.isNull(e.errors.$1); - Expect.equals("be", e.errors.$2?.error); + Expect.equals(be, e.errors.$2?.error); + checkDefaultError(e, 1, [be]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -45,8 +53,9 @@ void main() async { } on ParallelWaitError<(int?, bool?), (AsyncError?, AsyncError?)> catch (e, s) { Expect.equals((null, null), e.values); - Expect.equals("ie", e.errors.$1?.error); - Expect.equals("be", e.errors.$2?.error); + Expect.equals(ie, e.errors.$1?.error); + Expect.equals(be, e.errors.$2?.error); + checkDefaultError(e, 2, [ie, be]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -67,8 +76,9 @@ void main() async { (AsyncError?, AsyncError?, AsyncError?)> catch (e, s) { Expect.equals((true, null, 2), e.values); Expect.isNull(e.errors.$1); - Expect.equals("se", e.errors.$2?.error); + Expect.equals(se, e.errors.$2?.error); Expect.isNull(e.errors.$3); + checkDefaultError(e, 1, [se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -80,9 +90,10 @@ void main() async { } on ParallelWaitError<(bool?, String?, int?), (AsyncError?, AsyncError?, AsyncError?)> catch (e, s) { Expect.equals((null, null, null), e.values); - Expect.equals("be", e.errors.$1?.error); - Expect.equals("se", e.errors.$2?.error); - Expect.equals("ie", e.errors.$3?.error); + Expect.equals(be, e.errors.$1?.error); + Expect.equals(se, e.errors.$2?.error); + Expect.equals(ie, e.errors.$3?.error); + checkDefaultError(e, 3, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -103,9 +114,10 @@ void main() async { (AsyncError?, AsyncError?, AsyncError?, AsyncError?)> catch (e, s) { Expect.equals(("s", null, true, null), e.values); Expect.isNull(e.errors.$1); - Expect.equals("ie", e.errors.$2?.error); + Expect.equals(ie, e.errors.$2?.error); Expect.isNull(e.errors.$3); - Expect.equals("se", e.errors.$4?.error); + Expect.equals(se, e.errors.$4?.error); + checkDefaultError(e, 2, [ie, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -117,10 +129,11 @@ void main() async { } on ParallelWaitError<(String?, int?, bool?, String?), (AsyncError?, AsyncError?, AsyncError?, AsyncError?)> catch (e, s) { Expect.equals((null, null, null, null), e.values); - Expect.equals("se", e.errors.$1?.error); - Expect.equals("ie", e.errors.$2?.error); - Expect.equals("be", e.errors.$3?.error); - Expect.equals("se", e.errors.$4?.error); + Expect.equals(se, e.errors.$1?.error); + Expect.equals(ie, e.errors.$2?.error); + Expect.equals(be, e.errors.$3?.error); + Expect.equals(se, e.errors.$4?.error); + checkDefaultError(e, 4, [se, ie, be]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -148,10 +161,11 @@ void main() async { )> catch (e, s) { Expect.equals((2, null, "s", null, true), e.values); Expect.isNull(e.errors.$1); - Expect.equals("be", e.errors.$2?.error); + Expect.equals(be, e.errors.$2?.error); Expect.isNull(e.errors.$3); - Expect.equals("ie", e.errors.$4?.error); + Expect.equals(ie, e.errors.$4?.error); Expect.isNull(e.errors.$5); + checkDefaultError(e, 2, [ie, be]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -170,11 +184,12 @@ void main() async { AsyncError? )> catch (e, s) { Expect.equals((null, null, null, null, null), e.values); - Expect.equals("ie", e.errors.$1?.error); - Expect.equals("be", e.errors.$2?.error); - Expect.equals("se", e.errors.$3?.error); - Expect.equals("ie", e.errors.$4?.error); - Expect.equals("be", e.errors.$5?.error); + Expect.equals(ie, e.errors.$1?.error); + Expect.equals(be, e.errors.$2?.error); + Expect.equals(se, e.errors.$3?.error); + Expect.equals(ie, e.errors.$4?.error); + Expect.equals(be, e.errors.$5?.error); + checkDefaultError(e, 5, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -203,11 +218,12 @@ void main() async { )> catch (e, s) { Expect.equals((true, null, 2, null, "s", null), e.values); Expect.isNull(e.errors.$1); - Expect.equals("se", e.errors.$2?.error); + Expect.equals(se, e.errors.$2?.error); Expect.isNull(e.errors.$3); - Expect.equals("be", e.errors.$4?.error); + Expect.equals(be, e.errors.$4?.error); Expect.isNull(e.errors.$5); - Expect.equals("ie", e.errors.$6?.error); + Expect.equals(ie, e.errors.$6?.error); + checkDefaultError(e, 3, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -227,12 +243,13 @@ void main() async { AsyncError? )> catch (e, s) { Expect.equals((null, null, null, null, null, null), e.values); - Expect.equals("be", e.errors.$1?.error); - Expect.equals("se", e.errors.$2?.error); - Expect.equals("ie", e.errors.$3?.error); - Expect.equals("be", e.errors.$4?.error); - Expect.equals("se", e.errors.$5?.error); - Expect.equals("ie", e.errors.$6?.error); + Expect.equals(be, e.errors.$1?.error); + Expect.equals(se, e.errors.$2?.error); + Expect.equals(ie, e.errors.$3?.error); + Expect.equals(be, e.errors.$4?.error); + Expect.equals(se, e.errors.$5?.error); + Expect.equals(ie, e.errors.$6?.error); + checkDefaultError(e, 6, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -262,12 +279,13 @@ void main() async { )> catch (e, s) { Expect.equals(("s", null, true, null, 2, null, "s"), e.values); Expect.isNull(e.errors.$1); - Expect.equals("ie", e.errors.$2?.error); + Expect.equals(ie, e.errors.$2?.error); Expect.isNull(e.errors.$3); - Expect.equals("se", e.errors.$4?.error); + Expect.equals(se, e.errors.$4?.error); Expect.isNull(e.errors.$5); - Expect.equals("be", e.errors.$6?.error); + Expect.equals(be, e.errors.$6?.error); Expect.isNull(e.errors.$7); + checkDefaultError(e, 3, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -288,13 +306,14 @@ void main() async { AsyncError? )> catch (e, s) { Expect.equals((null, null, null, null, null, null, null), e.values); - Expect.equals("se", e.errors.$1?.error); - Expect.equals("ie", e.errors.$2?.error); - Expect.equals("be", e.errors.$3?.error); - Expect.equals("se", e.errors.$4?.error); - Expect.equals("ie", e.errors.$5?.error); - Expect.equals("be", e.errors.$6?.error); - Expect.equals("se", e.errors.$7?.error); + Expect.equals(se, e.errors.$1?.error); + Expect.equals(ie, e.errors.$2?.error); + Expect.equals(be, e.errors.$3?.error); + Expect.equals(se, e.errors.$4?.error); + Expect.equals(ie, e.errors.$5?.error); + Expect.equals(be, e.errors.$6?.error); + Expect.equals(se, e.errors.$7?.error); + checkDefaultError(e, 7, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -325,13 +344,14 @@ void main() async { )> catch (e, s) { Expect.equals((2, null, "s", null, true, null, 2, null), e.values); Expect.isNull(e.errors.$1); - Expect.equals("be", e.errors.$2?.error); + Expect.equals(be, e.errors.$2?.error); Expect.isNull(e.errors.$3); - Expect.equals("ie", e.errors.$4?.error); + Expect.equals(ie, e.errors.$4?.error); Expect.isNull(e.errors.$5); - Expect.equals("se", e.errors.$6?.error); + Expect.equals(se, e.errors.$6?.error); Expect.isNull(e.errors.$7); - Expect.equals("be", e.errors.$8?.error); + Expect.equals(be, e.errors.$8?.error); + checkDefaultError(e, 4, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -353,14 +373,15 @@ void main() async { AsyncError? )> catch (e, s) { Expect.equals((null, null, null, null, null, null, null, null), e.values); - Expect.equals("ie", e.errors.$1?.error); - Expect.equals("be", e.errors.$2?.error); - Expect.equals("se", e.errors.$3?.error); - Expect.equals("ie", e.errors.$4?.error); - Expect.equals("be", e.errors.$5?.error); - Expect.equals("se", e.errors.$6?.error); - Expect.equals("ie", e.errors.$7?.error); - Expect.equals("be", e.errors.$8?.error); + Expect.equals(ie, e.errors.$1?.error); + Expect.equals(be, e.errors.$2?.error); + Expect.equals(se, e.errors.$3?.error); + Expect.equals(ie, e.errors.$4?.error); + Expect.equals(be, e.errors.$5?.error); + Expect.equals(se, e.errors.$6?.error); + Expect.equals(ie, e.errors.$7?.error); + Expect.equals(be, e.errors.$8?.error); + checkDefaultError(e, 8, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -392,14 +413,15 @@ void main() async { )> catch (e, s) { Expect.equals((true, null, 2, null, "s", null, true, null, 2), e.values); Expect.isNull(e.errors.$1); - Expect.equals("se", e.errors.$2?.error); + Expect.equals(se, e.errors.$2?.error); Expect.isNull(e.errors.$3); - Expect.equals("be", e.errors.$4?.error); + Expect.equals(be, e.errors.$4?.error); Expect.isNull(e.errors.$5); - Expect.equals("ie", e.errors.$6?.error); + Expect.equals(ie, e.errors.$6?.error); Expect.isNull(e.errors.$7); - Expect.equals("se", e.errors.$8?.error); + Expect.equals(se, e.errors.$8?.error); Expect.isNull(e.errors.$9); + checkDefaultError(e, 4, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -423,15 +445,16 @@ void main() async { )> catch (e, s) { Expect.equals( (null, null, null, null, null, null, null, null, null), e.values); - Expect.equals("be", e.errors.$1?.error); - Expect.equals("se", e.errors.$2?.error); - Expect.equals("ie", e.errors.$3?.error); - Expect.equals("be", e.errors.$4?.error); - Expect.equals("se", e.errors.$5?.error); - Expect.equals("ie", e.errors.$6?.error); - Expect.equals("be", e.errors.$7?.error); - Expect.equals("se", e.errors.$8?.error); - Expect.equals("ie", e.errors.$9?.error); + Expect.equals(be, e.errors.$1?.error); + Expect.equals(se, e.errors.$2?.error); + Expect.equals(ie, e.errors.$3?.error); + Expect.equals(be, e.errors.$4?.error); + Expect.equals(se, e.errors.$5?.error); + Expect.equals(ie, e.errors.$6?.error); + Expect.equals(be, e.errors.$7?.error); + Expect.equals(se, e.errors.$8?.error); + Expect.equals(ie, e.errors.$9?.error); + checkDefaultError(e, 9, [ie, be, se]); } on Object catch (e) { Expect.fail("Did not throw expected error: ${e.runtimeType}"); } @@ -439,3 +462,21 @@ void main() async { asyncEnd(); } + +void checkDefaultError( + ParallelWaitError error, int errorCount, List expectedErrors) { + var toString = error.toString(); + if (errorCount > 1) { + Expect.contains("ParallelWaitError($errorCount errors):", toString); + } else { + Expect.contains("ParallelWaitError:", toString); + } + for (var expectedError in expectedErrors) { + if (toString.contains(expectedError.toString())) { + var expectedStack = errorStackMapping[expectedError]!; + Expect.equals(error.stackTrace.toString(), expectedStack.toString()); + return; + } + } + Expect.fail("Error toString did not contain one of the expected errors"); +}