[408] Reduce dependency on TCA in the dependencies (#413)

Following dependencies refactored to await/async
- RecoveryPhraseValidationFlowReducer
- RecoveryPhraseDisplayStore
- AppStore
- UserPreferencesStorage
- WrappedUserDefaults
which allowed to reduce imports of Combine/TCA
This commit is contained in:
Lukas Korba 2022-08-17 09:12:15 +02:00 committed by GitHub
parent 4c36aa39a2
commit 558675aced
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 97 additions and 124 deletions

View File

@ -6,7 +6,6 @@
// //
import Foundation import Foundation
import ComposableArchitecture
/// Live implementation of the `UserPreferences` using User Defaults /// Live implementation of the `UserPreferences` using User Defaults
/// according to https://developer.apple.com/documentation/foundation/userdefaults /// according to https://developer.apple.com/documentation/foundation/userdefaults
@ -50,8 +49,8 @@ struct UserPreferencesStorage {
getValue(forKey: Constants.zcashActiveAppSessionFrom.rawValue, default: appSessionFrom) getValue(forKey: Constants.zcashActiveAppSessionFrom.rawValue, default: appSessionFrom)
} }
func setActiveAppSessionFrom(_ timeInterval: TimeInterval) -> Effect<Never, Never> { func setActiveAppSessionFrom(_ timeInterval: TimeInterval) async {
setValue(timeInterval, forKey: Constants.zcashActiveAppSessionFrom.rawValue) await setValue(timeInterval, forKey: Constants.zcashActiveAppSessionFrom.rawValue)
} }
/// What is the set up currency /// What is the set up currency
@ -59,8 +58,8 @@ struct UserPreferencesStorage {
getValue(forKey: Constants.zcashCurrency.rawValue, default: convertedCurrency) getValue(forKey: Constants.zcashCurrency.rawValue, default: convertedCurrency)
} }
func setCurrency(_ string: String) -> Effect<Never, Never> { func setCurrency(_ string: String) async {
setValue(string, forKey: Constants.zcashCurrency.rawValue) await setValue(string, forKey: Constants.zcashCurrency.rawValue)
} }
/// Whether the fiat conversion is on/off /// Whether the fiat conversion is on/off
@ -68,8 +67,8 @@ struct UserPreferencesStorage {
getValue(forKey: Constants.zcashFiatConverted.rawValue, default: fiatConvertion) getValue(forKey: Constants.zcashFiatConverted.rawValue, default: fiatConvertion)
} }
func setIsFiatConverted(_ bool: Bool) -> Effect<Never, Never> { func setIsFiatConverted(_ bool: Bool) async {
setValue(bool, forKey: Constants.zcashFiatConverted.rawValue) await setValue(bool, forKey: Constants.zcashFiatConverted.rawValue)
} }
/// Whether user finished recovery phrase backup test /// Whether user finished recovery phrase backup test
@ -77,8 +76,8 @@ struct UserPreferencesStorage {
getValue(forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue, default: recoveryPhraseTestCompleted) getValue(forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue, default: recoveryPhraseTestCompleted)
} }
func setIsRecoveryPhraseTestCompleted(_ bool: Bool) -> Effect<Never, Never> { func setIsRecoveryPhraseTestCompleted(_ bool: Bool) async {
setValue(bool, forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue) await setValue(bool, forKey: Constants.zcashRecoveryPhraseTestCompleted.rawValue)
} }
/// Whether the user has been autoshielded in the running session /// Whether the user has been autoshielded in the running session
@ -86,17 +85,15 @@ struct UserPreferencesStorage {
getValue(forKey: Constants.zcashSessionAutoshielded.rawValue, default: sessionAutoshielded) getValue(forKey: Constants.zcashSessionAutoshielded.rawValue, default: sessionAutoshielded)
} }
func setIsSessionAutoshielded(_ bool: Bool) -> Effect<Never, Never> { func setIsSessionAutoshielded(_ bool: Bool) async {
setValue(bool, forKey: Constants.zcashSessionAutoshielded.rawValue) await setValue(bool, forKey: Constants.zcashSessionAutoshielded.rawValue)
} }
/// Use carefully: Deletes all user preferences from the User Defaults /// Use carefully: Deletes all user preferences from the User Defaults
func removeAll() -> Effect<Never, Never> { func removeAll() async {
var removals: [Effect<Never, Never>] = [] for key in Constants.allCases {
await userDefaults.remove(key.rawValue)
Constants.allCases.forEach { removals.append(userDefaults.remove($0.rawValue)) } }
return Effect.concatenate(removals)
} }
} }
@ -105,11 +102,9 @@ private extension UserPreferencesStorage {
userDefaults.objectForKey(forKey) as? Value ?? defaultIfNil userDefaults.objectForKey(forKey) as? Value ?? defaultIfNil
} }
func setValue<Value>(_ value: Value, forKey: String) -> Effect<Never, Never> { func setValue<Value>(_ value: Value, forKey: String) async {
let effect = userDefaults.setValue(value, forKey) await userDefaults.setValue(value, forKey)
_ = userDefaults.synchronize() _ = await userDefaults.synchronize()
return effect
} }
} }

