mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:49:47 +00:00
2db8f37cfa
Removes the need for requesting a full Script object, which can be extremely large when including source code. This change will have a relatively small impact on response sizes. Related issues: https://github.com/dart-lang/sdk/issues/47215, https://github.com/flutter/devtools/issues/3382 TEST=pkg/vm_service tests updated Change-Id: I27999c4b1da65d4f0c643fa8db1a019c0fd1d689 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/227640 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
189 lines
6.2 KiB
Dart
189 lines
6.2 KiB
Dart
// 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';
|
|
|
|
const int LINE_A = 24;
|
|
const int LINE_B = 26;
|
|
|
|
int value = 0;
|
|
|
|
int incValue(int amount) {
|
|
value += amount;
|
|
return amount;
|
|
}
|
|
|
|
Future testMain() async {
|
|
incValue(incValue(1)); // line A.
|
|
|
|
incValue(incValue(1)); // line B.
|
|
}
|
|
|
|
var 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);
|
|
|
|
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);
|
|
int resolvedLine =
|
|
script.getLineNumberFromTokenPos(bpt.location!.tokenPos!)!;
|
|
int resolvedCol =
|
|
script.getColumnNumberFromTokenPos(bpt.location!.tokenPos!)!;
|
|
print('$LINE_A:${col} -> ${resolvedLine}:${resolvedCol}');
|
|
if (col <= 12) {
|
|
expect(resolvedLine, LINE_A);
|
|
expect(bpt.location!.line, LINE_A);
|
|
expect(resolvedCol, 3);
|
|
expect(bpt.location!.column, 3);
|
|
} else if (col <= 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.
|
|
var 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, RPCError.kInvalidParams);
|
|
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;
|
|
}
|
|
|
|
main(args) => runIsolateTests(
|
|
args,
|
|
tests,
|
|
'add_breakpoint_rpc_kernel_test.dart',
|
|
testeeConcurrent: testMain,
|
|
pause_on_start: true,
|
|
);
|