diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bb8181d..6fc725c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,6 +59,7 @@ jobs: matrix: swift: - '5.10' + - '6.0' name: Ubuntu (Swift ${{ matrix.swift }}) runs-on: ubuntu-latest container: swift:${{ matrix.swift }} diff --git a/Package.resolved b/Package.resolved index 0c1bf166..ed9a1fdb 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "46c7c52f0c1617cc1d5bc47663541c21a6e6734ddf2ad859bf5bf5bc207fa8f4", + "originHash" : "b0e46c8707f648cbd1d708418b9df17059d230dae6d9892053bdfb8d1d11715b", "pins" : [ { "identity" : "combine-schedulers", "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/combine-schedulers", "state" : { - "revision" : "9fa31f4403da54855f1e2aeaeff478f4f0e40b13", - "version" : "1.0.2" + "revision" : "5928286acce13def418ec36d05a001a9641086f2", + "version" : "1.0.3" } }, { @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-clocks", "state" : { - "revision" : "b9b24b69e2adda099a1fa381cda1eeec272d5b53", - "version" : "1.0.5" + "revision" : "cc46202b53476d64e824e0b6612da09d84ffde8e", + "version" : "1.0.6" } }, { @@ -24,8 +24,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-concurrency-extras", "state" : { - "revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", - "version" : "1.1.0" + "revision" : "82a4ae7170d98d8538ec77238b7eb8e7199ef2e8", + "version" : "1.3.1" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "82645ec760917961cfa08c9c0c7104a57a0fa4b1", + "version" : "1.3.3" } }, { @@ -33,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-docc-plugin", "state" : { - "revision" : "2eb22993b3dfd0c0d32729b357c8dabb6cd44680", - "version" : "1.4.2" + "revision" : "85e4bb4e1cd62cec64a4b8e769dcefdf0c5b9d64", + "version" : "1.4.3" } }, { @@ -51,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-macro-testing", "state" : { - "revision" : "20c1a8f3b624fb5d1503eadcaa84743050c350f4", - "version" : "0.5.2" + "revision" : "0b80a098d4805a21c412b65f01ffde7b01aab2fa", + "version" : "0.6.0" } }, { @@ -60,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "6d932a79e7173b275b96c600c86c603cf84f153c", - "version" : "1.17.4" + "revision" : "b2d4cb30735f4fbc3a01963a9c658336dd21e9ba", + "version" : "1.18.1" } }, { @@ -69,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax", "state" : { - "revision" : "cb53fa1bd3219b0b23ded7dfdd3b2baff266fd25", - "version" : "600.0.0" + "revision" : "0687f71944021d616d34d922343dcef086855920", + "version" : "600.0.1" } }, { @@ -78,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", "state" : { - "revision" : "770f990d3e4eececb57ac04a6076e22f8c97daeb", - "version" : "1.4.2" + "revision" : "39de59b2d47f7ef3ca88a039dff3084688fe27f4", + "version" : "1.5.2" } } ], diff --git a/Sources/Dependencies/DependencyValues.swift b/Sources/Dependencies/DependencyValues.swift index 69e19b00..ba51b626 100644 --- a/Sources/Dependencies/DependencyValues.swift +++ b/Sources/Dependencies/DependencyValues.swift @@ -149,7 +149,7 @@ public struct DependencyValues: Sendable { .takeUnretainedValue() else { return } let testCaseWillStartBlock: @convention(block) (AnyObject) -> Void = { _ in - DependencyValues._current.cachedValues.cached = [:] + DependencyValues._current.cachedValues.resetCache() } let testCaseWillStartImp = imp_implementationWithBlock(testCaseWillStartBlock) class_addMethod( @@ -167,7 +167,7 @@ public struct DependencyValues: Sendable { if isTesting { XCTestObservationCenter.shared.addTestObserver( TestObserver { - DependencyValues._current.cachedValues.cached = [:] + DependencyValues._current.cachedValues.resetCache() } ) } @@ -191,7 +191,7 @@ public struct DependencyValues: Sendable { } #endif pRegisterTestObserver?({ - DependencyValues._current.cachedValues.cached = [:] + DependencyValues._current.cachedValues.resetCache() }) #endif } @@ -286,6 +286,8 @@ public struct DependencyValues: Sendable { reportIssue("Ignoring dependencies prepared in preview app entry point") return } + cachedValues.lock.lock() + defer { cachedValues.lock.unlock() } let cacheKey = CachedValues.CacheKey(id: TypeIdentifier(key), context: context) guard !cachedValues.cached.keys.contains(cacheKey) else { if cachedValues.cached[cacheKey]?.preparationID != DependencyValues.preparationID { @@ -405,7 +407,7 @@ public struct DependencyValues: Sendable { message: "'resetCache' is no longer necessary for most (unparameterized) '@Test' cases" ) public func resetCache() { - cachedValues.cached = [:] + cachedValues.resetCache() } } @@ -478,9 +480,15 @@ public final class CachedValues: @unchecked Sendable { let preparationID: UUID? } - private let lock = NSRecursiveLock() + public let lock = NSRecursiveLock() public var cached = [CacheKey: CachedValue]() + public func resetCache() { + lock.lock() + defer { lock.unlock() } + cached = [:] + } + func value( for key: Key.Type, context: DependencyContext, diff --git a/Tests/DependenciesTests/CacheTests.swift b/Tests/DependenciesTests/CacheTests.swift index ef06cc2d..76757040 100644 --- a/Tests/DependenciesTests/CacheTests.swift +++ b/Tests/DependenciesTests/CacheTests.swift @@ -5,7 +5,7 @@ final class CachedValueTests: XCTestCase { override func tearDown() { super.tearDown() CacheLocals.$skipFailure.withValue(true) { - DependencyValues._current.cachedValues.cached = [:] + DependencyValues._current.cachedValues.resetCache() } } diff --git a/Tests/DependenciesTests/DependencyValuesTests.swift b/Tests/DependenciesTests/DependencyValuesTests.swift index b2e0710a..046841df 100644 --- a/Tests/DependenciesTests/DependencyValuesTests.swift +++ b/Tests/DependenciesTests/DependencyValuesTests.swift @@ -437,30 +437,33 @@ final class DependencyValuesTests: XCTestCase { self.wait(for: [expectation], timeout: 1) } - @MainActor - func testEscapingInFeatureModel_InstanceVariablePropagated() async { - let expectation = self.expectation(description: "escape") - + // TODO: Remove this condition when Linux CI is updated to a more recent Swift 6. + #if !os(Linux) || compiler(<6) @MainActor - class FeatureModel /*: ObservableObject*/ { - @Dependency(\.fullDependency) var fullDependency - func doSomething(expectation: XCTestExpectation) { - DispatchQueue.main.async { - XCTAssertEqual(self.fullDependency.value, 42) - expectation.fulfill() + func testEscapingInFeatureModel_InstanceVariablePropagated() async { + let expectation = self.expectation(description: "escape") + + @MainActor + class FeatureModel /*: ObservableObject*/ { + @Dependency(\.fullDependency) var fullDependency + func doSomething(expectation: XCTestExpectation) { + DispatchQueue.main.async { + XCTAssertEqual(self.fullDependency.value, 42) + expectation.fulfill() + } } } - } - let model = withDependencies { - $0.fullDependency.value = 42 - } operation: { - FeatureModel() - } + let model = withDependencies { + $0.fullDependency.value = 42 + } operation: { + FeatureModel() + } - model.doSomething(expectation: expectation) - await fulfillment(of: [expectation], timeout: 1) - } + model.doSomething(expectation: expectation) + await fulfillment(of: [expectation], timeout: 1) + } + #endif func testEscapingInFeatureModel_NotPropagated() async { let expectation = self.expectation(description: "escape")