@@ -148,18 +148,7 @@ func callExitTest(
148
148
let actualExitCondition : ExitCondition
149
149
do {
150
150
let exitTest = ExitTest ( expectedExitCondition: expectedExitCondition, body: body, sourceLocation: sourceLocation)
151
- guard let exitCondition = try await configuration. exitTestHandler ( exitTest) else {
152
- // This exit test was not run by the handler. Return successfully (and
153
- // move on to the next one.)
154
- return __checkValue (
155
- true ,
156
- expression: expression,
157
- comments: comments ( ) ,
158
- isRequired: isRequired,
159
- sourceLocation: sourceLocation
160
- )
161
- }
162
- actualExitCondition = exitCondition
151
+ actualExitCondition = try await configuration. exitTestHandler ( exitTest)
163
152
} catch {
164
153
// An error here would indicate a problem in the exit test handler such as a
165
154
// failure to find the process' path, to construct arguments to the
@@ -206,8 +195,7 @@ extension ExitTest {
206
195
/// - Parameters:
207
196
/// - exitTest: The exit test that is starting.
208
197
///
209
- /// - Returns: The condition under which the exit test exited, or `nil` if the
210
- /// exit test was not invoked.
198
+ /// - Returns: The condition under which the exit test exited.
211
199
///
212
200
/// - Throws: Any error that prevents the normal invocation or execution of
213
201
/// the exit test.
@@ -223,7 +211,7 @@ extension ExitTest {
223
211
/// are available or the child environment is otherwise terminated. The parent
224
212
/// environment is then responsible for interpreting those results and
225
213
/// recording any issues that occur.
226
- public typealias Handler = @Sendable ( _ exitTest: borrowing ExitTest ) async throws -> ExitCondition ?
214
+ public typealias Handler = @Sendable ( _ exitTest: borrowing ExitTest ) async throws -> ExitCondition
227
215
228
216
/// Find the exit test function specified by the given command-line arguments,
229
217
/// if any.
@@ -256,59 +244,65 @@ extension ExitTest {
256
244
/// For a description of the inputs and outputs of this function, see the
257
245
/// documentation for ``ExitTest/Handler``.
258
246
static func handlerForSwiftPM( forXCTestCaseIdentifiedBy xcTestCaseIdentifier: String ? = nil ) -> Handler {
259
- let parentEnvironment = ProcessInfo . processInfo. environment
260
-
261
- return { exitTest in
262
- let actualExitCode : Int32
263
- let wasSignalled : Bool
264
- do {
265
- let childProcessURL : URL = try URL ( fileURLWithPath: CommandLine . executablePath, isDirectory: false )
247
+ // The environment could change between invocations if a test calls setenv()
248
+ // or unsetenv(), so we need to recompute the child environment each time.
249
+ // The executable and XCTest bundle paths should not change over time, so we
250
+ // can precompute them.
251
+ let childProcessExecutablePath = Result { try CommandLine . executablePath }
266
252
267
- // We only need to pass arguments when hosted by XCTest.
268
- var childArguments = [ String] ( )
269
- if let xcTestCaseIdentifier {
270
- #if os(macOS)
271
- childArguments += [ " -XCTest " , xcTestCaseIdentifier]
253
+ // We only need to pass arguments when hosted by XCTest.
254
+ let childArguments : [ String ] = {
255
+ var result = [ String] ( )
256
+ if let xcTestCaseIdentifier {
257
+ #if SWT_TARGET_OS_APPLE
258
+ result += [ " -XCTest " , xcTestCaseIdentifier]
272
259
#else
273
- childArguments . append ( xcTestCaseIdentifier)
260
+ result . append ( xcTestCaseIdentifier)
274
261
#endif
275
- if let xctestTargetPath = parentEnvironment [ " XCTestBundlePath " ] {
276
- childArguments. append ( xctestTargetPath)
277
- } else if let xctestTargetPath = CommandLine . arguments ( ) . last {
278
- childArguments. append ( xctestTargetPath)
279
- }
262
+ if let xctestTargetPath = Environment . variable ( named: " XCTestBundlePath " ) {
263
+ result. append ( xctestTargetPath)
264
+ } else if let xctestTargetPath = CommandLine . arguments ( ) . last {
265
+ result. append ( xctestTargetPath)
280
266
}
267
+ }
268
+ return result
269
+ } ( )
281
270
282
- // Inherit the environment from the parent process and add our own
283
- // variable indicating which exit test will run, then make any necessary
284
- // platform-specific changes.
285
- var childEnvironment : [ String : String ] = parentEnvironment
286
- childEnvironment [ " SWT_EXPERIMENTAL_EXIT_TEST_SOURCE_LOCATION " ] = try String ( data: JSONEncoder ( ) . encode ( exitTest. sourceLocation) , encoding: . utf8) !
271
+ return { exitTest in
272
+ let childProcessURL = try URL ( fileURLWithPath: childProcessExecutablePath. get ( ) , isDirectory: false )
273
+
274
+ // Inherit the environment from the parent process and make any necessary
275
+ // platform-specific changes.
276
+ var childEnvironment = ProcessInfo . processInfo. environment
287
277
#if SWT_TARGET_OS_APPLE
288
- if childEnvironment [ " XCTestSessionIdentifier " ] != nil {
289
- // We need to remove Xcode's environment variables from the child
290
- // environment to avoid accidentally accidentally recursing.
291
- for key in childEnvironment. keys where key. starts ( with: " XCTest " ) {
292
- childEnvironment. removeValue ( forKey: key)
293
- }
294
- }
278
+ // We need to remove Xcode's environment variables from the child
279
+ // environment to avoid accidentally accidentally recursing.
280
+ for key in childEnvironment. keys where key. starts ( with: " XCTest " ) {
281
+ childEnvironment. removeValue ( forKey: key)
282
+ }
295
283
#elseif os(Linux)
296
- if childEnvironment [ " SWIFT_BACKTRACE " ] == nil {
297
- // Disable interactive backtraces unless explicitly enabled to reduce
298
- // the noise level during the exit test. Only needed on Linux.
299
- childEnvironment [ " SWIFT_BACKTRACE " ] = " enable=no "
300
- }
284
+ if childEnvironment [ " SWIFT_BACKTRACE " ] == nil {
285
+ // Disable interactive backtraces unless explicitly enabled to reduce
286
+ // the noise level during the exit test. Only needed on Linux.
287
+ childEnvironment [ " SWIFT_BACKTRACE " ] = " enable=no "
288
+ }
301
289
#endif
290
+ // Insert a specific variable that tells the child process which exit test
291
+ // to run.
292
+ childEnvironment [ " SWT_EXPERIMENTAL_EXIT_TEST_SOURCE_LOCATION " ] = try String ( data: JSONEncoder ( ) . encode ( exitTest. sourceLocation) , encoding: . utf8) !
302
293
294
+ let actualExitCode : Int32
295
+ let wasSignalled : Bool
296
+ do {
303
297
( actualExitCode, wasSignalled) = try await withCheckedThrowingContinuation { continuation in
298
+ let process = Process ( )
299
+ process. executableURL = childProcessURL
300
+ process. arguments = childArguments
301
+ process. environment = childEnvironment
302
+ process. terminationHandler = { process in
303
+ continuation. resume ( returning: ( process. terminationStatus, process. terminationReason == . uncaughtSignal) )
304
+ }
304
305
do {
305
- let process = Process ( )
306
- process. executableURL = childProcessURL
307
- process. arguments = childArguments
308
- process. environment = childEnvironment
309
- process. terminationHandler = { process in
310
- continuation. resume ( returning: ( process. terminationStatus, process. terminationReason == . uncaughtSignal) )
311
- }
312
306
try process. run ( )
313
307
} catch {
314
308
continuation. resume ( throwing: error)
0 commit comments