diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index 9b2c1a77c..374bd9e3c 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -233,6 +233,10 @@ extension ExitTest { #endif } + /// The name of the environment variable used to identify the exit test to + /// call in a spawned exit test process. + private static let _idEnvironmentVariableName = "SWT_EXIT_TEST_ID" + /// Call the exit test in the current process. /// /// This function invokes the closure originally passed to @@ -713,6 +717,17 @@ extension ExitTest { #endif } + /// The ID of the exit test to run, if any, specified in the environment. + static var environmentIDForEntryPoint: ID? { + guard var idString = Environment.variable(named: Self._idEnvironmentVariableName) else { + return nil + } + + return try? idString.withUTF8 { idBuffer in + try JSON.decode(ExitTest.ID.self, from: UnsafeRawBufferPointer(idBuffer)) + } + } + /// Find the exit test function specified in the environment of the current /// process, if any. /// @@ -723,21 +738,15 @@ extension ExitTest { /// `__swiftPMEntryPoint()` function. The effect of using it under other /// configurations is undefined. static func findInEnvironmentForEntryPoint() -> Self? { - // Find the ID of the exit test to run, if any, in the environment block. - var id: ExitTest.ID? - if var idString = Environment.variable(named: "SWT_EXIT_TEST_ID") { - // Clear the environment variable. It's an implementation detail and exit - // test code shouldn't be dependent on it. Use ExitTest.current if needed! - Environment.setVariable(nil, named: "SWT_EXIT_TEST_ID") - - id = try? idString.withUTF8 { idBuffer in - try JSON.decode(ExitTest.ID.self, from: UnsafeRawBufferPointer(idBuffer)) - } - } - guard let id, var result = find(identifiedBy: id) else { + guard let id = environmentIDForEntryPoint, var result = find(identifiedBy: id) else { return nil } + // Since an exit test was found, clear the environment variable. It's an + // implementation detail and exit test code shouldn't be dependent on it. + // Use ExitTest.current if needed! + Environment.setVariable(nil, named: Self._idEnvironmentVariableName) + // If an exit test was found, inject back channel handling into its body. // External tools authors should set up their own back channel mechanisms // and ensure they're installed before calling ExitTest.callAsFunction(). @@ -867,7 +876,7 @@ extension ExitTest { // Insert a specific variable that tells the child process which exit test // to run. try JSON.withEncoding(of: exitTest.id) { json in - childEnvironment["SWT_EXIT_TEST_ID"] = String(decoding: json, as: UTF8.self) + childEnvironment[Self._idEnvironmentVariableName] = String(decoding: json, as: UTF8.self) } typealias ResultUpdater = @Sendable (inout ExitTest.Result) -> Void