mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:29:47 +00:00
Revert "[vm] Rename tests causal_stacks -> awaiter_stacks and improve harness."
This reverts commit 0c1b2722ed
.
Reason for revert: Failures on AOT (stack expectations unmet) and Windows (parse errors due to Windows paths) trybots.
Original change's description:
> [vm] Rename tests causal_stacks -> awaiter_stacks and improve harness.
>
> The main difference from the previous harness is that it
> allows auto updating the expectations instead of
> maintaining them manually.
>
> TEST=ci
>
> Change-Id: I80e303d3ecbcc834ac94fa089cabe4f8834cc661
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311400
> Reviewed-by: Alexander Markov <alexmarkov@google.com>
> Commit-Queue: Slava Egorov <vegorov@google.com>
Change-Id: I7311bf08403f4167f88f6204fde1a6fdee353f7d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311600
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
parent
1df39e243a
commit
516f238aa6
|
@ -2,7 +2,7 @@
|
|||
// 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.
|
||||
|
||||
// This test is derived from `runtime/tests/vm/dart/awaiter_stacks/utils.dart`.
|
||||
// This test is derived from `runtime/tests/vm/dart/causal_stacks/utils.dart`.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"../vm/dart/byte_array_test.dart",
|
||||
"../vm/dart/callee_side_type_checks_test.dart",
|
||||
"../vm/dart/catch_entry_state_test.dart",
|
||||
"../vm/dart/awaiter_stacks/sync_async_start_pkg_test_test.dart",
|
||||
"../vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart",
|
||||
"../vm/dart/deferred_loading_and_weak_serialization_references_test.dart",
|
||||
"../vm/dart/deferred_loading_call_modes_test.dart",
|
||||
"../vm/dart/deopt/allocate_array_test.dart",
|
||||
|
@ -3386,7 +3386,7 @@
|
|||
"../vm/dart_2/byte_array_test.dart",
|
||||
"../vm/dart_2/callee_side_type_checks_test.dart",
|
||||
"../vm/dart_2/catch_entry_state_test.dart",
|
||||
"../vm/dart_2/awaiter_stacks/sync_async_start_pkg_test_test.dart",
|
||||
"../vm/dart_2/causal_stacks/sync_async_start_pkg_test_test.dart",
|
||||
"../vm/dart_2/deferred_loading_and_weak_serialization_references_test.dart",
|
||||
"../vm/dart_2/deferred_loading_call_modes_test.dart",
|
||||
"../vm/dart_2/deopt/allocate_array_test.dart",
|
||||
|
|
|
@ -1,712 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
// Test functions:
|
||||
|
||||
Future<void> throwSync() {
|
||||
throw 'throw from throwSync';
|
||||
}
|
||||
|
||||
Future<void> throwAsync() async {
|
||||
await 0;
|
||||
throw 'throw from throwAsync';
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded at least once before throw:
|
||||
// ----
|
||||
Future<void> allYield() async {
|
||||
await 0;
|
||||
await allYield2();
|
||||
}
|
||||
|
||||
Future<void> allYield2() async {
|
||||
await 0;
|
||||
await allYield3();
|
||||
}
|
||||
|
||||
Future<void> allYield3() async {
|
||||
await 0;
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: None of the async functions yielded before the throw:
|
||||
// ----
|
||||
Future<void> noYields() async {
|
||||
await noYields2();
|
||||
}
|
||||
|
||||
Future<void> noYields2() async {
|
||||
await noYields3();
|
||||
}
|
||||
|
||||
Future<void> noYields3() async {
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Mixed yielding and non-yielding frames:
|
||||
// ----
|
||||
Future<void> mixedYields() async {
|
||||
await mixedYields2();
|
||||
}
|
||||
|
||||
Future<void> mixedYields2() async {
|
||||
await 0;
|
||||
await mixedYields3();
|
||||
}
|
||||
|
||||
Future<void> mixedYields3() async {
|
||||
return throwAsync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Non-async frame:
|
||||
// ----
|
||||
Future<void> syncSuffix() async {
|
||||
await syncSuffix2();
|
||||
}
|
||||
|
||||
Future<void> syncSuffix2() async {
|
||||
await 0;
|
||||
await syncSuffix3();
|
||||
}
|
||||
|
||||
Future<void> 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<Future> 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<Future> asyncStarThrowAsync() async* {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
await i;
|
||||
yield Future.value(i);
|
||||
await throwAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Future listenAsyncStarThrowAsync() async {
|
||||
final _output = [];
|
||||
// Listening to an async* doesn't create the usual await-for StreamIterator.
|
||||
StreamSubscription ss = asyncStarThrowAsync().listen((Future f) {
|
||||
_output.add('unique value');
|
||||
});
|
||||
await ss.asFuture();
|
||||
if (_output.length == 44) {
|
||||
print(_output);
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded and we run in a custom zone with a
|
||||
// custom error handler.
|
||||
// ----
|
||||
|
||||
Future<void> customErrorZone() async {
|
||||
final completer = Completer<void>();
|
||||
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();
|
||||
}).then(_doSomething);
|
||||
}
|
||||
|
||||
void _doSomething(_) {
|
||||
Expect.fail('Should not reach doSomething');
|
||||
}
|
||||
|
||||
Future<void> doTestAwait(Future f()) async {
|
||||
await f();
|
||||
Expect.fail('No exception thrown!');
|
||||
}
|
||||
|
||||
Future<void> doTestAwaitThen(Future f()) async {
|
||||
// Passing (e) {} to then() can cause the closure instructions to be
|
||||
// deduped, changing the stack trace to the deduped owner, so we
|
||||
// duplicate the Expect.fail() call in the closure.
|
||||
await f().then((e) => Expect.fail('No exception thrown!'));
|
||||
}
|
||||
|
||||
Future<void> doTestAwaitCatchError(Future f()) async {
|
||||
late Object error;
|
||||
late StackTrace stackTrace;
|
||||
await f().catchError((e, s) {
|
||||
error = e;
|
||||
stackTrace = s;
|
||||
});
|
||||
return Future.error(error, stackTrace);
|
||||
}
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
final tests = [
|
||||
allYield,
|
||||
noYields,
|
||||
mixedYields,
|
||||
syncSuffix,
|
||||
nonAsyncNoStack,
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
listenAsyncStarThrowAsync,
|
||||
customErrorZone,
|
||||
awaitTimeout,
|
||||
awaitWait,
|
||||
futureSyncWhenComplete,
|
||||
futureThen,
|
||||
];
|
||||
|
||||
for (var test in tests) {
|
||||
await harness.runTest(() => doTestAwait(test));
|
||||
await harness.runTest(() => doTestAwaitThen(test));
|
||||
await harness.runTest(() => doTestAwaitCatchError(test));
|
||||
}
|
||||
|
||||
harness.updateExpectations();
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#5 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#6 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#5 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#6 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#5 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#6 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 noYields3 (%test%)
|
||||
#2 noYields2 (%test%)
|
||||
#3 noYields (%test%)
|
||||
#4 doTestAwait (%test%)
|
||||
#5 main.<anonymous closure> (%test%)
|
||||
#6 runTest (harness.dart)
|
||||
#7 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 noYields3 (%test%)
|
||||
#2 noYields2 (%test%)
|
||||
#3 noYields (%test%)
|
||||
#4 doTestAwaitThen (%test%)
|
||||
#5 main.<anonymous closure> (%test%)
|
||||
#6 runTest (harness.dart)
|
||||
#7 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 noYields3 (%test%)
|
||||
#2 noYields2 (%test%)
|
||||
#3 noYields (%test%)
|
||||
#4 doTestAwaitCatchError (%test%)
|
||||
#5 main.<anonymous closure> (%test%)
|
||||
#6 runTest (harness.dart)
|
||||
#7 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 mixedYields2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 mixedYields (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 mixedYields2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 mixedYields (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 mixedYields2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 mixedYields (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 syncSuffix2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 syncSuffix (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 syncSuffix2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 syncSuffix (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 syncSuffix2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 syncSuffix (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 nonAsyncNoStack1 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 nonAsyncNoStack (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 nonAsyncNoStack1 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 nonAsyncNoStack (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 nonAsyncNoStack1 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 nonAsyncNoStack (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 asyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 asyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 asyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 customErrorZone.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 customErrorZone.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 customErrorZone.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.timeout.<anonymous closure> (future_impl.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitTimeout (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.timeout.<anonymous closure> (future_impl.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitTimeout (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.timeout.<anonymous closure> (future_impl.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitTimeout (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.wait.<anonymous closure> (future.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitWait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.wait.<anonymous closure> (future.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitWait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.wait.<anonymous closure> (future.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitWait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 futureThen.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 futureThen.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 futureThen.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -1,98 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
String effectOrder = '';
|
||||
StackTrace? stackAfterYield = null;
|
||||
|
||||
void emit(String m) => effectOrder += m;
|
||||
|
||||
main() async {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
harness.configure(currentExpectations);
|
||||
await harness.runTest(() async {
|
||||
emit('1');
|
||||
await for (final value in produce()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
}
|
||||
emit('8');
|
||||
Expect.equals('12345678', effectOrder);
|
||||
|
||||
effectOrder = '';
|
||||
|
||||
emit('1');
|
||||
await for (final value in produceYieldStar()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
break;
|
||||
}
|
||||
emit('6');
|
||||
Expect.equals('123456', effectOrder);
|
||||
|
||||
return Future.error('error', stackAfterYield!);
|
||||
});
|
||||
harness.updateExpectations();
|
||||
}
|
||||
|
||||
Stream<dynamic> produce() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('7');
|
||||
}
|
||||
|
||||
Stream produceInner() async* {
|
||||
emit('3');
|
||||
yield '|value|';
|
||||
emit('6');
|
||||
stackAfterYield = StackTrace.current;
|
||||
}
|
||||
|
||||
Stream<dynamic> produceYieldStar() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('x');
|
||||
}
|
||||
|
||||
Stream produceInnerYieldStar() async* {
|
||||
emit('3');
|
||||
yield* Stream.fromIterable(['|value|', '|value2|']);
|
||||
emit('x');
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 produceInner (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 produce (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 main.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -1,236 +0,0 @@
|
|||
// Copyright (c) 2023, 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:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:native_stack_traces/native_stack_traces.dart';
|
||||
|
||||
//
|
||||
// Test framework
|
||||
//
|
||||
|
||||
class _ParsedFrame {
|
||||
const _ParsedFrame();
|
||||
|
||||
static _ParsedFrame parse(String frame) {
|
||||
if (frame == '<asynchronous suspension>') {
|
||||
return const _AsynchronousGap();
|
||||
} else {
|
||||
return _DartFrame.parse(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _DartFrame extends _ParsedFrame {
|
||||
final int no;
|
||||
final String symbol;
|
||||
final String location;
|
||||
final int? lineNo;
|
||||
|
||||
_DartFrame({
|
||||
required this.no,
|
||||
required this.symbol,
|
||||
required this.location,
|
||||
required this.lineNo,
|
||||
});
|
||||
|
||||
static final _pattern = RegExp(
|
||||
r'^#(?<no>\d+)\s+(?<symbol>[^(]+)(\((?<location>(\w+:)?[^:]+)(:(?<line>\d+)(:(?<column>\d+))?)?\))?$');
|
||||
|
||||
static _DartFrame parse(String frame) {
|
||||
final match = _pattern.firstMatch(frame);
|
||||
if (match == null) {
|
||||
throw 'Failed to parse: $frame';
|
||||
}
|
||||
|
||||
final no = int.parse(match.namedGroup('no')!);
|
||||
final symbol = match.namedGroup('symbol')!.trim();
|
||||
var location = match.namedGroup('location')!;
|
||||
if (location.endsWith('_test.dart')) {
|
||||
location = '%test%';
|
||||
}
|
||||
final lineNo =
|
||||
location.endsWith('utils.dart') || location.endsWith('tests.dart')
|
||||
? match.namedGroup('line')
|
||||
: null;
|
||||
|
||||
return _DartFrame(
|
||||
no: no,
|
||||
symbol: symbol,
|
||||
location: location.split('/').last,
|
||||
lineNo: lineNo != null ? int.parse(lineNo) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'#$no $symbol ($location${lineNo != null ? ':$lineNo' : ''})';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other is! _DartFrame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return no == other.no &&
|
||||
symbol == other.symbol &&
|
||||
location == other.location &&
|
||||
lineNo == other.lineNo;
|
||||
}
|
||||
}
|
||||
|
||||
class _AsynchronousGap extends _ParsedFrame {
|
||||
const _AsynchronousGap();
|
||||
|
||||
@override
|
||||
String toString() => '<asynchronous suspension>';
|
||||
}
|
||||
|
||||
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
|
||||
|
||||
Future<List<_ParsedFrame>> _parseStack(String text) async {
|
||||
if (text.contains('*** *** ***')) {
|
||||
// Looks like DWARF stack traces mode.
|
||||
text = await Stream.fromIterable(text.split('\n'))
|
||||
.transform(DwarfStackTraceDecoder(_dwarf!))
|
||||
.where(_lineRE.hasMatch)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
return text
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.where((l) => l.isNotEmpty)
|
||||
.map(_ParsedFrame.parse)
|
||||
.toList();
|
||||
}
|
||||
|
||||
const _updatingExpectations = bool.fromEnvironment('update.expectations');
|
||||
|
||||
final _updatedExpectations = <String>[];
|
||||
late final List<String> _currentExpectations;
|
||||
|
||||
var _testIndex = 0;
|
||||
|
||||
late final Dwarf? _dwarf;
|
||||
|
||||
void configure(List<String> currentExpectations,
|
||||
{String debugInfoFilename = 'debug.so'}) {
|
||||
if (debugInfoFilename != null) {
|
||||
try {
|
||||
final testCompilationDir = Platform.environment['TEST_COMPILATION_DIR'];
|
||||
if (testCompilationDir != null) {
|
||||
debugInfoFilename = path.join(testCompilationDir, debugInfoFilename);
|
||||
}
|
||||
_dwarf = Dwarf.fromFile(debugInfoFilename)!;
|
||||
} on FileSystemException {
|
||||
// We're not running in precompiled mode, so the file doesn't exist and
|
||||
// we can continue normally.
|
||||
}
|
||||
}
|
||||
_currentExpectations = currentExpectations;
|
||||
}
|
||||
|
||||
Future<void> runTest(Future<void> Function() body) async {
|
||||
try {
|
||||
await body();
|
||||
} catch (e, st) {
|
||||
await checkExpectedStack(st);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkExpectedStack(StackTrace st) async {
|
||||
final expectedFramesString = _testIndex < _currentExpectations.length
|
||||
? _currentExpectations[_testIndex]
|
||||
: '';
|
||||
final stackTraceString = st.toString();
|
||||
final gotFrames = await _parseStack(stackTraceString);
|
||||
final normalizedStack = gotFrames.join('\n');
|
||||
if (_updatingExpectations) {
|
||||
_updatedExpectations.add(normalizedStack);
|
||||
} else {
|
||||
if (normalizedStack != expectedFramesString) {
|
||||
final expectedFrames = await _parseStack(expectedFramesString);
|
||||
final isDwarfMode = stackTraceString.contains('*** *** ***');
|
||||
print('''
|
||||
STACK TRACE MISMATCH -----------------
|
||||
GOT:
|
||||
$normalizedStack
|
||||
EXPECTED:
|
||||
$expectedFramesString
|
||||
--------------------------------------
|
||||
To regenate expectations run:
|
||||
\$ ${Platform.executable} -Dupdate.expectations=true ${Platform.script}
|
||||
--------------------------------------
|
||||
''');
|
||||
if (isDwarfMode) {
|
||||
print('''
|
||||
--------------------------------------
|
||||
RAW STACK:
|
||||
$st
|
||||
--------------------------------------
|
||||
''');
|
||||
}
|
||||
|
||||
Expect.equals(
|
||||
expectedFrames.length, gotFrames.length, 'wrong number of frames');
|
||||
for (var i = 0; i < expectedFrames.length; i++) {
|
||||
final expectedFrame = expectedFrames[i];
|
||||
final gotFrame = gotFrames[i];
|
||||
if (expectedFrame == gotFrame) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (expectedFrame is _DartFrame && gotFrame is _DartFrame) {
|
||||
Expect.equals(expectedFrame.symbol, gotFrame.symbol,
|
||||
'at frame #$i mismatched function name');
|
||||
Expect.equals(expectedFrame.location, gotFrame.location,
|
||||
'at frame #$i mismatched location');
|
||||
Expect.equals(expectedFrame.lineNo, gotFrame.lineNo,
|
||||
'at frame #$i mismatched line location');
|
||||
}
|
||||
|
||||
Expect.equals(expectedFrame, gotFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
_testIndex++;
|
||||
}
|
||||
|
||||
void updateExpectations([String? expectationsFile]) {
|
||||
if (!_updatingExpectations) {
|
||||
return;
|
||||
}
|
||||
|
||||
final sourceFilePath = expectationsFile != null
|
||||
? path.join(path.dirname(Platform.script.toFilePath()), expectationsFile)
|
||||
: Platform.script.toFilePath();
|
||||
final sourceFile = File(sourceFilePath);
|
||||
|
||||
final source = sourceFile.readAsStringSync();
|
||||
|
||||
final expectationsStart = source.lastIndexOf('// CURRENT EXPECTATIONS BEGIN');
|
||||
final updatedExpectationsString =
|
||||
[for (var s in _updatedExpectations) '"""\n$s"""'].join(",\n");
|
||||
|
||||
final newSource = source.substring(0, expectationsStart) +
|
||||
"""
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [${updatedExpectationsString}];
|
||||
// CURRENT EXPECTATIONS END
|
||||
""";
|
||||
|
||||
sourceFile.writeAsStringSync(newSource);
|
||||
print('updated expectations in ${sourceFile}!');
|
||||
}
|
||||
|
||||
// Check if we are running with obfuscation but without DWARF stack traces
|
||||
// then we don't have a way to deobfuscate the stack trace.
|
||||
bool shouldSkip() {
|
||||
final stack = StackTrace.current.toString();
|
||||
return !stack.contains('shouldSkip') && !stack.contains('*** ***');
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
|
||||
// when lazy async stacks are enabled by dropping frames below a synchronous
|
||||
// start to an async function.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
Future<StackTrace> firstMethod() async {
|
||||
return await secondMethod();
|
||||
}
|
||||
|
||||
Future<StackTrace> secondMethod() async {
|
||||
return StackTrace.current;
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setUpAll(() => harness.configure(currentExpectations));
|
||||
|
||||
test("Stacktrace includes sync-starts.", () async {
|
||||
final st = await firstMethod();
|
||||
await harness.checkExpectedStack(st);
|
||||
});
|
||||
|
||||
tearDownAll(() => harness.updateExpectations());
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 secondMethod (%test%)
|
||||
#1 firstMethod (%test%)
|
||||
#2 main.<anonymous closure> (%test%)
|
||||
#3 Declarer.test.<anonymous closure>.<anonymous closure> (declarer.dart)
|
||||
<asynchronous suspension>
|
||||
#4 Declarer.test.<anonymous closure> (declarer.dart)
|
||||
<asynchronous suspension>
|
||||
#5 Invoker._waitForOutstandingCallbacks.<anonymous closure> (invoker.dart)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -1,102 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
bool barRunning = false;
|
||||
|
||||
Future<void> foo() async {}
|
||||
|
||||
Future<void> bar() async {
|
||||
try {
|
||||
barRunning = true;
|
||||
await foo();
|
||||
} finally {
|
||||
barRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> runTest() {
|
||||
final Zone testZone = Zone.current.fork(
|
||||
specification: ZoneSpecification(
|
||||
registerUnaryCallback: _registerUnaryCallback,
|
||||
registerBinaryCallback: _registerBinaryCallback));
|
||||
return testZone.run(bar);
|
||||
}
|
||||
|
||||
StackTrace? registerUnaryCallbackStackTrace;
|
||||
StackTrace? registerBinaryCallbackStackTrace;
|
||||
|
||||
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerUnaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (barRunning) {
|
||||
Expect.isNull(registerUnaryCallbackStackTrace);
|
||||
registerUnaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerUnaryCallback(zone, f);
|
||||
}
|
||||
|
||||
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerBinaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (barRunning) {
|
||||
Expect.isNull(registerBinaryCallbackStackTrace);
|
||||
registerBinaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerBinaryCallback(zone, f);
|
||||
}
|
||||
|
||||
Future<void> main() async {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
await runTest();
|
||||
await harness.checkExpectedStack(registerUnaryCallbackStackTrace!);
|
||||
await harness.checkExpectedStack(registerBinaryCallbackStackTrace!);
|
||||
|
||||
harness.updateExpectations();
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 _registerUnaryCallback (%test%)
|
||||
#1 _CustomZone.registerUnaryCallback (zone.dart)
|
||||
#2 bar (%test%)
|
||||
#3 _rootRun (zone.dart)
|
||||
#4 _CustomZone.run (zone.dart)
|
||||
#5 runTest (%test%)
|
||||
#6 main (%test%)
|
||||
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#8 _RawReceivePort._handleMessage (isolate_patch.dart)""",
|
||||
"""
|
||||
#0 _registerBinaryCallback (%test%)
|
||||
#1 _CustomZone.registerBinaryCallback (zone.dart)
|
||||
#2 bar (%test%)
|
||||
#3 _rootRun (zone.dart)
|
||||
#4 _CustomZone.run (zone.dart)
|
||||
#5 runTest (%test%)
|
||||
#6 main (%test%)
|
||||
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#8 _RawReceivePort._handleMessage (isolate_patch.dart)"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
//
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=async_lazy_debug.so
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
// We won't have access to the debugging info file on Android.
|
||||
if (Platform.isAndroid) return;
|
||||
|
||||
await doTestsLazy('async_lazy_debug.so');
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// 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 'utils.dart';
|
||||
|
||||
Future<void> main(List<String> args) async => await doTestsLazy();
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2022, 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 'package:expect/expect.dart';
|
||||
|
||||
import 'utils.dart' show assertStack;
|
||||
|
||||
String effectOrder = '';
|
||||
StackTrace? stackAfterYield = null;
|
||||
|
||||
void emit(String m) => effectOrder += m;
|
||||
|
||||
main() async {
|
||||
emit('1');
|
||||
await for (final value in produce()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
}
|
||||
emit('8');
|
||||
Expect.equals('12345678', effectOrder);
|
||||
|
||||
assertStack(const <String>[
|
||||
r'^#0 produceInner .*$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 produce .*$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 main .*$',
|
||||
r'^<asynchronous suspension>$',
|
||||
], stackAfterYield!);
|
||||
|
||||
effectOrder = '';
|
||||
|
||||
emit('1');
|
||||
await for (final value in produceYieldStar()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
break;
|
||||
}
|
||||
emit('6');
|
||||
Expect.equals('123456', effectOrder);
|
||||
}
|
||||
|
||||
Stream<dynamic> produce() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('7');
|
||||
}
|
||||
|
||||
Stream produceInner() async* {
|
||||
emit('3');
|
||||
yield '|value|';
|
||||
emit('6');
|
||||
stackAfterYield = StackTrace.current;
|
||||
}
|
||||
|
||||
Stream<dynamic> produceYieldStar() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('x');
|
||||
}
|
||||
|
||||
Stream produceInnerYieldStar() async* {
|
||||
emit('3');
|
||||
yield* Stream.fromIterable(['|value|', '|value2|']);
|
||||
emit('x');
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
//
|
||||
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
|
||||
// when lazy async stacks are enabled by dropping frames below a synchronous
|
||||
// start to an async function.
|
||||
|
||||
import "package:test/test.dart";
|
||||
import "package:stack_trace/src/stack_zone_specification.dart";
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
void main() {
|
||||
test("Stacktrace includes sync-starts.", () async {
|
||||
final st = await firstMethod();
|
||||
expect("$st", allOf([contains("firstMethod"), contains("secondMethod")]));
|
||||
});
|
||||
}
|
||||
|
||||
Future<StackTrace> firstMethod() async {
|
||||
return await secondMethod();
|
||||
}
|
||||
|
||||
Future<StackTrace> secondMethod() async {
|
||||
return StackTrace.current;
|
||||
}
|
865
runtime/tests/vm/dart/causal_stacks/utils.dart
Normal file
865
runtime/tests/vm/dart/causal_stacks/utils.dart
Normal file
|
@ -0,0 +1,865 @@
|
|||
// 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<void> throwSync() {
|
||||
throw 'throw from throwSync';
|
||||
}
|
||||
|
||||
Future<void> throwAsync() async {
|
||||
await 0;
|
||||
throw 'throw from throwAsync';
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded at least once before throw:
|
||||
// ----
|
||||
Future<void> allYield() async {
|
||||
await 0;
|
||||
await allYield2();
|
||||
}
|
||||
|
||||
Future<void> allYield2() async {
|
||||
await 0;
|
||||
await allYield3();
|
||||
}
|
||||
|
||||
Future<void> allYield3() async {
|
||||
await 0;
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: None of the async functions yielded before the throw:
|
||||
// ----
|
||||
Future<void> noYields() async {
|
||||
await noYields2();
|
||||
}
|
||||
|
||||
Future<void> noYields2() async {
|
||||
await noYields3();
|
||||
}
|
||||
|
||||
Future<void> noYields3() async {
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Mixed yielding and non-yielding frames:
|
||||
// ----
|
||||
Future<void> mixedYields() async {
|
||||
await mixedYields2();
|
||||
}
|
||||
|
||||
Future<void> mixedYields2() async {
|
||||
await 0;
|
||||
await mixedYields3();
|
||||
}
|
||||
|
||||
Future<void> mixedYields3() async {
|
||||
return throwAsync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Non-async frame:
|
||||
// ----
|
||||
Future<void> syncSuffix() async {
|
||||
await syncSuffix2();
|
||||
}
|
||||
|
||||
Future<void> syncSuffix2() async {
|
||||
await 0;
|
||||
await syncSuffix3();
|
||||
}
|
||||
|
||||
Future<void> 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<Future> 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<Future> 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<void> customErrorZone() async {
|
||||
final completer = Completer<void>();
|
||||
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:
|
||||
|
||||
// Marker to tell the matcher to ignore the rest of the stack.
|
||||
const IGNORE_REMAINING_STACK = '#@ IGNORE_REMAINING_STACK #@';
|
||||
|
||||
// We want lines that either start with a frame index or an async gap marker.
|
||||
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
|
||||
|
||||
Future<void> assertStack(List<String> 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).
|
||||
bool usingDwarf = false;
|
||||
if (debugInfoFilename != null) {
|
||||
try {
|
||||
final dwarf = Dwarf.fromFile(debugInfoFilename)!;
|
||||
usingDwarf = true;
|
||||
frames = await Stream.fromIterable(original)
|
||||
.transform(DwarfStackTraceDecoder(dwarf))
|
||||
.where(_lineRE.hasMatch)
|
||||
.toList();
|
||||
} on FileSystemException {
|
||||
// We're not running in precompiled mode, so the file doesn't exist and
|
||||
// we can continue normally.
|
||||
}
|
||||
}
|
||||
|
||||
void printFrameInformation() {
|
||||
print('RegExps for expected stack:');
|
||||
expects.forEach((s) => print('"${s}"'));
|
||||
print('');
|
||||
if (usingDwarf) {
|
||||
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;
|
||||
}
|
||||
// If we encounter this special marker we ignore the rest of the stack.
|
||||
if (expects[i] == IGNORE_REMAINING_STACK) {
|
||||
return;
|
||||
}
|
||||
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<void> doTestAwait(Future f(), List<String> 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<void> doTestAwaitThen(Future f(), List<String> expectedStack,
|
||||
[String? debugInfoFilename]) async {
|
||||
// Caller catches but a then is set.
|
||||
try {
|
||||
// Passing (e) {} to then() can cause the closure instructions to be
|
||||
// deduped, changing the stack trace to the deduped 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<void> doTestAwaitCatchError(Future f(), List<String> 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":
|
||||
// ----
|
||||
|
||||
Future<void> doTestsLazy([String? debugInfoFilename]) async {
|
||||
// allYield
|
||||
{
|
||||
final allYieldExpected = const <String>[
|
||||
r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$',
|
||||
r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 allYield \(.*/utils.dart:29(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
allYield,
|
||||
allYieldExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
allYield,
|
||||
allYieldExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
allYield,
|
||||
allYieldExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// noYields
|
||||
{
|
||||
final noYieldsExpected = const <String>[
|
||||
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 <String>[
|
||||
r'^#4 doTestAwait ',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
noYields,
|
||||
noYieldsExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitThen ',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
noYields,
|
||||
noYieldsExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitCatchError ',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// mixedYields
|
||||
{
|
||||
final mixedYieldsExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 mixedYields2 \(.*/utils.dart:66(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 mixedYields \(.*/utils.dart:61(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
mixedYields,
|
||||
mixedYieldsExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
mixedYields,
|
||||
mixedYieldsExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
mixedYields,
|
||||
mixedYieldsExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// syncSuffix
|
||||
{
|
||||
final syncSuffixExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
syncSuffix,
|
||||
syncSuffixExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
syncSuffix,
|
||||
syncSuffixExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
syncSuffix,
|
||||
syncSuffixExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// nonAsyncNoStack
|
||||
{
|
||||
final nonAsyncNoStackExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
nonAsyncNoStack,
|
||||
nonAsyncNoStackExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
nonAsyncNoStack,
|
||||
nonAsyncNoStackExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
nonAsyncNoStack,
|
||||
nonAsyncNoStackExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitEveryAsyncStarThrowSync
|
||||
{
|
||||
final asyncStarThrowSyncExpected = const <String>[
|
||||
r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$',
|
||||
r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
asyncStarThrowSyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
asyncStarThrowSyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
asyncStarThrowSyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitEveryAsyncStarThrowAsync
|
||||
{
|
||||
final asyncStarThrowAsyncExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
asyncStarThrowAsyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
asyncStarThrowAsyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
asyncStarThrowAsyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// listenAsyncStarThrowAsync
|
||||
{
|
||||
final listenAsyncStartExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart:132(:56)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
|
||||
}
|
||||
|
||||
// customErrorZone
|
||||
{
|
||||
final customErrorZoneExpected = const <String>[
|
||||
r'#0 throwSync \(.*/utils.dart:16(:3)?\)$',
|
||||
r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
r'#3 allYield \(.*/utils.dart:29(:3)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
r'#4 customErrorZone.<anonymous closure> \(.*/utils.dart:144(:5)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
customErrorZone, customErrorZoneExpected, debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
customErrorZone, customErrorZoneExpected, debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
customErrorZone, customErrorZoneExpected, debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitTimeout
|
||||
{
|
||||
final awaitTimeoutExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 Future.timeout.<anonymous closure> \(dart:async/future_impl.dart',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitTimeout ',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitTimeout,
|
||||
awaitTimeoutExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitTimeout,
|
||||
awaitTimeoutExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitTimeout,
|
||||
awaitTimeoutExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitWait
|
||||
{
|
||||
final awaitWaitExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 Future.wait.<anonymous closure> \(dart:async/future.dart',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitWait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitWait,
|
||||
awaitWaitExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitWait,
|
||||
awaitWaitExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitWait,
|
||||
awaitWaitExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// futureSyncWhenComplete
|
||||
{
|
||||
final expected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
futureSyncWhenComplete,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#1 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
futureSyncWhenComplete,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#1 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
futureSyncWhenComplete,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#1 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// futureThen
|
||||
{
|
||||
final expected = const <String>[
|
||||
r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$',
|
||||
r'^#1 futureThen.<anonymous closure> ',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
futureThen,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#2 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
futureThen,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#2 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
futureThen,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#2 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2022, 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 'package:expect/expect.dart';
|
||||
|
||||
const String scriptName = 'zone_callback_stack_traces_test.dart';
|
||||
|
||||
Future<void> foo() async {}
|
||||
|
||||
Future<void> bar() async {
|
||||
await foo();
|
||||
}
|
||||
|
||||
Future<void> runTest() {
|
||||
final Zone testZone = Zone.current.fork(
|
||||
specification: ZoneSpecification(
|
||||
registerUnaryCallback: _registerUnaryCallback,
|
||||
registerBinaryCallback: _registerBinaryCallback));
|
||||
return testZone.run(bar);
|
||||
}
|
||||
|
||||
StackTrace? registerUnaryCallbackStackTrace;
|
||||
StackTrace? registerBinaryCallbackStackTrace;
|
||||
|
||||
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerUnaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (stackTrace.toString().contains('bar')) {
|
||||
Expect.isNull(registerUnaryCallbackStackTrace);
|
||||
registerUnaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerUnaryCallback(zone, f);
|
||||
}
|
||||
|
||||
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerBinaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (stackTrace.toString().contains('bar')) {
|
||||
Expect.isNull(registerBinaryCallbackStackTrace);
|
||||
registerBinaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerBinaryCallback(zone, f);
|
||||
}
|
||||
|
||||
void verifyStackTrace(List<String> expected, StackTrace stackTrace) {
|
||||
final List<String> actual = stackTrace
|
||||
.toString()
|
||||
.split('\n')
|
||||
.where((entry) => entry.contains(scriptName))
|
||||
.toList();
|
||||
print('Expected:\n${expected.join('\n')}');
|
||||
print('Actual:\n${actual.join('\n')}');
|
||||
Expect.equals(expected.length, actual.length);
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
if (!RegExp(expected[i]).hasMatch(actual[i])) {
|
||||
Expect.fail("Stack trace entry $i doesn't match:\n"
|
||||
" expected: ${expected[i]}\n actual: ${actual[i]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main() async {
|
||||
await runTest();
|
||||
verifyStackTrace([
|
||||
r'^#\d+ _registerUnaryCallback \(.*zone_callback_stack_traces_test.dart:30(:33)?\)$',
|
||||
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:14(:3)?\)$',
|
||||
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:22(:19)?\)$',
|
||||
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:70(:9)?\)$',
|
||||
], registerUnaryCallbackStackTrace!);
|
||||
|
||||
verifyStackTrace([
|
||||
r'^#\d+ _registerBinaryCallback \(.*zone_callback_stack_traces_test.dart:42(:33)?\)$',
|
||||
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:14(:3)?\)$',
|
||||
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:22(:19)?\)$',
|
||||
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:70(:9)?\)$',
|
||||
], registerBinaryCallbackStackTrace!);
|
||||
}
|
|
@ -1,14 +1,8 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
import 'awaiter_stacks/harness.dart' as harness;
|
||||
import 'causal_stacks/utils.dart' show assertStack, IGNORE_REMAINING_STACK;
|
||||
|
||||
class A {
|
||||
void takesA(A a) {
|
||||
|
@ -24,9 +18,7 @@ class B extends A {
|
|||
|
||||
StackTrace? trace = null;
|
||||
|
||||
void main() async {
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
void main() {
|
||||
A a = new A();
|
||||
A b = new B();
|
||||
try {
|
||||
|
@ -34,17 +26,9 @@ void main() async {
|
|||
} catch (e, st) {
|
||||
trace = st;
|
||||
}
|
||||
|
||||
await harness.checkExpectedStack(trace!);
|
||||
harness.updateExpectations();
|
||||
assertStack(const <String>[
|
||||
r'^#0 B.takesA \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:14(:27)?\)$',
|
||||
r'^#1 main \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:25(:7)?\)$',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace!);
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 B.takesA (%test%)
|
||||
#1 main (%test%)
|
||||
#2 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#3 _RawReceivePort._handleMessage (isolate_patch.dart)"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
||||
|
|
|
@ -2,32 +2,57 @@
|
|||
// 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 'awaiter_stacks/harness.dart' as harness;
|
||||
import 'causal_stacks/utils.dart';
|
||||
|
||||
main() async {
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
StackTrace trace = StackTrace.empty;
|
||||
|
||||
A.visible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 new A.visible',
|
||||
r'^#2 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
A.invisible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
visible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 visible',
|
||||
r'^#2 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
invisible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
visibleClosure(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 visibleClosure.visibleInner',
|
||||
r'^#2 visibleClosure',
|
||||
r'^#3 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
invisibleClosure(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
|
||||
harness.updateExpectations();
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 invisibleClosure',
|
||||
r'^#2 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
}
|
||||
|
||||
class A {
|
||||
|
@ -62,38 +87,3 @@ void invisibleClosure(void Function() fun) {
|
|||
|
||||
invisibleInner();
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 new A.visible (%test%)
|
||||
#2 main (%test%)
|
||||
#3 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#4 _RawReceivePort._handleMessage (isolate_patch.dart)""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 visible (%test%)
|
||||
#2 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 visibleClosure.visibleInner (%test%)
|
||||
#2 visibleClosure (%test%)
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 invisibleClosure (%test%)
|
||||
#2 main (%test%)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
||||
|
|
|
@ -1,46 +1,95 @@
|
|||
// Copyright (c) 2021, 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.
|
||||
//
|
||||
|
||||
// This test checks that --resolve-dwarf-paths outputs absolute and relative
|
||||
// paths in DWARF information.
|
||||
//
|
||||
// VMOptions=--dwarf-stack-traces --resolve-dwarf-paths --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// OtherResources=use_save_debugging_info_flag_program.dart
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:native_stack_traces/native_stack_traces.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'use_flag_test_helper.dart';
|
||||
|
||||
main(List<String> args) async {
|
||||
if (!isAOTRuntime) {
|
||||
return; // Running in JIT: AOT binaries not available.
|
||||
}
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
return;
|
||||
return; // SDK tree and dart_bootstrap not available on the test device.
|
||||
}
|
||||
|
||||
final isDwarfStackTraces = StackTrace.current.toString().contains('*** ***');
|
||||
if (!isDwarfStackTraces) {
|
||||
return;
|
||||
// These are the tools we need to be available to run on a given platform:
|
||||
if (!await testExecutable(genSnapshot)) {
|
||||
throw "Cannot run test as $genSnapshot not available";
|
||||
}
|
||||
if (!await testExecutable(dartPrecompiledRuntime)) {
|
||||
throw "Cannot run test as $dartPrecompiledRuntime not available";
|
||||
}
|
||||
if (!File(platformDill).existsSync()) {
|
||||
throw "Cannot run test as $platformDill does not exist";
|
||||
}
|
||||
|
||||
final dwarfPath =
|
||||
p.join(Platform.environment['TEST_COMPILATION_DIR']!, 'debug.so');
|
||||
final dwarf = Dwarf.fromFile(dwarfPath)!;
|
||||
runTests(obfuscate: false);
|
||||
runTests(obfuscate: true);
|
||||
}
|
||||
|
||||
final stack = StackTrace.current.toString();
|
||||
print(stack);
|
||||
final offsets = collectPCOffsets(stack.split('\n'));
|
||||
print(offsets);
|
||||
checkDwarfInfo(dwarf, offsets);
|
||||
void runTests({required bool obfuscate}) async {
|
||||
final pathSuffix = obfuscate ? 'obfuscated' : 'cleartext';
|
||||
await withTempDir('dwarf-flag-test-$pathSuffix', (String tempDir) async {
|
||||
final cwDir = path.dirname(Platform.script.toFilePath());
|
||||
final script =
|
||||
path.join(cwDir, 'use_save_debugging_info_flag_program.dart');
|
||||
final scriptDill = path.join(tempDir, 'flag_program.dill');
|
||||
|
||||
// Compile script to Kernel IR.
|
||||
await run(genKernel, <String>[
|
||||
'--aot',
|
||||
'--platform=$platformDill',
|
||||
'-o',
|
||||
scriptDill,
|
||||
script,
|
||||
]);
|
||||
|
||||
final scriptDwarfSnapshot = path.join(tempDir, 'dwarf.so');
|
||||
await run(genSnapshot, <String>[
|
||||
if (obfuscate) ...[
|
||||
'--obfuscate',
|
||||
'--save-obfuscation-map=${path.join(tempDir, 'obfuscation.map')}',
|
||||
],
|
||||
'--resolve-dwarf-paths',
|
||||
'--dwarf-stack-traces-mode',
|
||||
'--snapshot-kind=app-aot-elf',
|
||||
'--elf=$scriptDwarfSnapshot',
|
||||
scriptDill,
|
||||
]);
|
||||
|
||||
// Run the resulting Dwarf-AOT compiled script.
|
||||
final dwarfTrace = await runError(dartPrecompiledRuntime, <String>[
|
||||
scriptDwarfSnapshot,
|
||||
scriptDill,
|
||||
]);
|
||||
|
||||
final tracePCOffsets = collectPCOffsets(dwarfTrace);
|
||||
|
||||
// Check that translating the DWARF stack trace (without internal frames)
|
||||
// matches the symbolic stack trace.
|
||||
final dwarf = Dwarf.fromFile(scriptDwarfSnapshot);
|
||||
Expect.isNotNull(dwarf);
|
||||
checkDwarfInfo(dwarf!, tracePCOffsets);
|
||||
});
|
||||
}
|
||||
|
||||
void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
|
||||
final filenames = <String>{};
|
||||
for (final offset in offsets) {
|
||||
final callInfo = offset.callInfoFrom(dwarf, includeInternalFrames: true);
|
||||
final callInfo = offset.callInfoFrom(dwarf);
|
||||
Expect.isNotNull(callInfo);
|
||||
Expect.isNotEmpty(callInfo!);
|
||||
for (final e in callInfo) {
|
||||
|
@ -48,7 +97,7 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
|
|||
final entry = e as DartCallInfo;
|
||||
var filename = entry.filename;
|
||||
if (!filename.startsWith('/')) {
|
||||
filename = p.join(sdkDir, filename);
|
||||
filename = path.join(sdkDir, filename);
|
||||
}
|
||||
if (filenames.add(filename)) {
|
||||
Expect.isTrue(
|
||||
|
@ -61,6 +110,4 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
|
|||
print('- ${filename}');
|
||||
}
|
||||
Expect.isNotEmpty(filenames);
|
||||
Expect.isNotEmpty(filenames
|
||||
.where((p) => p.endsWith('use_resolve_dwarf_paths_flag_test.dart')));
|
||||
}
|
||||
|
|
|
@ -1,714 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// @dart=2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
// Test functions:
|
||||
|
||||
Future<void> throwSync() {
|
||||
throw 'throw from throwSync';
|
||||
}
|
||||
|
||||
Future<void> throwAsync() async {
|
||||
await 0;
|
||||
throw 'throw from throwAsync';
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded at least once before throw:
|
||||
// ----
|
||||
Future<void> allYield() async {
|
||||
await 0;
|
||||
await allYield2();
|
||||
}
|
||||
|
||||
Future<void> allYield2() async {
|
||||
await 0;
|
||||
await allYield3();
|
||||
}
|
||||
|
||||
Future<void> allYield3() async {
|
||||
await 0;
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: None of the async functions yielded before the throw:
|
||||
// ----
|
||||
Future<void> noYields() async {
|
||||
await noYields2();
|
||||
}
|
||||
|
||||
Future<void> noYields2() async {
|
||||
await noYields3();
|
||||
}
|
||||
|
||||
Future<void> noYields3() async {
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Mixed yielding and non-yielding frames:
|
||||
// ----
|
||||
Future<void> mixedYields() async {
|
||||
await mixedYields2();
|
||||
}
|
||||
|
||||
Future<void> mixedYields2() async {
|
||||
await 0;
|
||||
await mixedYields3();
|
||||
}
|
||||
|
||||
Future<void> mixedYields3() async {
|
||||
return throwAsync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Non-async frame:
|
||||
// ----
|
||||
Future<void> syncSuffix() async {
|
||||
await syncSuffix2();
|
||||
}
|
||||
|
||||
Future<void> syncSuffix2() async {
|
||||
await 0;
|
||||
await syncSuffix3();
|
||||
}
|
||||
|
||||
Future<void> 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<Future> 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<Future> asyncStarThrowAsync() async* {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
await i;
|
||||
yield Future.value(i);
|
||||
await throwAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Future listenAsyncStarThrowAsync() async {
|
||||
final _output = [];
|
||||
// Listening to an async* doesn't create the usual await-for StreamIterator.
|
||||
StreamSubscription ss = asyncStarThrowAsync().listen((Future f) {
|
||||
_output.add('unique value');
|
||||
});
|
||||
await ss.asFuture();
|
||||
if (_output.length == 44) {
|
||||
print(_output);
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded and we run in a custom zone with a
|
||||
// custom error handler.
|
||||
// ----
|
||||
|
||||
Future<void> customErrorZone() async {
|
||||
final completer = Completer<void>();
|
||||
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();
|
||||
}).then(_doSomething);
|
||||
}
|
||||
|
||||
void _doSomething(_) {
|
||||
Expect.fail('Should not reach doSomething');
|
||||
}
|
||||
|
||||
Future<void> doTestAwait(Future f()) async {
|
||||
await f();
|
||||
Expect.fail('No exception thrown!');
|
||||
}
|
||||
|
||||
Future<void> doTestAwaitThen(Future f()) async {
|
||||
// Passing (e) {} to then() can cause the closure instructions to be
|
||||
// deduped, changing the stack trace to the deduped owner, so we
|
||||
// duplicate the Expect.fail() call in the closure.
|
||||
await f().then((e) => Expect.fail('No exception thrown!'));
|
||||
}
|
||||
|
||||
Future<void> doTestAwaitCatchError(Future f()) async {
|
||||
Object error;
|
||||
StackTrace stackTrace;
|
||||
await f().catchError((e, s) {
|
||||
error = e;
|
||||
stackTrace = s;
|
||||
});
|
||||
return Future.error(error, stackTrace);
|
||||
}
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
final tests = [
|
||||
allYield,
|
||||
noYields,
|
||||
mixedYields,
|
||||
syncSuffix,
|
||||
nonAsyncNoStack,
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
listenAsyncStarThrowAsync,
|
||||
customErrorZone,
|
||||
awaitTimeout,
|
||||
awaitWait,
|
||||
futureSyncWhenComplete,
|
||||
futureThen,
|
||||
];
|
||||
|
||||
for (var test in tests) {
|
||||
await harness.runTest(() => doTestAwait(test));
|
||||
await harness.runTest(() => doTestAwaitThen(test));
|
||||
await harness.runTest(() => doTestAwaitCatchError(test));
|
||||
}
|
||||
|
||||
harness.updateExpectations();
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#5 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#6 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#5 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#6 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#5 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#6 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 noYields3 (%test%)
|
||||
#2 noYields2 (%test%)
|
||||
#3 noYields (%test%)
|
||||
#4 doTestAwait (%test%)
|
||||
#5 main.<anonymous closure> (%test%)
|
||||
#6 runTest (harness.dart)
|
||||
#7 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 noYields3 (%test%)
|
||||
#2 noYields2 (%test%)
|
||||
#3 noYields (%test%)
|
||||
#4 doTestAwaitThen (%test%)
|
||||
#5 main.<anonymous closure> (%test%)
|
||||
#6 runTest (harness.dart)
|
||||
#7 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 noYields3 (%test%)
|
||||
#2 noYields2 (%test%)
|
||||
#3 noYields (%test%)
|
||||
#4 doTestAwaitCatchError (%test%)
|
||||
#5 main.<anonymous closure> (%test%)
|
||||
#6 runTest (harness.dart)
|
||||
#7 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 mixedYields2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 mixedYields (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 mixedYields2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 mixedYields (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 mixedYields2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 mixedYields (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 syncSuffix2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 syncSuffix (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 syncSuffix2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 syncSuffix (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 syncSuffix2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 syncSuffix (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 nonAsyncNoStack1 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 nonAsyncNoStack (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 nonAsyncNoStack1 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 nonAsyncNoStack (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 nonAsyncNoStack1 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 nonAsyncNoStack (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 asyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 asyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 asyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowSync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 awaitEveryAsyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 asyncStarThrowAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 customErrorZone.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 customErrorZone.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 allYield3 (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 allYield2 (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 allYield (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 customErrorZone.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.timeout.<anonymous closure> (future_impl.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitTimeout (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.timeout.<anonymous closure> (future_impl.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitTimeout (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.timeout.<anonymous closure> (future_impl.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitTimeout (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.wait.<anonymous closure> (future.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitWait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.wait.<anonymous closure> (future.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitWait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 Future.wait.<anonymous closure> (future.dart)
|
||||
<asynchronous suspension>
|
||||
#2 awaitWait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#4 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#5 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwAsync (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 futureThen.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 doTestAwait (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 futureThen.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 doTestAwaitThen (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 throwSync (%test%)
|
||||
#1 futureThen.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 doTestAwaitCatchError (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -1,100 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// @dart=2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
String effectOrder = '';
|
||||
StackTrace stackAfterYield = null;
|
||||
|
||||
void emit(String m) => effectOrder += m;
|
||||
|
||||
main() async {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
harness.configure(currentExpectations);
|
||||
await harness.runTest(() async {
|
||||
emit('1');
|
||||
await for (final value in produce()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
}
|
||||
emit('8');
|
||||
Expect.equals('12345678', effectOrder);
|
||||
|
||||
effectOrder = '';
|
||||
|
||||
emit('1');
|
||||
await for (final value in produceYieldStar()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
break;
|
||||
}
|
||||
emit('6');
|
||||
Expect.equals('123456', effectOrder);
|
||||
|
||||
return Future.error('error', stackAfterYield);
|
||||
});
|
||||
harness.updateExpectations();
|
||||
}
|
||||
|
||||
Stream<dynamic> produce() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('7');
|
||||
}
|
||||
|
||||
Stream produceInner() async* {
|
||||
emit('3');
|
||||
yield '|value|';
|
||||
emit('6');
|
||||
stackAfterYield = StackTrace.current;
|
||||
}
|
||||
|
||||
Stream<dynamic> produceYieldStar() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('x');
|
||||
}
|
||||
|
||||
Stream produceInnerYieldStar() async* {
|
||||
emit('3');
|
||||
yield* Stream.fromIterable(['|value|', '|value2|']);
|
||||
emit('x');
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 produceInner (%test%)
|
||||
<asynchronous suspension>
|
||||
#1 produce (%test%)
|
||||
<asynchronous suspension>
|
||||
#2 main.<anonymous closure> (%test%)
|
||||
<asynchronous suspension>
|
||||
#3 runTest (harness.dart)
|
||||
<asynchronous suspension>
|
||||
#4 main (%test%)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -1,237 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
|
||||
// @dart=2.9
|
||||
|
||||
import 'dart:async';
|
||||
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 framework
|
||||
//
|
||||
|
||||
class _ParsedFrame {
|
||||
const _ParsedFrame();
|
||||
|
||||
static _ParsedFrame parse(String frame) {
|
||||
if (frame == '<asynchronous suspension>') {
|
||||
return const _AsynchronousGap();
|
||||
} else {
|
||||
return _DartFrame.parse(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _DartFrame extends _ParsedFrame {
|
||||
final int no;
|
||||
final String symbol;
|
||||
final String location;
|
||||
final int lineNo;
|
||||
|
||||
_DartFrame({
|
||||
this.no,
|
||||
this.symbol,
|
||||
this.location,
|
||||
this.lineNo,
|
||||
});
|
||||
|
||||
static final _pattern = RegExp(
|
||||
r'^#(?<no>\d+)\s+(?<symbol>[^(]+)(\((?<location>(\w+:)?[^:]+)(:(?<line>\d+)(:(?<column>\d+))?)?\))?$');
|
||||
|
||||
static _DartFrame parse(String frame) {
|
||||
final match = _pattern.firstMatch(frame);
|
||||
if (match == null) {
|
||||
throw 'Failed to parse: $frame';
|
||||
}
|
||||
|
||||
final no = int.parse(match.namedGroup('no'));
|
||||
final symbol = match.namedGroup('symbol').trim();
|
||||
var location = match.namedGroup('location');
|
||||
if (location.endsWith('_test.dart')) {
|
||||
location = '%test%';
|
||||
}
|
||||
final lineNo =
|
||||
location.endsWith('utils.dart') || location.endsWith('tests.dart')
|
||||
? match.namedGroup('line')
|
||||
: null;
|
||||
|
||||
return _DartFrame(
|
||||
no: no,
|
||||
symbol: symbol,
|
||||
location: location.split('/').last,
|
||||
lineNo: lineNo != null ? int.parse(lineNo) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'#$no $symbol ($location${lineNo != null ? ':$lineNo' : ''})';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other is _DartFrame) {
|
||||
return no == other.no &&
|
||||
symbol == other.symbol &&
|
||||
location == other.location &&
|
||||
lineNo == other.lineNo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class _AsynchronousGap extends _ParsedFrame {
|
||||
const _AsynchronousGap();
|
||||
|
||||
@override
|
||||
String toString() => '<asynchronous suspension>';
|
||||
}
|
||||
|
||||
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
|
||||
|
||||
Future<List<_ParsedFrame>> _parseStack(String text) async {
|
||||
if (text.contains('*** *** ***')) {
|
||||
// Looks like DWARF stack traces mode.
|
||||
text = await Stream.fromIterable(text.split('\n'))
|
||||
.transform(DwarfStackTraceDecoder(_dwarf))
|
||||
.where(_lineRE.hasMatch)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
return text
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.where((l) => l.isNotEmpty)
|
||||
.map(_ParsedFrame.parse)
|
||||
.toList();
|
||||
}
|
||||
|
||||
const _updatingExpectations = bool.fromEnvironment('update.expectations');
|
||||
|
||||
final _updatedExpectations = <String>[];
|
||||
List<String> _currentExpectations;
|
||||
|
||||
var _testIndex = 0;
|
||||
|
||||
Dwarf _dwarf;
|
||||
|
||||
void configure(List<String> currentExpectations,
|
||||
{String debugInfoFilename = 'debug.so'}) {
|
||||
if (debugInfoFilename != null) {
|
||||
try {
|
||||
final testCompilationDir = Platform.environment['TEST_COMPILATION_DIR'];
|
||||
if (testCompilationDir != null) {
|
||||
debugInfoFilename = path.join(testCompilationDir, debugInfoFilename);
|
||||
}
|
||||
_dwarf = Dwarf.fromFile(debugInfoFilename);
|
||||
} on FileSystemException {
|
||||
// We're not running in precompiled mode, so the file doesn't exist and
|
||||
// we can continue normally.
|
||||
}
|
||||
}
|
||||
_currentExpectations = currentExpectations;
|
||||
}
|
||||
|
||||
Future<void> runTest(Future<void> Function() body) async {
|
||||
try {
|
||||
await body();
|
||||
} catch (e, st) {
|
||||
await checkExpectedStack(st);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkExpectedStack(StackTrace st) async {
|
||||
final expectedFramesString = _testIndex < _currentExpectations.length
|
||||
? _currentExpectations[_testIndex]
|
||||
: '';
|
||||
final stackTraceString = st.toString();
|
||||
final gotFrames = await _parseStack(stackTraceString);
|
||||
final normalizedStack = gotFrames.join('\n');
|
||||
if (_updatingExpectations) {
|
||||
_updatedExpectations.add(normalizedStack);
|
||||
} else {
|
||||
if (normalizedStack != expectedFramesString) {
|
||||
final expectedFrames = await _parseStack(expectedFramesString);
|
||||
final isDwarfMode = stackTraceString.contains('*** *** ***');
|
||||
print('''
|
||||
STACK TRACE MISMATCH -----------------
|
||||
GOT:
|
||||
$normalizedStack
|
||||
EXPECTED:
|
||||
$expectedFramesString
|
||||
--------------------------------------
|
||||
To regenate expectations run:
|
||||
\$ ${Platform.executable} -Dupdate.expectations=true ${Platform.script}
|
||||
--------------------------------------
|
||||
''');
|
||||
if (isDwarfMode) {
|
||||
print('''
|
||||
--------------------------------------
|
||||
RAW STACK:
|
||||
$st
|
||||
--------------------------------------
|
||||
''');
|
||||
}
|
||||
|
||||
Expect.equals(
|
||||
expectedFrames.length, gotFrames.length, 'wrong number of frames');
|
||||
for (var i = 0; i < expectedFrames.length; i++) {
|
||||
final expectedFrame = expectedFrames[i];
|
||||
final gotFrame = gotFrames[i];
|
||||
if (expectedFrame == gotFrame) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (expectedFrame is _DartFrame && gotFrame is _DartFrame) {
|
||||
Expect.equals(expectedFrame.symbol, gotFrame.symbol,
|
||||
'at frame #$i mismatched function name');
|
||||
Expect.equals(expectedFrame.location, gotFrame.location,
|
||||
'at frame #$i mismatched location');
|
||||
Expect.equals(expectedFrame.lineNo, gotFrame.lineNo,
|
||||
'at frame #$i mismatched line location');
|
||||
}
|
||||
|
||||
Expect.equals(expectedFrame, gotFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
_testIndex++;
|
||||
}
|
||||
|
||||
void updateExpectations([String expectationsFile]) {
|
||||
if (!_updatingExpectations) {
|
||||
return;
|
||||
}
|
||||
|
||||
final sourceFilePath = expectationsFile != null
|
||||
? path.join(path.dirname(Platform.script.toFilePath()), expectationsFile)
|
||||
: Platform.script.toFilePath();
|
||||
final sourceFile = File(sourceFilePath);
|
||||
|
||||
final source = sourceFile.readAsStringSync();
|
||||
|
||||
final expectationsStart = source.lastIndexOf('// CURRENT EXPECTATIONS BEGIN');
|
||||
final updatedExpectationsString =
|
||||
[for (var s in _updatedExpectations) '"""\n$s"""'].join(",\n");
|
||||
|
||||
final newSource = source.substring(0, expectationsStart) +
|
||||
"""
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [${updatedExpectationsString}];
|
||||
// CURRENT EXPECTATIONS END
|
||||
""";
|
||||
|
||||
sourceFile.writeAsStringSync(newSource);
|
||||
print('updated expectations in ${sourceFile}!');
|
||||
}
|
||||
|
||||
// Check if we are running with obfuscation but without DWARF stack traces
|
||||
// then we don't have a way to deobfuscate the stack trace.
|
||||
bool shouldSkip() {
|
||||
final stack = StackTrace.current.toString();
|
||||
return !stack.contains('shouldSkip') && !stack.contains('*** ***');
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
|
||||
// when lazy async stacks are enabled by dropping frames below a synchronous
|
||||
// start to an async function.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// @dart=2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
Future<StackTrace> firstMethod() async {
|
||||
return await secondMethod();
|
||||
}
|
||||
|
||||
Future<StackTrace> secondMethod() async {
|
||||
return StackTrace.current;
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setUpAll(() => harness.configure(currentExpectations));
|
||||
|
||||
test("Stacktrace includes sync-starts.", () async {
|
||||
final st = await firstMethod();
|
||||
await harness.checkExpectedStack(st);
|
||||
});
|
||||
|
||||
tearDownAll(() => harness.updateExpectations());
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 secondMethod (%test%)
|
||||
#1 firstMethod (%test%)
|
||||
#2 main.<anonymous closure> (%test%)
|
||||
#3 Declarer.test.<anonymous closure>.<anonymous closure> (declarer.dart)
|
||||
<asynchronous suspension>
|
||||
#4 Declarer.test.<anonymous closure> (declarer.dart)
|
||||
<asynchronous suspension>
|
||||
#5 Invoker._waitForOutstandingCallbacks.<anonymous closure> (invoker.dart)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -1,104 +0,0 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// @dart=2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'harness.dart' as harness;
|
||||
|
||||
bool barRunning = false;
|
||||
|
||||
Future<void> foo() async {}
|
||||
|
||||
Future<void> bar() async {
|
||||
try {
|
||||
barRunning = true;
|
||||
await foo();
|
||||
} finally {
|
||||
barRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> runTest() {
|
||||
final Zone testZone = Zone.current.fork(
|
||||
specification: ZoneSpecification(
|
||||
registerUnaryCallback: _registerUnaryCallback,
|
||||
registerBinaryCallback: _registerBinaryCallback));
|
||||
return testZone.run(bar);
|
||||
}
|
||||
|
||||
StackTrace registerUnaryCallbackStackTrace;
|
||||
StackTrace registerBinaryCallbackStackTrace;
|
||||
|
||||
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerUnaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (barRunning) {
|
||||
Expect.isNull(registerUnaryCallbackStackTrace);
|
||||
registerUnaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerUnaryCallback(zone, f);
|
||||
}
|
||||
|
||||
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerBinaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (barRunning) {
|
||||
Expect.isNull(registerBinaryCallbackStackTrace);
|
||||
registerBinaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerBinaryCallback(zone, f);
|
||||
}
|
||||
|
||||
Future<void> main() async {
|
||||
if (harness.shouldSkip()) {
|
||||
return;
|
||||
}
|
||||
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
await runTest();
|
||||
await harness.checkExpectedStack(registerUnaryCallbackStackTrace);
|
||||
await harness.checkExpectedStack(registerBinaryCallbackStackTrace);
|
||||
|
||||
harness.updateExpectations();
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 _registerUnaryCallback (%test%)
|
||||
#1 _CustomZone.registerUnaryCallback (zone.dart)
|
||||
#2 bar (%test%)
|
||||
#3 _rootRun (zone.dart)
|
||||
#4 _CustomZone.run (zone.dart)
|
||||
#5 runTest (%test%)
|
||||
#6 main (%test%)
|
||||
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#8 _RawReceivePort._handleMessage (isolate_patch.dart)""",
|
||||
"""
|
||||
#0 _registerBinaryCallback (%test%)
|
||||
#1 _CustomZone.registerBinaryCallback (zone.dart)
|
||||
#2 bar (%test%)
|
||||
#3 _rootRun (zone.dart)
|
||||
#4 _CustomZone.run (zone.dart)
|
||||
#5 runTest (%test%)
|
||||
#6 main (%test%)
|
||||
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#8 _RawReceivePort._handleMessage (isolate_patch.dart)"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
//
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=async_lazy_debug.so
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
// We won't have access to the debugging info file on Android.
|
||||
if (Platform.isAndroid) return;
|
||||
|
||||
await doTestsLazy('async_lazy_debug.so');
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
Future<void> main(List<String> args) async => await doTestsLazy();
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
// @dart = 2.9
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'utils.dart' show assertStack;
|
||||
|
||||
String effectOrder = '';
|
||||
StackTrace stackAfterYield = null;
|
||||
|
||||
void emit(String m) => effectOrder += m;
|
||||
|
||||
main() async {
|
||||
emit('1');
|
||||
await for (final value in produce()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
}
|
||||
emit('8');
|
||||
Expect.equals('12345678', effectOrder);
|
||||
|
||||
assertStack(const <String>[
|
||||
r'^#0 produceInner .*$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 produce .*$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 main .*$',
|
||||
r'^<asynchronous suspension>$',
|
||||
], stackAfterYield);
|
||||
|
||||
effectOrder = '';
|
||||
|
||||
emit('1');
|
||||
await for (final value in produceYieldStar()) {
|
||||
emit('5');
|
||||
Expect.equals('|value|', value);
|
||||
break;
|
||||
}
|
||||
emit('6');
|
||||
Expect.equals('123456', effectOrder);
|
||||
}
|
||||
|
||||
Stream<dynamic> produce() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('7');
|
||||
}
|
||||
|
||||
Stream produceInner() async* {
|
||||
emit('3');
|
||||
yield '|value|';
|
||||
emit('6');
|
||||
stackAfterYield = StackTrace.current;
|
||||
}
|
||||
|
||||
Stream<dynamic> produceYieldStar() async* {
|
||||
emit('2');
|
||||
await for (String response in produceInner()) {
|
||||
emit('4');
|
||||
yield response;
|
||||
}
|
||||
emit('x');
|
||||
}
|
||||
|
||||
Stream produceInnerYieldStar() async* {
|
||||
emit('3');
|
||||
yield* Stream.fromIterable(['|value|', '|value2|']);
|
||||
emit('x');
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// 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.
|
||||
//
|
||||
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
|
||||
// when lazy async stacks are enabled by dropping frames below a synchronous
|
||||
// start to an async function.
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
import "package:test/test.dart";
|
||||
import "package:stack_trace/src/stack_zone_specification.dart";
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
void main() {
|
||||
test("Stacktrace includes sync-starts.", () async {
|
||||
final st = await firstMethod();
|
||||
expect("$st", allOf([contains("firstMethod"), contains("secondMethod")]));
|
||||
});
|
||||
}
|
||||
|
||||
Future<StackTrace> firstMethod() async {
|
||||
return await secondMethod();
|
||||
}
|
||||
|
||||
Future<StackTrace> secondMethod() async {
|
||||
return StackTrace.current;
|
||||
}
|
867
runtime/tests/vm/dart_2/causal_stacks/utils.dart
Normal file
867
runtime/tests/vm/dart_2/causal_stacks/utils.dart
Normal file
|
@ -0,0 +1,867 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
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<void> throwSync() {
|
||||
throw 'throw from throwSync';
|
||||
}
|
||||
|
||||
Future<void> throwAsync() async {
|
||||
await 0;
|
||||
throw 'throw from throwAsync';
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded at least once before throw:
|
||||
// ----
|
||||
Future<void> allYield() async {
|
||||
await 0;
|
||||
await allYield2();
|
||||
}
|
||||
|
||||
Future<void> allYield2() async {
|
||||
await 0;
|
||||
await allYield3();
|
||||
}
|
||||
|
||||
Future<void> allYield3() async {
|
||||
await 0;
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: None of the async functions yielded before the throw:
|
||||
// ----
|
||||
Future<void> noYields() async {
|
||||
await noYields2();
|
||||
}
|
||||
|
||||
Future<void> noYields2() async {
|
||||
await noYields3();
|
||||
}
|
||||
|
||||
Future<void> noYields3() async {
|
||||
throwSync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Mixed yielding and non-yielding frames:
|
||||
// ----
|
||||
Future<void> mixedYields() async {
|
||||
await mixedYields2();
|
||||
}
|
||||
|
||||
Future<void> mixedYields2() async {
|
||||
await 0;
|
||||
await mixedYields3();
|
||||
}
|
||||
|
||||
Future<void> mixedYields3() async {
|
||||
return throwAsync();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: Non-async frame:
|
||||
// ----
|
||||
Future<void> syncSuffix() async {
|
||||
await syncSuffix2();
|
||||
}
|
||||
|
||||
Future<void> syncSuffix2() async {
|
||||
await 0;
|
||||
await syncSuffix3();
|
||||
}
|
||||
|
||||
Future<void> 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<Future> 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<Future> 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) => 42);
|
||||
await ss.asFuture();
|
||||
}
|
||||
|
||||
// ----
|
||||
// Scenario: All async functions yielded and we run in a custom zone with a
|
||||
// custom error handler.
|
||||
// ----
|
||||
|
||||
Future<void> customErrorZone() async {
|
||||
final completer = Completer<void>();
|
||||
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:
|
||||
|
||||
// Marker to tell the matcher to ignore the rest of the stack.
|
||||
const IGNORE_REMAINING_STACK = '#@ IGNORE_REMAINING_STACK #@';
|
||||
|
||||
// We want lines that either start with a frame index or an async gap marker.
|
||||
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
|
||||
|
||||
Future<void> assertStack(List<String> 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).
|
||||
bool usingDwarf = false;
|
||||
if (debugInfoFilename != null) {
|
||||
try {
|
||||
final dwarf = Dwarf.fromFile(debugInfoFilename);
|
||||
usingDwarf = true;
|
||||
frames = await Stream.fromIterable(original)
|
||||
.transform(DwarfStackTraceDecoder(dwarf))
|
||||
.where(_lineRE.hasMatch)
|
||||
.toList();
|
||||
} on FileSystemException {
|
||||
// We're not running in precompiled mode, so the file doesn't exist and
|
||||
// we can continue normally.
|
||||
}
|
||||
}
|
||||
|
||||
void printFrameInformation() {
|
||||
print('RegExps for expected stack:');
|
||||
expects.forEach((s) => print('"${s}"'));
|
||||
print('');
|
||||
if (usingDwarf) {
|
||||
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;
|
||||
}
|
||||
// If we encounter this special marker we ignore the rest of the stack.
|
||||
if (expects[i] == IGNORE_REMAINING_STACK) {
|
||||
return;
|
||||
}
|
||||
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<void> doTestAwait(Future f(), List<String> 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<void> doTestAwaitThen(Future f(), List<String> expectedStack,
|
||||
[String debugInfoFilename]) async {
|
||||
// Caller catches but a then is set.
|
||||
try {
|
||||
// Passing (e) {} to then() can cause the closure instructions to be
|
||||
// deduped, changing the stack trace to the deduped 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<void> doTestAwaitCatchError(Future f(), List<String> expectedStack,
|
||||
[String debugInfoFilename]) async {
|
||||
// Caller doesn't catch, but we have a catchError set.
|
||||
StackTrace stackTrace;
|
||||
await f().catchError((e, s) {
|
||||
stackTrace = s;
|
||||
});
|
||||
return assertStack(expectedStack, stackTrace, debugInfoFilename);
|
||||
}
|
||||
|
||||
// ----
|
||||
// Test "Suites":
|
||||
// ----
|
||||
|
||||
Future<void> doTestsLazy([String debugInfoFilename]) async {
|
||||
// allYield
|
||||
{
|
||||
final allYieldExpected = const <String>[
|
||||
r'^#0 throwSync \(.*/utils.dart:18(:3)?\)$',
|
||||
r'^#1 allYield3 \(.*/utils.dart:41(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 allYield2 \(.*/utils.dart:36(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 allYield \(.*/utils.dart:31(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
allYield,
|
||||
allYieldExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
allYield,
|
||||
allYieldExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
allYield,
|
||||
allYieldExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// noYields
|
||||
{
|
||||
final noYieldsExpected = const <String>[
|
||||
r'^#0 throwSync \(.*/utils.dart:18(:3)?\)$',
|
||||
r'^#1 noYields3 \(.*/utils.dart:56(:3)?\)$',
|
||||
r'^#2 noYields2 \(.*/utils.dart:52(:9)?\)$',
|
||||
r'^#3 noYields \(.*/utils.dart:48(:9)?\)$',
|
||||
];
|
||||
await doTestAwait(
|
||||
noYields,
|
||||
noYieldsExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwait ',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
noYields,
|
||||
noYieldsExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitThen ',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
noYields,
|
||||
noYieldsExpected +
|
||||
const <String>[
|
||||
r'^#4 doTestAwaitCatchError ',
|
||||
r'^#5 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#6 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// mixedYields
|
||||
{
|
||||
final mixedYieldsExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 mixedYields2 \(.*/utils.dart:68(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 mixedYields \(.*/utils.dart:63(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
mixedYields,
|
||||
mixedYieldsExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
mixedYields,
|
||||
mixedYieldsExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
mixedYields,
|
||||
mixedYieldsExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// syncSuffix
|
||||
{
|
||||
final syncSuffixExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 syncSuffix2 \(.*/utils.dart:84(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 syncSuffix \(.*/utils.dart:79(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
syncSuffix,
|
||||
syncSuffixExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
syncSuffix,
|
||||
syncSuffixExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
syncSuffix,
|
||||
syncSuffixExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// nonAsyncNoStack
|
||||
{
|
||||
final nonAsyncNoStackExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 nonAsyncNoStack1 \(.*/utils.dart:97(:36)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 nonAsyncNoStack \(.*/utils.dart:95(:35)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
nonAsyncNoStack,
|
||||
nonAsyncNoStackExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
nonAsyncNoStack,
|
||||
nonAsyncNoStackExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
nonAsyncNoStack,
|
||||
nonAsyncNoStackExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitEveryAsyncStarThrowSync
|
||||
{
|
||||
final asyncStarThrowSyncExpected = const <String>[
|
||||
r'^#0 throwSync \(.+/utils.dart:18(:3)?\)$',
|
||||
r'^#1 asyncStarThrowSync \(.+/utils.dart:114(:11)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:106(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
asyncStarThrowSyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
asyncStarThrowSyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitEveryAsyncStarThrowSync,
|
||||
asyncStarThrowSyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitEveryAsyncStarThrowAsync
|
||||
{
|
||||
final asyncStarThrowAsyncExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 asyncStarThrowAsync \(.*/utils.dart:128(:5)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:119(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
asyncStarThrowAsyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
asyncStarThrowAsyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitEveryAsyncStarThrowAsync,
|
||||
asyncStarThrowAsyncExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// listenAsyncStarThrowAsync
|
||||
{
|
||||
final listenAsyncStartExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 asyncStarThrowAsync \(.*/utils.dart:128(:5)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart:134(:56)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
|
||||
}
|
||||
|
||||
// customErrorZone
|
||||
{
|
||||
final customErrorZoneExpected = const <String>[
|
||||
r'#0 throwSync \(.*/utils.dart:18(:3)?\)$',
|
||||
r'#1 allYield3 \(.*/utils.dart:41(:3)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
r'#2 allYield2 \(.*/utils.dart:36(:3)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
r'#3 allYield \(.*/utils.dart:31(:3)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
r'#4 customErrorZone.<anonymous closure> \(.*/utils.dart:146(:5)?\)$',
|
||||
r'<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
customErrorZone, customErrorZoneExpected, debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
customErrorZone, customErrorZoneExpected, debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
customErrorZone, customErrorZoneExpected, debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitTimeout
|
||||
{
|
||||
final awaitTimeoutExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 Future.timeout.<anonymous closure> \(dart:async/future_impl.dart',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitTimeout ',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitTimeout,
|
||||
awaitTimeoutExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitTimeout,
|
||||
awaitTimeoutExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitTimeout,
|
||||
awaitTimeoutExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// awaitWait
|
||||
{
|
||||
final awaitWaitExpected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#1 Future.wait.<anonymous closure> \(dart:async/future.dart',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 awaitWait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
awaitWait,
|
||||
awaitWaitExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
awaitWait,
|
||||
awaitWaitExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
awaitWait,
|
||||
awaitWaitExpected +
|
||||
const <String>[
|
||||
r'^#3 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#5 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// futureSyncWhenComplete
|
||||
{
|
||||
final expected = const <String>[
|
||||
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
futureSyncWhenComplete,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#1 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
futureSyncWhenComplete,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#1 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
futureSyncWhenComplete,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#1 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#2 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
|
||||
// futureThen
|
||||
{
|
||||
final expected = const <String>[
|
||||
r'^#0 throwSync \(.*/utils.dart:18(:3)?\)$',
|
||||
r'^#1 futureThen.<anonymous closure> ',
|
||||
r'^<asynchronous suspension>$',
|
||||
];
|
||||
await doTestAwait(
|
||||
futureThen,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#2 doTestAwait ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitThen(
|
||||
futureThen,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#2 doTestAwaitThen ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
await doTestAwaitCatchError(
|
||||
futureThen,
|
||||
expected +
|
||||
const <String>[
|
||||
r'^#2 doTestAwaitCatchError ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#3 doTestsLazy ',
|
||||
r'^<asynchronous suspension>$',
|
||||
r'^#4 main ',
|
||||
r'^<asynchronous suspension>$',
|
||||
],
|
||||
debugInfoFilename);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
const String scriptName = 'zone_callback_stack_traces_test.dart';
|
||||
|
||||
Future<void> foo() async {}
|
||||
|
||||
Future<void> bar() async {
|
||||
await foo();
|
||||
}
|
||||
|
||||
Future<void> runTest() {
|
||||
final Zone testZone = Zone.current.fork(
|
||||
specification: ZoneSpecification(
|
||||
registerUnaryCallback: _registerUnaryCallback,
|
||||
registerBinaryCallback: _registerBinaryCallback));
|
||||
return testZone.run(bar);
|
||||
}
|
||||
|
||||
StackTrace registerUnaryCallbackStackTrace;
|
||||
StackTrace registerBinaryCallbackStackTrace;
|
||||
|
||||
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerUnaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (stackTrace.toString().contains('bar')) {
|
||||
Expect.isNull(registerUnaryCallbackStackTrace);
|
||||
registerUnaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerUnaryCallback(zone, f);
|
||||
}
|
||||
|
||||
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
|
||||
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
|
||||
final stackTrace = StackTrace.current;
|
||||
print('registerBinaryCallback got stack trace:');
|
||||
print(stackTrace);
|
||||
if (stackTrace.toString().contains('bar')) {
|
||||
Expect.isNull(registerBinaryCallbackStackTrace);
|
||||
registerBinaryCallbackStackTrace = stackTrace;
|
||||
}
|
||||
return parent.registerBinaryCallback(zone, f);
|
||||
}
|
||||
|
||||
void verifyStackTrace(List<String> expected, StackTrace stackTrace) {
|
||||
final List<String> actual = stackTrace
|
||||
.toString()
|
||||
.split('\n')
|
||||
.where((entry) => entry.contains(scriptName))
|
||||
.toList();
|
||||
print('Expected:\n${expected.join('\n')}');
|
||||
print('Actual:\n${actual.join('\n')}');
|
||||
Expect.equals(expected.length, actual.length);
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
if (!RegExp(expected[i]).hasMatch(actual[i])) {
|
||||
Expect.fail("Stack trace entry $i doesn't match:\n"
|
||||
" expected: ${expected[i]}\n actual: ${actual[i]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main() async {
|
||||
await runTest();
|
||||
verifyStackTrace([
|
||||
r'^#\d+ _registerUnaryCallback \(.*zone_callback_stack_traces_test.dart:32(:33)?\)$',
|
||||
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:16(:3)?\)$',
|
||||
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:24(:19)?\)$',
|
||||
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:72(:9)?\)$',
|
||||
], registerUnaryCallbackStackTrace);
|
||||
|
||||
verifyStackTrace([
|
||||
r'^#\d+ _registerBinaryCallback \(.*zone_callback_stack_traces_test.dart:44(:33)?\)$',
|
||||
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:16(:3)?\)$',
|
||||
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:24(:19)?\)$',
|
||||
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:72(:9)?\)$',
|
||||
], registerBinaryCallbackStackTrace);
|
||||
}
|
|
@ -1,16 +1,10 @@
|
|||
// Copyright (c) 2023, 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.
|
||||
//
|
||||
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
|
||||
// make this test pass on vm-aot-dwarf-* builders.
|
||||
//
|
||||
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// @dart=2.9
|
||||
// @dart = 2.9
|
||||
|
||||
import 'awaiter_stacks/harness.dart' as harness;
|
||||
import 'causal_stacks/utils.dart' show assertStack, IGNORE_REMAINING_STACK;
|
||||
|
||||
class A {
|
||||
void takesA(A a) {
|
||||
|
@ -26,9 +20,7 @@ class B extends A {
|
|||
|
||||
StackTrace trace = null;
|
||||
|
||||
void main() async {
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
void main() {
|
||||
A a = new A();
|
||||
A b = new B();
|
||||
try {
|
||||
|
@ -36,17 +28,9 @@ void main() async {
|
|||
} catch (e, st) {
|
||||
trace = st;
|
||||
}
|
||||
|
||||
await harness.checkExpectedStack(trace);
|
||||
harness.updateExpectations();
|
||||
assertStack(const <String>[
|
||||
r'^#0 B.takesA \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:16(:27)?\)$',
|
||||
r'^#1 main \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:27(:7)?\)$',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 B.takesA (%test%)
|
||||
#1 main (%test%)
|
||||
#2 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#3 _RawReceivePort._handleMessage (isolate_patch.dart)"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
||||
|
|
|
@ -4,31 +4,57 @@
|
|||
|
||||
// @dart = 2.9
|
||||
|
||||
import 'awaiter_stacks/harness.dart' as harness;
|
||||
import 'causal_stacks/utils.dart';
|
||||
|
||||
main() async {
|
||||
harness.configure(currentExpectations);
|
||||
|
||||
StackTrace trace = StackTrace.empty;
|
||||
|
||||
A.visible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 new A.visible',
|
||||
r'^#2 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
A.invisible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
visible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 visible',
|
||||
r'^#2 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
invisible(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
visibleClosure(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 visibleClosure.visibleInner',
|
||||
r'^#2 visibleClosure',
|
||||
r'^#3 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
|
||||
invisibleClosure(() => trace = StackTrace.current);
|
||||
await harness.checkExpectedStack(trace);
|
||||
|
||||
harness.updateExpectations();
|
||||
await assertStack([
|
||||
r'^#0 main.<anonymous closure>',
|
||||
r'^#1 invisibleClosure',
|
||||
r'^#2 main',
|
||||
IGNORE_REMAINING_STACK,
|
||||
], trace);
|
||||
}
|
||||
|
||||
class A {
|
||||
|
@ -63,38 +89,3 @@ void invisibleClosure(void Function() fun) {
|
|||
|
||||
invisibleInner();
|
||||
}
|
||||
|
||||
// CURRENT EXPECTATIONS BEGIN
|
||||
final currentExpectations = [
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 new A.visible (%test%)
|
||||
#2 main (%test%)
|
||||
#3 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
|
||||
#4 _RawReceivePort._handleMessage (isolate_patch.dart)""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 visible (%test%)
|
||||
#2 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 visibleClosure.visibleInner (%test%)
|
||||
#2 visibleClosure (%test%)
|
||||
#3 main (%test%)
|
||||
<asynchronous suspension>""",
|
||||
"""
|
||||
#0 main.<anonymous closure> (%test%)
|
||||
#1 invisibleClosure (%test%)
|
||||
#2 main (%test%)
|
||||
<asynchronous suspension>"""
|
||||
];
|
||||
// CURRENT EXPECTATIONS END
|
||||
|
|
|
@ -1,49 +1,99 @@
|
|||
// Copyright (c) 2021, 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.
|
||||
//
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
// This test checks that --resolve-dwarf-paths outputs absolute and relative
|
||||
// paths in DWARF information.
|
||||
//
|
||||
// VMOptions=--dwarf-stack-traces --resolve-dwarf-paths --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
|
||||
|
||||
// @dart=2.9
|
||||
// OtherResources=use_save_debugging_info_flag_program.dart
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:native_stack_traces/native_stack_traces.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'use_flag_test_helper.dart';
|
||||
|
||||
main(List<String> args) async {
|
||||
if (!isAOTRuntime) {
|
||||
return; // Running in JIT: AOT binaries not available.
|
||||
}
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
return;
|
||||
return; // SDK tree and dart_bootstrap not available on the test device.
|
||||
}
|
||||
|
||||
final isDwarfStackTraces = StackTrace.current.toString().contains('*** ***');
|
||||
if (!isDwarfStackTraces) {
|
||||
return;
|
||||
// These are the tools we need to be available to run on a given platform:
|
||||
if (!await testExecutable(genSnapshot)) {
|
||||
throw "Cannot run test as $genSnapshot not available";
|
||||
}
|
||||
if (!await testExecutable(dartPrecompiledRuntime)) {
|
||||
throw "Cannot run test as $dartPrecompiledRuntime not available";
|
||||
}
|
||||
if (!File(platformDill).existsSync()) {
|
||||
throw "Cannot run test as $platformDill does not exist";
|
||||
}
|
||||
|
||||
final dwarfPath =
|
||||
p.join(Platform.environment['TEST_COMPILATION_DIR'], 'debug.so');
|
||||
final dwarf = Dwarf.fromFile(dwarfPath);
|
||||
runTests(obfuscate: false);
|
||||
runTests(obfuscate: true);
|
||||
}
|
||||
|
||||
final stack = StackTrace.current.toString();
|
||||
print(stack);
|
||||
final offsets = collectPCOffsets(stack.split('\n'));
|
||||
print(offsets);
|
||||
checkDwarfInfo(dwarf, offsets);
|
||||
void runTests({bool obfuscate}) async {
|
||||
final pathSuffix = obfuscate ? 'obfuscated' : 'cleartext';
|
||||
await withTempDir('dwarf-flag-test-$pathSuffix', (String tempDir) async {
|
||||
final cwDir = path.dirname(Platform.script.toFilePath());
|
||||
final script =
|
||||
path.join(cwDir, 'use_save_debugging_info_flag_program.dart');
|
||||
final scriptDill = path.join(tempDir, 'flag_program.dill');
|
||||
|
||||
// Compile script to Kernel IR.
|
||||
await run(genKernel, <String>[
|
||||
'--no-sound-null-safety',
|
||||
'--aot',
|
||||
'--platform=$platformDill',
|
||||
'-o',
|
||||
scriptDill,
|
||||
script,
|
||||
]);
|
||||
|
||||
final scriptDwarfSnapshot = path.join(tempDir, 'dwarf.so');
|
||||
await run(genSnapshot, <String>[
|
||||
if (obfuscate) ...[
|
||||
'--obfuscate',
|
||||
'--save-obfuscation-map=${path.join(tempDir, 'obfuscation.map')}',
|
||||
],
|
||||
'--no-sound-null-safety',
|
||||
'--resolve-dwarf-paths',
|
||||
'--dwarf-stack-traces-mode',
|
||||
'--snapshot-kind=app-aot-elf',
|
||||
'--elf=$scriptDwarfSnapshot',
|
||||
scriptDill,
|
||||
]);
|
||||
|
||||
// Run the resulting Dwarf-AOT compiled script.
|
||||
final dwarfTrace = await runError(dartPrecompiledRuntime, <String>[
|
||||
scriptDwarfSnapshot,
|
||||
scriptDill,
|
||||
]);
|
||||
|
||||
final tracePCOffsets = collectPCOffsets(dwarfTrace);
|
||||
|
||||
// Check that translating the DWARF stack trace (without internal frames)
|
||||
// matches the symbolic stack trace.
|
||||
final dwarf = Dwarf.fromFile(scriptDwarfSnapshot);
|
||||
Expect.isNotNull(dwarf);
|
||||
checkDwarfInfo(dwarf, tracePCOffsets);
|
||||
});
|
||||
}
|
||||
|
||||
void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
|
||||
print(offsets);
|
||||
final filenames = <String>{};
|
||||
for (final offset in offsets) {
|
||||
final callInfo = offset.callInfoFrom(dwarf, includeInternalFrames: true);
|
||||
final callInfo = offset.callInfoFrom(dwarf);
|
||||
Expect.isNotNull(callInfo);
|
||||
Expect.isNotEmpty(callInfo);
|
||||
for (final e in callInfo) {
|
||||
|
@ -51,7 +101,7 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
|
|||
final entry = e as DartCallInfo;
|
||||
var filename = entry.filename;
|
||||
if (!filename.startsWith('/')) {
|
||||
filename = p.join(sdkDir, filename);
|
||||
filename = path.join(sdkDir, filename);
|
||||
}
|
||||
if (filenames.add(filename)) {
|
||||
Expect.isTrue(
|
||||
|
@ -64,6 +114,4 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
|
|||
print('- ${filename}');
|
||||
}
|
||||
Expect.isNotEmpty(filenames);
|
||||
Expect.isNotEmpty(filenames
|
||||
.where((p) => p.endsWith('use_resolve_dwarf_paths_flag_test.dart')));
|
||||
}
|
||||
|
|
|
@ -141,10 +141,14 @@ dart_2/snapshot_depfile_test: SkipByDesign # Test needs to run from source
|
|||
|
||||
[ $compiler == dartkp ]
|
||||
dart/await_type_check_with_dynamic_loading_test: SkipByDesign # Uses dart:mirrors.
|
||||
dart/causal_stacks/async_throws_stack_no_causal_non_symbolic_test: SkipByDesign # --no-lazy... does nothing on precompiler.
|
||||
dart/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # --no-lazy... does nothing on precompiler.
|
||||
dart/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # Isolate.spawnUri is not supported in AOT.
|
||||
dart/redirection_type_shuffling_test: SkipByDesign # Uses dart:mirrors.
|
||||
dart/scavenger_abort_test: SkipSlow
|
||||
dart/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler.
|
||||
dart_2/causal_stacks/async_throws_stack_no_causal_non_symbolic_test: SkipByDesign # --no-lazy... does nothing on precompiler.
|
||||
dart_2/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # --no-lazy... does nothing on precompiler.
|
||||
dart_2/redirection_type_shuffling_test: SkipByDesign # Uses dart:mirrors.
|
||||
dart_2/scavenger_abort_test: SkipSlow
|
||||
dart_2/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler.
|
||||
|
@ -382,10 +386,10 @@ dart/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://d
|
|||
dart_2/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
|
||||
|
||||
[ $compiler == dartkp && $simulator ]
|
||||
dart/awaiter_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
|
||||
dart/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
|
||||
dart/isolates/fast_object_copy2_test*: Skip # Uses ffi which is not available on simulated architectures
|
||||
dart/isolates/fast_object_copy_test*: SkipSlow
|
||||
dart_2/awaiter_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
|
||||
dart_2/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
|
||||
dart_2/isolates/fast_object_copy_test*: SkipSlow
|
||||
|
||||
[ $compiler == dartkp && ($builder_tag == tsan || $simulator) ]
|
||||
|
@ -443,11 +447,11 @@ dart/run_appended_aot_snapshot_test: SkipByDesign # Tests the precompiled runtim
|
|||
dart_2/run_appended_aot_snapshot_test: SkipByDesign # Tests the precompiled runtime.
|
||||
|
||||
[ $builder_tag == dwarf || $builder_tag == obfuscated ]
|
||||
dart/awaiter_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/awaiter_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/awaiter_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/awaiter_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/awaiter_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/causal_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/causal_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/causal_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/causal_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/checked_parameter_assert_assignable_stacktrace_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart/error_messages_in_null_checks_test: SkipByDesign # Relies symbol names in stack traces
|
||||
dart/extension_names_test: SkipByDesign # Relies symbol names in stack traces
|
||||
|
@ -457,11 +461,11 @@ dart/invisible_function_pragma_test: SkipByDesign # Relies symbol names in stack
|
|||
dart/optimized_stacktrace_line_and_column_test: SkipByDesign # Relies symbol names in stack traces
|
||||
dart/optimized_stacktrace_line_test: SkipByDesign # Relies symbol names in stack traces
|
||||
dart/stacktrace_mixin_application_test: SkipByDesign # Relies symbol names in stack traces
|
||||
dart_2/awaiter_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/awaiter_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/awaiter_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/awaiter_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/awaiter_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/causal_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/causal_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/causal_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/causal_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/checked_parameter_assert_assignable_stacktrace_test: SkipByDesign # Asserts exact stacktrace output.
|
||||
dart_2/error_messages_in_null_checks_test: SkipByDesign # Relies on uris / symbol names
|
||||
dart_2/extension_names_test: SkipByDesign # Relies on uris / symbol names
|
||||
|
|
Loading…
Reference in a new issue