e1d687cb9e
This CL migrates the `dwds` and `dwds_test_common` packages into the Dart SDK repository. Key Changes: - Migration: Moved source code and tests into `pkg/dwds` & `pkg/dwds_test_common`. - Linting and path resolution were updated in https://github.com/dart-lang/webdev/pull/2797, https://github.com/dart-lang/webdev/pull/2798 & https://github.com/dart-lang/webdev/pull/2799 to support both environments (webdev and sdk). Testing: - All tests passing locally. - CI try bots are green. Design Doc: http://goto.google.com/migrating-webdev and http://goto.google.com/migrating-dwds Fixes https://github.com/dart-lang/sdk/issues/62100 Fixes https://github.com/dart-lang/sdk/issues/62101 Fixes https://github.com/dart-lang/sdk/issues/62102 Fixes https://github.com/dart-lang/sdk/issues/62103 Cq-Include-Trybots: luci.dart.try:pkg-win-release-try,pkg-win-release-arm64-try,pkg-mac-release-try,pkg-mac-release-arm64-try,pkg-linux-release-try,pkg-linux-release-arm64-try,pkg-linux-debug-try Change-Id: Icc2bf9a86efb79d04a67053962a4548fe6e894f7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494640 Reviewed-by: Nicholas Shahan <nshahan@google.com> Reviewed-by: Nate Biggs <natebiggs@google.com> Reviewed-by: Ivan Inozemtsev <iinozemtsev@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com> Reviewed-by: Mark Zhou <markzipan@google.com>
328 lines
10 KiB
Dart
328 lines
10 KiB
Dart
// 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:dwds_test_common/logging.dart';
|
|
import 'package:dwds_test_common/test_sdk_configuration.dart';
|
|
import 'package:test/test.dart';
|
|
import 'package:vm_service/vm_service.dart';
|
|
import 'package:vm_service_interface/vm_service_interface.dart';
|
|
|
|
import 'fixtures/context.dart';
|
|
import 'fixtures/project.dart';
|
|
import 'fixtures/utilities.dart';
|
|
|
|
void testCallStack({
|
|
required TestSdkConfigurationProvider provider,
|
|
required CompilationMode compilationMode,
|
|
bool verboseCompiler = false,
|
|
}) {
|
|
final project = TestProject.testPackage();
|
|
final context = TestContext(project, provider);
|
|
|
|
group('shared context |', () {
|
|
setUpAll(() async {
|
|
setCurrentLogWriter(debug: provider.verbose);
|
|
await context.setUp(
|
|
testSettings: TestSettings(
|
|
compilationMode: compilationMode,
|
|
enableExpressionEvaluation: true,
|
|
verboseCompiler: verboseCompiler,
|
|
moduleFormat: provider.ddcModuleFormat,
|
|
canaryFeatures: provider.canaryFeatures,
|
|
),
|
|
);
|
|
});
|
|
|
|
tearDownAll(() async {
|
|
await context.tearDown();
|
|
});
|
|
|
|
group('callStack |', () {
|
|
late VmServiceInterface service;
|
|
VM vm;
|
|
late Isolate isolate;
|
|
late String isolateId;
|
|
ScriptList scripts;
|
|
late ScriptRef mainScript;
|
|
late ScriptRef testLibraryScript;
|
|
late Stream<Event> stream;
|
|
|
|
setUp(() async {
|
|
setCurrentLogWriter(debug: provider.verbose);
|
|
service = context.service;
|
|
vm = await service.getVM();
|
|
isolate = await service.getIsolate(vm.isolates!.first.id!);
|
|
isolateId = isolate.id!;
|
|
scripts = await service.getScripts(isolateId);
|
|
|
|
await service.streamListen('Debug');
|
|
stream = service.onEvent('Debug');
|
|
|
|
final testPackage = project.packageName;
|
|
mainScript = scripts.scripts!.firstWhere(
|
|
(each) => each.uri!.contains('main.dart'),
|
|
);
|
|
testLibraryScript = scripts.scripts!.firstWhere(
|
|
(each) =>
|
|
each.uri!.contains('package:$testPackage/test_library.dart'),
|
|
);
|
|
});
|
|
|
|
tearDown(() async {
|
|
try {
|
|
await service.resume(isolateId);
|
|
} catch (_) {}
|
|
});
|
|
|
|
Future<void> onBreakPoint(
|
|
BreakpointTestData breakpoint,
|
|
Future<void> Function() body,
|
|
) async {
|
|
Breakpoint? bp;
|
|
try {
|
|
final bpId = breakpoint.bpId;
|
|
final script = breakpoint.script;
|
|
final line = await context.findBreakpointLine(
|
|
bpId,
|
|
isolateId,
|
|
script,
|
|
);
|
|
bp = await context.service.addBreakpointWithScriptUri(
|
|
isolateId,
|
|
script.uri!,
|
|
line,
|
|
);
|
|
|
|
expect(bp, isNotNull);
|
|
expect(bp.location, _matchBpLocation(script, line, 0));
|
|
|
|
await stream.firstWhere(
|
|
(Event event) => event.kind == EventKind.kPauseBreakpoint,
|
|
);
|
|
|
|
await body();
|
|
} finally {
|
|
// Remove breakpoint so it doesn't impact other tests or retries.
|
|
if (bp != null) {
|
|
await context.service.removeBreakpoint(isolateId, bp.id!);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> testCallStack(
|
|
List<BreakpointTestData> breakpoints, {
|
|
int frameIndex = 1,
|
|
}) async {
|
|
// Find lines the breakpoints are located on.
|
|
final lines = await Future.wait(
|
|
breakpoints.map(
|
|
(frame) =>
|
|
context.findBreakpointLine(frame.bpId, isolateId, frame.script),
|
|
),
|
|
);
|
|
|
|
// Get current stack.
|
|
final stack = await service.getStack(isolateId);
|
|
|
|
// Verify the stack is correct.
|
|
expect(stack.frames!.length, greaterThanOrEqualTo(lines.length));
|
|
final expected = [
|
|
for (var i = 0; i < lines.length; i++)
|
|
_matchFrame(
|
|
breakpoints[i].script,
|
|
breakpoints[i].function,
|
|
lines[i],
|
|
),
|
|
];
|
|
expect(stack.frames, containsAll(expected));
|
|
|
|
// Verify that expression evaluation is not failing.
|
|
final instance = await service.evaluateInFrame(
|
|
isolateId,
|
|
frameIndex,
|
|
'true',
|
|
);
|
|
expect(instance, isA<InstanceRef>());
|
|
}
|
|
|
|
test('breakpoint succeeds with correct callstack', () async {
|
|
// Expected breakpoints on the stack
|
|
final breakpoints = [
|
|
BreakpointTestData(
|
|
'printEnclosingObject',
|
|
'printEnclosingObject',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'printEnclosingFunctionMultiLine',
|
|
'printNestedObjectsMultiLine',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'callPrintEnclosingFunctionMultiLine',
|
|
'<closure>',
|
|
mainScript,
|
|
),
|
|
];
|
|
await onBreakPoint(breakpoints[0], () => testCallStack(breakpoints));
|
|
});
|
|
|
|
test('expression evaluation succeeds on parent frame', () async {
|
|
// Expected breakpoints on the stack
|
|
final breakpoints = [
|
|
BreakpointTestData(
|
|
'testLibraryClassConstructor',
|
|
'new',
|
|
testLibraryScript,
|
|
),
|
|
BreakpointTestData(
|
|
'createLibraryObject',
|
|
'printFieldFromLibraryClass',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'callPrintFieldFromLibraryClass',
|
|
'<closure>',
|
|
mainScript,
|
|
),
|
|
];
|
|
await onBreakPoint(
|
|
breakpoints[0],
|
|
() => testCallStack(breakpoints, frameIndex: 2),
|
|
);
|
|
});
|
|
|
|
test('breakpoint inside a line gives correct callstack', () async {
|
|
// Expected breakpoints on the stack
|
|
final breakpoints = [
|
|
BreakpointTestData('newEnclosedClass', 'new', mainScript),
|
|
BreakpointTestData(
|
|
'printNestedObjectMultiLine',
|
|
'printNestedObjectsMultiLine',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'callPrintEnclosingFunctionMultiLine',
|
|
'<closure>',
|
|
mainScript,
|
|
),
|
|
];
|
|
await onBreakPoint(breakpoints[0], () => testCallStack(breakpoints));
|
|
});
|
|
|
|
test('breakpoint gives correct callstack after step out', () async {
|
|
// Expected breakpoints on the stack
|
|
final breakpoints = [
|
|
BreakpointTestData('newEnclosedClass', 'new', mainScript),
|
|
BreakpointTestData(
|
|
'printEnclosingObjectMultiLine',
|
|
'printNestedObjectsMultiLine',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'callPrintEnclosingFunctionMultiLine',
|
|
'<closure>',
|
|
mainScript,
|
|
),
|
|
];
|
|
await onBreakPoint(breakpoints[0], () async {
|
|
await service.resume(isolateId, step: 'Out');
|
|
await stream.firstWhere(
|
|
(Event event) => event.kind == EventKind.kPauseInterrupted,
|
|
);
|
|
return testCallStack([breakpoints[1], breakpoints[2]]);
|
|
});
|
|
});
|
|
|
|
test('breakpoint gives correct callstack after step in', () async {
|
|
// Expected breakpoints on the stack
|
|
final breakpoints = [
|
|
BreakpointTestData('newEnclosedClass', 'new', mainScript),
|
|
BreakpointTestData(
|
|
'printNestedObjectMultiLine',
|
|
'printNestedObjectsMultiLine',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'callPrintEnclosingFunctionMultiLine',
|
|
'<closure>',
|
|
mainScript,
|
|
),
|
|
];
|
|
await onBreakPoint(breakpoints[1], () async {
|
|
await service.resume(isolateId, step: 'Into');
|
|
await stream.firstWhere(
|
|
(Event event) => event.kind == EventKind.kPauseInterrupted,
|
|
);
|
|
return testCallStack(breakpoints);
|
|
});
|
|
});
|
|
|
|
test(
|
|
'breakpoint gives correct callstack after step into chain calls',
|
|
() async {
|
|
// Expected breakpoints on the stack
|
|
final breakpoints = [
|
|
BreakpointTestData(
|
|
'createObjectWithMethod',
|
|
'createObject',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
// This is currently incorrect, should be printObjectMultiLine.
|
|
// See issue: https://github.com/dart-lang/sdk/issues/48874
|
|
'printMultiLine',
|
|
'printObjectMultiLine',
|
|
mainScript,
|
|
),
|
|
BreakpointTestData(
|
|
'callPrintObjectMultiLine',
|
|
'<closure>',
|
|
mainScript,
|
|
),
|
|
];
|
|
final bp = BreakpointTestData(
|
|
'printMultiLine',
|
|
'printObjectMultiLine',
|
|
mainScript,
|
|
);
|
|
await onBreakPoint(bp, () async {
|
|
await service.resume(isolateId, step: 'Into');
|
|
await stream.firstWhere(
|
|
(Event event) => event.kind == EventKind.kPauseInterrupted,
|
|
);
|
|
return testCallStack(breakpoints);
|
|
});
|
|
},
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|
|
Matcher _matchFrame(ScriptRef script, String function, int line) => isA<Frame>()
|
|
.having((frame) => frame.code!.name, 'function', function)
|
|
.having(
|
|
(frame) => frame.location,
|
|
'location',
|
|
_matchFrameLocation(script, line),
|
|
);
|
|
|
|
Matcher _matchBpLocation(ScriptRef script, int line, int column) =>
|
|
isA<SourceLocation>()
|
|
.having((loc) => loc.script, 'script', equals(script))
|
|
.having((loc) => loc.line, 'line', equals(line))
|
|
.having((loc) => loc.column, 'column', greaterThanOrEqualTo(column));
|
|
|
|
Matcher _matchFrameLocation(ScriptRef script, int line) => isA<SourceLocation>()
|
|
.having((loc) => loc.script, 'script', equals(script))
|
|
.having((loc) => loc.line, 'line', equals(line));
|
|
|
|
class BreakpointTestData {
|
|
String bpId;
|
|
String function;
|
|
ScriptRef script;
|
|
|
|
BreakpointTestData(this.bpId, this.function, this.script);
|
|
}
|