From 701b3f3d0e32a00c69f9bf096d61ab4dd769176d Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Wed, 16 Jul 2025 14:52:15 -0500 Subject: [PATCH 1/3] Only clear exit test ID env var upon successful lookup --- Sources/Testing/ExitTests/ExitTest.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index 9b2c1a77c..fd2a31230 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. + static let idEnvironmentVariableName = "SWT_EXIT_TEST_ID" + /// Call the exit test in the current process. /// /// This function invokes the closure originally passed to @@ -725,11 +729,7 @@ extension ExitTest { 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") - + if var idString = Environment.variable(named: Self.idEnvironmentVariableName) { id = try? idString.withUTF8 { idBuffer in try JSON.decode(ExitTest.ID.self, from: UnsafeRawBufferPointer(idBuffer)) } @@ -738,6 +738,11 @@ extension ExitTest { 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 +872,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 From 7b24c677810e2504e89e2a0e685621827b66ecb0 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Wed, 16 Jul 2025 15:13:28 -0500 Subject: [PATCH 2/3] Introduce an 'environmentIDForEntryPoint' property --- Sources/Testing/ExitTests/ExitTest.swift | 27 ++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index fd2a31230..ca3823bc2 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -235,7 +235,7 @@ extension ExitTest { /// The name of the environment variable used to identify the exit test to /// call in a spawned exit test process. - static let idEnvironmentVariableName = "SWT_EXIT_TEST_ID" + private static let _idEnvironmentVariableName = "SWT_EXIT_TEST_ID" /// Call the exit test in the current process. /// @@ -717,6 +717,18 @@ extension ExitTest { #endif } + /// The ID of the exit test to run, if any, specified in the environment. + static var environmentIDForEntryPoint: ID? { + var id: ExitTest.ID? + if var idString = Environment.variable(named: Self._idEnvironmentVariableName) { + id = try? idString.withUTF8 { idBuffer in + try JSON.decode(ExitTest.ID.self, from: UnsafeRawBufferPointer(idBuffer)) + } + } + + return id + } + /// Find the exit test function specified in the environment of the current /// process, if any. /// @@ -727,21 +739,14 @@ 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: Self.idEnvironmentVariableName) { - 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) + 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 @@ -872,7 +877,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[Self.idEnvironmentVariableName] = String(decoding: json, as: UTF8.self) + childEnvironment[Self._idEnvironmentVariableName] = String(decoding: json, as: UTF8.self) } typealias ResultUpdater = @Sendable (inout ExitTest.Result) -> Void From 506b3d1bfa19c846f294f9ea98616f3491fea9b9 Mon Sep 17 00:00:00 2001 From: Stuart Montgomery Date: Wed, 16 Jul 2025 15:18:16 -0500 Subject: [PATCH 3/3] Improve code style with guard --- Sources/Testing/ExitTests/ExitTest.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index ca3823bc2..374bd9e3c 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -719,14 +719,13 @@ extension ExitTest { /// The ID of the exit test to run, if any, specified in the environment. static var environmentIDForEntryPoint: ID? { - var id: ExitTest.ID? - if var idString = Environment.variable(named: Self._idEnvironmentVariableName) { - id = try? idString.withUTF8 { idBuffer in - try JSON.decode(ExitTest.ID.self, from: UnsafeRawBufferPointer(idBuffer)) - } + guard var idString = Environment.variable(named: Self._idEnvironmentVariableName) else { + return nil } - return id + 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