blob: d9200af2a570f643a3cfcf0f06c6ecc0ce17bdef [file] [log] [blame]
// Copyright (c) 2017, 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: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 = 31;
const LINE_B = 33;
// AUTOGENERATED END
int value = 0;
int incValue(int amount) {
value += amount;
return amount;
}
Future<void> testMain() async {
incValue(incValue(1)); // LINE_A.
incValue(incValue(1)); // LINE_B.
}
final tests = <IsolateTest>[
hasPausedAtStart,
// Test future breakpoints.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final rootLibId = rootLib.id!;
final scriptId = rootLib.scripts![0].id!;
final script = await service.getObject(isolateId, scriptId) as Script;
// Future breakpoint.
var futureBpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
expect(futureBpt1.breakpointNumber, 1);
expect(futureBpt1.resolved, isFalse);
expect(await futureBpt1.location!.line!, LINE_A);
expect(await futureBpt1.location!.column, null);
// Future breakpoint with specific column.
var futureBpt2 =
await service.addBreakpoint(isolateId, scriptId, LINE_A, column: 3);
expect(futureBpt2.breakpointNumber, 2);
expect(futureBpt2.resolved, isFalse);
expect(await futureBpt2.location!.line!, LINE_A);
expect(await futureBpt2.location!.column!, 3);
final int resolvedCount = await resumeAndCountResolvedBreakpointsUntilPause(
service,
isolate,
);
// After resolution the breakpoints have assigned line & column.
expect(resolvedCount, 2);
// Refresh objects
futureBpt1 =
await service.getObject(isolateId, futureBpt1.id!) as Breakpoint;
futureBpt2 =
await service.getObject(isolateId, futureBpt2.id!) as Breakpoint;
expect(futureBpt1.resolved, isTrue);
expect(
script.getLineNumberFromTokenPos(futureBpt1.location!.tokenPos!),
LINE_A,
);
expect(futureBpt1.location!.line, LINE_A);
expect(
script.getColumnNumberFromTokenPos(futureBpt1.location!.tokenPos!),
12,
);
expect(futureBpt1.location!.column, 12);
expect(futureBpt2.resolved, isTrue);
expect(
script.getLineNumberFromTokenPos(futureBpt2.location!.tokenPos!),
LINE_A,
);
expect(futureBpt2.location!.line, LINE_A);
expect(
script.getColumnNumberFromTokenPos(futureBpt2.location!.tokenPos!),
3,
);
expect(futureBpt2.location!.column, 3);
// The first breakpoint hits before value is modified.
InstanceRef result =
await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
expect(result.valueAsString, '0');
await service.resume(isolateId);
await hasStoppedAtBreakpoint(service, isolate);
// The second breakpoint hits after value has been modified once.
result =
await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
expect(result.valueAsString, '1');
// Remove the breakpoints.
expect(
(await service.removeBreakpoint(isolateId, futureBpt1.id!)).type,
'Success',
);
expect(
(await service.removeBreakpoint(isolateId, futureBpt2.id!)).type,
'Success',
);
},
// Test resolution of column breakpoints.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final rootLibId = isolate.rootLib!.id!;
final rootLib = await service.getObject(isolateId, rootLibId) as Library;
final scriptId = rootLib.scripts![0].id!;
final script = await service.getObject(isolateId, scriptId) as Script;
// Try all columns, including some columns that are too big.
for (int col = 1; col <= 50; col++) {
final bpt =
await service.addBreakpoint(isolateId, scriptId, LINE_A, column: col);
expect(bpt.resolved, isTrue);
final int resolvedLine = script.getLineNumberFromTokenPos(
bpt.location!.tokenPos!,
)!;
final int resolvedCol = script.getColumnNumberFromTokenPos(
bpt.location!.tokenPos!,
)!;
print('$LINE_A:$col -> $resolvedLine:$resolvedCol');
if (col < 12) {
// The second 'incValue' begins at column 12.
expect(resolvedLine, LINE_A);
expect(bpt.location!.line, LINE_A);
expect(resolvedCol, 3);
expect(bpt.location!.column, 3);
} else if (col <= 36) {
// The newline character at the end of LINE_A is at column 36.
expect(resolvedLine, LINE_A);
expect(bpt.location!.line, LINE_A);
expect(resolvedCol, 12);
expect(bpt.location!.column, 12);
} else {
expect(resolvedLine, LINE_B);
expect(bpt.location!.line, LINE_B);
expect(resolvedCol, 12);
expect(bpt.location!.column, 12);
}
expect(
(await service.removeBreakpoint(isolateId, bpt.id!)).type,
'Success',
);
}
// Make sure that a zero column is an error.
bool caughtException = false;
try {
await service.addBreakpoint(isolateId, scriptId, 20, column: 0);
expect(false, isTrue, reason: 'Unreachable');
} on RPCError catch (e) {
caughtException = true;
expect(e.code, RPCErrorKind.kInvalidParams.code);
expect(e.details, "addBreakpoint: invalid 'column' parameter: 0");
}
expect(caughtException, isTrue);
},
];
Future<int> resumeAndCountResolvedBreakpointsUntilPause(
VmService service,
Isolate isolate,
) async {
final completer = Completer<void>();
late StreamSubscription subscription;
int resolvedCount = 0;
subscription = service.onDebugEvent.listen((event) {
if (event.kind == EventKind.kBreakpointResolved) {
resolvedCount++;
} else if (event.kind == EventKind.kPauseBreakpoint) {
subscription.cancel();
service.streamCancel(EventStreams.kDebug);
completer.complete();
}
});
await service.streamListen(EventStreams.kDebug);
await service.resume(isolate.id!);
await completer.future;
return resolvedCount;
}
void main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'add_breakpoint_rpc_kernel_test.dart',
testeeConcurrent: testMain,
pauseOnStart: true,
);