| Index: runtime/observatory/tests/service/service_test_common.dart
|
| diff --git a/runtime/observatory/tests/service/service_test_common.dart b/runtime/observatory/tests/service/service_test_common.dart
|
| index 837d237c7ef50e270b374047754f1cb375298182..28cad861b4ee4f0e93afc1b801beaeef19e817b9 100644
|
| --- a/runtime/observatory/tests/service/service_test_common.dart
|
| +++ b/runtime/observatory/tests/service/service_test_common.dart
|
| @@ -5,6 +5,7 @@
|
| library service_test_common;
|
|
|
| import 'dart:async';
|
| +import 'dart:io' show Platform;
|
| import 'package:observatory/models.dart' as M;
|
| import 'package:observatory/service_common.dart';
|
| import 'package:unittest/unittest.dart';
|
| @@ -99,22 +100,21 @@ Future asyncStepOver(Isolate isolate) async {
|
| // Synthetic breakpoint add event. This is the first event we will
|
| // receive.
|
| bool isAdd = (event.kind == ServiceEvent.kBreakpointAdded) &&
|
| - (event.breakpoint.isSyntheticAsyncContinuation) &&
|
| - (event.owner == isolate);
|
| + (event.breakpoint.isSyntheticAsyncContinuation) &&
|
| + (event.owner == isolate);
|
| // Resume after synthetic breakpoint added. This is the second event
|
| // we will recieve.
|
| bool isResume = (event.kind == ServiceEvent.kResume) &&
|
| - (syntheticBreakpoint != null) &&
|
| - (event.owner == isolate);
|
| + (syntheticBreakpoint != null) &&
|
| + (event.owner == isolate);
|
| // Paused at synthetic breakpoint. This is the third event we will
|
| // receive.
|
| bool isPaused = (event.kind == ServiceEvent.kPauseBreakpoint) &&
|
| - (syntheticBreakpoint != null) &&
|
| - (event.breakpoint == syntheticBreakpoint);
|
| + (syntheticBreakpoint != null) &&
|
| + (event.breakpoint == syntheticBreakpoint);
|
| if (isAdd) {
|
| syntheticBreakpoint = event.breakpoint;
|
| - } else if (isResume) {
|
| - } else if (isPaused) {
|
| + } else if (isResume) {} else if (isPaused) {
|
| pausedAtSyntheticBreakpoint.complete(isolate);
|
| syntheticBreakpoint = null;
|
| cancelSubscription();
|
| @@ -157,21 +157,21 @@ Future<Isolate> hasPausedFor(Isolate isolate, String kind) {
|
| isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
|
| var subscription;
|
| subscription = stream.listen((ServiceEvent event) {
|
| - if ((isolate == event.isolate) && (event.kind == kind)) {
|
| - if (completer != null) {
|
| - // Reload to update isolate.pauseEvent.
|
| - print('Paused with $kind');
|
| - subscription.cancel();
|
| - completer.complete(isolate.reload());
|
| - completer = null;
|
| - }
|
| + if ((isolate == event.isolate) && (event.kind == kind)) {
|
| + if (completer != null) {
|
| + // Reload to update isolate.pauseEvent.
|
| + print('Paused with $kind');
|
| + subscription.cancel();
|
| + completer.complete(isolate.reload());
|
| + completer = null;
|
| }
|
| + }
|
| });
|
|
|
| // Pause may have happened before we subscribed.
|
| isolate.reload().then((_) {
|
| if ((isolate.pauseEvent != null) &&
|
| - isEventOfKind(isolate.pauseEvent, kind)) {
|
| + isEventOfKind(isolate.pauseEvent, kind)) {
|
| // Already waiting at a breakpoint.
|
| if (completer != null) {
|
| print('Paused with $kind');
|
| @@ -183,7 +183,7 @@ Future<Isolate> hasPausedFor(Isolate isolate, String kind) {
|
| });
|
| });
|
|
|
| - return completer.future; // Will complete when breakpoint hit.
|
| + return completer.future; // Will complete when breakpoint hit.
|
| }
|
|
|
| Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) {
|
| @@ -210,28 +210,26 @@ Future<Isolate> markDartColonLibrariesDebuggable(Isolate isolate) async {
|
| await isolate.reload();
|
| for (Library lib in isolate.libraries) {
|
| await lib.load();
|
| - if (lib.uri.startsWith('dart:') &&
|
| - !lib.uri.startsWith('dart:_')) {
|
| + if (lib.uri.startsWith('dart:') && !lib.uri.startsWith('dart:_')) {
|
| var setDebugParams = {
|
| - 'libraryId': lib.id,
|
| - 'isDebuggable': true,
|
| - };
|
| - Map<String, dynamic> result =
|
| - await isolate.invokeRpcNoUpgrade('setLibraryDebuggable',
|
| - setDebugParams);
|
| + 'libraryId': lib.id,
|
| + 'isDebuggable': true,
|
| + };
|
| + Map<String, dynamic> result = await isolate.invokeRpcNoUpgrade(
|
| + 'setLibraryDebuggable', setDebugParams);
|
| }
|
| }
|
| return isolate;
|
| }
|
|
|
| IsolateTest reloadSources([bool pause = false]) {
|
| - return (Isolate isolate) async {
|
| - Map<String, dynamic> params = <String, dynamic>{ };
|
| - if (pause == true) {
|
| - params['pause'] = pause;
|
| - }
|
| - return isolate.invokeRpc('reloadSources', params);
|
| - };
|
| + return (Isolate isolate) async {
|
| + Map<String, dynamic> params = <String, dynamic>{};
|
| + if (pause == true) {
|
| + params['pause'] = pause;
|
| + }
|
| + return isolate.invokeRpc('reloadSources', params);
|
| + };
|
| }
|
|
|
| // Currying is your friend.
|
| @@ -279,8 +277,8 @@ IsolateTest stoppedAtLine(int line) {
|
| };
|
| }
|
|
|
| -
|
| -IsolateTest stoppedInFunction(String functionName, {bool contains: false}) {
|
| +IsolateTest stoppedInFunction(String functionName,
|
| + {bool contains: false, bool includeOwner: false}) {
|
| return (Isolate isolate) async {
|
| print("Checking we are in function: $functionName");
|
|
|
| @@ -292,13 +290,18 @@ IsolateTest stoppedInFunction(String functionName, {bool contains: false}) {
|
|
|
| Frame topFrame = stack['frames'][0];
|
| ServiceFunction function = await topFrame.function.load();
|
| + String name = function.name;
|
| + if (includeOwner) {
|
| + ServiceFunction owner =
|
| + await (function.dartOwner as ServiceObject).load();
|
| + name = '${owner.name}.$name';
|
| + }
|
| final bool matches =
|
| - contains ? function.name.contains(functionName) :
|
| - function.name == functionName;
|
| + contains ? name.contains(functionName) : name == functionName;
|
| if (!matches) {
|
| StringBuffer sb = new StringBuffer();
|
| sb.write("Expected to be in function $functionName but "
|
| - "actually in function ${function.name}");
|
| + "actually in function $name");
|
| sb.write("\nFull stack trace:\n");
|
| for (Frame f in stack['frames']) {
|
| await f.function.load();
|
| @@ -314,7 +317,6 @@ IsolateTest stoppedInFunction(String functionName, {bool contains: false}) {
|
| };
|
| }
|
|
|
| -
|
| Future<Isolate> resumeIsolate(Isolate isolate) {
|
| Completer completer = new Completer();
|
| isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
|
| @@ -330,21 +332,18 @@ Future<Isolate> resumeIsolate(Isolate isolate) {
|
| return completer.future;
|
| }
|
|
|
| -
|
| Future resumeAndAwaitEvent(Isolate isolate, stream, onEvent) async {
|
| Completer completer = new Completer();
|
| var sub;
|
| - sub = await isolate.vm.listenEventStream(
|
| - stream,
|
| - (ServiceEvent event) {
|
| - var r = onEvent(event);
|
| - if (r is! Future) {
|
| - r = new Future.value(r);
|
| - }
|
| - r.then((x) => sub.cancel().then((_) {
|
| - completer.complete();
|
| - }));
|
| - });
|
| + sub = await isolate.vm.listenEventStream(stream, (ServiceEvent event) {
|
| + var r = onEvent(event);
|
| + if (r is! Future) {
|
| + r = new Future.value(r);
|
| + }
|
| + r.then((x) => sub.cancel().then((_) {
|
| + completer.complete();
|
| + }));
|
| + });
|
| await isolate.resume();
|
| return completer.future;
|
| }
|
| @@ -354,7 +353,6 @@ IsolateTest resumeIsolateAndAwaitEvent(stream, onEvent) {
|
| resumeAndAwaitEvent(isolate, stream, onEvent);
|
| }
|
|
|
| -
|
| Future<Isolate> stepOver(Isolate isolate) async {
|
| await isolate.stepOver();
|
| return hasStoppedAtBreakpoint(isolate);
|
| @@ -370,7 +368,6 @@ Future<Isolate> stepOut(Isolate isolate) async {
|
| return hasStoppedAtBreakpoint(isolate);
|
| }
|
|
|
| -
|
| Future isolateIsRunning(Isolate isolate) async {
|
| await isolate.reload();
|
| expect(isolate.running, true);
|
| @@ -387,9 +384,8 @@ Future<Class> getClassFromRootLib(Isolate isolate, String className) async {
|
| return null;
|
| }
|
|
|
| -
|
| -Future<Instance> rootLibraryFieldValue(Isolate isolate,
|
| - String fieldName) async {
|
| +Future<Instance> rootLibraryFieldValue(
|
| + Isolate isolate, String fieldName) async {
|
| Library rootLib = await isolate.rootLibrary.load();
|
| Field field = rootLib.variables.singleWhere((v) => v.name == fieldName);
|
| await field.load();
|
| @@ -425,9 +421,63 @@ IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) {
|
| };
|
| }
|
|
|
| +IsolateTest runStepIntoThroughProgramRecordingStops(List<String> recordStops) {
|
| + return (Isolate isolate) async {
|
| + Completer completer = new Completer();
|
| +
|
| + await subscribeToStream(isolate.vm, VM.kDebugStream,
|
| + (ServiceEvent event) async {
|
| + if (event.kind == ServiceEvent.kPauseBreakpoint) {
|
| + await isolate.reload();
|
| + // We are paused: Step into further.
|
| + Frame frame = isolate.topFrame;
|
| + recordStops.add(await frame.location.toUserString());
|
| + isolate.stepInto();
|
| + } else if (event.kind == ServiceEvent.kPauseExit) {
|
| + // We are at the exit: The test is done.
|
| + await cancelStreamSubscription(VM.kDebugStream);
|
| + completer.complete();
|
| + }
|
| + });
|
| + isolate.resume();
|
| + return completer.future;
|
| + };
|
| +}
|
| +
|
| IsolateTest checkRecordedStops(
|
| - List<String> recordStops, List<String> expectedStops) {
|
| + List<String> recordStops, List<String> expectedStops,
|
| + {bool removeDuplicates = false,
|
| + bool debugPrint = false,
|
| + String debugPrintFile,
|
| + int debugPrintLine}) {
|
| return (Isolate isolate) async {
|
| + if (debugPrint) {
|
| + for (int i = 0; i < recordStops.length; i++) {
|
| + String line = recordStops[i];
|
| + String output = line;
|
| + int firstColon = line.indexOf(":");
|
| + int lastColon = line.lastIndexOf(":");
|
| + if (debugPrintFile != null &&
|
| + debugPrintLine != null &&
|
| + firstColon > 0 &&
|
| + lastColon > 0) {
|
| + int lineNumber = int.parse(line.substring(firstColon + 1, lastColon));
|
| + int relativeLineNumber = lineNumber - debugPrintLine;
|
| + var columnNumber = line.substring(lastColon + 1);
|
| + var file = line.substring(0, firstColon);
|
| + if (file == debugPrintFile) {
|
| + output = '\$file:\${LINE+$relativeLineNumber}:$columnNumber';
|
| + }
|
| + }
|
| + String comma = i == recordStops.length - 1 ? "" : ",";
|
| + print('"$output"$comma');
|
| + }
|
| + }
|
| + if (removeDuplicates) {
|
| + recordStops = removeAdjacentDuplicates(recordStops);
|
| + expectedStops = removeAdjacentDuplicates(expectedStops);
|
| + }
|
| +
|
| int end = recordStops.length < expectedStops.length
|
| ? recordStops.length
|
| : expectedStops.length;
|
| @@ -439,3 +489,46 @@ IsolateTest checkRecordedStops(
|
| reason: "Expects at least ${expectedStops.length} breaks.");
|
| };
|
| }
|
| +
|
| +List<String> removeAdjacentDuplicates(List<String> fromList) {
|
| + List<String> result = <String>[];
|
| + String latestLine;
|
| + for (String s in fromList) {
|
| + if (s == latestLine) continue;
|
| + latestLine = s;
|
| + result.add(s);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +bool isKernel() {
|
| + for (String argument in Platform.executableArguments) {
|
| + if (argument.startsWith("--dfe=")) return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +E ifKernel<E>(E then, E otherwise) {
|
| + if (isKernel()) return then;
|
| + return otherwise;
|
| +}
|
| +
|
| +void ifKernelExecute(Function kernelFunction, Function nonKernelFunction) {
|
| + if (isKernel()) {
|
| + kernelFunction();
|
| + } else {
|
| + nonKernelFunction();
|
| + }
|
| +}
|
| +
|
| +void nonKernelExecute(Function nonKernelFunction) {
|
| + if (!isKernel()) {
|
| + nonKernelFunction();
|
| + }
|
| +}
|
| +
|
| +void kernelExecute(Function kernelFunction) {
|
| + if (isKernel()) {
|
| + kernelFunction();
|
| + }
|
| +}
|
|
|