Skip to content

Commit 4e7a085

Browse files
authored
Erase environment variables set by exit tests after reading them. (#1044)
The environment variables we currently use to pass information from the parent process to the child process are implementation details of exit tests and may change or be removed in a future update. To minimize the risk of code relying on these environment variables, and to avoid accidentally trying to open inherited file descriptors twice, clear the variables after reading them. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 1d28fa4 commit 4e7a085

File tree

3 files changed

+47
-39
lines changed

3 files changed

+47
-39
lines changed

Sources/Testing/ExitTests/ExitTest.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,10 @@ extension ExitTest {
457457
return nil
458458
}
459459

460+
// Erase the environment variable so that it cannot accidentally be opened
461+
// twice (nor, in theory, affect the code of the exit test.)
462+
Environment.setVariable(nil, named: "SWT_EXPERIMENTAL_BACKCHANNEL")
463+
460464
var fd: CInt?
461465
#if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
462466
fd = CInt(backChannelEnvironmentVariable)
@@ -487,6 +491,10 @@ extension ExitTest {
487491
// Find the ID of the exit test to run, if any, in the environment block.
488492
var id: ExitTest.ID?
489493
if var idString = Environment.variable(named: "SWT_EXPERIMENTAL_EXIT_TEST_ID") {
494+
// Clear the environment variable. It's an implementation detail and exit
495+
// test code shouldn't be dependent on it. Use ExitTest.current if needed!
496+
Environment.setVariable(nil, named: "SWT_EXPERIMENTAL_EXIT_TEST_ID")
497+
490498
id = try? idString.withUTF8 { idBuffer in
491499
try JSON.decode(ExitTest.ID.self, from: UnsafeRawBufferPointer(idBuffer))
492500
}

Sources/Testing/Support/Environment.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,42 @@ enum Environment {
235235
}
236236
}
237237
}
238+
239+
// MARK: - Setting variables
240+
241+
extension Environment {
242+
/// Set the environment variable with the specified name.
243+
///
244+
/// - Parameters:
245+
/// - value: The new value for the specified environment variable. Pass
246+
/// `nil` to remove the variable from the current process' environment.
247+
/// - name: The name of the environment variable.
248+
///
249+
/// - Returns: Whether or not the environment variable was successfully set.
250+
@discardableResult
251+
static func setVariable(_ value: String?, named name: String) -> Bool {
252+
#if SWT_NO_ENVIRONMENT_VARIABLES
253+
simulatedEnvironment.withLock { environment in
254+
environment[name] = value
255+
}
256+
return true
257+
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
258+
if let value {
259+
return 0 == setenv(name, value, 1)
260+
}
261+
return 0 == unsetenv(name)
262+
#elseif os(Windows)
263+
name.withCString(encodedAs: UTF16.self) { name in
264+
if let value {
265+
return value.withCString(encodedAs: UTF16.self) { value in
266+
SetEnvironmentVariableW(name, value)
267+
}
268+
}
269+
return SetEnvironmentVariableW(name, nil)
270+
}
271+
#else
272+
#warning("Platform-specific implementation missing: environment variables unavailable")
273+
return false
274+
#endif
275+
}
276+
}

Tests/TestingTests/Support/EnvironmentTests.swift

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -71,42 +71,3 @@ struct EnvironmentTests {
7171
#expect(Environment.flag(named: name) == false)
7272
}
7373
}
74-
75-
// MARK: - Fixtures
76-
77-
extension Environment {
78-
/// Set the environment variable with the specified name.
79-
///
80-
/// - Parameters:
81-
/// - value: The new value for the specified environment variable. Pass
82-
/// `nil` to remove the variable from the current process' environment.
83-
/// - name: The name of the environment variable.
84-
///
85-
/// - Returns: Whether or not the environment variable was successfully set.
86-
@discardableResult
87-
static func setVariable(_ value: String?, named name: String) -> Bool {
88-
#if SWT_NO_ENVIRONMENT_VARIABLES
89-
simulatedEnvironment.withLock { environment in
90-
environment[name] = value
91-
}
92-
return true
93-
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
94-
if let value {
95-
return 0 == setenv(name, value, 1)
96-
}
97-
return 0 == unsetenv(name)
98-
#elseif os(Windows)
99-
name.withCString(encodedAs: UTF16.self) { name in
100-
if let value {
101-
return value.withCString(encodedAs: UTF16.self) { value in
102-
SetEnvironmentVariableW(name, value)
103-
}
104-
}
105-
return SetEnvironmentVariableW(name, nil)
106-
}
107-
#else
108-
#warning("Platform-specific implementation missing: environment variables unavailable")
109-
return false
110-
#endif
111-
}
112-
}

0 commit comments

Comments
 (0)