diff --git a/Package.swift b/Package.swift index e1ebd75..c80fee6 100644 --- a/Package.swift +++ b/Package.swift @@ -39,7 +39,6 @@ let package = Package( if isDevelop { package.dependencies.append(contentsOf: [ - .package(url: "https://github.com/apple/swift-testing", exact: "0.3.0"), .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.10.0"), ]) if isObjcAvailable { @@ -53,7 +52,6 @@ if isDevelop { name: "StubNetworkKitTests", dependencies: [ "StubNetworkKit", - .product(name: "Testing", package: "swift-testing"), "Alamofire", ], resources: [.copy("_Fixtures")] @@ -63,6 +61,14 @@ if isDevelop { "APIKit", ]) } + #if compiler(<6.0) + package.dependencies.append(contentsOf: [ + .package(url: "https://github.com/apple/swift-testing", exact: "0.3.0"), + ]) + testTarget.dependencies.append(contentsOf: [ + .product(name: "Testing", package: "swift-testing"), + ]) + #endif package.targets.append(testTarget) if isObjcAvailable { diff --git a/Sources/StubNetworkKit/StubURLProtocol.swift b/Sources/StubNetworkKit/StubURLProtocol.swift index 0d56ebb..b232877 100644 --- a/Sources/StubNetworkKit/StubURLProtocol.swift +++ b/Sources/StubNetworkKit/StubURLProtocol.swift @@ -5,7 +5,7 @@ import FoundationNetworking // based on https://github.com/417-72KI/MultipartFormDataParser/blob/main/Tests/MultipartFormDataParserTests/StubURLProtocol.swift final class StubURLProtocol: URLProtocol { - nonisolated(unsafe) private(set) static var stubs: [Stub] = [] + private static let stubs = Lock([Stub]()) override static func canInit(with request: URLRequest) -> Bool { true @@ -54,17 +54,22 @@ final class StubURLProtocol: URLProtocol { extension StubURLProtocol { static func register(_ stub: Stub) { - stubs.append(stub) + stubs.withLock { stubs in + stubs.append(stub) + } } static func reset() { - stubs = [] + stubs.withLock { + $0 = [] + } } } private extension StubURLProtocol { func stub(with request: URLRequest) -> Stub? { - Self.stubs - .last(where: { $0.matcher(request) }) + Self.stubs.withLock { + $0.last(where: { $0.matcher(request) }) + } } } diff --git a/Sources/StubNetworkKit/Util/Lock.swift b/Sources/StubNetworkKit/Util/Lock.swift new file mode 100644 index 0000000..78165a8 --- /dev/null +++ b/Sources/StubNetworkKit/Util/Lock.swift @@ -0,0 +1,39 @@ +import Foundation + +#if canImport(os) +import os + +final class Lock: Sendable { + let lock: OSAllocatedUnfairLock + + init(_ initialState: State) { + lock = .init(initialState: initialState) + } +} + +extension Lock { + @inlinable + func withLock(_ body: @Sendable (inout State) throws -> R) rethrows -> R { + try lock.withLock(body) + } +} +#elseif canImport(Synchronization) +import Synchronization + +@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) +final class Lock: Sendable { + let lock: Mutex + + init(_ initialValue: Value) { + lock = .init(initialValue) + } +} + +@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) +extension Lock { + @inlinable + func withLock(_ body: (inout sending Value) throws(E) -> sending Result) throws(E) -> sending Result { + try lock.withLock(body) + } +} +#endif diff --git a/TestPlan.xctestplan b/TestPlan.xctestplan index b39a742..1b0ae2f 100644 --- a/TestPlan.xctestplan +++ b/TestPlan.xctestplan @@ -11,7 +11,6 @@ "defaultOptions" : { "maximumTestRepetitions" : 3, "nsZombieEnabled" : true, - "repeatInNewRunnerProcess" : true, "testRepetitionMode" : "retryOnFailure", "testTimeoutsEnabled" : true }, diff --git a/Tests/StubNetworkKitTests/Examples/StubNetworkKitTests_SwiftTesting.swift b/Tests/StubNetworkKitTests/Examples/StubNetworkKitTests_SwiftTesting.swift index e0f40f1..5fb7952 100644 --- a/Tests/StubNetworkKitTests/Examples/StubNetworkKitTests_SwiftTesting.swift +++ b/Tests/StubNetworkKitTests/Examples/StubNetworkKitTests_SwiftTesting.swift @@ -5,7 +5,11 @@ import FoundationNetworking import Testing import StubNetworkKit +#if compiler(<6.0) @Suite +#else +@Suite(.serialized) +#endif final class StubNetworkKitTests_SwiftTesting { init() { StubNetworking.option(printDebugLog: true,