// Copyright (c) 2019, 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 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:path/path.dart' as path; import 'package:expect/expect.dart'; import 'package:native_stack_traces/native_stack_traces.dart'; // Test functions: Future throwSync() { throw 'throw from throwSync'; } Future throwAsync() async { await 0; throw 'throw from throwAsync'; } // ---- // Scenario: All async functions yielded at least once before throw: // ---- Future allYield() async { await 0; await allYield2(); } Future allYield2() async { await 0; await allYield3(); } Future allYield3() async { await 0; throwSync(); } // ---- // Scenario: None of the async functions yielded before the throw: // ---- Future noYields() async { await noYields2(); } Future noYields2() async { await noYields3(); } Future noYields3() async { throwSync(); } // ---- // Scenario: Mixed yielding and non-yielding frames: // ---- Future mixedYields() async { await mixedYields2(); } Future mixedYields2() async { await 0; await mixedYields3(); } Future mixedYields3() async { return throwAsync(); } // ---- // Scenario: Non-async frame: // ---- Future syncSuffix() async { await syncSuffix2(); } Future syncSuffix2() async { await 0; await syncSuffix3(); } Future syncSuffix3() { return throwAsync(); } // ---- // Scenario: Caller is non-async, has no upwards stack: // ---- Future nonAsyncNoStack() async => await nonAsyncNoStack1(); Future nonAsyncNoStack1() async => await nonAsyncNoStack2(); Future nonAsyncNoStack2() async => Future.value(0).then((_) => throwAsync()); // ---- // Scenario: async*: // ---- Future awaitEveryAsyncStarThrowSync() async { await for (Future v in asyncStarThrowSync()) { await v; } } Stream asyncStarThrowSync() async* { for (int i = 0; i < 2; i++) { await i; yield throwSync(); } } Future awaitEveryAsyncStarThrowAsync() async { await for (Future v in asyncStarThrowAsync()) { await v; } } Stream asyncStarThrowAsync() async* { for (int i = 0; i < 2; i++) { await i; yield Future.value(i); await throwAsync(); } } Future listenAsyncStarThrowAsync() async { // Listening to an async* doesn't create the usual await-for StreamIterator. StreamSubscription ss = asyncStarThrowAsync().listen((Future f) {}); await ss.asFuture(); } // ---- // Scenario: All async functions yielded and we run in a custom zone with a // custom error handler. // ---- Future customErrorZone() async { final completer = Completer(); runZonedGuarded(() async { await allYield(); completer.complete(null); }, (e, s) { completer.completeError(e, s); }); return completer.future; } // ---- // Scenario: Future.timeout: // ---- Future awaitTimeout() async { await (throwAsync().timeout(Duration(seconds: 1))); } // ---- // Scenario: Future.wait: // ---- Future awaitWait() async { await Future.wait([ throwAsync(), () async { await Future.value(); }() ]); } // ---- // Scenario: Future.whenComplete: // ---- Future futureSyncWhenComplete() { return Future.sync(throwAsync).whenComplete(() => 'nop'); } // ---- // Scenario: Future.then: // ---- Future futureThen() { return Future.value(0).then((value) { throwSync(); }); } // Helpers: // We want lines that either start with a frame index or an async gap marker. final _lineRE = RegExp(r'^(?:#(?\d+)|)'); Future assertStack(List expects, StackTrace stackTrace, [String? debugInfoFilename]) async { final original = await Stream.value(stackTrace.toString()) .transform(const LineSplitter()) .toList(); var frames = original; // Use the DWARF stack decoder if we're running in --dwarf-stack-traces mode // and in precompiled mode (otherwise --dwarf-stack-traces has no effect). final decodeTrace = frames.first.startsWith('Warning:'); if (decodeTrace) { Expect.isNotNull(debugInfoFilename); final dwarf = Dwarf.fromFile(debugInfoFilename!)!; frames = await Stream.fromIterable(original) .transform(DwarfStackTraceDecoder(dwarf)) .where(_lineRE.hasMatch) .toList(); } void printFrameInformation() { print('RegExps for expected stack:'); expects.forEach((s) => print('"${s}"')); print(''); if (decodeTrace) { print('Non-symbolic actual stack:'); original.forEach(print); print(''); } print('Actual stack:'); frames.forEach(print); print(''); } for (int i = 0; i < expects.length; i++) { try { Expect.isTrue(i < frames.length, 'Expected at least ${expects.length} frames, found ${frames.length}'); } on ExpectException { // On failed expect, print full stack for reference. printFrameInformation(); print('Expected line ${i + 1} to be ${expects[i]} but was missing'); rethrow; } try { Expect.isTrue(RegExp(expects[i]).hasMatch(frames[i])); } on ExpectException { // On failed expect, print full stack for reference. printFrameInformation(); print('Expected line ${i + 1} to be `${expects[i]}` ' 'but was `${frames[i]}`'); rethrow; } } try { Expect.equals(expects.length, frames.length); } on ExpectException { // On failed expect, print full stack for reference. printFrameInformation(); rethrow; } } Future doTestAwait(Future f(), List expectedStack, [String? debugInfoFilename]) async { // Caller catches exception. try { await f(); Expect.fail('No exception thrown!'); } on String catch (e, s) { return assertStack(expectedStack, s, debugInfoFilename); } } Future doTestAwaitThen(Future f(), List expectedStack, [String? debugInfoFilename]) async { // Caller catches but a then is set. try { // Passing (e) {} to then() can cause the closure instructions to be // dedupped, changing the stack trace to the dedupped owner, so we // duplicate the Expect.fail() call in the closure. await f().then((e) => Expect.fail('No exception thrown!')); Expect.fail('No exception thrown!'); } on String catch (e, s) { return assertStack(expectedStack, s, debugInfoFilename); } } Future doTestAwaitCatchError(Future f(), List expectedStack, [String? debugInfoFilename]) async { // Caller doesn't catch, but we have a catchError set. late StackTrace stackTrace; await f().catchError((e, s) { stackTrace = s; }); return assertStack(expectedStack, stackTrace, debugInfoFilename); } // ---- // Test "Suites": // ---- // For: --no-lazy-async-stacks Future doTestsNoCausalNoLazy([String? debugInfoFilename]) async { { final expected = const [ r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', r'^#2 _RootZone.runUnary ', r'^#3 _FutureListener.handleValue ', r'^#4 Future._propagateToListeners.handleValueCallback ', r'^#5 Future._propagateToListeners ', // TODO(dart-vm): Figure out why this is inconsistent: r'^#6 Future.(_addListener|_prependListeners). ', r'^#7 _microtaskLoop ', r'^#8 _startMicrotaskLoop ', r'^#9 _runPendingImmediateCallback ', r'^#10 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(allYield, expected, debugInfoFilename); await doTestAwaitThen(allYield, expected, debugInfoFilename); await doTestAwaitCatchError(allYield, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', r'^#2 noYields3 \(.*/utils.dart:53(:23)?\)$', r'^#3 noYields2 \(.*/utils.dart:50(:9)?\)$', r'^#4 noYields2 \(.*/utils.dart:49(:23)?\)$', r'^#5 noYields \(.*/utils.dart:46(:9)?\)$', r'^#6 noYields \(.*/utils.dart:45(:22)?\)$', ]; final postfix = const [ r'^#9 doTestsNoCausalNoLazy ', r'^#10 _RootZone.runUnary ', r'^#11 _FutureListener.handleValue ', r'^#12 Future._propagateToListeners.handleValueCallback ', r'^#13 Future._propagateToListeners ', r'^#14 Future._addListener. ', r'^#15 _microtaskLoop ', r'^#16 _startMicrotaskLoop ', r'^#17 _runPendingImmediateCallback ', r'^#18 _RawReceivePortImpl._handleMessage ', ]; await 0; // Don't let the `await do..`s chain together. await doTestAwait( noYields, expected + const [ r'^#7 doTestAwait ', r'^#8 doTestAwait ', ] + postfix, debugInfoFilename); await 0; // Don't let the `await do..`s chain together. await doTestAwaitThen( noYields, expected + const [ r'^#7 doTestAwaitThen ', r'^#8 doTestAwaitThen ', ] + postfix, debugInfoFilename); await 0; // Don't let the `await do..`s chain together. await doTestAwaitCatchError( noYields, expected + const [ r'^#7 doTestAwaitCatchError ', r'^#8 doTestAwaitCatchError ', ] + postfix, debugInfoFilename); } { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', // TODO(dart-vm): Figure out why this is inconsistent: r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(mixedYields, expected, debugInfoFilename); await doTestAwaitThen(mixedYields, expected, debugInfoFilename); await doTestAwaitCatchError(mixedYields, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', // TODO(dart-vm): Figure out why this is inconsistent: r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(syncSuffix, expected, debugInfoFilename); await doTestAwaitThen(syncSuffix, expected, debugInfoFilename); await doTestAwaitCatchError(syncSuffix, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', // TODO(dart-vm): Figure out why this is inconsistent: r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(nonAsyncNoStack, expected, debugInfoFilename); await doTestAwaitThen(nonAsyncNoStack, expected, debugInfoFilename); await doTestAwaitCatchError(nonAsyncNoStack, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', r'^#2 _RootZone.runUnary \(.+\)$', r'^#3 _FutureListener.handleValue \(.+\)$', r'^#4 Future._propagateToListeners.handleValueCallback \(.+\)$', r'^#5 Future._propagateToListeners \(.+\)$', // TODO(dart-vm): Figure out why this is inconsistent: r'^#6 Future.(_addListener|_prependListeners). \(.+\)$', r'^#7 _microtaskLoop \(.+\)$', r'^#8 _startMicrotaskLoop \(.+\)$', r'^#9 _runPendingImmediateCallback \(.+\)$', r'^#10 _RawReceivePortImpl._handleMessage \(.+\)$', ]; await doTestAwait( awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); await doTestAwaitThen( awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); await doTestAwaitCatchError( awaitEveryAsyncStarThrowSync, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', // TODO(dart-vm): Figure out why this is inconsistent: r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait( awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); await doTestAwaitThen( awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); await doTestAwaitCatchError( awaitEveryAsyncStarThrowAsync, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', // TODO(dart-vm): Figure out why this is inconsistent: r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(listenAsyncStarThrowAsync, expected, debugInfoFilename); await doTestAwaitThen( listenAsyncStarThrowAsync, expected, debugInfoFilename); await doTestAwaitCatchError( listenAsyncStarThrowAsync, expected, debugInfoFilename); } { final expected = const [ r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', r'#2 _rootRunUnary ', r'#3 _CustomZone.runUnary ', r'#4 _FutureListener.handleValue ', r'#5 Future._propagateToListeners.handleValueCallback ', r'#6 Future._propagateToListeners ', r'#7 Future.(_addListener|_prependListeners). ', r'#8 _rootRun ', r'#9 _CustomZone.run ', r'#10 _CustomZone.runGuarded ', r'#11 _CustomZone.bindCallbackGuarded. ', r'#12 _microtaskLoop ', r'#13 _startMicrotaskLoop ', r'#14 _runPendingImmediateCallback ', r'#15 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(customErrorZone, expected, debugInfoFilename); await doTestAwaitThen(customErrorZone, expected, debugInfoFilename); await doTestAwaitCatchError(customErrorZone, expected, debugInfoFilename); } { final expected = const [ r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(awaitTimeout, expected, debugInfoFilename); await doTestAwaitThen(awaitTimeout, expected, debugInfoFilename); await doTestAwaitCatchError(awaitTimeout, expected, debugInfoFilename); } { final expected = const [ r'#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(awaitWait, expected, debugInfoFilename); await doTestAwaitThen(awaitWait, expected, debugInfoFilename); await doTestAwaitCatchError(awaitWait, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^#1 _RootZone.runUnary ', r'^#2 _FutureListener.handleValue ', r'^#3 Future._propagateToListeners.handleValueCallback ', r'^#4 Future._propagateToListeners ', r'^#5 Future.(_addListener|_prependListeners). ', r'^#6 _microtaskLoop ', r'^#7 _startMicrotaskLoop ', r'^#8 _runPendingImmediateCallback ', r'^#9 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(futureSyncWhenComplete, expected, debugInfoFilename); await doTestAwaitThen(futureSyncWhenComplete, expected, debugInfoFilename); await doTestAwaitCatchError( futureSyncWhenComplete, expected, debugInfoFilename); } { final expected = const [ r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'^#1 futureThen. \(.*/utils.dart:187(:5)?\)$', r'^#2 _RootZone.runUnary ', r'^#3 _FutureListener.handleValue ', r'^#4 Future._propagateToListeners.handleValueCallback ', r'^#5 Future._propagateToListeners ', r'^#6 Future._completeWithValue ', r'^#7 Future._asyncCompleteWithValue. ', r'^#8 _microtaskLoop ', r'^#9 _startMicrotaskLoop ', r'^#10 _runPendingImmediateCallback ', r'^#11 _RawReceivePortImpl._handleMessage ', ]; await doTestAwait(futureThen, expected, debugInfoFilename); await doTestAwaitThen(futureThen, expected, debugInfoFilename); await doTestAwaitCatchError(futureThen, expected, debugInfoFilename); } } // For: --lazy-async-stacks Future doTestsLazy([String? debugInfoFilename]) async { // allYield { final allYieldExpected = const [ r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$', r'^$', r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$', r'^$', r'^#3 allYield \(.*/utils.dart:29(:3)?\)$', r'^$', ]; await doTestAwait( allYield, allYieldExpected + const [ r'^#4 doTestAwait ', r'^$', r'^#5 doTestsLazy ', r'^$', r'^#6 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( allYield, allYieldExpected + const [ r'^#4 doTestAwaitThen ', r'^$', r'^#5 doTestsLazy ', r'^$', r'^#6 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( allYield, allYieldExpected + const [ r'^#4 doTestAwaitCatchError ', r'^$', r'^#5 doTestsLazy ', r'^$', r'^#6 main ', r'^$', ], debugInfoFilename); } // noYields { final noYieldsExpected = const [ r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$', r'^#2 noYields2 \(.*/utils.dart:50(:9)?\)$', r'^#3 noYields \(.*/utils.dart:46(:9)?\)$', ]; await doTestAwait( noYields, noYieldsExpected + const [ r'^#4 doTestAwait ', r'^#5 doTestsLazy ', r'^$', r'^#6 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( noYields, noYieldsExpected + const [ r'^#4 doTestAwaitThen ', r'^#5 doTestsLazy ', r'^$', r'^#6 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( noYields, noYieldsExpected + const [ r'^#4 doTestAwaitCatchError ', r'^#5 doTestsLazy ', r'^$', r'^#6 main ', r'^$', ], debugInfoFilename); } // mixedYields { final mixedYieldsExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 mixedYields2 \(.*/utils.dart:66(:3)?\)$', r'^$', r'^#2 mixedYields \(.*/utils.dart:61(:3)?\)$', r'^$', ]; await doTestAwait( mixedYields, mixedYieldsExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( mixedYields, mixedYieldsExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( mixedYields, mixedYieldsExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // syncSuffix { final syncSuffixExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$', r'^$', r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$', r'^$', ]; await doTestAwait( syncSuffix, syncSuffixExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( syncSuffix, syncSuffixExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( syncSuffix, syncSuffixExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // nonAsyncNoStack { final nonAsyncNoStackExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$', r'^$', r'^#2 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$', r'^$', ]; await doTestAwait( nonAsyncNoStack, nonAsyncNoStackExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( nonAsyncNoStack, nonAsyncNoStackExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( nonAsyncNoStack, nonAsyncNoStackExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // awaitEveryAsyncStarThrowSync { final asyncStarThrowSyncExpected = const [ r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$', r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$', r'^$', r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$', r'^$', ]; await doTestAwait( awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( awaitEveryAsyncStarThrowSync, asyncStarThrowSyncExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // awaitEveryAsyncStarThrowAsync { final asyncStarThrowAsyncExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', r'^$', r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$', r'^$', ]; await doTestAwait( awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( awaitEveryAsyncStarThrowAsync, asyncStarThrowAsyncExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // listenAsyncStarThrowAsync { final listenAsyncStartExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$', r'^$', r'^#2 listenAsyncStarThrowAsync. \(.+/utils.dart(:0)?\)$', r'^$', ]; await doTestAwait( listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); await doTestAwaitThen( listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); await doTestAwaitCatchError( listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename); } // customErrorZone { final customErrorZoneExpected = const [ r'#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$', r'$', r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$', r'$', r'#3 allYield \(.*/utils.dart:29(:3)?\)$', r'$', r'#4 customErrorZone. \(.*/utils.dart:144(:5)?\)$', r'$', ]; await doTestAwait( customErrorZone, customErrorZoneExpected, debugInfoFilename); await doTestAwaitThen( customErrorZone, customErrorZoneExpected, debugInfoFilename); await doTestAwaitCatchError( customErrorZone, customErrorZoneExpected, debugInfoFilename); } // awaitTimeout { final awaitTimeoutExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 Future.timeout. \(dart:async/future_impl.dart', r'^$', r'^#2 awaitTimeout ', r'^$', ]; await doTestAwait( awaitTimeout, awaitTimeoutExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( awaitTimeout, awaitTimeoutExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( awaitTimeout, awaitTimeoutExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // awaitWait { final awaitWaitExpected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', r'^#1 Future.wait. \(dart:async/future.dart', r'^$', r'^#2 awaitWait ', r'^$', ]; await doTestAwait( awaitWait, awaitWaitExpected + const [ r'^#3 doTestAwait ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( awaitWait, awaitWaitExpected + const [ r'^#3 doTestAwaitThen ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( awaitWait, awaitWaitExpected + const [ r'^#3 doTestAwaitCatchError ', r'^$', r'^#4 doTestsLazy ', r'^$', r'^#5 main ', r'^$', ], debugInfoFilename); } // futureSyncWhenComplete { final expected = const [ r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$', r'^$', ]; await doTestAwait( futureSyncWhenComplete, expected + const [ r'^#1 doTestAwait ', r'^$', r'^#2 doTestsLazy ', r'^$', r'^#3 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( futureSyncWhenComplete, expected + const [ r'^#1 doTestAwaitThen ', r'^$', r'^#2 doTestsLazy ', r'^$', r'^#3 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( futureSyncWhenComplete, expected + const [ r'^#1 doTestAwaitCatchError ', r'^$', r'^#2 doTestsLazy ', r'^$', r'^#3 main ', r'^$', ], debugInfoFilename); } // futureThen { final expected = const [ r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$', r'^#1 futureThen. ', r'^$', ]; await doTestAwait( futureThen, expected + const [ r'^#2 doTestAwait ', r'^$', r'^#3 doTestsLazy ', r'^$', r'^#4 main ', r'^$', ], debugInfoFilename); await doTestAwaitThen( futureThen, expected + const [ r'^#2 doTestAwaitThen ', r'^$', r'^#3 doTestsLazy ', r'^$', r'^#4 main ', r'^$', ], debugInfoFilename); await doTestAwaitCatchError( futureThen, expected + const [ r'^#2 doTestAwaitCatchError ', r'^$', r'^#3 doTestsLazy ', r'^$', r'^#4 main ', r'^$', ], debugInfoFilename); } }