diff --git a/secant.xcodeproj/project.pbxproj b/secant.xcodeproj/project.pbxproj index 2a72920..691a32e 100644 --- a/secant.xcodeproj/project.pbxproj +++ b/secant.xcodeproj/project.pbxproj @@ -103,6 +103,7 @@ 9E391129283F74590073DD9A /* Zatoshi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E391128283F74590073DD9A /* Zatoshi.swift */; }; 9E39112E283F91600073DD9A /* ZatoshiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E39112D283F91600073DD9A /* ZatoshiTests.swift */; }; 9E3911392848AD500073DD9A /* HomeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911382848AD500073DD9A /* HomeTests.swift */; }; + 9E39113B2848D5180073DD9A /* WrappedNumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E39113A2848D5180073DD9A /* WrappedNumberFormatter.swift */; }; 9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; }; 9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; }; 9E5BF63F2819542C00BA3F17 /* TransactionHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF63E2819542C00BA3F17 /* TransactionHistoryTests.swift */; }; @@ -294,6 +295,7 @@ 9E391128283F74590073DD9A /* Zatoshi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zatoshi.swift; sourceTree = ""; }; 9E39112D283F91600073DD9A /* ZatoshiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZatoshiTests.swift; sourceTree = ""; }; 9E3911382848AD500073DD9A /* HomeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTests.swift; sourceTree = ""; }; + 9E39113A2848D5180073DD9A /* WrappedNumberFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedNumberFormatter.swift; sourceTree = ""; }; 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = ""; }; 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantButtonStyles.swift; sourceTree = ""; }; 9E5BF63B2818305D00BA3F17 /* TransactionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionState.swift; sourceTree = ""; }; @@ -731,6 +733,7 @@ 9E01F81F2833861A000EFC57 /* WrappedCaptureDevice.swift */, 9E01F8232833C0D8000EFC57 /* WrappedURIParser.swift */, 9E87ADF028363DE400122FCC /* WrappedAudioServices.swift */, + 9E39113A2848D5180073DD9A /* WrappedNumberFormatter.swift */, ); path = Wrappers; sourceTree = ""; @@ -1317,6 +1320,7 @@ 9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */, F9971A5327680DD000A2DB75 /* ProfileStore.swift in Sources */, 669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */, + 9E39113B2848D5180073DD9A /* WrappedNumberFormatter.swift in Sources */, 2E8719CD27FB0D3B0082C926 /* CurrencySelectionView.swift in Sources */, F9971A6C27680E1000A2DB75 /* WalletInfoView.swift in Sources */, 9E5BF6502823E94900BA3F17 /* TransactionAddressTextFieldStore.swift in Sources */, diff --git a/secant/Features/Home/HomeStore.swift b/secant/Features/Home/HomeStore.swift index 0b4745b..608433d 100644 --- a/secant/Features/Home/HomeStore.swift +++ b/secant/Features/Home/HomeStore.swift @@ -181,6 +181,7 @@ extension HomeReducer { SendFlowEnvironment( derivationTool: environment.derivationTool, mnemonic: environment.mnemonic, + numberFormatter: .live(), SDKSynchronizer: environment.SDKSynchronizer, scheduler: environment.scheduler, walletStorage: environment.walletStorage diff --git a/secant/Features/Sandbox/SandboxView.swift b/secant/Features/Sandbox/SandboxView.swift index 62e7976..4b2b954 100644 --- a/secant/Features/Sandbox/SandboxView.swift +++ b/secant/Features/Sandbox/SandboxView.swift @@ -34,6 +34,7 @@ struct SandboxView: View { environment: SendFlowEnvironment( derivationTool: .live(), mnemonic: .live, + numberFormatter: .live(), SDKSynchronizer: LiveWrappedSDKSynchronizer(), scheduler: DispatchQueue.main.eraseToAnyScheduler(), walletStorage: .live() diff --git a/secant/Features/SendFlow/SendFlowStore.swift b/secant/Features/SendFlow/SendFlowStore.swift index ef35079..e16f97c 100644 --- a/secant/Features/SendFlow/SendFlowStore.swift +++ b/secant/Features/SendFlow/SendFlowStore.swift @@ -77,6 +77,7 @@ enum SendFlowAction: Equatable { struct SendFlowEnvironment { let derivationTool: WrappedDerivationTool let mnemonic: WrappedMnemonic + let numberFormatter: WrappedNumberFormatter let SDKSynchronizer: WrappedSDKSynchronizer let scheduler: AnySchedulerOf let walletStorage: WrappedWalletStorage @@ -202,7 +203,11 @@ extension SendFlowReducer { private static let transactionAmountInputReducer: SendFlowReducer = TransactionAmountTextFieldReducer.default.pullback( state: \SendFlowState.transactionAmountInputState, action: /SendFlowAction.transactionAmountInput, - environment: { _ in TransactionAmountTextFieldEnvironment() } + environment: { environment in + TransactionAmountTextFieldEnvironment( + numberFormatter: environment.numberFormatter + ) + } ) static func `default`(whenDone: @escaping () -> Void) -> SendFlowReducer { @@ -310,6 +315,7 @@ extension SendFlowStore { environment: SendFlowEnvironment( derivationTool: .live(), mnemonic: .live, + numberFormatter: .live(), SDKSynchronizer: LiveWrappedSDKSynchronizer(), scheduler: DispatchQueue.main.eraseToAnyScheduler(), walletStorage: .live() diff --git a/secant/Features/SendFlow/SendFlowView.swift b/secant/Features/SendFlow/SendFlowView.swift index e39a438..30ea537 100644 --- a/secant/Features/SendFlow/SendFlowView.swift +++ b/secant/Features/SendFlow/SendFlowView.swift @@ -43,6 +43,7 @@ struct SendFLowView_Previews: PreviewProvider { environment: SendFlowEnvironment( derivationTool: .live(), mnemonic: .live, + numberFormatter: .live(), SDKSynchronizer: LiveWrappedSDKSynchronizer(), scheduler: DispatchQueue.main.eraseToAnyScheduler(), walletStorage: .live() diff --git a/secant/Features/Settings/SettingsStore.swift b/secant/Features/Settings/SettingsStore.swift index 9616d58..62d4347 100644 --- a/secant/Features/Settings/SettingsStore.swift +++ b/secant/Features/Settings/SettingsStore.swift @@ -17,7 +17,7 @@ enum SettingsAction: Equatable { // MARK: - Environment -struct SettingsEnvironment: Equatable { } +struct SettingsEnvironment { } // MARK: - Reducer diff --git a/secant/Features/WalletInfo/WalletInfoStore.swift b/secant/Features/WalletInfo/WalletInfoStore.swift index 51fedc9..c951efe 100644 --- a/secant/Features/WalletInfo/WalletInfoStore.swift +++ b/secant/Features/WalletInfo/WalletInfoStore.swift @@ -17,7 +17,7 @@ enum WalletInfoAction: Equatable { // MARK: - Environment -struct WalletInfoEnvironment: Equatable { +struct WalletInfoEnvironment { } // MARK: - Reducer diff --git a/secant/UI Components/TextFields/TCATextField/TCATextFieldStore.swift b/secant/UI Components/TextFields/TCATextField/TCATextFieldStore.swift index 1cc6dbd..8513223 100644 --- a/secant/UI Components/TextFields/TCATextField/TCATextFieldStore.swift +++ b/secant/UI Components/TextFields/TCATextField/TCATextFieldStore.swift @@ -32,7 +32,7 @@ enum TCATextFieldAction: Equatable { // MARK: - Environment -struct TCATextFieldEnvironment: Equatable { } +struct TCATextFieldEnvironment { } // MARK: - Reducer @@ -52,7 +52,7 @@ extension TCATextFieldReducer { extension TCATextFieldStore { static var transaction: Self { .init( - initialState: .init(validationType: .floatingPoint, text: ""), + initialState: .init(validationType: .customFloatingPoint(.zcashNumberFormatter), text: ""), reducer: .default, environment: .init() ) diff --git a/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift b/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift index af9eb45..a3096a4 100644 --- a/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift +++ b/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextField.swift @@ -66,7 +66,9 @@ struct TransactionAmountTextField_Previews: PreviewProvider { ) ), reducer: .default, - environment: .init() + environment: .init( + numberFormatter: .live() + ) ) ) .preferredColorScheme(.dark) diff --git a/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextFieldStore.swift b/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextFieldStore.swift index 05ddc0a..339398d 100644 --- a/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextFieldStore.swift +++ b/secant/UI Components/TextFields/TransactionAmount/TransactionAmountTextFieldStore.swift @@ -36,7 +36,9 @@ enum TransactionAmountTextFieldAction: Equatable { case updateAmount } -struct TransactionAmountTextFieldEnvironment: Equatable {} +struct TransactionAmountTextFieldEnvironment { + let numberFormatter: WrappedNumberFormatter +} extension TransactionAmountTextFieldReducer { static let `default` = TransactionAmountTextFieldReducer.combine( @@ -47,7 +49,7 @@ extension TransactionAmountTextFieldReducer { ] ) - static let amountTextFieldReducer = TransactionAmountTextFieldReducer { state, action, _ in + static let amountTextFieldReducer = TransactionAmountTextFieldReducer { state, action, environment in switch action { case .setMax: let maxValueAsZec = Decimal(state.maxValue) / Decimal(Zatoshi.Constants.oneZecInZatoshi) @@ -56,8 +58,7 @@ extension TransactionAmountTextFieldReducer { NSDecimalNumber(decimal: maxValueAsZec).roundedZec : NSDecimalNumber(decimal: maxValueAsZec * state.zecPrice).roundedZec - // TODO: these test will be updated with the NumberFormater dependency to handle locale, issue #312 (https://github.com/zcash/secant-ios-wallet/issues/312) - let decimalString = NumberFormatter.zcashNumberFormatter.string(from: maxCurrencyConvertedValue) ?? "" + let decimalString = environment.numberFormatter.string(maxCurrencyConvertedValue) ?? "" state.textFieldState.text = "\(decimalString)" return Effect(value: .updateAmount) @@ -70,8 +71,7 @@ extension TransactionAmountTextFieldReducer { return Effect(value: .updateAmount) case .updateAmount: - // TODO: these test will be updated with the NumberFormater dependency to handle locale, issue #312 (https://github.com/zcash/secant-ios-wallet/issues/312) - guard var number = NumberFormatter.zcashNumberFormatter.number(from: state.textFieldState.text) else { + guard var number = environment.numberFormatter.number(state.textFieldState.text) else { state.amount = 0 return .none } @@ -85,8 +85,7 @@ extension TransactionAmountTextFieldReducer { return .none case .currencySelection: - // TODO: these test will be updated with the NumberFormater dependency to handle locale, issue #312 (https://github.com/zcash/secant-ios-wallet/issues/312) - guard let number = NumberFormatter.zcashNumberFormatter.number(from: state.textFieldState.text) else { + guard let number = environment.numberFormatter.number(state.textFieldState.text) else { state.amount = 0 return .none } @@ -97,8 +96,7 @@ extension TransactionAmountTextFieldReducer { number.decimalValue / state.zecPrice : number.decimalValue * state.zecPrice - // TODO: these test will be updated with the NumberFormater dependency to handle locale, issue #312 (https://github.com/zcash/secant-ios-wallet/issues/312) - let decimalString = NumberFormatter.zcashNumberFormatter.string(from: NSDecimalNumber(decimal: newValue)) ?? "" + let decimalString = environment.numberFormatter.string(NSDecimalNumber(decimal: newValue)) ?? "" state.textFieldState.text = "\(decimalString)" return Effect(value: .updateAmount) } @@ -133,6 +131,9 @@ extension TransactionAmountTextFieldStore { static let placeholder = TransactionAmountTextFieldStore( initialState: .placeholder, reducer: .default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live() + ) ) } diff --git a/secant/Utils/Strings.swift b/secant/Utils/Strings.swift index 49b7302..ffe952f 100644 --- a/secant/Utils/Strings.swift +++ b/secant/Utils/Strings.swift @@ -9,28 +9,12 @@ extension String { } } -extension NumberFormatter { - static let zcashNumberFormatter: NumberFormatter = { - var formatter = NumberFormatter() - formatter.maximumFractionDigits = 8 - formatter.maximumIntegerDigits = 8 - formatter.numberStyle = .decimal - formatter.usesGroupingSeparator = true - return formatter - }() -} - -extension String { - var doubleValue: Double? { - return NumberFormatter.zcashNumberFormatter.number(from: self)?.doubleValue - } -} - extension String { private static let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}" private static let phoneRegex = "^^\\+(?:[0-9]?){6,14}[0-9]$" public enum ValidationType: Equatable { + case customFloatingPoint(NumberFormatter) case custom(String) case email case floatingPoint @@ -40,6 +24,9 @@ extension String { func isValid(text: String) -> Bool { switch self { + case .customFloatingPoint(let numberFormatter): + return text.validate(using: numberFormatter) + case .custom(let regex): return text.validate(using: regex) @@ -47,7 +34,7 @@ extension String { return text.validate(using: .emailRegex) case .floatingPoint: - return text.doubleValue != nil + return NumberFormatter.zcashNumberFormatter.number(from: text) != nil case .maxLength(let length): return text.count <= length && !text.isEmpty @@ -61,6 +48,10 @@ extension String { } } + private func validate(using numberFormatter: NumberFormatter) -> Bool { + numberFormatter.number(from: self) != nil + } + private func validate(using regex: String) -> Bool { guard let regex = try? NSRegularExpression(pattern: regex) else { return false } diff --git a/secant/Wrappers/WrappedNumberFormatter.swift b/secant/Wrappers/WrappedNumberFormatter.swift new file mode 100644 index 0000000..da8259a --- /dev/null +++ b/secant/Wrappers/WrappedNumberFormatter.swift @@ -0,0 +1,33 @@ +// +// WrappedNumberFormatter.swift +// secant-testnet +// +// Created by Lukáš Korba on 02.06.2022. +// + +import Foundation + +extension NumberFormatter { + static let zcashNumberFormatter: NumberFormatter = { + var formatter = NumberFormatter() + formatter.maximumFractionDigits = 8 + formatter.maximumIntegerDigits = 8 + formatter.numberStyle = .decimal + formatter.usesGroupingSeparator = true + return formatter + }() +} + +struct WrappedNumberFormatter { + let string: (NSDecimalNumber) -> String? + let number: (String) -> NSNumber? +} + +extension WrappedNumberFormatter { + static func live(numberFormatter: NumberFormatter = NumberFormatter.zcashNumberFormatter) -> Self { + Self( + string: { numberFormatter.string(from: $0) }, + number: { numberFormatter.number(from: $0) } + ) + } +} diff --git a/secantTests/SendTests/SendTests.swift b/secantTests/SendTests/SendTests.swift index e4daec2..5e25d19 100644 --- a/secantTests/SendTests/SendTests.swift +++ b/secantTests/SendTests/SendTests.swift @@ -10,16 +10,21 @@ import XCTest import ComposableArchitecture import ZcashLightClientKit -// TODO: these test will be updated with the NumberFormater dependency to handle locale, issue #312 (https://github.com/zcash/secant-ios-wallet/issues/312) - // swiftlint:disable type_body_length class SendTests: XCTestCase { var storage = WalletStorage(secItem: .live) + let usNumberFormatter = NumberFormatter() override func setUp() { super.setUp() storage.zcashStoredWalletPrefix = "test_send_" storage.deleteData(forKey: WalletStorage.Constants.zcashStoredWallet) + + usNumberFormatter.maximumFractionDigits = 8 + usNumberFormatter.maximumIntegerDigits = 8 + usNumberFormatter.numberStyle = .decimal + usNumberFormatter.usesGroupingSeparator = true + usNumberFormatter.locale = Locale(identifier: "en_US") } func testSendSucceeded() throws { @@ -32,6 +37,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: MockWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: storage) @@ -88,6 +94,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: storage) @@ -127,6 +134,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -169,6 +177,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -193,6 +202,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -219,8 +229,6 @@ class SendTests: XCTestCase { } func testFundsSufficiency() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testFundsSufficiency is designed to test US locale only") - let sendState = SendFlowState( transaction: .placeholder, transactionAddressInputState: .placeholder, @@ -228,7 +236,11 @@ class SendTests: XCTestCase { TransactionAmountTextFieldState( currencySelectionState: CurrencySelectionState(), maxValue: 501_300, - textFieldState: .amount + textFieldState: + TCATextFieldState( + validationType: .customFloatingPoint(usNumberFormatter), + text: "" + ) ) ) @@ -237,6 +249,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(numberFormatter: usNumberFormatter), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -280,20 +293,32 @@ class SendTests: XCTestCase { } func testDifferentAmountFormats() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testDifferentAmountFormats is designed to test US locale only") - let testScheduler = DispatchQueue.test let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(numberFormatter: usNumberFormatter), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) ) let store = TestStore( - initialState: .placeholder, + initialState: .init( + route: nil, + transaction: .placeholder, + transactionAddressInputState: .placeholder, + transactionAmountInputState: + TransactionAmountTextFieldState( + currencySelectionState: CurrencySelectionState(), + textFieldState: + TCATextFieldState( + validationType: .customFloatingPoint(usNumberFormatter), + text: "" + ) + ) + ), reducer: SendFlowReducer.default, environment: testEnvironment ) @@ -313,8 +338,6 @@ class SendTests: XCTestCase { } func testValidForm() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testValidForm is designed to test US locale only") - let sendState = SendFlowState( transaction: .placeholder, transactionAddressInputState: .placeholder, @@ -325,7 +348,7 @@ class SendTests: XCTestCase { maxValue: 501_302, textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "0.00501301" ) ) @@ -336,6 +359,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -381,6 +405,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -426,6 +451,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) @@ -471,6 +497,7 @@ class SendTests: XCTestCase { let testEnvironment = SendFlowEnvironment( derivationTool: .live(), mnemonic: .mock, + numberFormatter: .live(), SDKSynchronizer: TestWrappedSDKSynchronizer(), scheduler: testScheduler.eraseToAnyScheduler(), walletStorage: .live(walletStorage: WalletStorage(secItem: .live)) diff --git a/secantTests/SendTests/TransactionAmountInputTests.swift b/secantTests/SendTests/TransactionAmountInputTests.swift index 4a13170..314e716 100644 --- a/secantTests/SendTests/TransactionAmountInputTests.swift +++ b/secantTests/SendTests/TransactionAmountInputTests.swift @@ -9,12 +9,19 @@ import XCTest @testable import secant_testnet import ComposableArchitecture -// TODO: these test will be updated with the NumberFormater dependency to handle locale, issue #312 (https://github.com/zcash/secant-ios-wallet/issues/312) - class TransactionAmountTextFieldTests: XCTestCase { - func testMaxValue() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testMaxValue is designed to test US locale only") + let usNumberFormatter = NumberFormatter() + + override func setUp() { + super.setUp() + usNumberFormatter.maximumFractionDigits = 8 + usNumberFormatter.maximumIntegerDigits = 8 + usNumberFormatter.numberStyle = .decimal + usNumberFormatter.usesGroupingSeparator = true + usNumberFormatter.locale = Locale(identifier: "en_US") + } + func testMaxValue() throws { let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -22,12 +29,15 @@ class TransactionAmountTextFieldTests: XCTestCase { maxValue: 501_301, textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "0.002" ) ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.setMax) { state in @@ -52,7 +62,10 @@ class TransactionAmountTextFieldTests: XCTestCase { ) ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live() + ) ) store.send(.clearValue) { state in @@ -62,8 +75,6 @@ class TransactionAmountTextFieldTests: XCTestCase { } func testZec_to_UsdConvertedAmount() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testZec_to_UsdConvertedAmount is designed to test US locale only") - let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -73,13 +84,16 @@ class TransactionAmountTextFieldTests: XCTestCase { ), textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "1.0" ), zecPrice: 1000.0 ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.currencySelection(.swapCurrencyType)) { state in @@ -93,8 +107,6 @@ class TransactionAmountTextFieldTests: XCTestCase { } func testBigZecAmount_to_UsdConvertedAmount() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testBigZecAmount_to_UsdConvertedAmount is designed to test US locale only") - let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -104,13 +116,16 @@ class TransactionAmountTextFieldTests: XCTestCase { ), textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "25000" ), zecPrice: 1000.0 ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.currencySelection(.swapCurrencyType)) { state in @@ -124,8 +139,6 @@ class TransactionAmountTextFieldTests: XCTestCase { } func testUsd_to_ZecConvertedAmount() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testUsd_to_ZecConvertedAmount is designed to test US locale only") - let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -135,13 +148,16 @@ class TransactionAmountTextFieldTests: XCTestCase { ), textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "1 000" ), zecPrice: 1000.0 ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.currencySelection(.swapCurrencyType)) { state in @@ -155,8 +171,6 @@ class TransactionAmountTextFieldTests: XCTestCase { } func testIfAmountIsMax() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testIfAmountIsMax is designed to test US locale only") - let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -167,13 +181,16 @@ class TransactionAmountTextFieldTests: XCTestCase { maxValue: 100_000_000, textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "5" ), zecPrice: 1000.0 ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.textField(.set("1 000"))) { state in @@ -196,8 +213,6 @@ class TransactionAmountTextFieldTests: XCTestCase { } func testMaxZecValue() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testMaxZecValue is designed to test US locale only") - let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -208,13 +223,16 @@ class TransactionAmountTextFieldTests: XCTestCase { maxValue: 200_000_000, textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "5" ), zecPrice: 1000.0 ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.setMax) { state in @@ -227,8 +245,6 @@ class TransactionAmountTextFieldTests: XCTestCase { } func testMaxUsdValue() throws { - try XCTSkipUnless(Locale.current.regionCode == "US", "testMaxUsdValue is designed to test US locale only") - let store = TestStore( initialState: TransactionAmountTextFieldState( @@ -239,13 +255,16 @@ class TransactionAmountTextFieldTests: XCTestCase { maxValue: 200_000_000, textFieldState: TCATextFieldState( - validationType: .floatingPoint, + validationType: .customFloatingPoint(usNumberFormatter), text: "5" ), zecPrice: 1000.0 ), reducer: TransactionAmountTextFieldReducer.default, - environment: TransactionAmountTextFieldEnvironment() + environment: + TransactionAmountTextFieldEnvironment( + numberFormatter: .live(numberFormatter: usNumberFormatter) + ) ) store.send(.setMax) { state in diff --git a/secantTests/UtilTests/ZatoshiTests.swift b/secantTests/UtilTests/ZatoshiTests.swift index 9c0dfde..b5cf3cb 100644 --- a/secantTests/UtilTests/ZatoshiTests.swift +++ b/secantTests/UtilTests/ZatoshiTests.swift @@ -9,6 +9,17 @@ import XCTest @testable import secant_testnet class ZatoshiTests: XCTestCase { + let usNumberFormatter = NumberFormatter() + + override func setUp() { + super.setUp() + usNumberFormatter.maximumFractionDigits = 8 + usNumberFormatter.maximumIntegerDigits = 8 + usNumberFormatter.numberStyle = .decimal + usNumberFormatter.usesGroupingSeparator = true + usNumberFormatter.locale = Locale(identifier: "en_US") + } + func testLowerBound() throws { let number = Zatoshi(amount: -Zatoshi.Constants.maxZatoshi - 1) @@ -122,7 +133,7 @@ class ZatoshiTests: XCTestCase { // so we convert it to string, in that case we are prooving it to be rendered // to the user exactly the way we want XCTAssertEqual( - number.decimalString(), + number.decimalString(formatter: usNumberFormatter), "1.42857143", "Zatoshi tests: the value is expected to be 1.42857143 but it's \(number.decimalString())" ) @@ -149,9 +160,9 @@ class ZatoshiTests: XCTestCase { } func testStringToZatoshi() throws { - if let number = Zatoshi.from(decimalString: "200.0") { + if let number = Zatoshi.from(decimalString: "200.0", formatter: usNumberFormatter) { XCTAssertEqual( - number.decimalString(), + number.decimalString(formatter: usNumberFormatter), "200", "Zatoshi tests: `testStringToZec` the value is expected to be 200 but it's \(number.decimalString())" ) @@ -159,7 +170,7 @@ class ZatoshiTests: XCTestCase { XCTFail("Zatoshi tests: `testStringToZatoshi` failed to convert number.") } - if let number = Zatoshi.from(decimalString: "0.02836478949923") { + if let number = Zatoshi.from(decimalString: "0.02836478949923", formatter: usNumberFormatter) { XCTAssertEqual( number.amount, 2_836_479,