test(macos): make env/defaults helper Swift 6-safe
This commit is contained in:
@@ -94,7 +94,7 @@ struct LowCoverageHelperTests {
|
||||
}
|
||||
|
||||
@Test func gatewayLaunchAgentHelpers() async throws {
|
||||
try await TestIsolation.withEnvValues(
|
||||
await TestIsolation.withEnvValues(
|
||||
[
|
||||
"CLAWDBOT_GATEWAY_BIND": "Lan",
|
||||
"CLAWDBOT_GATEWAY_TOKEN": " secret ",
|
||||
|
||||
@@ -6,7 +6,7 @@ actor TestIsolationLock {
|
||||
private var locked = false
|
||||
private var waiters: [CheckedContinuation<Void, Never>] = []
|
||||
|
||||
private func lock() async {
|
||||
func acquire() async {
|
||||
if !self.locked {
|
||||
self.locked = true
|
||||
return
|
||||
@@ -17,7 +17,7 @@ actor TestIsolationLock {
|
||||
// `unlock()` resumed us; lock is now held for this caller.
|
||||
}
|
||||
|
||||
private func unlock() {
|
||||
func release() {
|
||||
if self.waiters.isEmpty {
|
||||
self.locked = false
|
||||
return
|
||||
@@ -25,78 +25,90 @@ actor TestIsolationLock {
|
||||
let next = self.waiters.removeFirst()
|
||||
next.resume()
|
||||
}
|
||||
|
||||
func withLock<T: Sendable>(_ body: @Sendable () async throws -> T) async rethrows -> T {
|
||||
await self.lock()
|
||||
defer { self.unlock() }
|
||||
return try await body()
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
enum TestIsolation {
|
||||
static func withIsolatedState<T: Sendable>(
|
||||
static func withIsolatedState<T>(
|
||||
env: [String: String?] = [:],
|
||||
defaults: [String: Any?] = [:],
|
||||
_ body: @Sendable () async throws -> T) async rethrows -> T
|
||||
_ body: () async throws -> T) async rethrows -> T
|
||||
{
|
||||
try await TestIsolationLock.shared.withLock {
|
||||
var previousEnv: [String: String?] = [:]
|
||||
for (key, value) in env {
|
||||
previousEnv[key] = getenv(key).map { String(cString: $0) }
|
||||
if let value {
|
||||
setenv(key, value, 1)
|
||||
} else {
|
||||
unsetenv(key)
|
||||
}
|
||||
await TestIsolationLock.shared.acquire()
|
||||
var previousEnv: [String: String?] = [:]
|
||||
for (key, value) in env {
|
||||
previousEnv[key] = getenv(key).map { String(cString: $0) }
|
||||
if let value {
|
||||
setenv(key, value, 1)
|
||||
} else {
|
||||
unsetenv(key)
|
||||
}
|
||||
}
|
||||
|
||||
let userDefaults = UserDefaults.standard
|
||||
var previousDefaults: [String: Any?] = [:]
|
||||
for (key, value) in defaults {
|
||||
previousDefaults[key] = userDefaults.object(forKey: key)
|
||||
let userDefaults = UserDefaults.standard
|
||||
var previousDefaults: [String: Any?] = [:]
|
||||
for (key, value) in defaults {
|
||||
previousDefaults[key] = userDefaults.object(forKey: key)
|
||||
if let value {
|
||||
userDefaults.set(value, forKey: key)
|
||||
} else {
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let result = try await body()
|
||||
for (key, value) in previousDefaults {
|
||||
if let value {
|
||||
userDefaults.set(value, forKey: key)
|
||||
} else {
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
defer {
|
||||
for (key, value) in previousDefaults {
|
||||
if let value {
|
||||
userDefaults.set(value, forKey: key)
|
||||
} else {
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
}
|
||||
for (key, value) in previousEnv {
|
||||
if let value {
|
||||
setenv(key, value, 1)
|
||||
} else {
|
||||
unsetenv(key)
|
||||
}
|
||||
for (key, value) in previousEnv {
|
||||
if let value {
|
||||
setenv(key, value, 1)
|
||||
} else {
|
||||
unsetenv(key)
|
||||
}
|
||||
}
|
||||
|
||||
return try await body()
|
||||
await TestIsolationLock.shared.release()
|
||||
return result
|
||||
} catch {
|
||||
for (key, value) in previousDefaults {
|
||||
if let value {
|
||||
userDefaults.set(value, forKey: key)
|
||||
} else {
|
||||
userDefaults.removeObject(forKey: key)
|
||||
}
|
||||
}
|
||||
for (key, value) in previousEnv {
|
||||
if let value {
|
||||
setenv(key, value, 1)
|
||||
} else {
|
||||
unsetenv(key)
|
||||
}
|
||||
}
|
||||
await TestIsolationLock.shared.release()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
static func withEnvValues<T: Sendable>(
|
||||
static func withEnvValues<T>(
|
||||
_ values: [String: String?],
|
||||
_ body: @Sendable () async throws -> T) async rethrows -> T
|
||||
_ body: () async throws -> T) async rethrows -> T
|
||||
{
|
||||
try await Self.withIsolatedState(env: values, defaults: [:], body)
|
||||
}
|
||||
|
||||
static func withUserDefaultsValues<T: Sendable>(
|
||||
static func withUserDefaultsValues<T>(
|
||||
_ values: [String: Any?],
|
||||
_ body: @Sendable () async throws -> T) async rethrows -> T
|
||||
_ body: () async throws -> T) async rethrows -> T
|
||||
{
|
||||
try await Self.withIsolatedState(env: [:], defaults: values, body)
|
||||
}
|
||||
|
||||
static func tempConfigPath() -> String {
|
||||
nonisolated static func tempConfigPath() -> String {
|
||||
FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("clawdbot-test-config-\(UUID().uuidString).json")
|
||||
.path
|
||||
|
||||
Reference in New Issue
Block a user