View File

@ -322,11 +322,12 @@ extension AppReducer {
// (https://github.com/zcash/secant-ios-wallet/issues/370) // (https://github.com/zcash/secant-ios-wallet/issues/370)
return .none return .none
} }
return .run { send in
do { do {
return try process(url: url, with: environment) await send(try await process(url: url, with: environment))
} catch { } catch {
// TODO: error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221) // TODO: error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
return .none }
} }
case .deeplinkHome: case .deeplinkHome:
@ -391,7 +392,6 @@ extension AppReducer {
environment: { environment in environment: { environment in
RecoveryPhraseValidationFlowEnvironment( RecoveryPhraseValidationFlowEnvironment(
scheduler: environment.scheduler, scheduler: environment.scheduler,
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .test, pasteboard: .test,
feedbackGenerator: .silent, feedbackGenerator: .silent,
recoveryPhraseRandomizer: environment.recoveryPhraseRandomizer recoveryPhraseRandomizer: environment.recoveryPhraseRandomizer
@ -405,7 +405,7 @@ extension AppReducer {
environment: { environment in environment: { environment in
RecoveryPhraseDisplayEnvironment( RecoveryPhraseDisplayEnvironment(
scheduler: environment.scheduler, scheduler: environment.scheduler,
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) }, newPhrase: { .init(words: RecoveryPhrase.placeholder.words) },
pasteboard: .live, pasteboard: .live,
feedbackGenerator: environment.feedbackGenerator feedbackGenerator: environment.feedbackGenerator
) )
@ -494,14 +494,14 @@ extension AppReducer {
} }
} }
static func process(url: URL, with environment: AppEnvironment) throws -> Effect<AppAction, Never> { static func process(url: URL, with environment: AppEnvironment) async throws -> AppAction {
let deeplink = try environment.deeplinkHandler.resolveDeeplinkURL(url, environment.derivationTool) let deeplink = try environment.deeplinkHandler.resolveDeeplinkURL(url, environment.derivationTool)
switch deeplink { switch deeplink {
case .home: case .home:
return Effect(value: .deeplinkHome) return .deeplinkHome
case let .send(amount, address, memo): case let .send(amount, address, memo):
return Effect(value: .deeplinkSend(Zatoshi(amount), address, memo)) return .deeplinkSend(Zatoshi(amount), address, memo)
} }
} }
} }

View File

@ -25,14 +25,14 @@ enum RecoveryPhraseDisplayAction: Equatable {
case createPhrase case createPhrase
case copyToBufferPressed case copyToBufferPressed
case finishedPressed case finishedPressed
case phraseResponse(Result<RecoveryPhrase, RecoveryPhraseError>) case phraseResponse(RecoveryPhrase)
} }
// MARK: - Environment // MARK: - Environment
struct RecoveryPhraseDisplayEnvironment { struct RecoveryPhraseDisplayEnvironment {
let scheduler: AnySchedulerOf<DispatchQueue> let scheduler: AnySchedulerOf<DispatchQueue>
let newPhrase: () -> Effect<RecoveryPhrase, RecoveryPhraseError> let newPhrase: () async throws -> RecoveryPhrase
let pasteboard: WrappedPasteboard let pasteboard: WrappedPasteboard
let feedbackGenerator: WrappedFeedbackGenerator let feedbackGenerator: WrappedFeedbackGenerator
} }
@ -40,7 +40,7 @@ struct RecoveryPhraseDisplayEnvironment {
extension RecoveryPhraseDisplayEnvironment { extension RecoveryPhraseDisplayEnvironment {
static let demo = Self( static let demo = Self(
scheduler: DispatchQueue.main.eraseToAnyScheduler(), scheduler: DispatchQueue.main.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) }, newPhrase: { .init(words: RecoveryPhrase.placeholder.words) },
pasteboard: .test, pasteboard: .test,
feedbackGenerator: .silent feedbackGenerator: .silent
) )
@ -52,23 +52,27 @@ extension RecoveryPhraseDisplayReducer {
static let `default` = RecoveryPhraseDisplayReducer { state, action, environment in static let `default` = RecoveryPhraseDisplayReducer { state, action, environment in
switch action { switch action {
case .createPhrase: case .createPhrase:
return environment.newPhrase() return .run { send in
.receive(on: environment.scheduler) do {
.catchToEffect(RecoveryPhraseDisplayAction.phraseResponse) await send(.phraseResponse(try await environment.newPhrase()))
} catch {
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/129
}
}
case .copyToBufferPressed: case .copyToBufferPressed:
guard let phrase = state.phrase?.toString() else { return .none } guard let phrase = state.phrase?.toString() else { return .none }
environment.pasteboard.setString(phrase) environment.pasteboard.setString(phrase)
state.showCopyToBufferAlert = true state.showCopyToBufferAlert = true
return .none return .none
case .finishedPressed: case .finishedPressed:
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/47 // TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/47
return .none return .none
case let .phraseResponse(.success(phrase)):
case let .phraseResponse(phrase):
state.phrase = phrase state.phrase = phrase
return .none return .none
case .phraseResponse(.failure):
// TODO: remove this when feature is implemented in https://github.com/zcash/secant-ios-wallet/issues/129
return .none
} }
} }
} }

