Skip to content

Commit adcdc6d

Browse files
committed
Incorporate editioral feedback
1 parent 7da5cd4 commit adcdc6d

File tree

4 files changed

+71
-75
lines changed

4 files changed

+71
-75
lines changed

Sources/Testing/ExitTests/ExitTest.Condition.swift

+11-9
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ extension ExitTest {
5757
@available(*, unavailable, message: "Exit tests are not available on this platform.")
5858
#endif
5959
extension ExitTest.Condition {
60-
/// A condition that matches when a process terminates successfully with exit
61-
/// code `EXIT_SUCCESS`.
60+
/// A condition that matches when a process exits normally.
61+
///
62+
/// This condition matches the exit code `EXIT_SUCCESS`.
6263
///
6364
/// @Metadata {
6465
/// @Available(Swift, introduced: 6.2)
@@ -75,8 +76,10 @@ extension ExitTest.Condition {
7576
#endif
7677
}
7778

78-
/// A condition that matches when a process terminates abnormally with any
79-
/// exit code other than `EXIT_SUCCESS` or with any signal.
79+
/// A condition that matches when a process exits abnormally
80+
///
81+
/// This condition matches any exit code other than `EXIT_SUCCESS` or any
82+
/// signal that causes the process to exit.
8083
///
8184
/// @Metadata {
8285
/// @Available(Swift, introduced: 6.2)
@@ -96,7 +99,7 @@ extension ExitTest.Condition {
9699
/// exit code.
97100
///
98101
/// - Parameters:
99-
/// - exitCode: The exit code yielded by the process.
102+
/// - exitCode: The exit code reported by the process.
100103
///
101104
/// The C programming language defines two standard exit codes, `EXIT_SUCCESS`
102105
/// and `EXIT_FAILURE`. Platforms may additionally define their own
@@ -116,7 +119,7 @@ extension ExitTest.Condition {
116119
/// }
117120
///
118121
/// On macOS, FreeBSD, OpenBSD, and Windows, the full exit code reported by
119-
/// the process is yielded to the parent process. Linux and other POSIX-like
122+
/// the process is reported to the parent process. Linux and other POSIX-like
120123
/// systems may only reliably report the low unsigned 8 bits (0–255) of
121124
/// the exit code.
122125
///
@@ -131,11 +134,10 @@ extension ExitTest.Condition {
131134
#endif
132135
}
133136

134-
/// Creates a condition that matches when a process terminates with a given
135-
/// signal.
137+
/// Creates a condition that matches when a process exits with a given signal.
136138
///
137139
/// - Parameters:
138-
/// - signal: The signal that terminated the process.
140+
/// - signal: The signal that caused the process to exit.
139141
///
140142
/// The C programming language defines a number of standard signals. Platforms
141143
/// may additionally define their own non-standard signal codes:

Sources/Testing/ExitTests/ExitTest.Result.swift

+1-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ extension ExitTest {
2323
/// @Available(Swift, introduced: 6.2)
2424
/// }
2525
public struct Result: Sendable {
26-
/// The status of the process hosting the exit test at the time it exits.
27-
///
28-
/// When the exit test passes, the value of this property is equal to the
29-
/// exit status reported by the process that hosted the exit test.
26+
/// The exit status reported by the process hosting the exit test.
3027
///
3128
/// @Metadata {
3229
/// @Available(Swift, introduced: 6.2)

Sources/Testing/ExitTests/StatusAtExit.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
private import _TestingInternals
1212

13-
/// An enumeration describing possible status a process will yield on exit.
13+
/// An enumeration describing possible status a process will report on exit.
1414
///
1515
/// You can convert an instance of this type to an instance of
1616
/// ``ExitTest/Condition`` using ``ExitTest/Condition/init(_:)``. That value
@@ -26,10 +26,10 @@ private import _TestingInternals
2626
@available(*, unavailable, message: "Exit tests are not available on this platform.")
2727
#endif
2828
public enum StatusAtExit: Sendable {
29-
/// The process terminated with the given exit code.
29+
/// The process exited with the given exit code.
3030
///
3131
/// - Parameters:
32-
/// - exitCode: The exit code yielded by the process.
32+
/// - exitCode: The exit code reported by the process.
3333
///
3434
/// The C programming language defines two standard exit codes, `EXIT_SUCCESS`
3535
/// and `EXIT_FAILURE`. Platforms may additionally define their own
@@ -49,7 +49,7 @@ public enum StatusAtExit: Sendable {
4949
/// }
5050
///
5151
/// On macOS, FreeBSD, OpenBSD, and Windows, the full exit code reported by
52-
/// the process is yielded to the parent process. Linux and other POSIX-like
52+
/// the process is reported to the parent process. Linux and other POSIX-like
5353
/// systems may only reliably report the low unsigned 8 bits (0–255) of
5454
/// the exit code.
5555
///
@@ -58,10 +58,10 @@ public enum StatusAtExit: Sendable {
5858
/// }
5959
case exitCode(_ exitCode: CInt)
6060

61-
/// The process terminated with the given signal.
61+
/// The process exited with the given signal.
6262
///
6363
/// - Parameters:
64-
/// - signal: The signal that terminated the process.
64+
/// - signal: The signal that caused the process to exit.
6565
///
6666
/// The C programming language defines a number of standard signals. Platforms
6767
/// may additionally define their own non-standard signal codes:

Sources/Testing/Testing.docc/exit-testing.md

+53-56
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ See https://swift.org/CONTRIBUTORS.txt for Swift project authors
1414
@Available(Swift, introduced: 6.2)
1515
}
1616

17-
Use exit tests to test functionality that may cause a test process to exit.
17+
Use exit tests to test functionality that might cause a test process to exit.
1818

1919
## Overview
2020

21-
Your code may contain calls to [`precondition()`](https://developer.apple.com/documentation/swift/precondition(_:_:file:line:)),
21+
Your code might contain calls to [`precondition()`](https://developer.apple.com/documentation/swift/precondition(_:_:file:line:)),
2222
[`fatalError()`](https://developer.apple.com/documentation/swift/fatalerror(_:file:line:)),
23-
or other functions that may cause the current process to exit. For example:
23+
or other functions that can cause the current process to exit. For example:
2424

2525
```swift
2626
extension Customer {
@@ -33,9 +33,9 @@ extension Customer {
3333
```
3434

3535
In this function, if `food.isDelicious` or `food.isNutritious` is `false`, the
36-
precondition will fail and Swift will force the process to exit. You can write
37-
an exit test to validate preconditions like the ones above and to make sure that
38-
your functions correctly catch invalid inputs.
36+
precondition fails and Swift forces the process to exit. You can write an exit
37+
test to validate preconditions like the ones above and to make sure that your
38+
functions correctly catch invalid inputs.
3939

4040
- Note: Exit tests are available on macOS, Linux, FreeBSD, OpenBSD, and Windows.
4141

@@ -54,46 +54,65 @@ or the ``require(exitsWith:observing:_:sourceLocation:performing:)`` macro:
5454
}
5555
```
5656

57-
The closure or function reference you pass to these macros is the body of the
58-
exit test. When an exit test is performed at runtime, the testing library starts
59-
a new process with the same executable as the current process. The current task
60-
is then suspended (as with `await`) and waits for the child process to
61-
exit. The exit test's body is not called in the parent process.
62-
63-
Meanwhile, in the child process, the body is called directly. To ensure a clean
64-
environment for execution, the body is not called within the context of the
65-
original test. Instead, it is treated as if it were the `main()` function of the
66-
child process.
57+
The closure or function reference you pass to the macro is the body of the exit
58+
test. When an exit test is performed at runtime, the testing library starts a
59+
new process with the same executable as the current process. The current task is
60+
then suspended (as with `await`) and waits for the child process to exit.
61+
62+
The parent process never calls the body of the exit test. Instead, the child
63+
process treats the body of the exit test as its `main()` function and calls it
64+
directly.
65+
66+
- Note: Because the body acts as the `main()` function of a new process, it
67+
can't capture any state originating in the parent process or from its lexical
68+
context. For example, the following exit test will fail to compile because it
69+
captures a variable declared outside the exit test itself:
70+
71+
```swift
72+
@Test func `Customer won't eat food unless it's nutritious`() async {
73+
let isNutritious = false
74+
await #expect(exitsWith: .failure) {
75+
var food = ...
76+
food.isNutritious = isNutritious // ❌ ERROR: trying to capture state here
77+
Customer.current.eat(food)
78+
}
79+
}
80+
```
6781

68-
If the body returns before the child process exits, it is allowed to return and
69-
the process exits naturally. If an error is thrown from the body, it is handled
70-
as if the error were thrown from `main()` and the process is forced to exit.
82+
If the body returns before the child process exits, the process exits as if
83+
`main()` returned normally. If the body throws an error, Swift handles it as if
84+
it were thrown from `main()` and forces the process to exit abnormally.
7185

7286
### Specify an exit condition
7387

74-
When you create an exit test, you must specify how you expect the child process
75-
will exit by passing an instance of ``ExitTest/Condition``:
88+
When you create an exit test, specify how you expect the child process exits by
89+
passing an instance of ``ExitTest/Condition``:
7690

77-
- If the exit test's body should run to completion or exit normally (for
78-
example, by calling `exit(EXIT_SUCCESS)` from the C standard library), pass
79-
``ExitTest/Condition/success``.
80-
- If the body will cause the child process to exit with some failure, but the
91+
- If you expect the exit test's body to run to completion or exit normally (for
92+
example, by calling [`exit(EXIT_SUCCESS)`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/exit.3.html)
93+
from the C standard library), pass ``ExitTest/Condition/success``.
94+
- If you expect the body to cause the child process to exit abnormally, but the
8195
exact status reported by the system is not important, pass
8296
``ExitTest/Condition/failure``.
8397
- If you need to check for a specific exit code or signal, pass
8498
``ExitTest/Condition/exitCode(_:)`` or ``ExitTest/Condition/signal(_:)``.
8599

86100
When the child process exits, the parent process resumes and compares the exit
87101
status of the child process against the expected exit condition you passed. If
88-
they match, the exit test has passed; otherwise, it has failed and the testing
89-
library records an issue.
102+
they match, the exit test passes; otherwise, it fails and the testing library
103+
records an issue.
90104

91105
### Gather output from the child process
92106

107+
The ``expect(exitsWith:observing:_:sourceLocation:performing:)`` and
108+
``require(exitsWith:observing:_:sourceLocation:performing:)`` macros return an
109+
instance of ``ExitTest/Result`` that contains information about the state of the
110+
child process.
111+
93112
By default, the child process is configured without a standard output or
94113
standard error stream. If your test needs to review the content of either of
95-
these streams, you can pass its key path to ``expect(exitsWith:observing:_:sourceLocation:performing:)``
96-
or ``require(exitsWith:observing:_:sourceLocation:performing:)``:
114+
these streams, pass the key path to the corresponding ``ExitTest/Result``
115+
property to the macro:
97116

98117
```swift
99118
extension Customer {
@@ -120,36 +139,14 @@ extension Customer {
120139
}
121140
```
122141

123-
- Note: The content of the standard output and standard error streams may
124-
contain any arbitrary sequence of bytes, including sequences that are not
125-
valid UTF-8 and cannot be decoded by [`String.init(cString:)`](https://developer.apple.com/documentation/swift/string/init(cstring:)-6kr8s).
142+
- Note: The content of the standard output and standard error streams can
143+
contain any arbitrary sequence of bytes, including sequences that aren't valid
144+
UTF-8 and can't be decoded by [`String.init(cString:)`](https://developer.apple.com/documentation/swift/string/init(cstring:)-6kr8s).
126145
These streams are globally accessible within the child process, and any code
127146
running in an exit test may write to it including the operating system and any
128-
third-party dependencies you have declared in your package.
147+
third-party dependencies you declare in your package description or Xcode
148+
project.
129149

130150
The testing library always sets ``ExitTest/Result/statusAtExit`` to the actual
131151
exit status of the child process (as reported by the system) even if you do not
132152
pass it.
133-
134-
### Constraints on exit tests
135-
136-
#### State cannot be captured
137-
138-
Exit tests cannot capture any state originating in the parent process or from
139-
the enclosing lexical context. For example, the following exit test will fail to
140-
compile because it captures a variable declared outside the exit test itself:
141-
142-
```swift
143-
@Test func `Customer won't eat food unless it's nutritious`() async {
144-
let isNutritious = false
145-
await #expect(exitsWith: .failure) {
146-
var food = ...
147-
food.isNutritious = isNutritious // ❌ ERROR: trying to capture state here
148-
Customer.current.eat(food)
149-
}
150-
}
151-
```
152-
153-
#### Exit tests cannot be nested
154-
155-
An exit test cannot run within another exit test.

0 commit comments

Comments
 (0)