Line data Source code
1 : // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 : // for details. All rights reserved. Use of this source code is governed by a
3 : // BSD-style license that can be found in the LICENSE file.
4 :
5 : import 'dart:async';
6 : import 'dart:isolate';
7 :
8 : import 'package:stack_trace/stack_trace.dart';
9 :
10 : import '../frontend/expect.dart';
11 :
12 : /// An exception that was thrown remotely.
13 : ///
14 : /// This could be an exception thrown in a different isolate, a different
15 : /// process, or on an entirely different computer.
16 : class RemoteException implements Exception {
17 : /// The original exception's message, if it had one.
18 : ///
19 : /// If the original exception was a plain string, this will contain that
20 : /// string.
21 : final String message;
22 :
23 : /// The value of the original exception's `runtimeType.toString()`.
24 : final String type;
25 :
26 : /// The value of the original exception's `toString()`.
27 : final String _toString;
28 :
29 : /// Serializes [error] and [stackTrace] into a JSON-safe object.
30 : ///
31 : /// Other than JSON- and isolate-safety, no guarantees are made about the
32 : /// serialized format.
33 : static serialize(error, StackTrace stackTrace) {
34 : var message;
35 0 : if (error is String) {
36 : message = error;
37 : } else {
38 : try {
39 0 : message = error.message.toString();
40 0 : } on NoSuchMethodError catch (_) {
41 : // Do nothing.
42 : }
43 : }
44 :
45 : // It's possible (although unlikely) for a user-defined class to have
46 : // multiple of these supertypes. That's fine, though, since we only care
47 : // about core-library-raised IsolateSpawnExceptions anyway.
48 : var supertype;
49 0 : if (error is TestFailure) {
50 : supertype = 'TestFailure';
51 0 : } else if (error is IsolateSpawnException) {
52 : supertype = 'IsolateSpawnException';
53 : }
54 :
55 0 : return {
56 : 'message': message,
57 0 : 'type': error.runtimeType.toString(),
58 : 'supertype': supertype,
59 0 : 'toString': error.toString(),
60 0 : 'stackChain': new Chain.forTrace(stackTrace).toString()
61 : };
62 : }
63 :
64 : /// Deserializes an exception serialized with [RemoteException.serialize].
65 : ///
66 : /// The returned [AsyncError] is guaranteed to have a [RemoteException] as its
67 : /// error and a [Chain] as its stack trace.
68 : static AsyncError deserialize(serialized) {
69 0 : return new AsyncError(_deserializeException(serialized),
70 0 : new Chain.parse(serialized['stackChain']));
71 : }
72 :
73 : /// Deserializes the exception portion of [serialized].
74 : static RemoteException _deserializeException(serialized) {
75 0 : var message = serialized['message'];
76 0 : var type = serialized['type'];
77 0 : var toString = serialized['toString'];
78 :
79 0 : switch (serialized['supertype']) {
80 0 : case 'TestFailure':
81 0 : return new _RemoteTestFailure(message, type, toString);
82 0 : case 'IsolateSpawnException':
83 0 : return new _RemoteIsolateSpawnException(message, type, toString);
84 : default:
85 0 : return new RemoteException._(message, type, toString);
86 : }
87 : }
88 :
89 0 : RemoteException._(this.message, this.type, this._toString);
90 :
91 0 : String toString() => _toString;
92 : }
93 :
94 : /// A subclass of [RemoteException] that implements [TestFailure].
95 : ///
96 : /// It's important to preserve [TestFailure]-ness, because tests have different
97 : /// results depending on whether an exception was a failure or an error.
98 : class _RemoteTestFailure extends RemoteException implements TestFailure {
99 : _RemoteTestFailure(String message, String type, String toString)
100 0 : : super._(message, type, toString);
101 : }
102 :
103 : /// A subclass of [RemoteException] that implements [IsolateSpawnException].
104 : class _RemoteIsolateSpawnException extends RemoteException
105 : implements IsolateSpawnException {
106 : _RemoteIsolateSpawnException(String message, String type, String toString)
107 0 : : super._(message, type, toString);
108 : }
|