blob: 29a8ba4ea82c37d89d7acd8cbb206d4210ffad92 [file] [log] [blame]
// 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 'package:observatory/models.dart' as M;
import 'package:observatory/service_io.dart';
import 'package:test/test.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
const int LINE = 113;
const int LINE_A = 24;
const int LINE_B = 38;
const int LINE_C = 50;
const int LINE_D = 65;
const int LINE_E = 83;
const int LINE_F = 99;
// break statement
Stream<int> testBreak() async* {
for (int t = 0; t < 10; t++) {
try {
if (t == 1) break;
await throwException(); // LINE_A
} catch (e) {
} finally {
yield t;
}
}
}
// return statement
Stream<int> testReturn() async* {
for (int t = 0; t < 10; t++) {
try {
yield t;
if (t == 1) return;
await throwException(); // LINE_B
} catch (e) {
} finally {
yield t;
}
}
}
// Multiple functions
Stream<int> testMultipleFunctions() async* {
try {
yield 0;
await throwException(); // LINE_C
} catch (e) {
} finally {
yield 1;
}
}
// continue statement
Stream<int> testContinueSwitch() async* {
int currentState = 0;
switch (currentState) {
case 0:
{
try {
if (currentState == 1) continue label;
await throwException(); // LINE_D
} catch (e) {
} finally {
yield 0;
}
yield 1;
break;
}
label:
case 1:
break;
}
}
Stream<int> testNestFinally() async* {
int i = 0;
try {
if (i == 1) return;
await throwException(); //LINE_E
} catch (e) {
} finally {
try {
yield i;
} finally {
yield 1;
}
yield 1;
}
}
Stream<int> testAsyncClosureInFinally() async* {
int i = 0;
try {
if (i == 1) return;
await throwException(); //LINE_F
} catch (e) {
} finally {
inner() async {
await Future.delayed(Duration(milliseconds: 10));
}
await inner;
yield 1;
}
}
Future<void> throwException() async {
await Future.delayed(Duration(milliseconds: 10));
throw new Exception(""); // LINE
}
code() async {
await for (var _ in testBreak()) {}
await for (var _ in testReturn()) {}
await for (var _ in testMultipleFunctions()) {}
await for (var _ in testContinueSwitch()) {}
await for (var _ in testNestFinally()) {}
await for (var _ in testAsyncClosureInFinally()) {}
}
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtLine(LINE),
resumeIsolate,
for (var line in [LINE_A, LINE_B, LINE_C, LINE_D, LINE_E, LINE_F]) ...[
hasStoppedAtBreakpoint,
stoppedAtLine(LINE),
_expectSecondFrameFromTheTopToBeAt(line),
resumeIsolate,
],
hasStoppedAtExit
];
Future<void> Function(Isolate) _expectSecondFrameFromTheTopToBeAt(int line) {
return (isolate) async {
ServiceMap stack = await isolate.getStack();
expect(stack['asyncCausalFrames'], isNotNull);
expect(stack['asyncCausalFrames'].length, greaterThanOrEqualTo(3));
// Check second top frame contains correct line number.
final frames = (stack['asyncCausalFrames'] as List).cast<Frame>();
expect(frames[0].kind, M.FrameKind.regular);
final script0 = frames[0].location!.script;
expect(script0.tokenToLine(frames[0].location!.tokenPos), equals(LINE));
expect(frames[1].kind, M.FrameKind.asyncSuspensionMarker);
expect(frames[2].location, isNotNull);
expect(frames[2].kind, M.FrameKind.asyncCausal);
final script2 = frames[2].location!.script;
expect(script2.tokenToLine(frames[2].location!.tokenPos), equals(line));
};
}
main(args) {
runIsolateTestsSynchronous(args, tests,
testeeConcurrent: code, pause_on_start: true, pause_on_exit: true);
}