Skip to content

Commit 8e5195c

Browse files
bkonyiCommit Queue
authored andcommitted
[ dart:io ] Added override for exit(...) in IOOverrides
This will allow for `package:test` to handle test cases which call `exit(...)` without the test suite being aborted due to the VM shutting down. See dart-lang/test#2248 Change-Id: I09e78460d2b87ba7ea755d7538a1446ecb566d0b CoreLibraryReviewExempt: Only adds override behavior, does not change API surface. Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/377380 Commit-Queue: Ben Konyi <[email protected]> Reviewed-by: Brian Quinlan <[email protected]>
1 parent d1ee514 commit 8e5195c

File tree

4 files changed

+52
-10
lines changed

4 files changed

+52
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
- **Breaking Change** [#56468][]: Marked `IOOverrides` as an `abstract base`
2828
class.
29+
- Added ability to override behavior of `exit(...)` to `IOOverrides`.
2930

3031
[#56468]: https://github.com/dart-lang/sdk/issues/56468
3132

sdk/lib/io/overrides.dart

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ abstract base class IOOverrides {
108108
Stdin Function()? stdin,
109109
Stdout Function()? stdout,
110110
Stdout Function()? stderr,
111+
112+
// Process exit
113+
@Since("3.10") Never Function(int)? exit,
111114
}) {
112115
// Avoid building chains of override scopes. Just copy outer scope's
113116
// functions and `_previous`.
@@ -156,6 +159,9 @@ abstract base class IOOverrides {
156159
stdin ?? currentScope?._stdin,
157160
stdout ?? currentScope?._stdout,
158161
stderr ?? currentScope?._stderr,
162+
163+
// Process exit
164+
exit ?? currentScope?._exit,
159165
);
160166
return dart_async.runZoned<R>(
161167
body,
@@ -292,7 +298,7 @@ abstract base class IOOverrides {
292298

293299
/// Asynchronously returns a [Socket] connected to the given host and port.
294300
///
295-
/// When this override is installed, this functions overrides the behavior of
301+
/// When this override is installed, this function overrides the behavior of
296302
/// `Socket.connect(...)`.
297303
Future<Socket> socketConnect(
298304
host,
@@ -313,7 +319,7 @@ abstract base class IOOverrides {
313319
/// Asynchronously returns a [ConnectionTask] that connects to the given host
314320
/// and port when successful.
315321
///
316-
/// When this override is installed, this functions overrides the behavior of
322+
/// When this override is installed, this function overrides the behavior of
317323
/// `Socket.startConnect(...)`.
318324
Future<ConnectionTask<Socket>> socketStartConnect(
319325
host,
@@ -334,7 +340,7 @@ abstract base class IOOverrides {
334340
/// Asynchronously returns a [ServerSocket] that connects to the given address
335341
/// and port when successful.
336342
///
337-
/// When this override is installed, this functions overrides the behavior of
343+
/// When this override is installed, this function overrides the behavior of
338344
/// `ServerSocket.bind(...)`.
339345
Future<ServerSocket> serverSocketBind(
340346
address,
@@ -352,6 +358,22 @@ abstract base class IOOverrides {
352358
);
353359
}
354360

361+
// Process exit
362+
363+
/// Exit the Dart VM process immediately with the given exit code.
364+
///
365+
/// When this override is installed, this function overrides the behavior of
366+
/// `exit(...)`.
367+
@Since("3.10")
368+
Never exit(int code) {
369+
if (!_EmbedderConfig._mayExit) {
370+
throw new UnsupportedError(
371+
"This embedder disallows calling dart:io's exit()",
372+
);
373+
}
374+
_ProcessUtils._exit(code);
375+
}
376+
355377
// Standard streams
356378

357379
/// The standard input stream of data read by this program.
@@ -440,6 +462,9 @@ final class _IOOverridesScope extends IOOverrides {
440462
final Stdout Function()? _stdout;
441463
final Stdout Function()? _stderr;
442464

465+
// Process exit
466+
final Never Function(int)? _exit;
467+
443468
_IOOverridesScope(
444469
this._previous,
445470

@@ -480,6 +505,9 @@ final class _IOOverridesScope extends IOOverrides {
480505
this._stdin,
481506
this._stdout,
482507
this._stderr,
508+
509+
// Process exit
510+
this._exit,
483511
);
484512

485513
// Directory
@@ -662,6 +690,11 @@ final class _IOOverridesScope extends IOOverrides {
662690
shared: shared,
663691
);
664692

693+
// Process exit
694+
@override
695+
Never exit(int code) =>
696+
_exit?.call(code) ?? _previous?.exit.call(code) ?? super.exit(code);
697+
665698
// Standard streams
666699
@override
667700
Stdin get stdin => _stdin?.call() ?? _previous?.stdin ?? super.stdin;

sdk/lib/io/process.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,16 @@ class _ProcessUtils {
5151
/// program to the surrounding environment. This will avoid any
5252
/// cross-platform issues.
5353
Never exit(int code) {
54-
ArgumentError.checkNotNull(code, "code");
55-
if (!_EmbedderConfig._mayExit) {
56-
throw new UnsupportedError(
57-
"This embedder disallows calling dart:io's exit()",
58-
);
54+
IOOverrides? overrides = IOOverrides.current;
55+
if (overrides == null) {
56+
if (!_EmbedderConfig._mayExit) {
57+
throw new UnsupportedError(
58+
"This embedder disallows calling dart:io's exit()",
59+
);
60+
}
61+
_ProcessUtils._exit(code);
5962
}
60-
_ProcessUtils._exit(code);
63+
overrides.exit(code);
6164
}
6265

6366
/// Set the global exit code for the Dart VM.
@@ -71,7 +74,6 @@ Never exit(int code) {
7174
/// See [exit] for more information on how to chose a value for the
7275
/// exit code.
7376
void set exitCode(int code) {
74-
ArgumentError.checkNotNull(code, "code");
7577
_ProcessUtils._setExitCode(code);
7678
}
7779

tests/standalone/io/io_override_test.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ Future<ServerSocket> serverSocketBind(
208208
throw "";
209209
}
210210

211+
Never exitOverride(int code) {
212+
throw code;
213+
}
214+
211215
class StdinMock extends Stream<List<int>> implements Stdin {
212216
bool echoMode = false;
213217
bool echoNewlineMode = false;
@@ -278,6 +282,7 @@ Future<Null> ioOverridesRunTest() async {
278282
Expect.isTrue(stdin is StdinMock);
279283
Expect.identical(stdout, stdoutMock);
280284
Expect.identical(stderr, stderrMock);
285+
Expect.throws<int>(() => exit(42), (int code) => code == 42);
281286
},
282287
createDirectory: DirectoryMock.createDirectory,
283288
getCurrentDirectory: DirectoryMock.getCurrent,
@@ -299,6 +304,7 @@ Future<Null> ioOverridesRunTest() async {
299304
stdin: () => StdinMock(),
300305
stdout: () => stdoutMock,
301306
stderr: () => stderrMock,
307+
exit: exitOverride,
302308
);
303309
Expect.isFalse(new Directory("directory") is DirectoryMock);
304310
Expect.isTrue(new Directory("directory") is Directory);

0 commit comments

Comments
 (0)