Skip to content

Commit

Permalink
Add targeted dependency cache reset, useful for non-single entry poin…
Browse files Browse the repository at this point in the history
…t systems.
  • Loading branch information
ChristianRiboldi committed Dec 17, 2024
1 parent a0f3ffd commit f52bbbc
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 2 deletions.
18 changes: 18 additions & 0 deletions Sources/Dependencies/DependencyValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,24 @@ public struct DependencyValues: Sendable {
public func resetCache() {
cachedValues.cached = [:]
}

// Allows you to reset a single dependency key
public static func reset<Value>(_ keyPath: KeyPath<DependencyValues, Value> & Sendable) {
reset(by: TypeIdentifier(Value.self))
}

// Allows you to reset a single dependency key
public static func reset<Key: TestDependencyKey>(_ key: Key.Type) {
reset(by: TypeIdentifier(Key.self))
}

private static func reset(by typeId: TypeIdentifier) {
let context =
_current.storage[ObjectIdentifier(DependencyContextKey.self)] as? DependencyContext
?? defaultContext
let cachedKey = CachedValues.CacheKey(id: typeId, context: context)
_current.cachedValues.cached.removeValue(forKey: cachedKey)
}
}

struct CurrentDependency {
Expand Down
44 changes: 43 additions & 1 deletion Tests/DependenciesTests/DependencyValuesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,44 @@ final class DependencyValuesTests: XCTestCase {
XCTAssertEqual(reuseClient.count(), 0)
#endif
}

#if !os(Linux) && !os(WASI) && !os(Windows)
func testFullDependencyReset_KeyPathLiveContext() async {
await withDependencies {
$0.context = .live
} operation: {
@Dependency(\.cachedDependency) var cachedDependency: CachedDependency
var value = await cachedDependency.increment()
XCTAssertEqual(value, 1)
value = await cachedDependency.increment()
XCTAssertEqual(value, 2)
value = await cachedDependency.increment()
XCTAssertEqual(value, 3)
DependencyValues.reset(\.cachedDependency)
value = await cachedDependency.increment()
XCTAssertEqual(value, 1)
}
}
#endif

#if !os(Linux) && !os(WASI) && !os(Windows)
func testFullDependencyReset_ObjectKeyLiveContext() async {
await withDependencies {
$0.context = .live
} operation: {
@Dependency(\.cachedDependency) var cachedDependency: CachedDependency
var value = await cachedDependency.increment()
XCTAssertEqual(value, 1)
value = await cachedDependency.increment()
XCTAssertEqual(value, 2)
value = await cachedDependency.increment()
XCTAssertEqual(value, 3)
DependencyValues.reset(CachedDependency.self)
value = await cachedDependency.increment()
XCTAssertEqual(value, 1)
}
}
#endif

func testBinding() {
withDependencies {
Expand Down Expand Up @@ -927,7 +965,11 @@ extension DependencyValues {
}
}

actor CachedDependency: TestDependencyKey {
actor CachedDependency: DependencyKey {
static var liveValue: CachedDependency {
CachedDependency()
}

static var testValue: CachedDependency {
CachedDependency()
}
Expand Down
48 changes: 47 additions & 1 deletion Tests/DependenciesTests/SwiftTestingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,38 @@ import ConcurrencyExtras
#expect(value == 1)
#endif
}

@Test
func cacheTargetedKeypathReset_liveContext() {
withDependencies {
$0.context = .live
} operation: {
@Dependency(Client.self) var client
var value = client.increment()
#expect(value == 1)
value = client.increment()
#expect(value == 2)
DependencyValues.reset(\.client)
value = client.increment()
#expect(value == 1)
}
}

@Test
func cacheTargetedTypeReset_liveContext() {
withDependencies {
$0.context = .live
} operation: {
@Dependency(Client.self) var client
var value = client.increment()
#expect(value == 1)
value = client.increment()
#expect(value == 2)
DependencyValues.reset(Client.self)
value = client.increment()
#expect(value == 1)
}
}

@Test(.dependency(\.date.now, Date(timeIntervalSinceReferenceDate: 0)))
func trait() {
Expand Down Expand Up @@ -94,9 +126,17 @@ import ConcurrencyExtras
}
}

private struct Client: TestDependencyKey {
private struct Client: DependencyKey {
var increment: @Sendable () -> Int
static var liveValue: Client {
getClient()
}

static var testValue: Client {
getClient()
}

static func getClient() -> Client {
let count = LockIsolated(0)
return Self {
count.withValue {
Expand All @@ -106,6 +146,12 @@ import ConcurrencyExtras
}
}
}
private extension DependencyValues {
var client: Client {
get { self[Client.self] }
set { self[Client.self] = newValue }
}
}

class ClassClient {
var count = 0
Expand Down

0 comments on commit f52bbbc

Please sign in to comment.