View File

@ -112,7 +112,6 @@ enum RecoveryPhraseValidationFlowAction: Equatable {
struct RecoveryPhraseValidationFlowEnvironment { struct RecoveryPhraseValidationFlowEnvironment {
let scheduler: AnySchedulerOf<DispatchQueue> let scheduler: AnySchedulerOf<DispatchQueue>
let newPhrase: () -> Effect<RecoveryPhrase, RecoveryPhraseError>
let pasteboard: WrappedPasteboard let pasteboard: WrappedPasteboard
let feedbackGenerator: WrappedFeedbackGenerator let feedbackGenerator: WrappedFeedbackGenerator
let recoveryPhraseRandomizer: WrappedRecoveryPhraseRandomizer let recoveryPhraseRandomizer: WrappedRecoveryPhraseRandomizer
@ -121,7 +120,6 @@ struct RecoveryPhraseValidationFlowEnvironment {
extension RecoveryPhraseValidationFlowEnvironment { extension RecoveryPhraseValidationFlowEnvironment {
static let demo = Self( static let demo = Self(
scheduler: DispatchQueue.main.eraseToAnyScheduler(), scheduler: DispatchQueue.main.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .test, pasteboard: .test,
feedbackGenerator: .silent, feedbackGenerator: .silent,
recoveryPhraseRandomizer: .live recoveryPhraseRandomizer: .live
@ -129,7 +127,6 @@ extension RecoveryPhraseValidationFlowEnvironment {
static let live = Self( static let live = Self(
scheduler: DispatchQueue.main.eraseToAnyScheduler(), scheduler: DispatchQueue.main.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .live, pasteboard: .live,
feedbackGenerator: .haptic, feedbackGenerator: .haptic,
recoveryPhraseRandomizer: .live recoveryPhraseRandomizer: .live

View File

@ -6,13 +6,12 @@
// //
import Foundation import Foundation
import ComposableArchitecture
struct WrappedUserDefaults { struct WrappedUserDefaults {
let objectForKey: (String) -> Any? let objectForKey: @Sendable (String) -> Any?
let remove: (String) -> Effect<Never, Never> let remove: @Sendable (String) async -> Void
let setValue: (Any?, String) -> Effect<Never, Never> let setValue: @Sendable (Any?, String) async -> Void
let synchronize: () -> Bool let synchronize: @Sendable () async -> Bool
} }
extension WrappedUserDefaults { extension WrappedUserDefaults {
@ -20,25 +19,17 @@ extension WrappedUserDefaults {
userDefaults: UserDefaults = .standard userDefaults: UserDefaults = .standard
) -> Self { ) -> Self {
Self( Self(
objectForKey: userDefaults.object(forKey:), objectForKey: { userDefaults.object(forKey: $0) },
remove: { key in remove: { userDefaults.removeObject(forKey: $0) },
.fireAndForget { setValue: { userDefaults.set($0, forKey: $1) },
userDefaults.removeObject(forKey: key) synchronize: { userDefaults.synchronize() }
}
},
setValue: { value, key in
.fireAndForget {
userDefaults.set(value, forKey: key)
}
},
synchronize: userDefaults.synchronize
) )
} }
static let mock = WrappedUserDefaults( static let mock = WrappedUserDefaults(
objectForKey: { _ in }, objectForKey: { _ in },
remove: { _ in .none }, remove: { _ in },
setValue: { _, _ in .none }, setValue: { _, _ in },
synchronize: { true } synchronize: { true }
) )
} }

View File

@ -35,7 +35,7 @@ class RecoveryPhraseDisplayReducerTests: XCTestCase {
environment: .demo environment: .demo
) )
store.send(.phraseResponse(.success(.placeholder))) { store.send(.phraseResponse(.placeholder)) {
$0.phrase = .placeholder $0.phrase = .placeholder
$0.showCopyToBufferAlert = false $0.showCopyToBufferAlert = false
} }

View File

@ -9,8 +9,8 @@ import XCTest
@testable import secant_testnet @testable import secant_testnet
import ComposableArchitecture import ComposableArchitecture
import ZcashLightClientKit import ZcashLightClientKit
import Combine
@MainActor
class DeeplinkTests: XCTestCase { class DeeplinkTests: XCTestCase {
func testActionDeeplinkHome_SameRouteLevel() throws { func testActionDeeplinkHome_SameRouteLevel() throws {
let testEnvironment = AppEnvironment.mock let testEnvironment = AppEnvironment.mock
@ -73,7 +73,7 @@ class DeeplinkTests: XCTestCase {
} }
} }
func testDeeplinkRequest_homeURL() throws { func testDeeplinkRequest_homeURL() async throws {
let synchronizer = TestWrappedSDKSynchronizer() let synchronizer = TestWrappedSDKSynchronizer()
synchronizer.updateStateChanged(.synced) synchronizer.updateStateChanged(.synced)
@ -107,14 +107,16 @@ class DeeplinkTests: XCTestCase {
return XCTFail("Deeplink: 'testDeeplinkRequest_homeURL' URL is expected to be valid.") return XCTFail("Deeplink: 'testDeeplinkRequest_homeURL' URL is expected to be valid.")
} }
store.send(.deeplink(url)) await store.send(.deeplink(url))
store.receive(.deeplinkHome) { state in await store.receive(.deeplinkHome) { state in
state.route = .home state.route = .home
} }
await store.finish()
} }
func testDeeplinkRequest_sendURL_amount() throws { func testDeeplinkRequest_sendURL_amount() async throws {
let synchronizer = TestWrappedSDKSynchronizer() let synchronizer = TestWrappedSDKSynchronizer()
synchronizer.updateStateChanged(.synced) synchronizer.updateStateChanged(.synced)
@ -148,22 +150,24 @@ class DeeplinkTests: XCTestCase {
return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.") return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.")
} }
store.send(.deeplink(url)) await store.send(.deeplink(url))
let amount = Zatoshi(123_000_000) let amount = Zatoshi(123_000_000)
let address = "" let address = ""
let memo = "" let memo = ""
store.receive(.deeplinkSend(amount, address, memo)) { state in await store.receive(.deeplinkSend(amount, address, memo)) { state in
state.route = .home state.route = .home
state.homeState.route = .send state.homeState.route = .send
state.homeState.sendState.amount = amount state.homeState.sendState.amount = amount
state.homeState.sendState.address = address state.homeState.sendState.address = address
state.homeState.sendState.memoState.text = memo state.homeState.sendState.memoState.text = memo
} }
await store.finish()
} }
func testDeeplinkRequest_sendURL_allFields() throws { func testDeeplinkRequest_sendURL_allFields() async throws {
let synchronizer = TestWrappedSDKSynchronizer() let synchronizer = TestWrappedSDKSynchronizer()
synchronizer.updateStateChanged(.synced) synchronizer.updateStateChanged(.synced)
@ -197,18 +201,20 @@ class DeeplinkTests: XCTestCase {
return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.") return XCTFail("Deeplink: 'testDeeplinkRequest_sendURL_amount' URL is expected to be valid.")
} }
store.send(.deeplink(url)) await store.send(.deeplink(url))
let amount = Zatoshi(123_000_000) let amount = Zatoshi(123_000_000)
let address = "address" let address = "address"
let memo = "some text" let memo = "some text"
store.receive(.deeplinkSend(amount, address, memo)) { state in await store.receive(.deeplinkSend(amount, address, memo)) { state in
state.route = .home state.route = .home
state.homeState.route = .send state.homeState.route = .send
state.homeState.sendState.amount = amount state.homeState.sendState.amount = amount
state.homeState.sendState.address = address state.homeState.sendState.address = address
state.homeState.sendState.memoState.text = memo state.homeState.sendState.memoState.text = memo
} }
await store.finish()
} }
} }

View File

@ -14,7 +14,6 @@ class RecoveryPhraseValidationTests: XCTestCase {
let testEnvironment = RecoveryPhraseValidationFlowEnvironment( let testEnvironment = RecoveryPhraseValidationFlowEnvironment(
scheduler: testScheduler.eraseToAnyScheduler(), scheduler: testScheduler.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .test, pasteboard: .test,
feedbackGenerator: .silent, feedbackGenerator: .silent,
recoveryPhraseRandomizer: .live recoveryPhraseRandomizer: .live

View File

@ -7,16 +7,13 @@
import XCTest import XCTest
@testable import secant_testnet @testable import secant_testnet
import Combine
class UserPreferencesStorageTests: XCTestCase { class UserPreferencesStorageTests: XCTestCase {
private var cancellables: [AnyCancellable] = []
// swiftlint:disable:next implicitly_unwrapped_optional // swiftlint:disable:next implicitly_unwrapped_optional
var storage: UserPreferencesStorage! var storage: UserPreferencesStorage!
override func setUp() { override func setUp() async throws {
super.setUp() try await super.setUp()
guard let userDefaults = UserDefaults.init(suiteName: "test") else { guard let userDefaults = UserDefaults.init(suiteName: "test") else {
XCTFail("UserPreferencesStorageTests: UserDefaults.init(suiteName: \"test\") failed to initialize") XCTFail("UserPreferencesStorageTests: UserDefaults.init(suiteName: \"test\") failed to initialize")
@ -31,16 +28,12 @@ class UserPreferencesStorageTests: XCTestCase {
sessionAutoshielded: false, sessionAutoshielded: false,
userDefaults: .live(userDefaults: userDefaults) userDefaults: .live(userDefaults: userDefaults)
) )
storage.removeAll() await storage.removeAll()
.sink(receiveValue: { _ in })
.store(in: &cancellables)
} }
override func tearDown() { override func tearDown() async throws {
super.tearDown() try await super.tearDown()
storage.removeAll() await storage.removeAll()
.sink(receiveValue: { _ in })
.store(in: &cancellables)
storage = nil storage = nil
} }
@ -68,42 +61,32 @@ class UserPreferencesStorageTests: XCTestCase {
// MARK: - Set new values in the live UserDefaults environment // MARK: - Set new values in the live UserDefaults environment
func testAppSessionFrom_setNewValue() throws { func testAppSessionFrom_setNewValue() async throws {
storage.setActiveAppSessionFrom(87654321.0) await storage.setActiveAppSessionFrom(87654321.0)
.sink(receiveValue: { _ in })
.store(in: &cancellables)
XCTAssertEqual(87654321.0, storage.activeAppSessionFrom, "User Preferences: `activeAppSessionFrom` default doesn't match.") XCTAssertEqual(87654321.0, storage.activeAppSessionFrom, "User Preferences: `activeAppSessionFrom` default doesn't match.")
} }
func testConvertedCurrency_setNewValue() throws { func testConvertedCurrency_setNewValue() async throws {
storage.setCurrency("CZK") await storage.setCurrency("CZK")
.sink(receiveValue: { _ in })
.store(in: &cancellables)
XCTAssertEqual("CZK", storage.currency, "User Preferences: `currency` default doesn't match.") XCTAssertEqual("CZK", storage.currency, "User Preferences: `currency` default doesn't match.")
} }
func testFiatConvertion_setNewValue() throws { func testFiatConvertion_setNewValue() async throws {
storage.setIsFiatConverted(false) await storage.setIsFiatConverted(false)
.sink(receiveValue: { _ in })
.store(in: &cancellables)
XCTAssertEqual(false, storage.isFiatConverted, "User Preferences: `isFiatConverted` default doesn't match.") XCTAssertEqual(false, storage.isFiatConverted, "User Preferences: `isFiatConverted` default doesn't match.")
} }
func testRecoveryPhraseTestCompleted_setNewValue() throws { func testRecoveryPhraseTestCompleted_setNewValue() async throws {
storage.setIsRecoveryPhraseTestCompleted(false) await storage.setIsRecoveryPhraseTestCompleted(false)
.sink(receiveValue: { _ in })
.store(in: &cancellables)
XCTAssertEqual(false, storage.isRecoveryPhraseTestCompleted, "User Preferences: `isRecoveryPhraseTestCompleted` default doesn't match.") XCTAssertEqual(false, storage.isRecoveryPhraseTestCompleted, "User Preferences: `isRecoveryPhraseTestCompleted` default doesn't match.")
} }
func testSessionAutoshielded_setNewValue() throws { func testSessionAutoshielded_setNewValue() async throws {
storage.setIsSessionAutoshielded(true) await storage.setIsSessionAutoshielded(true)
.sink(receiveValue: { _ in })
.store(in: &cancellables)
XCTAssertEqual(true, storage.isSessionAutoshielded, "User Preferences: `isSessionAutoshielded` default doesn't match.") XCTAssertEqual(true, storage.isSessionAutoshielded, "User Preferences: `isSessionAutoshielded` default doesn't match.")
} }
@ -113,8 +96,8 @@ class UserPreferencesStorageTests: XCTestCase {
func testAppSessionFrom_mocked() throws { func testAppSessionFrom_mocked() throws {
let mockedUD = WrappedUserDefaults( let mockedUD = WrappedUserDefaults(
objectForKey: { _ in 87654321.0 }, objectForKey: { _ in 87654321.0 },
remove: { _ in .none }, remove: { _ in },
setValue: { _, _ in .none }, setValue: { _, _ in },
synchronize: { true } synchronize: { true }
) )
@ -133,8 +116,8 @@ class UserPreferencesStorageTests: XCTestCase {
func testConvertedCurrency_mocked() throws { func testConvertedCurrency_mocked() throws {
let mockedUD = WrappedUserDefaults( let mockedUD = WrappedUserDefaults(
objectForKey: { _ in "CZK" }, objectForKey: { _ in "CZK" },
remove: { _ in .none }, remove: { _ in },
setValue: { _, _ in .none }, setValue: { _, _ in },
synchronize: { true } synchronize: { true }
) )
@ -153,8 +136,8 @@ class UserPreferencesStorageTests: XCTestCase {
func testFiatConvertion_mocked() throws { func testFiatConvertion_mocked() throws {
let mockedUD = WrappedUserDefaults( let mockedUD = WrappedUserDefaults(
objectForKey: { _ in false }, objectForKey: { _ in false },
remove: { _ in .none }, remove: { _ in },
setValue: { _, _ in .none }, setValue: { _, _ in },
synchronize: { true } synchronize: { true }
) )
@ -173,8 +156,8 @@ class UserPreferencesStorageTests: XCTestCase {
func testRecoveryPhraseTestCompleted_mocked() throws { func testRecoveryPhraseTestCompleted_mocked() throws {
let mockedUD = WrappedUserDefaults( let mockedUD = WrappedUserDefaults(
objectForKey: { _ in false }, objectForKey: { _ in false },
remove: { _ in .none }, remove: { _ in },
setValue: { _, _ in .none }, setValue: { _, _ in },
synchronize: { true } synchronize: { true }
) )
@ -193,8 +176,8 @@ class UserPreferencesStorageTests: XCTestCase {
func testSessionAutoshielded_mocked() throws { func testSessionAutoshielded_mocked() throws {
let mockedUD = WrappedUserDefaults( let mockedUD = WrappedUserDefaults(
objectForKey: { _ in true }, objectForKey: { _ in true },
remove: { _ in .none }, remove: { _ in },
setValue: { _, _ in .none }, setValue: { _, _ in },
synchronize: { true } synchronize: { true }
) )
@ -212,7 +195,7 @@ class UserPreferencesStorageTests: XCTestCase {
// MARK: - Remove all keys from the live UD environment // MARK: - Remove all keys from the live UD environment
func testRemoveAll() throws { func testRemoveAll() async throws {
guard let userDefaults = UserDefaults.init(suiteName: "test") else { guard let userDefaults = UserDefaults.init(suiteName: "test") else {
XCTFail("User Preferences: UserDefaults.init(suiteName: \"test\") failed to initialize") XCTFail("User Preferences: UserDefaults.init(suiteName: \"test\") failed to initialize")
return return
@ -224,9 +207,7 @@ class UserPreferencesStorageTests: XCTestCase {
} }
// remove it // remove it
storage?.removeAll() await storage?.removeAll()
.sink(receiveValue: { _ in })
.store(in: &cancellables)
// check the presence // check the presence
UserPreferencesStorage.Constants.allCases.forEach { UserPreferencesStorage.Constants.allCases.forEach {