blob: b43867c21ee9a405c72140a7eb819b17444283b1 [file] [log] [blame]
// 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.
// ignore_for_file: empty_catches
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
// AUTOGENERATED START
//
// Update these constants by running:
//
// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
//
const LINE_A = 33;
const LINE_B = 47;
const LINE_C = 59;
const LINE_D = 74;
const LINE_E = 92;
const LINE_F = 108;
const LINE_G = 122;
// AUTOGENERATED END
// 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* {
final 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* {
final 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* {
final int i = 0;
try {
if (i == 1) return;
await throwException(); // LINE_F
} catch (e) {
} finally {
Future<void> inner() async {
await Future.delayed(Duration(milliseconds: 10));
}
await inner();
yield 1;
}
}
Future<void> throwException() async {
await Future.delayed(Duration(milliseconds: 10));
throw Exception(''); // LINE_G
}
Future<void> 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()) {}
}
final tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtLine(LINE_G),
resumeIsolate,
for (final line in [LINE_A, LINE_B, LINE_C, LINE_D, LINE_E, LINE_F]) ...[
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_G),
_expectSecondFrameFromTheTopToBeAt(line),
resumeIsolate,
],
hasStoppedAtExit,
];
Future<void> Function(VmService, IsolateRef) _expectSecondFrameFromTheTopToBeAt(
int line,
) {
return (VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final stack = await service.getStack(isolateId);
final frames = stack.asyncCausalFrames!;
expect(frames.length, greaterThanOrEqualTo(3));
// Check second top frame contains correct line number.
expect(frames[0].kind, FrameKind.kRegular);
final frame0Location = frames[0].location!;
final script0 = await service.getObject(
isolateId,
frame0Location.script!.id!,
) as Script;
expect(
script0.getLineNumberFromTokenPos(frame0Location.tokenPos!),
LINE_G,
);
expect(frames[1].kind, FrameKind.kAsyncSuspensionMarker);
expect(frames[2].location, isNotNull);
expect(frames[2].kind, FrameKind.kAsyncCausal);
final frame2Location = frames[2].location!;
final script2 = await service.getObject(
isolateId,
frame2Location.script!.id!,
) as Script;
expect(
script2.getLineNumberFromTokenPos(frames[2].location!.tokenPos!),
line,
);
};
}
void main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'yield_positions_with_finally_test.dart',
testeeConcurrent: code,
pauseOnStart: true,
pauseOnExit: true,
);