Skip to content
This repository has been archived by the owner on Aug 1, 2019. It is now read-only.

Commit

Permalink
Add support for setExceptionPauseMode (#38)
Browse files Browse the repository at this point in the history
Add support for setExceptionMode.
  • Loading branch information
DanTup authored and jacob314 committed Jul 23, 2018
1 parent 3f33780 commit 93254ff
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* Add `VMStep.OverAsyncSuspension` to allow continuing until execution returns from
an await, yield, or yield* statement (only valid when
`VMPauseEvent.atAsyncSuspension` is `true`).
* Add `VMIsolate.setExceptionPauseMode` and `VMIsolate.exceptionPauseMode` to
return/set pause behaviour for exceptions.

## 0.2.5+1

Expand Down
30 changes: 29 additions & 1 deletion lib/src/isolate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ class VMIsolateRef {
"resume", step == VMStep.resume ? {} : {"step": step._value});
}

/// Sets the pause behaviour for exceptions.
Future setExceptionPauseMode(VMExceptionPauseMode mode) =>
_scope.sendRequest("setExceptionPauseMode", {"mode": mode._value});

/// Sets the [name] of the isolate.
///
/// Note that since this object is immutable, it needs to be reloaded to see
Expand Down Expand Up @@ -399,6 +403,9 @@ class VMIsolateRef {

/// A full isolate on the remote VM.
class VMIsolate extends VMIsolateRef {
/// The current pause on exception mode for this isolate.
final VMExceptionPauseMode exceptionPauseMode;

/// The time that the isolate started running.
final DateTime startTime;

Expand Down Expand Up @@ -433,7 +440,9 @@ class VMIsolate extends VMIsolateRef {
final List<String> extensionRpcs;

VMIsolate._(Scope scope, Map json)
: startTime = new DateTime.fromMillisecondsSinceEpoch(
: exceptionPauseMode =
new VMExceptionPauseMode._(json["exceptionPauseMode"]),
startTime = new DateTime.fromMillisecondsSinceEpoch(
// Prior to v3.0, this was emitted as a double rather than an int.
json["startTime"].round()),
livePorts = json["livePorts"],
Expand Down Expand Up @@ -510,6 +519,25 @@ class VMStep {
String toString() => _value;
}

/// An enum of exception pause behaviour for use in [VMIsolateRef.setExceptionPauseMode].
class VMExceptionPauseMode {
/// The isolate will not pause on any exceptions.
static const none = const VMExceptionPauseMode._("None");

/// The isolate will pause on any unhandled exceptions.
static const unhandled = const VMExceptionPauseMode._("Unhandled");

/// The isolate will pause on all exceptions.
static const all = const VMExceptionPauseMode._("All");

/// The string name of the exception pause mode.
final String _value;

const VMExceptionPauseMode._(this._value);

String toString() => _value;
}

/// An event posted via `postEvent` from the `dart:developer` package.
class VMExtensionEvent {
/// The kind, which identifies the type of event and its source.
Expand Down
125 changes: 125 additions & 0 deletions test/exception_handling_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (c) 2018, 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:test/test.dart';
import 'package:vm_service_client/vm_service_client.dart';

import 'utils.dart';

VMServiceClient client;

void main() {
tearDown(() {
if (client != null) client.close();
});

test("does not pause on exceptions by default", () async {
client = await runAndConnect(main: r"""
throw 'err';
print('Done!');
""", flags: ["--pause-isolates-on-start"]);
final isolate = (await client.getVM()).isolates.first;

// Pauses-on-start.
await isolate.waitUntilPaused();

await isolate.resume();
await isolate.waitUntilPaused();
expect((await isolate.load()).pauseEvent,
new isInstanceOf<VMPauseExitEvent>());
});

test("unhandled pauses only on unhandled exceptions", () async {
client = await runAndConnect(main: r"""
try {
throw 'err2'; // line 8
} catch (e) {
}
throw 'err'; // line 12
print('Done!');
""", flags: ["--pause-isolates-on-start"]);

var isolate = (await client.getVM()).isolates.first;

// Pauses-on-start.
await isolate.waitUntilPaused();
await isolate.setExceptionPauseMode(VMExceptionPauseMode.unhandled);

// Except pause on the second throw.
await isolate.resume();
await isolate.waitUntilPaused();
final frame = (await isolate.getStack()).frames.first;
expect(await sourceLine(frame.location), equals(12));

// Resume and expect termination.
await isolate.resume();
await isolate.waitUntilPaused();
expect((await isolate.load()).pauseEvent,
new isInstanceOf<VMPauseExitEvent>());
});

test("all pauses only on all exceptions", () async {
client = await runAndConnect(main: r"""
try {
throw 'err2'; // line 8
} catch (e) {
}
throw 'err'; // line 12
print('Done!');
""", flags: ["--pause-isolates-on-start"]);

var isolate = (await client.getVM()).isolates.first;

// Pauses-on-start.
await isolate.waitUntilPaused();
await isolate.setExceptionPauseMode(VMExceptionPauseMode.all);

// Except pause on the first throw.
await isolate.resume();
await isolate.waitUntilPaused();
var frame = (await isolate.getStack()).frames.first;
expect(await sourceLine(frame.location), equals(8));

// Except pause on the second throw.
await isolate.resume();
await isolate.waitUntilPaused();
frame = (await isolate.getStack()).frames.first;
expect(await sourceLine(frame.location), equals(12));

// Resume and expect termination.
await isolate.resume();
await isolate.waitUntilPaused();
expect((await isolate.load()).pauseEvent,
new isInstanceOf<VMPauseExitEvent>());
});

test("exception mode can be read and set", () async {
client = await runAndConnect(flags: ["--pause-isolates-on-start"]);

var isolate = (await client.getVM()).isolates.first;

// Pauses-on-start.
await isolate.waitUntilPaused();

expect((await isolate.load()).exceptionPauseMode.toString(),
equals(VMExceptionPauseMode.none.toString()));

await isolate.setExceptionPauseMode(VMExceptionPauseMode.unhandled);
expect((await isolate.load()).exceptionPauseMode.toString(),
equals(VMExceptionPauseMode.unhandled.toString()));

await isolate.setExceptionPauseMode(VMExceptionPauseMode.all);
expect((await isolate.load()).exceptionPauseMode.toString(),
equals(VMExceptionPauseMode.all.toString()));

await isolate.setExceptionPauseMode(VMExceptionPauseMode.none);
expect((await isolate.load()).exceptionPauseMode.toString(),
equals(VMExceptionPauseMode.none.toString()));
});
}

0 comments on commit 93254ff

Please sign in to comment.