OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 /// Helper functions for running code in a Zone. | 5 /// Helper functions for running code in a Zone. |
6 library testing.zone_helper; | 6 library testing.zone_helper; |
7 | 7 |
8 import 'dart:async' show | 8 import 'dart:async' show |
9 Completer, | 9 Completer, |
10 Future, | 10 Future, |
11 ZoneSpecification, | 11 ZoneSpecification, |
12 runZoned; | 12 runZoned; |
13 | 13 |
| 14 import 'dart:io' show |
| 15 exit, |
| 16 stderr; |
| 17 |
14 import 'dart:isolate' show | 18 import 'dart:isolate' show |
15 Capability, | 19 Capability, |
16 Isolate, | 20 Isolate, |
17 ReceivePort; | 21 ReceivePort; |
18 | 22 |
19 import 'log.dart' show | 23 import 'log.dart' show |
20 logUncaughtError; | 24 logUncaughtError; |
21 | 25 |
22 Future runGuarded( | 26 Future runGuarded( |
23 Future f(), | 27 Future f(), |
24 {void printLineOnStdout(line), | 28 {void printLineOnStdout(line), |
25 void handleLateError(error, StackTrace stackTrace)}) { | 29 void handleLateError(error, StackTrace stackTrace)}) { |
26 | 30 |
27 var printWrapper; | 31 var printWrapper; |
28 if (printLineOnStdout != null) { | 32 if (printLineOnStdout != null) { |
29 printWrapper = (_1, _2, _3, String line) { | 33 printWrapper = (_1, _2, _3, String line) { |
30 printLineOnStdout(line); | 34 printLineOnStdout(line); |
31 }; | 35 }; |
32 } | 36 } |
33 | 37 |
34 Completer completer = new Completer(); | 38 Completer completer = new Completer(); |
35 | 39 |
36 handleUncaughtError(error, StackTrace stackTrace) { | 40 handleUncaughtError(error, StackTrace stackTrace) { |
37 logUncaughtError(error, stackTrace); | 41 logUncaughtError(error, stackTrace); |
38 if (!completer.isCompleted) { | 42 if (!completer.isCompleted) { |
39 completer.completeError(error, stackTrace); | 43 completer.completeError(error, stackTrace); |
40 } else if (handleLateError != null) { | 44 } else if (handleLateError != null) { |
41 handleLateError(error, stackTrace); | 45 handleLateError(error, stackTrace); |
42 } else { | 46 } else { |
43 // Delegate to parent. | 47 String errorString = "error.toString() failed."; |
44 throw error; | 48 try { |
| 49 errorString = "$error"; |
| 50 } catch (_) { |
| 51 // Ignored. |
| 52 } |
| 53 stderr.write("$errorString\n" + |
| 54 (stackTrace == null ? "" : "$stackTrace")); |
| 55 stderr.flush(); |
| 56 exit(255); |
45 } | 57 } |
46 } | 58 } |
47 | 59 |
48 ZoneSpecification specification = new ZoneSpecification(print: printWrapper); | 60 ZoneSpecification specification = new ZoneSpecification(print: printWrapper); |
49 | 61 |
50 ReceivePort errorPort = new ReceivePort(); | 62 ReceivePort errorPort = new ReceivePort(); |
51 Future errorFuture = errorPort.listen((List errors) { | 63 Future errorFuture = errorPort.listen((List errors) { |
52 Isolate.current.removeErrorListener(errorPort.sendPort); | 64 Isolate.current.removeErrorListener(errorPort.sendPort); |
53 errorPort.close(); | 65 errorPort.close(); |
54 var error = errors[0]; | 66 var error = errors[0]; |
55 var stackTrace = errors[1]; | 67 var stackTrace = errors[1]; |
56 if (stackTrace != null) { | 68 if (stackTrace != null) { |
57 stackTrace = new StackTrace.fromString(stackTrace); | 69 stackTrace = new StackTrace.fromString(stackTrace); |
58 } | 70 } |
59 handleUncaughtError(error, stackTrace); | 71 handleUncaughtError(error, stackTrace); |
60 }).asFuture(); | 72 }).asFuture(); |
61 | 73 |
| 74 Isolate.current.setErrorsFatal(false); |
62 Isolate.current.addErrorListener(errorPort.sendPort); | 75 Isolate.current.addErrorListener(errorPort.sendPort); |
63 return acknowledgeControlMessages(Isolate.current).then((_) { | 76 return acknowledgeControlMessages(Isolate.current).then((_) { |
64 runZoned( | 77 runZoned( |
65 () => new Future(f).then(completer.complete), | 78 () => new Future(f).then(completer.complete), |
66 zoneSpecification: specification, | 79 zoneSpecification: specification, |
67 onError: handleUncaughtError); | 80 onError: handleUncaughtError); |
68 | 81 |
69 return completer.future.whenComplete(() { | 82 return completer.future.whenComplete(() { |
70 errorPort.close(); | 83 errorPort.close(); |
71 Isolate.current.removeErrorListener(errorPort.sendPort); | 84 Isolate.current.removeErrorListener(errorPort.sendPort); |
72 return acknowledgeControlMessages(Isolate.current) | 85 return acknowledgeControlMessages(Isolate.current) |
73 .then((_) => errorFuture); | 86 .then((_) => errorFuture); |
74 }); | 87 }); |
75 }); | 88 }); |
76 } | 89 } |
77 | 90 |
78 /// Ping [isolate] to ensure control messages have been delivered. Control | 91 /// Ping [isolate] to ensure control messages have been delivered. Control |
79 /// messages are things like [Isolate.addErrorListener] and | 92 /// messages are things like [Isolate.addErrorListener] and |
80 /// [Isolate.addOnExitListener]. | 93 /// [Isolate.addOnExitListener]. |
81 Future acknowledgeControlMessages(Isolate isolate, {Capability resume}) { | 94 Future acknowledgeControlMessages(Isolate isolate, {Capability resume}) { |
82 ReceivePort ping = new ReceivePort(); | 95 ReceivePort ping = new ReceivePort(); |
83 Isolate.current.ping(ping.sendPort); | 96 Isolate.current.ping(ping.sendPort); |
84 if (resume == null) { | 97 if (resume == null) { |
85 return ping.first; | 98 return ping.first; |
86 } else { | 99 } else { |
87 return ping.first.then((_) => isolate.resume(resume)); | 100 return ping.first.then((_) => isolate.resume(resume)); |
88 } | 101 } |
89 } | 102 } |
OLD | NEW |