From 5a729d9f7e577211d5abcc48deb976396ad9e345 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Thu, 29 Sep 2022 15:04:13 +0200 Subject: [PATCH] Add BackupStorage utility --- .../Utils/BackupStorage.swift | 66 +++++++++++++++++ .../Utils/BackupStorageTests.swift | 70 +++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 Sources/XXMessengerClient/Utils/BackupStorage.swift create mode 100644 Tests/XXMessengerClientTests/Utils/BackupStorageTests.swift diff --git a/Sources/XXMessengerClient/Utils/BackupStorage.swift b/Sources/XXMessengerClient/Utils/BackupStorage.swift new file mode 100644 index 00000000..b13c86cb --- /dev/null +++ b/Sources/XXMessengerClient/Utils/BackupStorage.swift @@ -0,0 +1,66 @@ +import Foundation +import XCTestDynamicOverlay +import XXClient + +public struct BackupStorage { + public struct Backup: Equatable { + public init( + date: Date, + data: Data + ) { + self.date = date + self.data = data + } + + public var date: Date + public var data: Data + } + + public typealias Observer = (Backup?) -> Void + + public var store: (Data) -> Void + public var observe: (@escaping Observer) -> Cancellable + public var remove: () -> Void +} + +extension BackupStorage { + public static func live( + now: @escaping () -> Date + ) -> BackupStorage { + var observers: [UUID: Observer] = [:] + var backup: Backup? + func notifyObservers() { + observers.values.forEach { $0(backup) } + } + + return BackupStorage( + store: { data in + backup = Backup( + date: now(), + data: data + ) + notifyObservers() + }, + observe: { observer in + let id = UUID() + observers[id] = observer + defer { observers[id]?(backup) } + return Cancellable { + observers[id] = nil + } + }, + remove: { + backup = nil + notifyObservers() + } + ) + } +} + +extension BackupStorage { + public static let unimplemented = BackupStorage( + store: XCTUnimplemented("\(Self.self).store"), + observe: XCTUnimplemented("\(Self.self).observe", placeholder: Cancellable {}), + remove: XCTUnimplemented("\(Self.self).remove") + ) +} diff --git a/Tests/XXMessengerClientTests/Utils/BackupStorageTests.swift b/Tests/XXMessengerClientTests/Utils/BackupStorageTests.swift new file mode 100644 index 00000000..3dc8272e --- /dev/null +++ b/Tests/XXMessengerClientTests/Utils/BackupStorageTests.swift @@ -0,0 +1,70 @@ +import CustomDump +import XCTest +@testable import XXMessengerClient + +final class BackupStorageTests: XCTestCase { + func testStorage() { + var now: Date = .init(0) + let storage: BackupStorage = .live( + now: { now } + ) + + var didObserveA: [BackupStorage.Backup?] = [] + let observerA = storage.observe { backup in + didObserveA.append(backup) + } + + XCTAssertNoDifference(didObserveA, [nil]) + + now = .init(1) + didObserveA = [] + let data1 = "data-1".data(using: .utf8)! + storage.store(data1) + + XCTAssertNoDifference(didObserveA, [.init(date: .init(1), data: data1)]) + + now = .init(2) + didObserveA = [] + var didObserveB: [BackupStorage.Backup?] = [] + let observerB = storage.observe { backup in + didObserveB.append(backup) + } + + XCTAssertNoDifference(didObserveA, []) + XCTAssertNoDifference(didObserveB, [.init(date: .init(1), data: data1)]) + + now = .init(3) + didObserveA = [] + didObserveB = [] + let data2 = "data-2".data(using: .utf8)! + storage.store(data2) + + XCTAssertNoDifference(didObserveA, [.init(date: .init(3), data: data2)]) + XCTAssertNoDifference(didObserveB, [.init(date: .init(3), data: data2)]) + + now = .init(4) + didObserveA = [] + didObserveB = [] + observerA.cancel() + storage.remove() + + XCTAssertNoDifference(didObserveA, []) + XCTAssertNoDifference(didObserveB, [nil]) + + now = .init(5) + didObserveA = [] + didObserveB = [] + observerB.cancel() + let data3 = "data-3".data(using: .utf8)! + storage.store(data3) + + XCTAssertNoDifference(didObserveA, []) + XCTAssertNoDifference(didObserveB, []) + } +} + +private extension Date { + init(_ timeIntervalSince1970: TimeInterval) { + self.init(timeIntervalSince1970: timeIntervalSince1970) + } +} -- GitLab