Skip to content

Commit ec72cfe

Browse files
committed
Add targeted dependency cache reset, useful for non-single entry point systems.
1 parent a0f3ffd commit ec72cfe

File tree

3 files changed

+108
-2
lines changed

3 files changed

+108
-2
lines changed

Sources/Dependencies/DependencyValues.swift

+18
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,24 @@ public struct DependencyValues: Sendable {
388388
public func resetCache() {
389389
cachedValues.cached = [:]
390390
}
391+
392+
// Allows you to reset a single dependency key
393+
public static func reset<Value>(_ keyPath: KeyPath<DependencyValues, Value> & Sendable) {
394+
reset(by: TypeIdentifier(Value.self))
395+
}
396+
397+
// Allows you to reset a single dependency key
398+
public static func reset<Key: TestDependencyKey>(_ key: Key.Type) {
399+
reset(by: TypeIdentifier(Key.self))
400+
}
401+
402+
private static func reset(by typeId: TypeIdentifier) {
403+
let context =
404+
_current.storage[ObjectIdentifier(DependencyContextKey.self)] as? DependencyContext
405+
?? defaultContext
406+
let cachedKey = CachedValues.CacheKey(id: typeId, context: context)
407+
_current.cachedValues.cached.removeValue(forKey: cachedKey)
408+
}
391409
}
392410

393411
struct CurrentDependency {

Tests/DependenciesTests/DependencyValuesTests.swift

+43-1
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,44 @@ final class DependencyValuesTests: XCTestCase {
293293
XCTAssertEqual(reuseClient.count(), 0)
294294
#endif
295295
}
296+
297+
#if !os(Linux) && !os(WASI) && !os(Windows)
298+
func testFullDependencyReset_KeyPathLiveContext() async {
299+
await withDependencies {
300+
$0.context = .live
301+
} operation: {
302+
@Dependency(\.cachedDependency) var cachedDependency: CachedDependency
303+
var value = await cachedDependency.increment()
304+
XCTAssertEqual(value, 1)
305+
value = await cachedDependency.increment()
306+
XCTAssertEqual(value, 2)
307+
value = await cachedDependency.increment()
308+
XCTAssertEqual(value, 3)
309+
DependencyValues.reset(\.cachedDependency)
310+
value = await cachedDependency.increment()
311+
XCTAssertEqual(value, 1)
312+
}
313+
}
314+
#endif
315+
316+
#if !os(Linux) && !os(WASI) && !os(Windows)
317+
func testFullDependencyReset_ObjectKeyLiveContext() async {
318+
await withDependencies {
319+
$0.context = .live
320+
} operation: {
321+
@Dependency(\.cachedDependency) var cachedDependency: CachedDependency
322+
var value = await cachedDependency.increment()
323+
XCTAssertEqual(value, 1)
324+
value = await cachedDependency.increment()
325+
XCTAssertEqual(value, 2)
326+
value = await cachedDependency.increment()
327+
XCTAssertEqual(value, 3)
328+
DependencyValues.reset(CachedDependency.self)
329+
value = await cachedDependency.increment()
330+
XCTAssertEqual(value, 1)
331+
}
332+
}
333+
#endif
296334

297335
func testBinding() {
298336
withDependencies {
@@ -927,7 +965,11 @@ extension DependencyValues {
927965
}
928966
}
929967

930-
actor CachedDependency: TestDependencyKey {
968+
actor CachedDependency: DependencyKey {
969+
static var liveValue: CachedDependency {
970+
CachedDependency()
971+
}
972+
931973
static var testValue: CachedDependency {
932974
CachedDependency()
933975
}

Tests/DependenciesTests/SwiftTestingTests.swift

+47-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,38 @@ import ConcurrencyExtras
4949
#expect(value == 1)
5050
#endif
5151
}
52+
53+
@Test
54+
func cacheTargetedKeypathReset_liveContext() {
55+
withDependencies {
56+
$0.context = .live
57+
} operation: {
58+
@Dependency(Client.self) var client
59+
var value = client.increment()
60+
#expect(value == 1)
61+
value = client.increment()
62+
#expect(value == 2)
63+
DependencyValues.reset(\.client)
64+
value = client.increment()
65+
#expect(value == 1)
66+
}
67+
}
68+
69+
@Test
70+
func cacheTargetedTypeReset_liveContext() {
71+
withDependencies {
72+
$0.context = .live
73+
} operation: {
74+
@Dependency(Client.self) var client
75+
var value = client.increment()
76+
#expect(value == 1)
77+
value = client.increment()
78+
#expect(value == 2)
79+
DependencyValues.reset(Client.self)
80+
value = client.increment()
81+
#expect(value == 1)
82+
}
83+
}
5284

5385
@Test(.dependency(\.date.now, Date(timeIntervalSinceReferenceDate: 0)))
5486
func trait() {
@@ -94,9 +126,17 @@ import ConcurrencyExtras
94126
}
95127
}
96128

97-
private struct Client: TestDependencyKey {
129+
private struct Client: DependencyKey {
98130
var increment: @Sendable () -> Int
131+
static var liveValue: Client {
132+
getClient()
133+
}
134+
99135
static var testValue: Client {
136+
getClient()
137+
}
138+
139+
static func getClient() -> Client {
100140
let count = LockIsolated(0)
101141
return Self {
102142
count.withValue {
@@ -106,6 +146,12 @@ import ConcurrencyExtras
106146
}
107147
}
108148
}
149+
private extension DependencyValues {
150+
var client: Client {
151+
get { self[Client.self] }
152+
set { self[Client.self] = newValue }
153+
}
154+
}
109155

110156
class ClassClient {
111157
var count = 0

0 commit comments

Comments
 (0)