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 : 7 : import 'package:stack_trace/stack_trace.dart'; 8 : 9 : import 'test_failure.dart'; 10 : 11 : /// An exception that was thrown remotely. 12 : /// 13 : /// This could be an exception thrown in a different isolate, a different 14 : /// process, or on an entirely different computer. 15 : class RemoteException implements Exception { 16 : /// The original exception's message, if it had one. 17 : /// 18 : /// If the original exception was a plain string, this will contain that 19 : /// string. 20 : final String? message; 21 : 22 : /// The value of the original exception's `runtimeType.toString()`. 23 : final String type; 24 : 25 : /// The value of the original exception's `toString()`. 26 : final String _toString; 27 : 28 : /// Serializes [error] and [stackTrace] into a JSON-safe object. 29 : /// 30 : /// Other than JSON- and isolate-safety, no guarantees are made about the 31 : /// serialized format. 32 0 : static Map<String, dynamic> serialize(error, StackTrace stackTrace) { 33 : String? message; 34 0 : if (error is String) { 35 : message = error; 36 : } else { 37 : try { 38 0 : message = error.message.toString(); 39 0 : } on NoSuchMethodError catch (_) { 40 : // Do nothing. 41 : } 42 : } 43 : 44 0 : final supertype = (error is TestFailure) ? 'TestFailure' : null; 45 : 46 0 : return { 47 : 'message': message, 48 0 : 'type': error.runtimeType.toString(), 49 : 'supertype': supertype, 50 0 : 'toString': error.toString(), 51 0 : 'stackChain': Chain.forTrace(stackTrace).toString() 52 : }; 53 : } 54 : 55 : /// Deserializes an exception serialized with [RemoteException.serialize]. 56 : /// 57 : /// The returned [AsyncError] is guaranteed to have a [RemoteException] as its 58 : /// error and a [Chain] as its stack trace. 59 0 : static AsyncError deserialize(serialized) { 60 0 : return AsyncError(_deserializeException(serialized), 61 0 : Chain.parse(serialized['stackChain'] as String)); 62 : } 63 : 64 : /// Deserializes the exception portion of [serialized]. 65 0 : static RemoteException _deserializeException(serialized) { 66 0 : final message = serialized['message'] as String?; 67 0 : final type = serialized['type'] as String; 68 0 : final toString = serialized['toString'] as String; 69 : 70 0 : switch (serialized['supertype'] as String?) { 71 0 : case 'TestFailure': 72 0 : return _RemoteTestFailure(message, type, toString); 73 : default: 74 0 : return RemoteException._(message, type, toString); 75 : } 76 : } 77 : 78 0 : RemoteException._(this.message, this.type, this._toString); 79 : 80 0 : @override 81 0 : String toString() => _toString; 82 : } 83 : 84 : /// A subclass of [RemoteException] that implements [TestFailure]. 85 : /// 86 : /// It's important to preserve [TestFailure]-ness, because tests have different 87 : /// results depending on whether an exception was a failure or an error. 88 : class _RemoteTestFailure extends RemoteException implements TestFailure { 89 0 : _RemoteTestFailure(String? message, String type, String toString) 90 0 : : super._(message, type, toString); 91 : }