Skip to content

Commit 0ad8bbe

Browse files
committed
Add unit tests for Storage and HybridStorage
1 parent cf81739 commit 0ad8bbe

File tree

7 files changed

+62
-30
lines changed

7 files changed

+62
-30
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
final class ObservationToken {
1+
public final class ObservationToken {
22
private let cancellationClosure: () -> Void
33

44
init(cancellationClosure: @escaping () -> Void) {
55
self.cancellationClosure = cancellationClosure
66
}
77

8-
func cancel() {
8+
public func cancel() {
99
cancellationClosure()
1010
}
1111
}

Source/Shared/Storage/HybridStorage.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import Foundation
22

33
/// Use both memory and disk storage. Try on memory first.
4-
public final class HybridStorage<T>: StoreObservable {
4+
public final class HybridStorage<T> {
55
public let memoryStorage: MemoryStorage<T>
66
public let diskStorage: DiskStorage<T>
7-
8-
var observations = [UUID : (HybridStorage<T>, StoreChange) -> Void]()
7+
public let registry = StorageObservationRegister<HybridStorage>()
98

109
public init(memoryStorage: MemoryStorage<T>, diskStorage: DiskStorage<T>) {
1110
self.memoryStorage = memoryStorage
@@ -28,25 +27,25 @@ extension HybridStorage: StorageAware {
2827
public func removeObject(forKey key: String) throws {
2928
memoryStorage.removeObject(forKey: key)
3029
try diskStorage.removeObject(forKey: key)
31-
notifyObservers(of: .singleDeletion)
30+
registry.notifyObservers(about: .singleDeletion, in: self)
3231
}
3332

3433
public func setObject(_ object: T, forKey key: String, expiry: Expiry? = nil) throws {
3534
memoryStorage.setObject(object, forKey: key, expiry: expiry)
3635
try diskStorage.setObject(object, forKey: key, expiry: expiry)
37-
notifyObservers(of: .addition)
36+
registry.notifyObservers(about: .addition, in: self)
3837
}
3938

4039
public func removeAll() throws {
4140
memoryStorage.removeAll()
4241
try diskStorage.removeAll()
43-
notifyObservers(of: .allDeletion)
42+
registry.notifyObservers(about: .allDeletion, in: self)
4443
}
4544

4645
public func removeExpiredObjects() throws {
4746
memoryStorage.removeExpiredObjects()
4847
try diskStorage.removeExpiredObjects()
49-
notifyObservers(of: .expiredDeletion)
48+
registry.notifyObservers(about: .expiredDeletion, in: self)
5049
}
5150
}
5251

Source/Shared/Storage/Storage.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import Dispatch
33

44
/// Manage storage. Use memory storage if specified.
55
/// Synchronous by default. Use `async` for asynchronous operations.
6-
public final class Storage<T>: StoreObservable {
6+
public final class Storage<T> {
77
/// Used for sync operations
88
let syncStorage: SyncStorage<T>
99
let asyncStorage: AsyncStorage<T>
1010

11-
var observations = [UUID : (Storage, StoreChange) -> Void]()
11+
public let registry = StorageObservationRegister<Storage>()
1212

1313
/// Initialize storage with configuration options.
1414
///
@@ -48,14 +48,15 @@ public final class Storage<T>: StoreObservable {
4848

4949
private func subscribeToChanges() {
5050
subscribeToChanges(in: syncStorage.innerStorage)
51-
if syncStorage !== asyncStorage {
51+
if syncStorage.innerStorage !== asyncStorage.innerStorage {
5252
subscribeToChanges(in: asyncStorage.innerStorage)
5353
}
5454
}
5555

5656
private func subscribeToChanges(in storage: HybridStorage<T>) {
57-
storage.observeChanges { [weak self] _, change in
58-
self?.notifyObservers(of: change)
57+
storage.registry.register { [weak self] _, change in
58+
guard let strongSelf = self else { return }
59+
self?.registry.notifyObservers(about: change, in: strongSelf)
5960
}
6061
}
6162
}

Source/Shared/Storage/StoreChange.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
public enum StoreChange {
1+
public enum StorageChange {
22
case addition
33
case singleDeletion
44
case allDeletion
Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
import Foundation
22

3-
protocol StoreObservable: class {
4-
var observations: [UUID : (Self, StoreChange) -> Void] { get set }
5-
}
3+
public final class StorageObservationRegister<T: StorageAware> {
4+
public typealias Observation = (T, StorageChange) -> Void
5+
private(set) var observations = [UUID: Observation]()
66

7-
extension StoreObservable {
87
@discardableResult
9-
public func observeChanges(using closure: @escaping (Self, StoreChange) -> Void) -> ObservationToken {
8+
public func register(observation: @escaping Observation) -> ObservationToken {
109
let id = UUID()
11-
observations[id] = closure
10+
observations[id] = observation
1211

1312
return ObservationToken { [weak self] in
1413
self?.observations.removeValue(forKey: id)
1514
}
1615
}
1716

18-
func notifyObservers(of change: StoreChange) {
19-
observations.values.forEach { [weak self] closure in
20-
guard let strongSelf = self else {
21-
return
22-
}
23-
closure(strongSelf, change)
17+
public func deregister(token: ObservationToken) {
18+
token.cancel()
19+
}
20+
21+
public func deregisterAll() {
22+
observations.removeAll()
23+
}
24+
25+
func notifyObservers(about change: StorageChange, in storage: T) {
26+
observations.values.forEach { closure in
27+
closure(storage, change)
2428
}
2529
}
2630
}

Tests/iOS/Tests/Storage/HybridStorageTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,20 @@ final class HybridStorageTests: XCTestCase {
156156
XCTAssertNotNil(try? storage.object(forKey: key2))
157157
}
158158
}
159+
160+
func testRegisterObservations() throws {
161+
var changes = [StorageChange]()
162+
163+
storage.registry.register { storage, change in
164+
changes.append(change)
165+
}
166+
167+
try storage.setObject(testObject, forKey: "user1")
168+
try storage.setObject(testObject, forKey: "user2")
169+
try storage.removeObject(forKey: "user1")
170+
try storage.removeExpiredObjects()
171+
try storage.removeAll()
172+
173+
XCTAssertEqual(changes, [.addition, .addition, .singleDeletion, .expiredDeletion, .allDeletion])
174+
}
159175
}

Tests/iOS/Tests/Storage/StorageTests.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import XCTest
2-
import Cache
2+
@testable import Cache
33

44
final class StorageTests: XCTestCase {
55
private var storage: Storage<User>!
@@ -97,7 +97,19 @@ final class StorageTests: XCTestCase {
9797
XCTAssertEqual(cachedObject.firstName, "John")
9898
}
9999

100-
func testObserveAddition() {
101-
100+
func testRegisterObservations() throws {
101+
var changes = [StorageChange]()
102+
103+
storage.registry.register { storage, change in
104+
changes.append(change)
105+
}
106+
107+
try storage.setObject(user, forKey: "user1")
108+
try storage.setObject(user, forKey: "user2")
109+
try storage.removeObject(forKey: "user1")
110+
try storage.removeExpiredObjects()
111+
try storage.removeAll()
112+
113+
XCTAssertEqual(changes, [.addition, .addition, .singleDeletion, .expiredDeletion, .allDeletion])
102114
}
103115
}

0 commit comments

Comments
 (0)