- all dependencies are now consolidated - cleanup of dependencies - getting rid of all .live instances in the tests - all dependencies use mocked or noOp instances
This commit is contained in:
parent
7839d56977
commit
c8b97a8266
|
@ -68,7 +68,7 @@
|
|||
2EDA07A027EDE18C00D6F09B /* TCATextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDA079F27EDE18C00D6F09B /* TCATextField.swift */; };
|
||||
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDA07A127EDE1AE00D6F09B /* TextFieldFooter.swift */; };
|
||||
2EDA07A427EDE2A900D6F09B /* DebugFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EDA07A327EDE2A900D6F09B /* DebugFrame.swift */; };
|
||||
34429C6E28E703CD00F2B929 /* TransactionSendingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34429C6D28E703CD00F2B929 /* TransactionSendingTests.swift */; };
|
||||
34429C6E28E703CD00F2B929 /* TransactionSendingSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34429C6D28E703CD00F2B929 /* TransactionSendingSnapshotTests.swift */; };
|
||||
3448CB3228E47666006ADEDB /* NotEnoughFreeSpaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */; };
|
||||
3448CB3728E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */; };
|
||||
346715A528E2027D0035F7C4 /* CheckCircleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346715A428E2027D0035F7C4 /* CheckCircleStore.swift */; };
|
||||
|
@ -94,12 +94,23 @@
|
|||
66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */; };
|
||||
66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */; };
|
||||
66DC733F271D88CC0053CBB6 /* StandardButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */; };
|
||||
9E01F8242833C0D8000EFC57 /* WrappedURIParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E01F8232833C0D8000EFC57 /* WrappedURIParser.swift */; };
|
||||
9E01F8282833CDA0000EFC57 /* ScanTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E01F8272833CDA0000EFC57 /* ScanTests.swift */; };
|
||||
9E02B56A27FED43E005B809B /* WrappedFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E02B56927FED43E005B809B /* WrappedFileManager.swift */; };
|
||||
9E02B56A27FED43E005B809B /* FileManagerInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E02B56927FED43E005B809B /* FileManagerInterface.swift */; };
|
||||
9E02B56C27FED475005B809B /* DatabaseFilesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E02B56B27FED475005B809B /* DatabaseFilesTests.swift */; };
|
||||
9E153A5F2920CE2700112F41 /* MnemonicInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A5E2920CD5100112F41 /* MnemonicInterface.swift */; };
|
||||
9E153A602920CE2700112F41 /* MnemonicLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A5C2920CD5100112F41 /* MnemonicLiveKey.swift */; };
|
||||
9E153A612920CE2700112F41 /* MnemonicMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A5B2920CD5100112F41 /* MnemonicMocks.swift */; };
|
||||
9E153A622920CE2700112F41 /* MnemonicTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A5D2920CD5100112F41 /* MnemonicTestKey.swift */; };
|
||||
9E153A6729210B3B00112F41 /* PasteboardLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A6429210B3B00112F41 /* PasteboardLiveKey.swift */; };
|
||||
9E153A6829210B3B00112F41 /* PasteboardInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A6529210B3B00112F41 /* PasteboardInterface.swift */; };
|
||||
9E153A6929210B3B00112F41 /* PasteboardTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A6629210B3B00112F41 /* PasteboardTestKey.swift */; };
|
||||
9E153A6E292167FF00112F41 /* ZcashSDKEnvironmentLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A6B292167FF00112F41 /* ZcashSDKEnvironmentLiveKey.swift */; };
|
||||
9E153A6F292167FF00112F41 /* ZcashSDKEnvironmentTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A6C292167FF00112F41 /* ZcashSDKEnvironmentTestKey.swift */; };
|
||||
9E153A70292167FF00112F41 /* ZcashSDKEnvironmentInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A6D292167FF00112F41 /* ZcashSDKEnvironmentInterface.swift */; };
|
||||
9E153A7529216EFB00112F41 /* UserDefaultsLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A7229216EFB00112F41 /* UserDefaultsLiveKey.swift */; };
|
||||
9E153A7629216EFB00112F41 /* UserDefaultsInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A7329216EFB00112F41 /* UserDefaultsInterface.swift */; };
|
||||
9E153A7729216EFB00112F41 /* UserDefaultsTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E153A7429216EFB00112F41 /* UserDefaultsTestKey.swift */; };
|
||||
9E2AC0FF27D8EC120042AA47 /* MnemonicSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2AC0FE27D8EC120042AA47 /* MnemonicSwift */; };
|
||||
9E2AC10127D8EF0B0042AA47 /* WrappedMnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2AC10027D8EF0B0042AA47 /* WrappedMnemonic.swift */; };
|
||||
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99827CF704D00649636 /* ImportWalletStore.swift */; };
|
||||
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */; };
|
||||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99B27CF704D00649636 /* ImportWalletView.swift */; };
|
||||
|
@ -111,22 +122,15 @@
|
|||
9E39112E283F91600073DD9A /* ZatoshiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E39112D283F91600073DD9A /* ZatoshiTests.swift */; };
|
||||
9E391132284644580073DD9A /* AppInitializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E391131284644580073DD9A /* AppInitializationTests.swift */; };
|
||||
9E3911392848AD500073DD9A /* HomeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911382848AD500073DD9A /* HomeTests.swift */; };
|
||||
9E39113B2848D5180073DD9A /* WrappedNumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E39113A2848D5180073DD9A /* WrappedNumberFormatter.swift */; };
|
||||
9E39113F2848EC360073DD9A /* WrappedRecoveryPhraseRandomizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E39113E2848EC350073DD9A /* WrappedRecoveryPhraseRandomizer.swift */; };
|
||||
9E3911482848EEB90073DD9A /* RecoveryPhraseRandomizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911422848EEB90073DD9A /* RecoveryPhraseRandomizer.swift */; };
|
||||
9E3911492848EEB90073DD9A /* URIParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911432848EEB90073DD9A /* URIParser.swift */; };
|
||||
9E39114A2848EEB90073DD9A /* UserPreferencesStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911442848EEB90073DD9A /* UserPreferencesStorage.swift */; };
|
||||
9E39114B2848EEB90073DD9A /* ZCashSDKEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911452848EEB90073DD9A /* ZCashSDKEnvironment.swift */; };
|
||||
9E39114C2848EEB90073DD9A /* DatabaseFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911462848EEB90073DD9A /* DatabaseFiles.swift */; };
|
||||
9E39114D2848EEB90073DD9A /* WalletStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911472848EEB90073DD9A /* WalletStorage.swift */; };
|
||||
9E39115E284E3E350073DD9A /* secantUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4E7A2526B364180058B01E /* secantUITests.swift */; };
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; };
|
||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; };
|
||||
9E5BF63F2819542C00BA3F17 /* WalletEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF63E2819542C00BA3F17 /* WalletEventsTests.swift */; };
|
||||
9E5BF641281FD7B600BA3F17 /* TransactionFailedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF640281FD7B600BA3F17 /* TransactionFailedView.swift */; };
|
||||
9E5BF644281FEC9900BA3F17 /* SendTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF643281FEC9900BA3F17 /* SendTests.swift */; };
|
||||
9E5BF6462821028C00BA3F17 /* WrappedUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF6452821028C00BA3F17 /* WrappedUserDefaults.swift */; };
|
||||
9E5BF648282277BE00BA3F17 /* WrappedNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF647282277BE00BA3F17 /* WrappedNotificationCenter.swift */; };
|
||||
9E5BF648282277BE00BA3F17 /* NotificationCenterInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF647282277BE00BA3F17 /* NotificationCenterInterface.swift */; };
|
||||
9E5BF64F2823E94900BA3F17 /* TransactionAddressTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF64D2823E94900BA3F17 /* TransactionAddressTextField.swift */; };
|
||||
9E5BF6502823E94900BA3F17 /* TransactionAddressTextFieldStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5BF64E2823E94900BA3F17 /* TransactionAddressTextFieldStore.swift */; };
|
||||
9E66122A287717A900C75B70 /* HomeCircularProgressSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E661229287717A900C75B70 /* HomeCircularProgressSnapshotTests.swift */; };
|
||||
|
@ -140,11 +144,6 @@
|
|||
9E6713F8289BC58C00A6796F /* BalanceBreakdownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6713F5289BC58C00A6796F /* BalanceBreakdownView.swift */; };
|
||||
9E6713FA289BE0E100A6796F /* ClearBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6713F9289BE0E100A6796F /* ClearBackgroundView.swift */; };
|
||||
9E69A24D27FB002800A55317 /* WelcomeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E69A24C27FB002800A55317 /* WelcomeStore.swift */; };
|
||||
9E6EF2CB291287BB00CA007B /* FeedbackGeneratorKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6EF2CA291287BB00CA007B /* FeedbackGeneratorKey.swift */; };
|
||||
9E6EF2CD2913B06300CA007B /* NumberFormatterKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6EF2CC2913B06300CA007B /* NumberFormatterKey.swift */; };
|
||||
9E6EF2CF2913B11A00CA007B /* SDKSynchronizerKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6EF2CE2913B11A00CA007B /* SDKSynchronizerKey.swift */; };
|
||||
9E6EF2D12913B75400CA007B /* MnemonicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6EF2D02913B75400CA007B /* MnemonicKey.swift */; };
|
||||
9E6EF2D32913B79A00CA007B /* WalletStorageKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6EF2D22913B79A00CA007B /* WalletStorageKey.swift */; };
|
||||
9E7225F12889539300DF7F17 /* SettingsSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7225F02889539300DF7F17 /* SettingsSnapshotTests.swift */; };
|
||||
9E7225F3288AB6DD00DF7F17 /* MultipleLineTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7225F2288AB6DD00DF7F17 /* MultipleLineTextField.swift */; };
|
||||
9E7225F6288AC71A00DF7F17 /* MultiLineTextFieldStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7225F5288AC71A00DF7F17 /* MultiLineTextFieldStore.swift */; };
|
||||
|
@ -159,8 +158,6 @@
|
|||
9E7FE0D3282D274E00C374E8 /* Date+Readable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0D2282D274E00C374E8 /* Date+Readable.swift */; };
|
||||
9E7FE0D5282D281800C374E8 /* Array+Chunked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0D4282D281800C374E8 /* Array+Chunked.swift */; };
|
||||
9E7FE0D7282D286500C374E8 /* RecoveryPhrase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0D6282D286500C374E8 /* RecoveryPhrase.swift */; };
|
||||
9E7FE0D9282D289B00C374E8 /* WrappedFeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0D8282D289B00C374E8 /* WrappedFeedbackGenerator.swift */; };
|
||||
9E7FE0DB282D28F100C374E8 /* WrappedPasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0DA282D28F100C374E8 /* WrappedPasteboard.swift */; };
|
||||
9E7FE0DD282D298900C374E8 /* ValidationWord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0DC282D298900C374E8 /* ValidationWord.swift */; };
|
||||
9E7FE0DF282D2DD600C374E8 /* ZcashBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0DE282D2DD600C374E8 /* ZcashBadge.swift */; };
|
||||
9E7FE0E6282E7B1100C374E8 /* StoredWallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7FE0E5282E7B1100C374E8 /* StoredWallet.swift */; };
|
||||
|
@ -183,13 +180,41 @@
|
|||
9EAB46782860A1D2002904A0 /* WalletEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB46772860A1D2002904A0 /* WalletEvent.swift */; };
|
||||
9EAB467A2861EA6A002904A0 /* TransactionRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB46792861EA6A002904A0 /* TransactionRowView.swift */; };
|
||||
9EAFEB822805793200199FC9 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB812805793200199FC9 /* AppTests.swift */; };
|
||||
9EAFEB84280597B700199FC9 /* WrappedSecItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB83280597B700199FC9 /* WrappedSecItem.swift */; };
|
||||
9EAFEB862805A23100199FC9 /* WrappedSecItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB852805A23100199FC9 /* WrappedSecItemTests.swift */; };
|
||||
9EAFEB882806E5AE00199FC9 /* WrappedSDKSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB872806E5AE00199FC9 /* WrappedSDKSynchronizer.swift */; };
|
||||
9EAFEB84280597B700199FC9 /* SecItemInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB83280597B700199FC9 /* SecItemInterface.swift */; };
|
||||
9EAFEB862805A23100199FC9 /* SecItemClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB852805A23100199FC9 /* SecItemClientTests.swift */; };
|
||||
9EAFEB882806E5AE00199FC9 /* SDKSynchronizerInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB872806E5AE00199FC9 /* SDKSynchronizerInterface.swift */; };
|
||||
9EAFEB8F2808183D00199FC9 /* SandboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB8D2808183D00199FC9 /* SandboxView.swift */; };
|
||||
9EAFEB902808183D00199FC9 /* SandboxStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAFEB8E2808183D00199FC9 /* SandboxStore.swift */; };
|
||||
9EAFEB9128081E9400199FC9 /* HomeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93874ED273C4DE200F0E875 /* HomeStore.swift */; };
|
||||
9EAFEB9228081E9400199FC9 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93874EF273C4DE200F0E875 /* HomeView.swift */; };
|
||||
9EB8638C2922CD4A003D0F8B /* FeedbackGeneratorTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863892922CC4D003D0F8B /* FeedbackGeneratorTestKey.swift */; };
|
||||
9EB8638D2922CD4A003D0F8B /* FeedbackGeneratorLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB8638B2922CC4D003D0F8B /* FeedbackGeneratorLiveKey.swift */; };
|
||||
9EB8638E2922CD4A003D0F8B /* FeedbackGeneratorInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB8638A2922CC4D003D0F8B /* FeedbackGeneratorInterface.swift */; };
|
||||
9EB863932922D036003D0F8B /* NumberFormatterInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863902922D035003D0F8B /* NumberFormatterInterface.swift */; };
|
||||
9EB863942922D036003D0F8B /* NumberFormatterLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863912922D035003D0F8B /* NumberFormatterLiveKey.swift */; };
|
||||
9EB863952922D036003D0F8B /* NumberFormatterTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863922922D036003D0F8B /* NumberFormatterTestKey.swift */; };
|
||||
9EB8639A2923935B003D0F8B /* WalletStorageTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863972923935B003D0F8B /* WalletStorageTestKey.swift */; };
|
||||
9EB8639B2923935B003D0F8B /* WalletStorageInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863982923935B003D0F8B /* WalletStorageInterface.swift */; };
|
||||
9EB8639C2923935B003D0F8B /* WalletStorageLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863992923935B003D0F8B /* WalletStorageLiveKey.swift */; };
|
||||
9EB8639D29239405003D0F8B /* WalletStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911472848EEB90073DD9A /* WalletStorage.swift */; };
|
||||
9EB863A1292398A8003D0F8B /* URIParserInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB8639F292398A8003D0F8B /* URIParserInterface.swift */; };
|
||||
9EB863A2292398A8003D0F8B /* URIParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863A0292398A8003D0F8B /* URIParser.swift */; };
|
||||
9EB863A729239DCB003D0F8B /* RecoveryPhraseRandomizerTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863A429239DCB003D0F8B /* RecoveryPhraseRandomizerTestKey.swift */; };
|
||||
9EB863A829239DCB003D0F8B /* RecoveryPhraseRandomizerLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863A529239DCB003D0F8B /* RecoveryPhraseRandomizerLiveKey.swift */; };
|
||||
9EB863A929239DCB003D0F8B /* RecoveryPhraseRandomizerInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863A629239DCB003D0F8B /* RecoveryPhraseRandomizerInterface.swift */; };
|
||||
9EB863AA29239EB2003D0F8B /* RecoveryPhraseRandomizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E3911422848EEB90073DD9A /* RecoveryPhraseRandomizer.swift */; };
|
||||
9EB863B92923C6D7003D0F8B /* FileManagerLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863B82923C6D7003D0F8B /* FileManagerLive.swift */; };
|
||||
9EB863BB2923C6F8003D0F8B /* NotificationCenterLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863BA2923C6F8003D0F8B /* NotificationCenterLive.swift */; };
|
||||
9EB863BD2923C704003D0F8B /* NotificationCenterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863BC2923C704003D0F8B /* NotificationCenterTest.swift */; };
|
||||
9EB863BF2923C72C003D0F8B /* SecItemLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863BE2923C72C003D0F8B /* SecItemLive.swift */; };
|
||||
9EB863C12923C779003D0F8B /* URIParserLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863C02923C779003D0F8B /* URIParserLive.swift */; };
|
||||
9EB863C32923C807003D0F8B /* URIParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863C22923C807003D0F8B /* URIParserTest.swift */; };
|
||||
9EB863C52923C8AF003D0F8B /* FileManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863C42923C8AF003D0F8B /* FileManagerTest.swift */; };
|
||||
9EB863C72923C93B003D0F8B /* UserPreferencesStorageLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863C62923C93B003D0F8B /* UserPreferencesStorageLive.swift */; };
|
||||
9EB863C92923C953003D0F8B /* UserPreferencesStorageMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863C82923C953003D0F8B /* UserPreferencesStorageMocks.swift */; };
|
||||
9EB863CB2923CA20003D0F8B /* SDKSynchronizerLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863CA2923CA20003D0F8B /* SDKSynchronizerLive.swift */; };
|
||||
9EB863CD2923CA28003D0F8B /* SDKSynchronizerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863CC2923CA28003D0F8B /* SDKSynchronizerTest.swift */; };
|
||||
9EB863D02923D3FC003D0F8B /* SDKSynchronizerMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB863CE2923CA32003D0F8B /* SDKSynchronizerMocks.swift */; };
|
||||
9EBDF947291D75B2000A1A05 /* DiskSpaceCheckerInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF946291D75B2000A1A05 /* DiskSpaceCheckerInterface.swift */; };
|
||||
9EBDF949291D75BF000A1A05 /* DiskSpaceCheckerLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF948291D75BF000A1A05 /* DiskSpaceCheckerLiveKey.swift */; };
|
||||
9EBDF94B291D75C7000A1A05 /* DiskSpaceCheckerTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF94A291D75C7000A1A05 /* DiskSpaceCheckerTestKey.swift */; };
|
||||
|
@ -197,7 +222,6 @@
|
|||
9EBDF953291E5E86000A1A05 /* DatabaseFilesTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF94F291E5E86000A1A05 /* DatabaseFilesTestKey.swift */; };
|
||||
9EBDF955291E5E86000A1A05 /* DatabaseFilesInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF951291E5E86000A1A05 /* DatabaseFilesInterface.swift */; };
|
||||
9EBDF956291E5E86000A1A05 /* DatabaseFilesLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF952291E5E86000A1A05 /* DatabaseFilesLiveKey.swift */; };
|
||||
9EBDF958291E6418000A1A05 /* DatabaseFilesMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF957291E6418000A1A05 /* DatabaseFilesMocks.swift */; };
|
||||
9EBDF95F291E657B000A1A05 /* DeeplinkLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF95B291E657B000A1A05 /* DeeplinkLiveKey.swift */; };
|
||||
9EBDF960291E657B000A1A05 /* DeeplinkTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF95C291E657B000A1A05 /* DeeplinkTestKey.swift */; };
|
||||
9EBDF961291E657B000A1A05 /* DeeplinkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDF95D291E657B000A1A05 /* DeeplinkInterface.swift */; };
|
||||
|
@ -222,12 +246,9 @@
|
|||
9EDDEAA22829610D00B4100C /* CurrencySelectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EDDEA9F2829610D00B4100C /* CurrencySelectionTests.swift */; };
|
||||
9EDDEAA32829610D00B4100C /* TransactionAmountInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EDDEAA02829610D00B4100C /* TransactionAmountInputTests.swift */; };
|
||||
9EDDEAA42829610D00B4100C /* TransactionAddressInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EDDEAA12829610D00B4100C /* TransactionAddressInputTests.swift */; };
|
||||
9EF1082B29114B93003D8097 /* PasteboardKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF1082A29114B93003D8097 /* PasteboardKey.swift */; };
|
||||
9EF1082D29114BCD003D8097 /* NewRecoveryPhraseKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF1082C29114BCD003D8097 /* NewRecoveryPhraseKey.swift */; };
|
||||
9EF8135C27ECC25E0075AF48 /* WalletStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */; };
|
||||
9EF8135D27ECC25E0075AF48 /* UserPreferencesStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8135B27ECC25E0075AF48 /* UserPreferencesStorageTests.swift */; };
|
||||
9EF8136027F043CC0075AF48 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8135F27F043CC0075AF48 /* AppDelegate.swift */; };
|
||||
9EF8139127F191BF0075AF48 /* WrappedWalletStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8139027F191BF0075AF48 /* WrappedWalletStorage.swift */; };
|
||||
9EF8139C27F47AED0075AF48 /* InitializationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EF8139B27F47AED0075AF48 /* InitializationState.swift */; };
|
||||
F9322DC0273B555C00C105B5 /* NavigationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9322DBF273B555C00C105B5 /* NavigationLinks.swift */; };
|
||||
F93673D62742CB840099C6AF /* Previews.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93673D52742CB840099C6AF /* Previews.swift */; };
|
||||
|
@ -341,7 +362,7 @@
|
|||
2EDA079F27EDE18C00D6F09B /* TCATextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TCATextField.swift; sourceTree = "<group>"; };
|
||||
2EDA07A127EDE1AE00D6F09B /* TextFieldFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldFooter.swift; sourceTree = "<group>"; };
|
||||
2EDA07A327EDE2A900D6F09B /* DebugFrame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugFrame.swift; sourceTree = "<group>"; };
|
||||
34429C6D28E703CD00F2B929 /* TransactionSendingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionSendingTests.swift; sourceTree = "<group>"; };
|
||||
34429C6D28E703CD00F2B929 /* TransactionSendingSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionSendingSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFreeSpaceView.swift; sourceTree = "<group>"; };
|
||||
3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFeeSpaceSnapshots.swift; sourceTree = "<group>"; };
|
||||
346715A428E2027D0035F7C4 /* CheckCircleStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircleStore.swift; sourceTree = "<group>"; };
|
||||
|
@ -366,11 +387,22 @@
|
|||
66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingProgressIndicator.swift; sourceTree = "<group>"; };
|
||||
66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtonStyle.swift; sourceTree = "<group>"; };
|
||||
66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardButtonStyle.swift; sourceTree = "<group>"; };
|
||||
9E01F8232833C0D8000EFC57 /* WrappedURIParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedURIParser.swift; sourceTree = "<group>"; };
|
||||
9E01F8272833CDA0000EFC57 /* ScanTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanTests.swift; sourceTree = "<group>"; };
|
||||
9E02B56927FED43E005B809B /* WrappedFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedFileManager.swift; sourceTree = "<group>"; };
|
||||
9E02B56927FED43E005B809B /* FileManagerInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerInterface.swift; sourceTree = "<group>"; };
|
||||
9E02B56B27FED475005B809B /* DatabaseFilesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseFilesTests.swift; sourceTree = "<group>"; };
|
||||
9E2AC10027D8EF0B0042AA47 /* WrappedMnemonic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedMnemonic.swift; sourceTree = "<group>"; };
|
||||
9E153A5B2920CD5100112F41 /* MnemonicMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicMocks.swift; sourceTree = "<group>"; };
|
||||
9E153A5C2920CD5100112F41 /* MnemonicLiveKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicLiveKey.swift; sourceTree = "<group>"; };
|
||||
9E153A5D2920CD5100112F41 /* MnemonicTestKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicTestKey.swift; sourceTree = "<group>"; };
|
||||
9E153A5E2920CD5100112F41 /* MnemonicInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicInterface.swift; sourceTree = "<group>"; };
|
||||
9E153A6429210B3B00112F41 /* PasteboardLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteboardLiveKey.swift; sourceTree = "<group>"; };
|
||||
9E153A6529210B3B00112F41 /* PasteboardInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteboardInterface.swift; sourceTree = "<group>"; };
|
||||
9E153A6629210B3B00112F41 /* PasteboardTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteboardTestKey.swift; sourceTree = "<group>"; };
|
||||
9E153A6B292167FF00112F41 /* ZcashSDKEnvironmentLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashSDKEnvironmentLiveKey.swift; sourceTree = "<group>"; };
|
||||
9E153A6C292167FF00112F41 /* ZcashSDKEnvironmentTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashSDKEnvironmentTestKey.swift; sourceTree = "<group>"; };
|
||||
9E153A6D292167FF00112F41 /* ZcashSDKEnvironmentInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashSDKEnvironmentInterface.swift; sourceTree = "<group>"; };
|
||||
9E153A7229216EFB00112F41 /* UserDefaultsLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsLiveKey.swift; sourceTree = "<group>"; };
|
||||
9E153A7329216EFB00112F41 /* UserDefaultsInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsInterface.swift; sourceTree = "<group>"; };
|
||||
9E153A7429216EFB00112F41 /* UserDefaultsTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsTestKey.swift; sourceTree = "<group>"; };
|
||||
9E2DF99827CF704D00649636 /* ImportWalletStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletStore.swift; sourceTree = "<group>"; };
|
||||
9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportSeedEditor.swift; sourceTree = "<group>"; };
|
||||
9E2DF99B27CF704D00649636 /* ImportWalletView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletView.swift; sourceTree = "<group>"; };
|
||||
|
@ -382,12 +414,8 @@
|
|||
9E39112D283F91600073DD9A /* ZatoshiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZatoshiTests.swift; sourceTree = "<group>"; };
|
||||
9E391131284644580073DD9A /* AppInitializationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInitializationTests.swift; sourceTree = "<group>"; };
|
||||
9E3911382848AD500073DD9A /* HomeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTests.swift; sourceTree = "<group>"; };
|
||||
9E39113A2848D5180073DD9A /* WrappedNumberFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedNumberFormatter.swift; sourceTree = "<group>"; };
|
||||
9E39113E2848EC350073DD9A /* WrappedRecoveryPhraseRandomizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WrappedRecoveryPhraseRandomizer.swift; sourceTree = "<group>"; };
|
||||
9E3911422848EEB90073DD9A /* RecoveryPhraseRandomizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseRandomizer.swift; sourceTree = "<group>"; };
|
||||
9E3911432848EEB90073DD9A /* URIParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIParser.swift; sourceTree = "<group>"; };
|
||||
9E3911442848EEB90073DD9A /* UserPreferencesStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserPreferencesStorage.swift; sourceTree = "<group>"; };
|
||||
9E3911452848EEB90073DD9A /* ZCashSDKEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZCashSDKEnvironment.swift; sourceTree = "<group>"; };
|
||||
9E3911462848EEB90073DD9A /* DatabaseFiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseFiles.swift; sourceTree = "<group>"; };
|
||||
9E3911472848EEB90073DD9A /* WalletStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletStorage.swift; sourceTree = "<group>"; };
|
||||
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = "<group>"; };
|
||||
|
@ -396,8 +424,7 @@
|
|||
9E5BF63E2819542C00BA3F17 /* WalletEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEventsTests.swift; sourceTree = "<group>"; };
|
||||
9E5BF640281FD7B600BA3F17 /* TransactionFailedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionFailedView.swift; sourceTree = "<group>"; };
|
||||
9E5BF643281FEC9900BA3F17 /* SendTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendTests.swift; sourceTree = "<group>"; };
|
||||
9E5BF6452821028C00BA3F17 /* WrappedUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedUserDefaults.swift; sourceTree = "<group>"; };
|
||||
9E5BF647282277BE00BA3F17 /* WrappedNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedNotificationCenter.swift; sourceTree = "<group>"; };
|
||||
9E5BF647282277BE00BA3F17 /* NotificationCenterInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterInterface.swift; sourceTree = "<group>"; };
|
||||
9E5BF64D2823E94900BA3F17 /* TransactionAddressTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionAddressTextField.swift; sourceTree = "<group>"; };
|
||||
9E5BF64E2823E94900BA3F17 /* TransactionAddressTextFieldStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionAddressTextFieldStore.swift; sourceTree = "<group>"; };
|
||||
9E661229287717A900C75B70 /* HomeCircularProgressSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCircularProgressSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -410,11 +437,6 @@
|
|||
9E6713F6289BC58C00A6796F /* BalanceBreakdownStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceBreakdownStore.swift; sourceTree = "<group>"; };
|
||||
9E6713F9289BE0E100A6796F /* ClearBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearBackgroundView.swift; sourceTree = "<group>"; };
|
||||
9E69A24C27FB002800A55317 /* WelcomeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeStore.swift; sourceTree = "<group>"; };
|
||||
9E6EF2CA291287BB00CA007B /* FeedbackGeneratorKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGeneratorKey.swift; sourceTree = "<group>"; };
|
||||
9E6EF2CC2913B06300CA007B /* NumberFormatterKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormatterKey.swift; sourceTree = "<group>"; };
|
||||
9E6EF2CE2913B11A00CA007B /* SDKSynchronizerKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKSynchronizerKey.swift; sourceTree = "<group>"; };
|
||||
9E6EF2D02913B75400CA007B /* MnemonicKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicKey.swift; sourceTree = "<group>"; };
|
||||
9E6EF2D22913B79A00CA007B /* WalletStorageKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletStorageKey.swift; sourceTree = "<group>"; };
|
||||
9E7225F02889539300DF7F17 /* SettingsSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E7225F2288AB6DD00DF7F17 /* MultipleLineTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleLineTextField.swift; sourceTree = "<group>"; };
|
||||
9E7225F5288AC71A00DF7F17 /* MultiLineTextFieldStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiLineTextFieldStore.swift; sourceTree = "<group>"; };
|
||||
|
@ -428,8 +450,6 @@
|
|||
9E7FE0D2282D274E00C374E8 /* Date+Readable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Readable.swift"; sourceTree = "<group>"; };
|
||||
9E7FE0D4282D281800C374E8 /* Array+Chunked.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Chunked.swift"; sourceTree = "<group>"; };
|
||||
9E7FE0D6282D286500C374E8 /* RecoveryPhrase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhrase.swift; sourceTree = "<group>"; };
|
||||
9E7FE0D8282D289B00C374E8 /* WrappedFeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedFeedbackGenerator.swift; sourceTree = "<group>"; };
|
||||
9E7FE0DA282D28F100C374E8 /* WrappedPasteboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedPasteboard.swift; sourceTree = "<group>"; };
|
||||
9E7FE0DC282D298900C374E8 /* ValidationWord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidationWord.swift; sourceTree = "<group>"; };
|
||||
9E7FE0DE282D2DD600C374E8 /* ZcashBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZcashBadge.swift; sourceTree = "<group>"; };
|
||||
9E7FE0E5282E7B1100C374E8 /* StoredWallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredWallet.swift; sourceTree = "<group>"; };
|
||||
|
@ -449,11 +469,37 @@
|
|||
9EAB46772860A1D2002904A0 /* WalletEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEvent.swift; sourceTree = "<group>"; };
|
||||
9EAB46792861EA6A002904A0 /* TransactionRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionRowView.swift; sourceTree = "<group>"; };
|
||||
9EAFEB812805793200199FC9 /* AppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTests.swift; sourceTree = "<group>"; };
|
||||
9EAFEB83280597B700199FC9 /* WrappedSecItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedSecItem.swift; sourceTree = "<group>"; };
|
||||
9EAFEB852805A23100199FC9 /* WrappedSecItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedSecItemTests.swift; sourceTree = "<group>"; };
|
||||
9EAFEB872806E5AE00199FC9 /* WrappedSDKSynchronizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedSDKSynchronizer.swift; sourceTree = "<group>"; };
|
||||
9EAFEB83280597B700199FC9 /* SecItemInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecItemInterface.swift; sourceTree = "<group>"; };
|
||||
9EAFEB852805A23100199FC9 /* SecItemClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecItemClientTests.swift; sourceTree = "<group>"; };
|
||||
9EAFEB872806E5AE00199FC9 /* SDKSynchronizerInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKSynchronizerInterface.swift; sourceTree = "<group>"; };
|
||||
9EAFEB8D2808183D00199FC9 /* SandboxView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SandboxView.swift; sourceTree = "<group>"; };
|
||||
9EAFEB8E2808183D00199FC9 /* SandboxStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SandboxStore.swift; sourceTree = "<group>"; };
|
||||
9EB863892922CC4D003D0F8B /* FeedbackGeneratorTestKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGeneratorTestKey.swift; sourceTree = "<group>"; };
|
||||
9EB8638A2922CC4D003D0F8B /* FeedbackGeneratorInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGeneratorInterface.swift; sourceTree = "<group>"; };
|
||||
9EB8638B2922CC4D003D0F8B /* FeedbackGeneratorLiveKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGeneratorLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EB863902922D035003D0F8B /* NumberFormatterInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatterInterface.swift; sourceTree = "<group>"; };
|
||||
9EB863912922D035003D0F8B /* NumberFormatterLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatterLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EB863922922D036003D0F8B /* NumberFormatterTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatterTestKey.swift; sourceTree = "<group>"; };
|
||||
9EB863972923935B003D0F8B /* WalletStorageTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletStorageTestKey.swift; sourceTree = "<group>"; };
|
||||
9EB863982923935B003D0F8B /* WalletStorageInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletStorageInterface.swift; sourceTree = "<group>"; };
|
||||
9EB863992923935B003D0F8B /* WalletStorageLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletStorageLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EB8639F292398A8003D0F8B /* URIParserInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIParserInterface.swift; sourceTree = "<group>"; };
|
||||
9EB863A0292398A8003D0F8B /* URIParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIParser.swift; sourceTree = "<group>"; };
|
||||
9EB863A429239DCB003D0F8B /* RecoveryPhraseRandomizerTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseRandomizerTestKey.swift; sourceTree = "<group>"; };
|
||||
9EB863A529239DCB003D0F8B /* RecoveryPhraseRandomizerLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseRandomizerLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EB863A629239DCB003D0F8B /* RecoveryPhraseRandomizerInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseRandomizerInterface.swift; sourceTree = "<group>"; };
|
||||
9EB863B82923C6D7003D0F8B /* FileManagerLive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerLive.swift; sourceTree = "<group>"; };
|
||||
9EB863BA2923C6F8003D0F8B /* NotificationCenterLive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterLive.swift; sourceTree = "<group>"; };
|
||||
9EB863BC2923C704003D0F8B /* NotificationCenterTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterTest.swift; sourceTree = "<group>"; };
|
||||
9EB863BE2923C72C003D0F8B /* SecItemLive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecItemLive.swift; sourceTree = "<group>"; };
|
||||
9EB863C02923C779003D0F8B /* URIParserLive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URIParserLive.swift; sourceTree = "<group>"; };
|
||||
9EB863C22923C807003D0F8B /* URIParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URIParserTest.swift; sourceTree = "<group>"; };
|
||||
9EB863C42923C8AF003D0F8B /* FileManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerTest.swift; sourceTree = "<group>"; };
|
||||
9EB863C62923C93B003D0F8B /* UserPreferencesStorageLive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferencesStorageLive.swift; sourceTree = "<group>"; };
|
||||
9EB863C82923C953003D0F8B /* UserPreferencesStorageMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferencesStorageMocks.swift; sourceTree = "<group>"; };
|
||||
9EB863CA2923CA20003D0F8B /* SDKSynchronizerLive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKSynchronizerLive.swift; sourceTree = "<group>"; };
|
||||
9EB863CC2923CA28003D0F8B /* SDKSynchronizerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKSynchronizerTest.swift; sourceTree = "<group>"; };
|
||||
9EB863CE2923CA32003D0F8B /* SDKSynchronizerMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKSynchronizerMocks.swift; sourceTree = "<group>"; };
|
||||
9EBDF946291D75B2000A1A05 /* DiskSpaceCheckerInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskSpaceCheckerInterface.swift; sourceTree = "<group>"; };
|
||||
9EBDF948291D75BF000A1A05 /* DiskSpaceCheckerLiveKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskSpaceCheckerLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EBDF94A291D75C7000A1A05 /* DiskSpaceCheckerTestKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskSpaceCheckerTestKey.swift; sourceTree = "<group>"; };
|
||||
|
@ -461,7 +507,6 @@
|
|||
9EBDF94F291E5E86000A1A05 /* DatabaseFilesTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseFilesTestKey.swift; sourceTree = "<group>"; };
|
||||
9EBDF951291E5E86000A1A05 /* DatabaseFilesInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseFilesInterface.swift; sourceTree = "<group>"; };
|
||||
9EBDF952291E5E86000A1A05 /* DatabaseFilesLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseFilesLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EBDF957291E6418000A1A05 /* DatabaseFilesMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseFilesMocks.swift; sourceTree = "<group>"; };
|
||||
9EBDF95B291E657B000A1A05 /* DeeplinkLiveKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeeplinkLiveKey.swift; sourceTree = "<group>"; };
|
||||
9EBDF95C291E657B000A1A05 /* DeeplinkTestKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeeplinkTestKey.swift; sourceTree = "<group>"; };
|
||||
9EBDF95D291E657B000A1A05 /* DeeplinkInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeeplinkInterface.swift; sourceTree = "<group>"; };
|
||||
|
@ -486,12 +531,9 @@
|
|||
9EDDEA9F2829610D00B4100C /* CurrencySelectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrencySelectionTests.swift; sourceTree = "<group>"; };
|
||||
9EDDEAA02829610D00B4100C /* TransactionAmountInputTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionAmountInputTests.swift; sourceTree = "<group>"; };
|
||||
9EDDEAA12829610D00B4100C /* TransactionAddressInputTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionAddressInputTests.swift; sourceTree = "<group>"; };
|
||||
9EF1082A29114B93003D8097 /* PasteboardKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteboardKey.swift; sourceTree = "<group>"; };
|
||||
9EF1082C29114BCD003D8097 /* NewRecoveryPhraseKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewRecoveryPhraseKey.swift; sourceTree = "<group>"; };
|
||||
9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletStorageTests.swift; sourceTree = "<group>"; };
|
||||
9EF8135B27ECC25E0075AF48 /* UserPreferencesStorageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserPreferencesStorageTests.swift; sourceTree = "<group>"; };
|
||||
9EF8135F27F043CC0075AF48 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
9EF8139027F191BF0075AF48 /* WrappedWalletStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedWalletStorage.swift; sourceTree = "<group>"; };
|
||||
9EF8139B27F47AED0075AF48 /* InitializationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializationState.swift; sourceTree = "<group>"; };
|
||||
F9322DBF273B555C00C105B5 /* NavigationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationLinks.swift; sourceTree = "<group>"; };
|
||||
F93673D52742CB840099C6AF /* Previews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Previews.swift; sourceTree = "<group>"; };
|
||||
|
@ -616,7 +658,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
0DA13CA326C1960A00E3B610 /* Models */,
|
||||
9E02B56827FED42D005B809B /* Wrappers */,
|
||||
9E7FE0BB282D1DC200C374E8 /* Utils */,
|
||||
9E7FE0BD282D1DE100C374E8 /* Dependencies */,
|
||||
6654C73B2715A3F000901167 /* Features */,
|
||||
|
@ -798,7 +839,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
346715A728E20FE40035F7C4 /* TransactionConfirmationSnapshotTests.swift */,
|
||||
34429C6D28E703CD00F2B929 /* TransactionSendingTests.swift */,
|
||||
34429C6D28E703CD00F2B929 /* TransactionSendingSnapshotTests.swift */,
|
||||
);
|
||||
path = SendSnapshotTests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -912,23 +953,45 @@
|
|||
path = ScanTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E02B56827FED42D005B809B /* Wrappers */ = {
|
||||
9E153A5A2920CCE700112F41 /* Mnemonic */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E7FE0D8282D289B00C374E8 /* WrappedFeedbackGenerator.swift */,
|
||||
9E02B56927FED43E005B809B /* WrappedFileManager.swift */,
|
||||
9E2AC10027D8EF0B0042AA47 /* WrappedMnemonic.swift */,
|
||||
9E5BF647282277BE00BA3F17 /* WrappedNotificationCenter.swift */,
|
||||
9E39113A2848D5180073DD9A /* WrappedNumberFormatter.swift */,
|
||||
9E7FE0DA282D28F100C374E8 /* WrappedPasteboard.swift */,
|
||||
9E39113E2848EC350073DD9A /* WrappedRecoveryPhraseRandomizer.swift */,
|
||||
9EAFEB872806E5AE00199FC9 /* WrappedSDKSynchronizer.swift */,
|
||||
9EAFEB83280597B700199FC9 /* WrappedSecItem.swift */,
|
||||
9E01F8232833C0D8000EFC57 /* WrappedURIParser.swift */,
|
||||
9E5BF6452821028C00BA3F17 /* WrappedUserDefaults.swift */,
|
||||
9EF8139027F191BF0075AF48 /* WrappedWalletStorage.swift */,
|
||||
9E153A5E2920CD5100112F41 /* MnemonicInterface.swift */,
|
||||
9E153A5C2920CD5100112F41 /* MnemonicLiveKey.swift */,
|
||||
9E153A5D2920CD5100112F41 /* MnemonicTestKey.swift */,
|
||||
9E153A5B2920CD5100112F41 /* MnemonicMocks.swift */,
|
||||
);
|
||||
path = Wrappers;
|
||||
path = Mnemonic;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E153A6329210AF800112F41 /* Pasteboard */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E153A6529210B3B00112F41 /* PasteboardInterface.swift */,
|
||||
9E153A6429210B3B00112F41 /* PasteboardLiveKey.swift */,
|
||||
9E153A6629210B3B00112F41 /* PasteboardTestKey.swift */,
|
||||
);
|
||||
path = Pasteboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E153A6A292167BF00112F41 /* ZcashSDKEnvironment */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E153A6D292167FF00112F41 /* ZcashSDKEnvironmentInterface.swift */,
|
||||
9E153A6B292167FF00112F41 /* ZcashSDKEnvironmentLiveKey.swift */,
|
||||
9E153A6C292167FF00112F41 /* ZcashSDKEnvironmentTestKey.swift */,
|
||||
);
|
||||
path = ZcashSDKEnvironment;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E153A7129216EBD00112F41 /* UserDefaults */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E153A7329216EFB00112F41 /* UserDefaultsInterface.swift */,
|
||||
9E153A7229216EFB00112F41 /* UserDefaultsLiveKey.swift */,
|
||||
9E153A7429216EFB00112F41 /* UserDefaultsTestKey.swift */,
|
||||
);
|
||||
path = UserDefaults;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E2DF99727CF704D00649636 /* ImportWallet */ = {
|
||||
|
@ -1167,19 +1230,21 @@
|
|||
9EBDF959291E654F000A1A05 /* Deeplink */,
|
||||
9EBDF971291F79C9000A1A05 /* DerivationTool */,
|
||||
9EBDF945291D759B000A1A05 /* DiskSpaceChecker */,
|
||||
9EB863882922CC0E003D0F8B /* FeedbackGenerator */,
|
||||
9EB863B52923C4ED003D0F8B /* FileManager */,
|
||||
9EBDF981291F91B1000A1A05 /* LocalAuthentication */,
|
||||
9E3911422848EEB90073DD9A /* RecoveryPhraseRandomizer.swift */,
|
||||
9E3911432848EEB90073DD9A /* URIParser.swift */,
|
||||
9E3911442848EEB90073DD9A /* UserPreferencesStorage.swift */,
|
||||
9E3911472848EEB90073DD9A /* WalletStorage.swift */,
|
||||
9E3911452848EEB90073DD9A /* ZCashSDKEnvironment.swift */,
|
||||
9E6EF2D02913B75400CA007B /* MnemonicKey.swift */,
|
||||
9E6EF2D22913B79A00CA007B /* WalletStorageKey.swift */,
|
||||
9EF1082A29114B93003D8097 /* PasteboardKey.swift */,
|
||||
9EF1082C29114BCD003D8097 /* NewRecoveryPhraseKey.swift */,
|
||||
9E6EF2CA291287BB00CA007B /* FeedbackGeneratorKey.swift */,
|
||||
9E6EF2CC2913B06300CA007B /* NumberFormatterKey.swift */,
|
||||
9E6EF2CE2913B11A00CA007B /* SDKSynchronizerKey.swift */,
|
||||
9E153A5A2920CCE700112F41 /* Mnemonic */,
|
||||
9EB863B42923C490003D0F8B /* NotificationCenter */,
|
||||
9EB8638F2922D000003D0F8B /* NumberFormatter */,
|
||||
9E153A6329210AF800112F41 /* Pasteboard */,
|
||||
9EB863A329239D95003D0F8B /* RecoveryPhraseRandomizer */,
|
||||
9EB863B62923C539003D0F8B /* SDKSynchronizer */,
|
||||
9EB863B32923C465003D0F8B /* SecItem */,
|
||||
9EB8639E29239891003D0F8B /* URIParser */,
|
||||
9E153A7129216EBD00112F41 /* UserDefaults */,
|
||||
9EB863B72923C55A003D0F8B /* UserPreferencesStorage */,
|
||||
9EB86396292392F6003D0F8B /* WalletStorage */,
|
||||
9E153A6A292167BF00112F41 /* ZcashSDKEnvironment */,
|
||||
);
|
||||
path = Dependencies;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1360,6 +1425,109 @@
|
|||
path = Sandbox;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863882922CC0E003D0F8B /* FeedbackGenerator */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EB8638A2922CC4D003D0F8B /* FeedbackGeneratorInterface.swift */,
|
||||
9EB8638B2922CC4D003D0F8B /* FeedbackGeneratorLiveKey.swift */,
|
||||
9EB863892922CC4D003D0F8B /* FeedbackGeneratorTestKey.swift */,
|
||||
);
|
||||
path = FeedbackGenerator;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB8638F2922D000003D0F8B /* NumberFormatter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EB863902922D035003D0F8B /* NumberFormatterInterface.swift */,
|
||||
9EB863912922D035003D0F8B /* NumberFormatterLiveKey.swift */,
|
||||
9EB863922922D036003D0F8B /* NumberFormatterTestKey.swift */,
|
||||
);
|
||||
path = NumberFormatter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB86396292392F6003D0F8B /* WalletStorage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E3911472848EEB90073DD9A /* WalletStorage.swift */,
|
||||
9EB863982923935B003D0F8B /* WalletStorageInterface.swift */,
|
||||
9EB863992923935B003D0F8B /* WalletStorageLiveKey.swift */,
|
||||
9EB863972923935B003D0F8B /* WalletStorageTestKey.swift */,
|
||||
);
|
||||
path = WalletStorage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB8639E29239891003D0F8B /* URIParser */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EB863A0292398A8003D0F8B /* URIParser.swift */,
|
||||
9EB8639F292398A8003D0F8B /* URIParserInterface.swift */,
|
||||
9EB863C02923C779003D0F8B /* URIParserLive.swift */,
|
||||
9EB863C22923C807003D0F8B /* URIParserTest.swift */,
|
||||
);
|
||||
path = URIParser;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863A329239D95003D0F8B /* RecoveryPhraseRandomizer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E3911422848EEB90073DD9A /* RecoveryPhraseRandomizer.swift */,
|
||||
9EB863A629239DCB003D0F8B /* RecoveryPhraseRandomizerInterface.swift */,
|
||||
9EB863A529239DCB003D0F8B /* RecoveryPhraseRandomizerLiveKey.swift */,
|
||||
9EB863A429239DCB003D0F8B /* RecoveryPhraseRandomizerTestKey.swift */,
|
||||
);
|
||||
path = RecoveryPhraseRandomizer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863B32923C465003D0F8B /* SecItem */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EAFEB83280597B700199FC9 /* SecItemInterface.swift */,
|
||||
9EB863BE2923C72C003D0F8B /* SecItemLive.swift */,
|
||||
);
|
||||
path = SecItem;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863B42923C490003D0F8B /* NotificationCenter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E5BF647282277BE00BA3F17 /* NotificationCenterInterface.swift */,
|
||||
9EB863BA2923C6F8003D0F8B /* NotificationCenterLive.swift */,
|
||||
9EB863BC2923C704003D0F8B /* NotificationCenterTest.swift */,
|
||||
);
|
||||
path = NotificationCenter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863B52923C4ED003D0F8B /* FileManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E02B56927FED43E005B809B /* FileManagerInterface.swift */,
|
||||
9EB863B82923C6D7003D0F8B /* FileManagerLive.swift */,
|
||||
9EB863C42923C8AF003D0F8B /* FileManagerTest.swift */,
|
||||
);
|
||||
path = FileManager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863B62923C539003D0F8B /* SDKSynchronizer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EAFEB872806E5AE00199FC9 /* SDKSynchronizerInterface.swift */,
|
||||
9EB863CA2923CA20003D0F8B /* SDKSynchronizerLive.swift */,
|
||||
9EB863CC2923CA28003D0F8B /* SDKSynchronizerTest.swift */,
|
||||
9EB863CE2923CA32003D0F8B /* SDKSynchronizerMocks.swift */,
|
||||
);
|
||||
path = SDKSynchronizer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EB863B72923C55A003D0F8B /* UserPreferencesStorage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E3911442848EEB90073DD9A /* UserPreferencesStorage.swift */,
|
||||
9EB863C62923C93B003D0F8B /* UserPreferencesStorageLive.swift */,
|
||||
9EB863C82923C953003D0F8B /* UserPreferencesStorageMocks.swift */,
|
||||
);
|
||||
path = UserPreferencesStorage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EBDF945291D759B000A1A05 /* DiskSpaceChecker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1379,7 +1547,6 @@
|
|||
9EBDF951291E5E86000A1A05 /* DatabaseFilesInterface.swift */,
|
||||
9EBDF952291E5E86000A1A05 /* DatabaseFilesLiveKey.swift */,
|
||||
9EBDF94F291E5E86000A1A05 /* DatabaseFilesTestKey.swift */,
|
||||
9EBDF957291E6418000A1A05 /* DatabaseFilesMocks.swift */,
|
||||
);
|
||||
path = DatabaseFiles;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1451,7 +1618,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
9EF8135A27ECC25E0075AF48 /* WalletStorageTests.swift */,
|
||||
9EAFEB852805A23100199FC9 /* WrappedSecItemTests.swift */,
|
||||
9EAFEB852805A23100199FC9 /* SecItemClientTests.swift */,
|
||||
9EF8135B27ECC25E0075AF48 /* UserPreferencesStorageTests.swift */,
|
||||
9E02B56B27FED475005B809B /* DatabaseFilesTests.swift */,
|
||||
9E39112D283F91600073DD9A /* ZatoshiTests.swift */,
|
||||
|
@ -1785,14 +1952,17 @@
|
|||
9EBDF975291F79F9000A1A05 /* DerivationToolInterface.swift in Sources */,
|
||||
660558F8270C862F009D6954 /* XCAssets+Generated.swift in Sources */,
|
||||
9EAFEB902808183D00199FC9 /* SandboxStore.swift in Sources */,
|
||||
9EB863A929239DCB003D0F8B /* RecoveryPhraseRandomizerInterface.swift in Sources */,
|
||||
0D35CC46277A36E00074316A /* ScrollableWhenScaled.swift in Sources */,
|
||||
9E39114A2848EEB90073DD9A /* UserPreferencesStorage.swift in Sources */,
|
||||
9E153A612920CE2700112F41 /* MnemonicMocks.swift in Sources */,
|
||||
34DA414728E4385800F8CC61 /* TransactionSendingView.swift in Sources */,
|
||||
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */,
|
||||
9EBDF96E291ECED4000A1A05 /* CaptureDeviceLiveKey.swift in Sources */,
|
||||
9EBDF968291ECDA2000A1A05 /* AudioServicesInterface.swift in Sources */,
|
||||
9EB863BD2923C704003D0F8B /* NotificationCenterTest.swift in Sources */,
|
||||
9EB863A829239DCB003D0F8B /* RecoveryPhraseRandomizerLiveKey.swift in Sources */,
|
||||
2EDA07A027EDE18C00D6F09B /* TCATextField.swift in Sources */,
|
||||
9E7FE0DB282D28F100C374E8 /* WrappedPasteboard.swift in Sources */,
|
||||
9EBDF961291E657B000A1A05 /* DeeplinkInterface.swift in Sources */,
|
||||
9EBDF977291F79F9000A1A05 /* DerivationToolTestKey.swift in Sources */,
|
||||
2EB7758727FC67FD00269373 /* TransactionAmountTextFieldStore.swift in Sources */,
|
||||
|
@ -1801,29 +1971,30 @@
|
|||
9EBDF960291E657B000A1A05 /* DeeplinkTestKey.swift in Sources */,
|
||||
34E0AF1128DEE5220034CF37 /* Wedge.swift in Sources */,
|
||||
F96B41E8273B501F0021B49A /* TransactionDetailView.swift in Sources */,
|
||||
9EB863942922D036003D0F8B /* NumberFormatterLiveKey.swift in Sources */,
|
||||
9EBDF947291D75B2000A1A05 /* DiskSpaceCheckerInterface.swift in Sources */,
|
||||
9E02B56A27FED43E005B809B /* WrappedFileManager.swift in Sources */,
|
||||
9E02B56A27FED43E005B809B /* FileManagerInterface.swift in Sources */,
|
||||
663FABA2271D876C00E495F8 /* SecondaryButton.swift in Sources */,
|
||||
9E7CB6202874143800A02233 /* AddressDetailsStore.swift in Sources */,
|
||||
9E6EF2D12913B75400CA007B /* MnemonicKey.swift in Sources */,
|
||||
0DC487C32772574C00BE6A63 /* RecoveryPhraseBackupSucceededView.swift in Sources */,
|
||||
2EB1C5E827D77F6100BC43D7 /* TCATextFieldStore.swift in Sources */,
|
||||
9E5BF648282277BE00BA3F17 /* WrappedNotificationCenter.swift in Sources */,
|
||||
9EF1082D29114BCD003D8097 /* NewRecoveryPhraseKey.swift in Sources */,
|
||||
9E5BF648282277BE00BA3F17 /* NotificationCenterInterface.swift in Sources */,
|
||||
0D8A43C4272AEEDE005A6414 /* SecantTextStyles.swift in Sources */,
|
||||
9E5BF641281FD7B600BA3F17 /* TransactionFailedView.swift in Sources */,
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */,
|
||||
0DACFA7F27208CE00039EEA5 /* Clamped.swift in Sources */,
|
||||
9EAB467A2861EA6A002904A0 /* TransactionRowView.swift in Sources */,
|
||||
9E6EF2CB291287BB00CA007B /* FeedbackGeneratorKey.swift in Sources */,
|
||||
9EB8638C2922CD4A003D0F8B /* FeedbackGeneratorTestKey.swift in Sources */,
|
||||
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidationFlowStore.swift in Sources */,
|
||||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */,
|
||||
9EBDF967291ECDA2000A1A05 /* AudioServicesTestKey.swift in Sources */,
|
||||
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
|
||||
9EBDF97E291F7EB0000A1A05 /* AppVersionInterface.swift in Sources */,
|
||||
6654C73E2715A41300901167 /* OnboardingFlowStore.swift in Sources */,
|
||||
9E7FE0D9282D289B00C374E8 /* WrappedFeedbackGenerator.swift in Sources */,
|
||||
9EB863CB2923CA20003D0F8B /* SDKSynchronizerLive.swift in Sources */,
|
||||
9EB863A1292398A8003D0F8B /* URIParserInterface.swift in Sources */,
|
||||
2E6CF8DD27D78319004DCD7A /* CurrencySelectionStore.swift in Sources */,
|
||||
9E153A7729216EFB00112F41 /* UserDefaultsTestKey.swift in Sources */,
|
||||
9EBEF87A27CE369800B4F343 /* RecoveryPhraseValidationFlowView.swift in Sources */,
|
||||
9E6713F7289BC58C00A6796F /* BalanceBreakdownStore.swift in Sources */,
|
||||
9E66122C2877188700C75B70 /* SyncStatusSnapshot.swift in Sources */,
|
||||
|
@ -1834,28 +2005,34 @@
|
|||
9EBDF986291F91EF000A1A05 /* LocalAuthenticationLiveKey.swift in Sources */,
|
||||
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */,
|
||||
F9971A5327680DD000A2DB75 /* ProfileStore.swift in Sources */,
|
||||
9E39114D2848EEB90073DD9A /* WalletStorage.swift in Sources */,
|
||||
346D41E428DF0B8600963F36 /* CheckCircle.swift in Sources */,
|
||||
9EB863AA29239EB2003D0F8B /* RecoveryPhraseRandomizer.swift in Sources */,
|
||||
9EB863C52923C8AF003D0F8B /* FileManagerTest.swift in Sources */,
|
||||
9EB863BF2923C72C003D0F8B /* SecItemLive.swift in Sources */,
|
||||
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */,
|
||||
9E39113B2848D5180073DD9A /* WrappedNumberFormatter.swift in Sources */,
|
||||
9EB863B92923C6D7003D0F8B /* FileManagerLive.swift in Sources */,
|
||||
9EBDF97C291F7EB0000A1A05 /* AppVersionTestKey.swift in Sources */,
|
||||
2E8719CD27FB0D3B0082C926 /* CurrencySelectionView.swift in Sources */,
|
||||
9EB863A729239DCB003D0F8B /* RecoveryPhraseRandomizerTestKey.swift in Sources */,
|
||||
F9971A6C27680E1000A2DB75 /* WalletInfoView.swift in Sources */,
|
||||
9E5BF6502823E94900BA3F17 /* TransactionAddressTextFieldStore.swift in Sources */,
|
||||
9EB863932922D036003D0F8B /* NumberFormatterInterface.swift in Sources */,
|
||||
F9EEB8162742C2210032EEB8 /* WithStateBinding.swift in Sources */,
|
||||
9E7FE0D3282D274E00C374E8 /* Date+Readable.swift in Sources */,
|
||||
F93673D62742CB840099C6AF /* Previews.swift in Sources */,
|
||||
9EB8638E2922CD4A003D0F8B /* FeedbackGeneratorInterface.swift in Sources */,
|
||||
0D18581B272728D60046B928 /* PhraseChip.swift in Sources */,
|
||||
9E7FE0F92832824C00C374E8 /* QRCodeScanView.swift in Sources */,
|
||||
9E3911482848EEB90073DD9A /* RecoveryPhraseRandomizer.swift in Sources */,
|
||||
9E153A6F292167FF00112F41 /* ZcashSDKEnvironmentTestKey.swift in Sources */,
|
||||
0DF482BA2787ADA800EB37D6 /* ConditionalModifier.swift in Sources */,
|
||||
9E7225F3288AB6DD00DF7F17 /* MultipleLineTextField.swift in Sources */,
|
||||
3448CB3228E47666006ADEDB /* NotEnoughFreeSpaceView.swift in Sources */,
|
||||
9EBDF985291F91EF000A1A05 /* LocalAuthenticationHandlerInterface.swift in Sources */,
|
||||
9E7FE0EC282E7D9400C374E8 /* TransactionState.swift in Sources */,
|
||||
9EB863CD2923CA28003D0F8B /* SDKSynchronizerTest.swift in Sources */,
|
||||
9E2F1C8F280EDE09004E65FE /* Drawer.swift in Sources */,
|
||||
665C963F272C26E600BC04FB /* CircularFrameBackground.swift in Sources */,
|
||||
9EAFEB882806E5AE00199FC9 /* WrappedSDKSynchronizer.swift in Sources */,
|
||||
9EAFEB882806E5AE00199FC9 /* SDKSynchronizerInterface.swift in Sources */,
|
||||
0DB8AA81271DC7520035BC9D /* DesignGuide.swift in Sources */,
|
||||
F9971A4D27680DC400A2DB75 /* AppStore.swift in Sources */,
|
||||
9EAFEB9228081E9400199FC9 /* HomeView.swift in Sources */,
|
||||
|
@ -1863,29 +2040,31 @@
|
|||
9EAFEB8F2808183D00199FC9 /* SandboxView.swift in Sources */,
|
||||
0D7CE63427349B5D0020E050 /* View+WhenDraggable.swift in Sources */,
|
||||
0D3D04082728B3440032ABC1 /* RecoveryPhraseDisplayView.swift in Sources */,
|
||||
9EBDF958291E6418000A1A05 /* DatabaseFilesMocks.swift in Sources */,
|
||||
9EB863A2292398A8003D0F8B /* URIParser.swift in Sources */,
|
||||
9EB863C12923C779003D0F8B /* URIParserLive.swift in Sources */,
|
||||
9EBDF987291F91EF000A1A05 /* LocalAuthenticationTestKey.swift in Sources */,
|
||||
F9971A5F27680DF600A2DB75 /* ScanView.swift in Sources */,
|
||||
9E39114C2848EEB90073DD9A /* DatabaseFiles.swift in Sources */,
|
||||
F9971A4E27680DC400A2DB75 /* AppView.swift in Sources */,
|
||||
9E3911492848EEB90073DD9A /* URIParser.swift in Sources */,
|
||||
9EBDF94B291D75C7000A1A05 /* DiskSpaceCheckerTestKey.swift in Sources */,
|
||||
9E153A7529216EFB00112F41 /* UserDefaultsLiveKey.swift in Sources */,
|
||||
2EA11F5B27467EF800709571 /* OnboardingFooterView.swift in Sources */,
|
||||
9EBDF96F291ECED4000A1A05 /* CaptureDeviceTestKey.swift in Sources */,
|
||||
9EBDF949291D75BF000A1A05 /* DiskSpaceCheckerLiveKey.swift in Sources */,
|
||||
66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */,
|
||||
9E7225F6288AC71A00DF7F17 /* MultiLineTextFieldStore.swift in Sources */,
|
||||
2EDA07A427EDE2A900D6F09B /* DebugFrame.swift in Sources */,
|
||||
9E6EF2CF2913B11A00CA007B /* SDKSynchronizerKey.swift in Sources */,
|
||||
9E153A602920CE2700112F41 /* MnemonicLiveKey.swift in Sources */,
|
||||
9E6612332878338C00C75B70 /* LottieAnimation.swift in Sources */,
|
||||
9EB863C92923C953003D0F8B /* UserPreferencesStorageMocks.swift in Sources */,
|
||||
0D3D040A2728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift in Sources */,
|
||||
9EAB4671285A1C77002904A0 /* Deeplink.swift in Sources */,
|
||||
9E2AC10127D8EF0B0042AA47 /* WrappedMnemonic.swift in Sources */,
|
||||
9E7FE0D7282D286500C374E8 /* RecoveryPhrase.swift in Sources */,
|
||||
9EBDF989291F9428000A1A05 /* LocalAuthenticationMocks.swift in Sources */,
|
||||
660558F7270C862F009D6954 /* Fonts+Generated.swift in Sources */,
|
||||
F96B41E7273B501F0021B49A /* WalletEventsFlowStore.swift in Sources */,
|
||||
9E7FE0E6282E7B1100C374E8 /* StoredWallet.swift in Sources */,
|
||||
9E153A7629216EFB00112F41 /* UserDefaultsInterface.swift in Sources */,
|
||||
9EAFEB9128081E9400199FC9 /* HomeStore.swift in Sources */,
|
||||
9EBDF980291F8261000A1A05 /* AppVersionMocks.swift in Sources */,
|
||||
F9971A5A27680DDE00A2DB75 /* RequestView.swift in Sources */,
|
||||
|
@ -1896,18 +2075,21 @@
|
|||
9EBDF966291ECDA2000A1A05 /* AudioServicesLiveKey.swift in Sources */,
|
||||
F9C165BF2740403600592F76 /* SendFlowStore.swift in Sources */,
|
||||
0D4E7A0926B364170058B01E /* SecantApp.swift in Sources */,
|
||||
9EB863BB2923C6F8003D0F8B /* NotificationCenterLive.swift in Sources */,
|
||||
9EB8639C2923935B003D0F8B /* WalletStorageLiveKey.swift in Sources */,
|
||||
9EB8639B2923935B003D0F8B /* WalletStorageInterface.swift in Sources */,
|
||||
66DC733F271D88CC0053CBB6 /* StandardButtonStyle.swift in Sources */,
|
||||
663FABA0271D876200E495F8 /* PrimaryButton.swift in Sources */,
|
||||
663FAB9C271D874D00E495F8 /* ActiveButton.swift in Sources */,
|
||||
9EBDF956291E5E86000A1A05 /* DatabaseFilesLiveKey.swift in Sources */,
|
||||
9E2F1C842809B606004E65FE /* DebugMenu.swift in Sources */,
|
||||
9E153A5F2920CE2700112F41 /* MnemonicInterface.swift in Sources */,
|
||||
9E153A6729210B3B00112F41 /* PasteboardLiveKey.swift in Sources */,
|
||||
34E0AF0F28DEE4C70034CF37 /* HoldToSendButton.swift in Sources */,
|
||||
F9C165C02740403600592F76 /* TransactionConfirmationView.swift in Sources */,
|
||||
0DF2DC5427235E3E00FA31E2 /* View+InnerShadow.swift in Sources */,
|
||||
9E6EF2CD2913B06300CA007B /* NumberFormatterKey.swift in Sources */,
|
||||
9E39113F2848EC360073DD9A /* WrappedRecoveryPhraseRandomizer.swift in Sources */,
|
||||
9EAFEB84280597B700199FC9 /* WrappedSecItem.swift in Sources */,
|
||||
9E5BF6462821028C00BA3F17 /* WrappedUserDefaults.swift in Sources */,
|
||||
9E153A70292167FF00112F41 /* ZcashSDKEnvironmentInterface.swift in Sources */,
|
||||
9EAFEB84280597B700199FC9 /* SecItemInterface.swift in Sources */,
|
||||
F9971A6B27680E1000A2DB75 /* WalletInfoStore.swift in Sources */,
|
||||
9EBDF953291E5E86000A1A05 /* DatabaseFilesTestKey.swift in Sources */,
|
||||
9E7FE0F628327F6F00C374E8 /* ScanUIView.swift in Sources */,
|
||||
|
@ -1921,40 +2103,46 @@
|
|||
0D8A43C6272B129C005A6414 /* WordChipGrid.swift in Sources */,
|
||||
66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */,
|
||||
9EBDF96D291ECED4000A1A05 /* CaptureDeviceInterface.swift in Sources */,
|
||||
9EB8638D2922CD4A003D0F8B /* FeedbackGeneratorLiveKey.swift in Sources */,
|
||||
0D7DF08C271DCC0E00530046 /* ScreenBackground.swift in Sources */,
|
||||
9E01F8242833C0D8000EFC57 /* WrappedURIParser.swift in Sources */,
|
||||
346715A528E2027D0035F7C4 /* CheckCircleStore.swift in Sources */,
|
||||
9EF1082B29114B93003D8097 /* PasteboardKey.swift in Sources */,
|
||||
F9C165C22740403600592F76 /* CreateTransactionView.swift in Sources */,
|
||||
9EBDF955291E5E86000A1A05 /* DatabaseFilesInterface.swift in Sources */,
|
||||
9EBDF976291F79F9000A1A05 /* DerivationToolLiveKey.swift in Sources */,
|
||||
F9C165B4274031F600592F76 /* Bindings.swift in Sources */,
|
||||
2E35F99A27B3E99C00EB79CD /* TextFieldTitleAccessoryButtonStyle.swift in Sources */,
|
||||
9E153A6929210B3B00112F41 /* PasteboardTestKey.swift in Sources */,
|
||||
9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */,
|
||||
9E6713F8289BC58C00A6796F /* BalanceBreakdownView.swift in Sources */,
|
||||
F9971A6627680DFE00A2DB75 /* SettingsView.swift in Sources */,
|
||||
F96B41EB273B50520021B49A /* Strings.swift in Sources */,
|
||||
9EB863D02923D3FC003D0F8B /* SDKSynchronizerMocks.swift in Sources */,
|
||||
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */,
|
||||
F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */,
|
||||
F9971A6027680DF600A2DB75 /* ScanStore.swift in Sources */,
|
||||
9EF8139127F191BF0075AF48 /* WrappedWalletStorage.swift in Sources */,
|
||||
9EB863952922D036003D0F8B /* NumberFormatterTestKey.swift in Sources */,
|
||||
9EAB46782860A1D2002904A0 /* WalletEvent.swift in Sources */,
|
||||
9EB8639D29239405003D0F8B /* WalletStorage.swift in Sources */,
|
||||
0DFE93E1272C9ECB000FCCA5 /* RecoveryPhraseBackupView.swift in Sources */,
|
||||
9E153A622920CE2700112F41 /* MnemonicTestKey.swift in Sources */,
|
||||
9E69A24D27FB002800A55317 /* WelcomeStore.swift in Sources */,
|
||||
9EB863C32923C807003D0F8B /* URIParserTest.swift in Sources */,
|
||||
9E153A6829210B3B00112F41 /* PasteboardInterface.swift in Sources */,
|
||||
F9C165CB2741AB5D00592F76 /* SendFlowView.swift in Sources */,
|
||||
9E7FE0DD282D298900C374E8 /* ValidationWord.swift in Sources */,
|
||||
9E39114B2848EEB90073DD9A /* ZCashSDKEnvironment.swift in Sources */,
|
||||
9EB8639A2923935B003D0F8B /* WalletStorageTestKey.swift in Sources */,
|
||||
0D0781C4278750E30083ACD7 /* WelcomeView.swift in Sources */,
|
||||
9EBDF95F291E657B000A1A05 /* DeeplinkLiveKey.swift in Sources */,
|
||||
F9971A6527680DFE00A2DB75 /* SettingsStore.swift in Sources */,
|
||||
9EF8139C27F47AED0075AF48 /* InitializationState.swift in Sources */,
|
||||
0D0781C9278776D20083ACD7 /* ZcashSymbol.swift in Sources */,
|
||||
9EB863C72923C93B003D0F8B /* UserPreferencesStorageLive.swift in Sources */,
|
||||
2E8719CB27FB09990082C926 /* TransactionAmountTextField.swift in Sources */,
|
||||
9E6EF2D32913B79A00CA007B /* WalletStorageKey.swift in Sources */,
|
||||
9E7CB6212874143800A02233 /* AddressDetailsView.swift in Sources */,
|
||||
9E6713FA289BE0E100A6796F /* ClearBackgroundView.swift in Sources */,
|
||||
34E5F2F328E46DB700C17E5F /* DiskSpaceChecker.swift in Sources */,
|
||||
F9C165C42740403600592F76 /* TransactionSentView.swift in Sources */,
|
||||
9E153A6E292167FF00112F41 /* ZcashSDKEnvironmentLiveKey.swift in Sources */,
|
||||
F9971A5927680DDE00A2DB75 /* RequestStore.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1972,14 +2160,14 @@
|
|||
9EDDEAA42829610D00B4100C /* TransactionAddressInputTests.swift in Sources */,
|
||||
9E7CB6272874269F00A02233 /* ProfileSnapshotTests.swift in Sources */,
|
||||
9E92AF0828530EBF007367AD /* View+UIImage.swift in Sources */,
|
||||
34429C6E28E703CD00F2B929 /* TransactionSendingTests.swift in Sources */,
|
||||
34429C6E28E703CD00F2B929 /* TransactionSendingSnapshotTests.swift in Sources */,
|
||||
6654C7442715A4AC00901167 /* OnboardingStoreTests.swift in Sources */,
|
||||
9E94C62328AA7EE0008256E9 /* BalanceBreakdownSnapshotTests.swift in Sources */,
|
||||
9E39112E283F91600073DD9A /* ZatoshiTests.swift in Sources */,
|
||||
9E9ECC9B28589E150099D5A2 /* ImportWalletSnapshotTests.swift in Sources */,
|
||||
9EDDEAA32829610D00B4100C /* TransactionAmountInputTests.swift in Sources */,
|
||||
9E7CB6242874246800A02233 /* ProfileTests.swift in Sources */,
|
||||
9EAFEB862805A23100199FC9 /* WrappedSecItemTests.swift in Sources */,
|
||||
9EAFEB862805A23100199FC9 /* SecItemClientTests.swift in Sources */,
|
||||
3448CB3728E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift in Sources */,
|
||||
9E9ECC9828589E150099D5A2 /* WelcomeSnapshotTests.swift in Sources */,
|
||||
9E7CB6122869882D00A02233 /* WalletEventsSnapshotTests.swift in Sources */,
|
||||
|
|
|
@ -16,7 +16,7 @@ extension CaptureDeviceClient: TestDependencyKey {
|
|||
}
|
||||
|
||||
extension CaptureDeviceClient {
|
||||
static let noop = Self(
|
||||
static let noOp = Self(
|
||||
isTorchAvailable: { false },
|
||||
torch: { _ in }
|
||||
)
|
||||
|
|
|
@ -20,9 +20,9 @@ struct DatabaseFiles {
|
|||
case filesPresentCheck
|
||||
}
|
||||
|
||||
private let fileManager: WrappedFileManager
|
||||
private let fileManager: FileManagerClient
|
||||
|
||||
init(fileManager: WrappedFileManager) {
|
||||
init(fileManager: FileManagerClient) {
|
||||
self.fileManager = fileManager
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,6 @@ struct DatabaseFilesClient {
|
|||
let outputParamsURLFor: (ZcashNetwork) throws -> URL
|
||||
let pendingDbURLFor: (ZcashNetwork) throws -> URL
|
||||
let spendParamsURLFor: (ZcashNetwork) throws -> URL
|
||||
let areDbFilesPresentFor: (ZcashNetwork) throws -> Bool
|
||||
var areDbFilesPresentFor: (ZcashNetwork) throws -> Bool
|
||||
let nukeDbFilesFor: (ZcashNetwork) throws -> Void
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// DatabaseFilesMocks.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2022.
|
||||
//
|
||||
|
||||
extension DatabaseFilesClient {
|
||||
static let throwing = DatabaseFilesClient(
|
||||
documentsDirectory: {
|
||||
throw DatabaseFiles.DatabaseFilesError.getDocumentsURL
|
||||
},
|
||||
cacheDbURLFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.getCacheURL
|
||||
},
|
||||
dataDbURLFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.getDataURL
|
||||
},
|
||||
outputParamsURLFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.getOutputParamsURL
|
||||
},
|
||||
pendingDbURLFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.getPendingURL
|
||||
},
|
||||
spendParamsURLFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.getSpendParamsURL
|
||||
},
|
||||
areDbFilesPresentFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.filesPresentCheck
|
||||
},
|
||||
nukeDbFilesFor: { _ in
|
||||
throw DatabaseFiles.DatabaseFilesError.nukeFiles
|
||||
}
|
||||
)
|
||||
}
|
|
@ -5,18 +5,38 @@
|
|||
// Created by Lukáš Korba on 11.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension DatabaseFilesClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
documentsDirectory: XCTUnimplemented("\(Self.self).documentsDirectory"),
|
||||
cacheDbURLFor: XCTUnimplemented("\(Self.self).cacheDbURLFor"),
|
||||
dataDbURLFor: XCTUnimplemented("\(Self.self).dataDbURLFor"),
|
||||
outputParamsURLFor: XCTUnimplemented("\(Self.self).outputParamsURLFor"),
|
||||
pendingDbURLFor: XCTUnimplemented("\(Self.self).pendingDbURLFor"),
|
||||
spendParamsURLFor: XCTUnimplemented("\(Self.self).spendParamsURLFor"),
|
||||
documentsDirectory: XCTUnimplemented("\(Self.self).documentsDirectory", placeholder: .emptyURL),
|
||||
cacheDbURLFor: XCTUnimplemented("\(Self.self).cacheDbURLFor", placeholder: .emptyURL),
|
||||
dataDbURLFor: XCTUnimplemented("\(Self.self).dataDbURLFor", placeholder: .emptyURL),
|
||||
outputParamsURLFor: XCTUnimplemented("\(Self.self).outputParamsURLFor", placeholder: .emptyURL),
|
||||
pendingDbURLFor: XCTUnimplemented("\(Self.self).pendingDbURLFor", placeholder: .emptyURL),
|
||||
spendParamsURLFor: XCTUnimplemented("\(Self.self).spendParamsURLFor", placeholder: .emptyURL),
|
||||
areDbFilesPresentFor: XCTUnimplemented("\(Self.self).areDbFilesPresentFor", placeholder: false),
|
||||
nukeDbFilesFor: XCTUnimplemented("\(Self.self).nukeDbFilesFor")
|
||||
)
|
||||
}
|
||||
|
||||
extension URL {
|
||||
/// The `DatabaseFilesClient` API returns an instance of the URL or throws an error.
|
||||
/// In order to use placeholders for the URL we need a URL instance, hence `emptyURL` and force unwrapp.
|
||||
static let emptyURL = URL(string: "http://empty.url")!// swiftlint:disable:this force_unwrapping
|
||||
}
|
||||
|
||||
extension DatabaseFilesClient {
|
||||
static let noOp = Self(
|
||||
documentsDirectory: { .emptyURL },
|
||||
cacheDbURLFor: { _ in .emptyURL },
|
||||
dataDbURLFor: { _ in .emptyURL },
|
||||
outputParamsURLFor: { _ in .emptyURL },
|
||||
pendingDbURLFor: { _ in .emptyURL },
|
||||
spendParamsURLFor: { _ in .emptyURL },
|
||||
areDbFilesPresentFor: { _ in false },
|
||||
nukeDbFilesFor: { _ in }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import ZcashLightClientKit
|
|||
extension DerivationToolClient: DependencyKey {
|
||||
static let liveValue = DerivationToolClient.live()
|
||||
|
||||
static func live(derivationTool: DerivationTool = DerivationTool(networkType: .mainnet)) -> Self {
|
||||
static func live(derivationTool: DerivationTool = DerivationTool(networkType: .testnet)) -> Self {
|
||||
Self(
|
||||
deriveViewingKeys: { seed, numberOfAccounts in
|
||||
try derivationTool.deriveViewingKeys(seed: seed, numberOfAccounts: numberOfAccounts)
|
||||
|
|
|
@ -43,7 +43,7 @@ extension DerivationToolClient {
|
|||
}
|
||||
|
||||
extension DerivationToolClient {
|
||||
static let noop = Self(
|
||||
static let noOp = Self(
|
||||
deriveViewingKeys: { _, _ in [] },
|
||||
deriveViewingKey: { _ in "" },
|
||||
deriveSpendingKeys: { _, _ in [] },
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// FeedbackGeneratorInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var feedbackGenerator: FeedbackGeneratorClient {
|
||||
get { self[FeedbackGeneratorClient.self] }
|
||||
set { self[FeedbackGeneratorClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct FeedbackGeneratorClient {
|
||||
let generateSuccessFeedback: () -> Void
|
||||
let generateWarningFeedback: () -> Void
|
||||
let generateErrorFeedback: () -> Void
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// FeedbackGeneratorLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ComposableArchitecture
|
||||
|
||||
extension FeedbackGeneratorClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
generateSuccessFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.success) },
|
||||
generateWarningFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.warning) },
|
||||
generateErrorFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.error) }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// FeedbackGeneratorTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension FeedbackGeneratorClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
generateSuccessFeedback: XCTUnimplemented("\(Self.self).generateSuccessFeedback"),
|
||||
generateWarningFeedback: XCTUnimplemented("\(Self.self).generateWarningFeedback"),
|
||||
generateErrorFeedback: XCTUnimplemented("\(Self.self).generateErrorFeedback")
|
||||
)
|
||||
}
|
||||
|
||||
extension FeedbackGeneratorClient {
|
||||
static let noOp = Self(
|
||||
generateSuccessFeedback: { },
|
||||
generateWarningFeedback: { },
|
||||
generateErrorFeedback: { }
|
||||
)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// FeedbackGeneratorKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 02.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
private enum FeedbackGeneratorKey: DependencyKey {
|
||||
static let liveValue = WrappedFeedbackGenerator.haptic
|
||||
static let testValue = WrappedFeedbackGenerator.silent
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var feedbackGenerator: WrappedFeedbackGenerator {
|
||||
get { self[FeedbackGeneratorKey.self] }
|
||||
set { self[FeedbackGeneratorKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// FileManagerClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 07.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct FileManagerClient {
|
||||
let url: (FileManager.SearchPathDirectory, FileManager.SearchPathDomainMask, URL?, Bool) throws -> URL
|
||||
let fileExists: (String) -> Bool
|
||||
let removeItem: (URL) throws -> Void
|
||||
}
|
|
@ -1,20 +1,14 @@
|
|||
//
|
||||
// WrappedFileManager.swift
|
||||
// FileManagerLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 07.04.2022.
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct WrappedFileManager {
|
||||
let url: (FileManager.SearchPathDirectory, FileManager.SearchPathDomainMask, URL?, Bool) throws -> URL
|
||||
let fileExists: (String) -> Bool
|
||||
let removeItem: (URL) throws -> Void
|
||||
}
|
||||
|
||||
extension WrappedFileManager {
|
||||
static let live = WrappedFileManager(
|
||||
extension FileManagerClient {
|
||||
static let live = FileManagerClient(
|
||||
url: { searchPathDirectory, searchPathDomainMask, appropriateForURL, shouldCreate in
|
||||
try FileManager.default.url(for: searchPathDirectory, in: searchPathDomainMask, appropriateFor: appropriateForURL, create: shouldCreate)
|
||||
},
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// FileManagerTest.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension FileManagerClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
url: XCTUnimplemented("\(Self.self).url"),
|
||||
fileExists: XCTUnimplemented("\(Self.self).fileExists", placeholder: false),
|
||||
removeItem: XCTUnimplemented("\(Self.self).removeItem")
|
||||
)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// MnemonicInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var mnemonic: MnemonicClient {
|
||||
get { self[MnemonicClient.self] }
|
||||
set { self[MnemonicClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct MnemonicClient {
|
||||
/// Random 24 words mnemonic phrase
|
||||
var randomMnemonic: () throws -> String
|
||||
/// Random 24 words mnemonic phrase as array of words
|
||||
var randomMnemonicWords: () throws -> [String]
|
||||
/// Generate deterministic seed from mnemonic phrase
|
||||
var toSeed: (String) throws -> [UInt8]
|
||||
/// Get this mnemonic phrase as array of words
|
||||
var asWords: (String) throws -> [String]
|
||||
/// Validates whether the given mnemonic is correct
|
||||
var isValid: (String) throws -> Void
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// MnemonicLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import MnemonicSwift
|
||||
|
||||
extension MnemonicClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
randomMnemonic: {
|
||||
try Mnemonic.generateMnemonic(strength: 256)
|
||||
},
|
||||
randomMnemonicWords: {
|
||||
try Mnemonic.generateMnemonic(strength: 256).components(separatedBy: " ")
|
||||
},
|
||||
toSeed: { mnemonic in
|
||||
let data = try Mnemonic.deterministicSeedBytes(from: mnemonic)
|
||||
|
||||
return [UInt8](data)
|
||||
},
|
||||
asWords: { mnemonic in
|
||||
mnemonic.components(separatedBy: " ")
|
||||
},
|
||||
isValid: { mnemonic in
|
||||
try Mnemonic.validate(mnemonic: mnemonic)
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,48 +1,14 @@
|
|||
//
|
||||
// WrappedMnemonic.swift
|
||||
// MnemonicMocks.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03/09/2022.
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MnemonicSwift
|
||||
|
||||
struct WrappedMnemonic {
|
||||
/// Random 24 words mnemonic phrase
|
||||
var randomMnemonic: () throws -> String
|
||||
/// Random 24 words mnemonic phrase as array of words
|
||||
var randomMnemonicWords: () throws -> [String]
|
||||
/// Generate deterministic seed from mnemonic phrase
|
||||
var toSeed: (String) throws -> [UInt8]
|
||||
/// Get this mnemonic phrase as array of words
|
||||
var asWords: (String) throws -> [String]
|
||||
/// Validates whether the given mnemonic is correct
|
||||
var isValid: (String) throws -> Void
|
||||
}
|
||||
|
||||
extension WrappedMnemonic {
|
||||
static let live = WrappedMnemonic(
|
||||
randomMnemonic: {
|
||||
try Mnemonic.generateMnemonic(strength: 256)
|
||||
},
|
||||
randomMnemonicWords: {
|
||||
try Mnemonic.generateMnemonic(strength: 256).components(separatedBy: " ")
|
||||
},
|
||||
toSeed: { mnemonic in
|
||||
let data = try Mnemonic.deterministicSeedBytes(from: mnemonic)
|
||||
|
||||
return [UInt8](data)
|
||||
},
|
||||
asWords: { mnemonic in
|
||||
mnemonic.components(separatedBy: " ")
|
||||
},
|
||||
isValid: { mnemonic in
|
||||
try Mnemonic.validate(mnemonic: mnemonic)
|
||||
}
|
||||
)
|
||||
|
||||
static let mock = WrappedMnemonic(
|
||||
extension MnemonicClient {
|
||||
static let mock = MnemonicClient(
|
||||
randomMnemonic: {
|
||||
"""
|
||||
still champion voice habit trend flight \
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// MnemonicTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension MnemonicClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
randomMnemonic: XCTUnimplemented("\(Self.self).randomMnemonic", placeholder: ""),
|
||||
randomMnemonicWords: XCTUnimplemented("\(Self.self).randomMnemonicWords", placeholder: []),
|
||||
toSeed: XCTUnimplemented("\(Self.self).toSeed", placeholder: []),
|
||||
asWords: XCTUnimplemented("\(Self.self).asWords", placeholder: []),
|
||||
isValid: XCTUnimplemented("\(Self.self).isValid")
|
||||
)
|
||||
}
|
||||
|
||||
extension MnemonicClient {
|
||||
static let noOp = Self(
|
||||
randomMnemonic: { "" },
|
||||
randomMnemonicWords: { [] },
|
||||
toSeed: { _ in [] },
|
||||
asWords: { _ in [] },
|
||||
isValid: { _ in }
|
||||
)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// MnemonicKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
private enum MnemonicKey: DependencyKey {
|
||||
static let liveValue = WrappedMnemonic.live
|
||||
static let testValue = WrappedMnemonic.mock
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var mnemonic: WrappedMnemonic {
|
||||
get { self[MnemonicKey.self] }
|
||||
set { self[MnemonicKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// NewRecoveryPhrase.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 01.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
// TODO: Ensure that sensitive information can't be logged intentionally or by accident #444.
|
||||
// https://github.com/zcash/secant-ios-wallet/issues/444
|
||||
private enum NewRecoveryPhraseKey: DependencyKey {
|
||||
static let liveValue = { RecoveryPhrase.init(words: RecoveryPhrase.placeholder.words) }
|
||||
static let testValue = { RecoveryPhrase.init(words: RecoveryPhrase.placeholder.words) }
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var newRecoveryPhrase: () -> RecoveryPhrase {
|
||||
get { self[NewRecoveryPhraseKey.self] }
|
||||
set { self[NewRecoveryPhraseKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// NotificationCenter.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 04.05.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct NotificationCenterClient {
|
||||
let publisherFor: (Notification.Name) -> NotificationCenter.Publisher?
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// NotificationCenterLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NotificationCenterClient {
|
||||
static let live = NotificationCenterClient(
|
||||
publisherFor: { NotificationCenter.default.publisher(for: $0) }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// NotificationCenterTest.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension NotificationCenterClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
publisherFor: XCTUnimplemented("\(Self.self).publisherFor", placeholder: nil)
|
||||
)
|
||||
}
|
||||
|
||||
extension NotificationCenterClient {
|
||||
static let noOp = NotificationCenterClient(
|
||||
publisherFor: { _ in nil }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// AppVersionInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var numberFormatter: NumberFormatterClient {
|
||||
get { self[NumberFormatterClient.self] }
|
||||
set { self[NumberFormatterClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct NumberFormatterClient {
|
||||
var string: (NSDecimalNumber) -> String?
|
||||
var number: (String) -> NSNumber?
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
//
|
||||
// WrappedNumberFormatter.swift
|
||||
// NumberFormatterLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 02.06.2022.
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension NumberFormatter {
|
||||
static let zcashNumberFormatter: NumberFormatter = {
|
||||
|
@ -27,12 +28,9 @@ extension NumberFormatter {
|
|||
}()
|
||||
}
|
||||
|
||||
struct WrappedNumberFormatter {
|
||||
let string: (NSDecimalNumber) -> String?
|
||||
let number: (String) -> NSNumber?
|
||||
}
|
||||
extension NumberFormatterClient: DependencyKey {
|
||||
static let liveValue = NumberFormatterClient.live()
|
||||
|
||||
extension WrappedNumberFormatter {
|
||||
static func live(numberFormatter: NumberFormatter = NumberFormatter.zcashNumberFormatter) -> Self {
|
||||
Self(
|
||||
string: { numberFormatter.string(from: $0) },
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// NumberFormatterTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension NumberFormatterClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
string: XCTUnimplemented("\(Self.self).string", placeholder: nil),
|
||||
number: XCTUnimplemented("\(Self.self).number", placeholder: nil)
|
||||
)
|
||||
}
|
||||
|
||||
extension NumberFormatterClient {
|
||||
static let noOp = Self(
|
||||
string: { _ in nil },
|
||||
number: { _ in nil }
|
||||
)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// NumberFormatterKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
private enum NumberFormatterKey: DependencyKey {
|
||||
static let liveValue = WrappedNumberFormatter.live()
|
||||
static let testValue = WrappedNumberFormatter.live()
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var numberFormatter: WrappedNumberFormatter {
|
||||
get { self[NumberFormatterKey.self] }
|
||||
set { self[NumberFormatterKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// PasteboardInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var pasteboard: PasteboardClient {
|
||||
get { self[PasteboardClient.self] }
|
||||
set { self[PasteboardClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct PasteboardClient {
|
||||
let setString: (String) -> Void
|
||||
let getString: () -> String?
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// PasteboardLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import UIKit
|
||||
|
||||
extension PasteboardClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
setString: { UIPasteboard.general.string = $0 },
|
||||
getString: { UIPasteboard.general.string }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// PasteboardTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension PasteboardClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
setString: XCTUnimplemented("\(Self.self).setString"),
|
||||
getString: XCTUnimplemented("\(Self.self).getString", placeholder: "")
|
||||
)
|
||||
|
||||
private struct TestPasteboard {
|
||||
static var general = TestPasteboard()
|
||||
var string: String?
|
||||
}
|
||||
|
||||
static let testPasteboard = Self(
|
||||
setString: { TestPasteboard.general.string = $0 },
|
||||
getString: { TestPasteboard.general.string }
|
||||
)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// PasteboardKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 01.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
// TODO: Ensure that sensitive information can't be logged intentionally or by accident #444.
|
||||
// https://github.com/zcash/secant-ios-wallet/issues/444
|
||||
private enum PasteboardKey: DependencyKey {
|
||||
static let liveValue = WrappedPasteboard.live
|
||||
static let testValue = WrappedPasteboard.test
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var pasteboard: WrappedPasteboard {
|
||||
get { self[PasteboardKey.self] }
|
||||
set { self[PasteboardKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
struct RecoveryPhraseRandomizer {
|
||||
func random(phrase: RecoveryPhrase) -> RecoveryPhraseValidationFlowReducer.State {
|
||||
|
@ -22,20 +21,8 @@ struct RecoveryPhraseRandomizer {
|
|||
}
|
||||
|
||||
func randomIndices() -> [Int] {
|
||||
return (0..<RecoveryPhraseValidationFlowReducer.State.phraseChunks).map { _ in
|
||||
(0..<RecoveryPhraseValidationFlowReducer.State.phraseChunks).map { _ in
|
||||
Int.random(in: 0 ..< RecoveryPhraseValidationFlowReducer.State.wordGroupSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum RecoveryPhraseRandomKey: DependencyKey {
|
||||
static let liveValue = WrappedRecoveryPhraseRandomizer.live
|
||||
static let testValue = WrappedRecoveryPhraseRandomizer.live
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var randomPhrase: WrappedRecoveryPhraseRandomizer {
|
||||
get { self[RecoveryPhraseRandomKey.self] }
|
||||
set { self[RecoveryPhraseRandomKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// RecoveryPhraseRandomizerInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var randomRecoveryPhrase: RecoveryPhraseRandomizerClient {
|
||||
get { self[RecoveryPhraseRandomizerClient.self] }
|
||||
set { self[RecoveryPhraseRandomizerClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct RecoveryPhraseRandomizerClient {
|
||||
let random: (RecoveryPhrase) -> RecoveryPhraseValidationFlowReducer.State
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// RecoveryPhraseRandomizerLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension RecoveryPhraseRandomizerClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
random: { RecoveryPhraseRandomizer().random(phrase: $0) }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// RecoveryPhraseRandomizerTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension RecoveryPhraseRandomizerClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
random: XCTUnimplemented("\(Self.self).random", placeholder: .placeholder)
|
||||
)
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// SDKSynchronizerClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension DependencyValues {
|
||||
var sdkSynchronizer: SDKSynchronizerClient {
|
||||
get { self[SDKSynchronizerDependency.self] }
|
||||
set { self[SDKSynchronizerDependency.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
enum SDKSynchronizerState: Equatable {
|
||||
case unknown
|
||||
case transactionsUpdated
|
||||
case started
|
||||
case progressUpdated
|
||||
case statusWillUpdate
|
||||
case synced
|
||||
case stopped
|
||||
case disconnected
|
||||
case syncing
|
||||
case downloading
|
||||
case validating
|
||||
case scanning
|
||||
case enhancing
|
||||
case fetching
|
||||
case minedTransaction
|
||||
case foundTransactions
|
||||
case failed
|
||||
case connectionStateChanged
|
||||
}
|
||||
|
||||
protocol SDKSynchronizerClient {
|
||||
var notificationCenter: NotificationCenterClient { get }
|
||||
var synchronizer: SDKSynchronizer? { get }
|
||||
var stateChanged: CurrentValueSubject<SDKSynchronizerState, Never> { get }
|
||||
var walletBirthday: BlockHeight? { get }
|
||||
var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState? { get }
|
||||
|
||||
func prepareWith(initializer: Initializer) throws
|
||||
func start(retry: Bool) throws
|
||||
func stop()
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?)
|
||||
func statusSnapshot() -> SyncStatusSnapshot
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws
|
||||
|
||||
func getShieldedBalance() -> WalletBalance?
|
||||
func getTransparentBalance() -> WalletBalance?
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never>
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never>
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never>
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress?
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress?
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never>
|
||||
}
|
||||
|
||||
extension SDKSynchronizerClient {
|
||||
func start() throws {
|
||||
try start(retry: false)
|
||||
}
|
||||
|
||||
func getTransparentAddress() -> TransparentAddress? {
|
||||
getTransparentAddress(account: 0)
|
||||
}
|
||||
|
||||
func getShieldedAddress() -> SaplingShieldedAddress? {
|
||||
getShieldedAddress(account: 0)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
//
|
||||
// SDKSynchronizerLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
enum SDKSynchronizerDependency: DependencyKey {
|
||||
static let liveValue: SDKSynchronizerClient = LiveSDKSynchronizerClient()
|
||||
}
|
||||
|
||||
class LiveSDKSynchronizerClient: SDKSynchronizerClient {
|
||||
private var cancellables: [AnyCancellable] = []
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<SDKSynchronizerState, Never>
|
||||
private(set) var notificationCenter: NotificationCenterClient
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: NotificationCenterClient = .live) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
deinit {
|
||||
synchronizer?.stop()
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws {
|
||||
synchronizer = try SDKSynchronizer(initializer: initializer)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerStarted)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.synchronizerStarted() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerSynced)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] output in
|
||||
let synchronizerState = output.userInfo?[SDKSynchronizer.NotificationKeys.synchronizerState] as? SDKSynchronizer.SynchronizerState
|
||||
self?.synchronizerSynced(synchronizerState)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerProgressUpdated)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.synchronizerProgressUpdated() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerStopped)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.synchronizerStopped() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
try synchronizer?.prepare()
|
||||
walletBirthday = initializer.walletBirthday
|
||||
}
|
||||
|
||||
func start(retry: Bool) throws {
|
||||
try synchronizer?.start(retry: retry)
|
||||
}
|
||||
|
||||
func stop() {
|
||||
synchronizer?.stop()
|
||||
}
|
||||
|
||||
func synchronizerStarted() {
|
||||
stateChanged.send(.started)
|
||||
}
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) {
|
||||
stateChanged.send(.synced)
|
||||
latestScannedSynchronizerState = synchronizerState
|
||||
}
|
||||
|
||||
func synchronizerProgressUpdated() {
|
||||
stateChanged.send(.progressUpdated)
|
||||
}
|
||||
|
||||
func synchronizerStopped() {
|
||||
stateChanged.send(.stopped)
|
||||
}
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot {
|
||||
guard let synchronizer = synchronizer else {
|
||||
return .default
|
||||
}
|
||||
|
||||
return SyncStatusSnapshot.snapshotFor(state: synchronizer.status)
|
||||
}
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws {
|
||||
try synchronizer?.rewind(policy)
|
||||
}
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? {
|
||||
latestScannedSynchronizerState?.shieldedBalance
|
||||
}
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? {
|
||||
latestScannedSynchronizerState?.transparentBalance
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let clearedTransactions = try? synchronizer?.allClearedTransactions() {
|
||||
return Effect(value: clearedTransactions.map {
|
||||
let transaction = TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let pendingTransactions = try? synchronizer?.allPendingTransactions(),
|
||||
let syncedBlockHeight = synchronizer?.latestScannedHeight {
|
||||
return Effect(value: pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let pendingTransactions = try? synchronizer?.allPendingTransactions(),
|
||||
let clearedTransactions = try? synchronizer?.allClearedTransactions(),
|
||||
let syncedBlockHeight = synchronizer?.latestScannedHeight {
|
||||
let clearedTxs: [WalletEvent] = clearedTransactions.map {
|
||||
let transaction = TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
let pendingTxs: [WalletEvent] = pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
let txs = clearedTxs.filter { cleared in
|
||||
pendingTxs.first { pending in
|
||||
pending.id == cleared.id
|
||||
} == nil
|
||||
}
|
||||
return .merge(
|
||||
Effect(value: txs),
|
||||
Effect(value: pendingTxs)
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? {
|
||||
synchronizer?.getTransparentAddress(accountIndex: account)
|
||||
}
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? {
|
||||
synchronizer?.getShieldedAddress(accountIndex: account)
|
||||
}
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
Deferred {
|
||||
Future { [weak self] promise in
|
||||
self?.synchronizer?.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: zatoshi,
|
||||
toAddress: recipientAddress,
|
||||
memo: memo,
|
||||
from: account) { result in
|
||||
switch result {
|
||||
case .failure(let error as NSError):
|
||||
promise(.failure(error))
|
||||
case .success(let pendingTx):
|
||||
promise(.success(TransactionState(pendingTransaction: pendingTx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.mapError { $0 as NSError }
|
||||
.catchToEffect()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
//
|
||||
// SDKSynchronizerMocks.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension SDKSynchronizerDependency {
|
||||
static let mock: SDKSynchronizerClient = MockSDKSynchronizerClient()
|
||||
}
|
||||
|
||||
class MockSDKSynchronizerClient: SDKSynchronizerClient {
|
||||
private var cancellables: [AnyCancellable] = []
|
||||
private(set) var notificationCenter: NotificationCenterClient
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<SDKSynchronizerState, Never>
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: NotificationCenterClient = .noOp) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws { }
|
||||
|
||||
func start(retry: Bool) throws { }
|
||||
|
||||
func stop() { }
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws { }
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? {
|
||||
WalletBalance(verified: Zatoshi(12345000), total: Zatoshi(12345000))
|
||||
}
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? {
|
||||
WalletBalance(verified: Zatoshi(12345000), total: Zatoshi(12345000))
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "cc33"),
|
||||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(4), uuid: "dd44"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(
|
||||
date: 1651039606,
|
||||
amount: Zatoshi(6),
|
||||
status: .paid(success: false),
|
||||
uuid: "ff66"
|
||||
),
|
||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(7), uuid: "gg77"),
|
||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(8), status: .paid(success: true), uuid: "hh88"),
|
||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(9), uuid: "ii99")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
return .merge(
|
||||
getAllClearedTransactions(),
|
||||
getAllPendingTransactions()
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
}
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? { nil }
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? { "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8" }
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
let transactionState = TransactionState(
|
||||
expirationHeight: 40,
|
||||
memo: memo,
|
||||
minedHeight: 50,
|
||||
shielded: true,
|
||||
zAddress: "tteafadlamnelkqe",
|
||||
fee: Zatoshi(10),
|
||||
id: "id",
|
||||
status: .paid(success: true),
|
||||
timestamp: 1234567,
|
||||
zecAmount: Zatoshi(10)
|
||||
)
|
||||
|
||||
return Effect(value: Result.success(transactionState))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
//
|
||||
// SDKSynchronizerTest.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension SDKSynchronizerDependency: TestDependencyKey {
|
||||
static let testValue: SDKSynchronizerClient = NoopSDKSynchronizer()
|
||||
}
|
||||
|
||||
class NoopSDKSynchronizer: SDKSynchronizerClient {
|
||||
private(set) var notificationCenter: NotificationCenterClient
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<SDKSynchronizerState, Never>
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: NotificationCenterClient = .noOp) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws { }
|
||||
|
||||
func start(retry: Bool) throws { }
|
||||
|
||||
func stop() { }
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws { }
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? { nil }
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? { nil }
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> { Effect(value: []) }
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> { Effect(value: []) }
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> { Effect(value: []) }
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? { nil }
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? { nil }
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
Effect(value: Result.failure(SynchronizerError.criticalError as NSError))
|
||||
}
|
||||
|
||||
func updateStateChanged(_ newState: SDKSynchronizerState) {
|
||||
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
|
||||
}
|
||||
}
|
||||
|
||||
class T2estSDKSynchronizerClient: SDKSynchronizerClient {
|
||||
private(set) var blockProcessor: CompactBlockProcessor?
|
||||
private(set) var notificationCenter: NotificationCenterClient
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<SDKSynchronizerState, Never>
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: NotificationCenterClient = .noOp) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws { }
|
||||
|
||||
func start(retry: Bool) throws { }
|
||||
|
||||
func stop() { }
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws { }
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? { nil }
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? { nil }
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "cc33"),
|
||||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(4), uuid: "dd44"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(
|
||||
date: 1651039606,
|
||||
amount: Zatoshi(6),
|
||||
status: .paid(success: false),
|
||||
uuid: "ff66"
|
||||
),
|
||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(7), uuid: "gg77"),
|
||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(8), status: .paid(success: true), uuid: "hh88"),
|
||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(9), uuid: "ii99")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
return .merge(
|
||||
getAllClearedTransactions(),
|
||||
getAllPendingTransactions()
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
}
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? { nil }
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? { "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8" }
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
return Effect(value: Result.failure(SynchronizerError.criticalError as NSError))
|
||||
}
|
||||
|
||||
func updateStateChanged(_ newState: SDKSynchronizerState) {
|
||||
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// SDKSynchronizerKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
private enum SDKSynchronizerKey: DependencyKey {
|
||||
static let liveValue: WrappedSDKSynchronizer = LiveWrappedSDKSynchronizer()
|
||||
static let testValue: WrappedSDKSynchronizer = MockWrappedSDKSynchronizer()
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var sdkSynchronizer: WrappedSDKSynchronizer {
|
||||
get { self[SDKSynchronizerKey.self] }
|
||||
set { self[SDKSynchronizerKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// SecItemClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Security
|
||||
|
||||
struct SecItemClient {
|
||||
let copyMatching: (CFDictionary, inout CFTypeRef?) -> OSStatus
|
||||
let add: (CFDictionary, inout CFTypeRef?) -> OSStatus
|
||||
let update: (CFDictionary, CFDictionary) -> OSStatus
|
||||
let delete: (CFDictionary) -> OSStatus
|
||||
}
|
|
@ -1,22 +1,15 @@
|
|||
//
|
||||
// WrappedSecItem.swift
|
||||
// SecItemLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.04.2022.
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Security
|
||||
|
||||
struct WrappedSecItem {
|
||||
let copyMatching: (CFDictionary, inout CFTypeRef?) -> OSStatus
|
||||
let add: (CFDictionary, inout CFTypeRef?) -> OSStatus
|
||||
let update: (CFDictionary, CFDictionary) -> OSStatus
|
||||
let delete: (CFDictionary) -> OSStatus
|
||||
}
|
||||
|
||||
extension WrappedSecItem {
|
||||
static let live = WrappedSecItem(
|
||||
extension SecItemClient {
|
||||
static let live = SecItemClient(
|
||||
copyMatching: { query, result in
|
||||
SecItemCopyMatching(query, &result)
|
||||
},
|
|
@ -6,7 +6,6 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
struct URIParser {
|
||||
enum URIParserError: Error { }
|
||||
|
@ -21,15 +20,3 @@ struct URIParser {
|
|||
try derivationTool.isValidZcashAddress(uri)
|
||||
}
|
||||
}
|
||||
|
||||
private enum URIParserKey: DependencyKey {
|
||||
static let liveValue = WrappedURIParser.live()
|
||||
static let testValue = WrappedURIParser.live()
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var uriParser: WrappedURIParser {
|
||||
get { self[URIParserKey.self] }
|
||||
set { self[URIParserKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// URIParserClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 17.05.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var uriParser: URIParserClient {
|
||||
get { self[URIParserClient.self] }
|
||||
set { self[URIParserClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct URIParserClient {
|
||||
var isValidURI: (String) throws -> Bool
|
||||
}
|
||||
|
|
@ -1,17 +1,15 @@
|
|||
//
|
||||
// WrappedURIParser.swift
|
||||
// URIParserLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 17.05.2022.
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
struct WrappedURIParser {
|
||||
let isValidURI: (String) throws -> Bool
|
||||
}
|
||||
|
||||
extension WrappedURIParser {
|
||||
extension URIParserClient: DependencyKey {
|
||||
static let liveValue = URIParserClient.live()
|
||||
|
||||
static func live(uriParser: URIParser = URIParser(derivationTool: .live())) -> Self {
|
||||
Self(
|
||||
isValidURI: { uri in
|
||||
|
@ -20,4 +18,3 @@ extension WrappedURIParser {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// URIParserTest.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension URIParserClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
isValidURI: XCTUnimplemented("\(Self.self).isValidURI", placeholder: false)
|
||||
)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// UserDefaultsInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
/// `UserDefaults` is thread-safe class. Because of that we can mark it as `Sendable` on our own. If it's marked as `Sendable` in `Foundation` in
|
||||
/// future we can simply remove this line and be ok. This is probably simpliest and easiest way how to fix warnings about `UserDefaults` not being
|
||||
/// sendable.
|
||||
extension UserDefaults: @unchecked Sendable { }
|
||||
|
||||
extension DependencyValues {
|
||||
var userDefaults: UserDefaultsClient {
|
||||
get { self[UserDefaultsClient.self] }
|
||||
set { self[UserDefaultsClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct UserDefaultsClient {
|
||||
let objectForKey: @Sendable (String) -> Any?
|
||||
let remove: @Sendable (String) async -> Void
|
||||
let setValue: @Sendable (Any?, String) async -> Void
|
||||
let synchronize: @Sendable () async -> Bool
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// UserDefaultsLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension UserDefaultsClient: DependencyKey {
|
||||
static let liveValue = UserDefaultsClient.live()
|
||||
|
||||
static func live(userDefaults: UserDefaults = .standard) -> Self {
|
||||
Self(
|
||||
objectForKey: { userDefaults.object(forKey: $0) },
|
||||
remove: { userDefaults.removeObject(forKey: $0) },
|
||||
setValue: { userDefaults.set($0, forKey: $1) },
|
||||
synchronize: { userDefaults.synchronize() }
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// UserDefaultsTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension UserDefaultsClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
objectForKey: XCTUnimplemented("\(Self.self).objectForKey", placeholder: nil),
|
||||
remove: XCTUnimplemented("\(Self.self).remove"),
|
||||
setValue: XCTUnimplemented("\(Self.self).setValue"),
|
||||
synchronize: XCTUnimplemented("\(Self.self).synchronize", placeholder: false)
|
||||
)
|
||||
}
|
||||
|
||||
extension UserDefaultsClient {
|
||||
static let noOp = Self(
|
||||
objectForKey: { _ in nil },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
synchronize: { false }
|
||||
)
|
||||
}
|
|
@ -26,7 +26,7 @@ struct UserPreferencesStorage {
|
|||
private let recoveryPhraseTestCompleted: Bool
|
||||
private let sessionAutoshielded: Bool
|
||||
|
||||
private let userDefaults: WrappedUserDefaults
|
||||
private let userDefaults: UserDefaultsClient
|
||||
|
||||
init(
|
||||
appSessionFrom: TimeInterval,
|
||||
|
@ -34,7 +34,7 @@ struct UserPreferencesStorage {
|
|||
fiatConvertion: Bool,
|
||||
recoveryPhraseTestCompleted: Bool,
|
||||
sessionAutoshielded: Bool,
|
||||
userDefaults: WrappedUserDefaults
|
||||
userDefaults: UserDefaultsClient
|
||||
) {
|
||||
self.appSessionFrom = appSessionFrom
|
||||
self.convertedCurrency = convertedCurrency
|
||||
|
@ -107,23 +107,3 @@ private extension UserPreferencesStorage {
|
|||
_ = await userDefaults.synchronize()
|
||||
}
|
||||
}
|
||||
|
||||
extension UserPreferencesStorage {
|
||||
static let live = UserPreferencesStorage(
|
||||
appSessionFrom: Date().timeIntervalSince1970,
|
||||
convertedCurrency: "USD",
|
||||
fiatConvertion: true,
|
||||
recoveryPhraseTestCompleted: false,
|
||||
sessionAutoshielded: true,
|
||||
userDefaults: .live()
|
||||
)
|
||||
|
||||
static let mock = UserPreferencesStorage(
|
||||
appSessionFrom: 1651039606.0,
|
||||
convertedCurrency: "USD",
|
||||
fiatConvertion: true,
|
||||
recoveryPhraseTestCompleted: false,
|
||||
sessionAutoshielded: true,
|
||||
userDefaults: .mock
|
||||
)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// UserPreferencesStorageLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension UserPreferencesStorage {
|
||||
static let live = UserPreferencesStorage(
|
||||
appSessionFrom: Date().timeIntervalSince1970,
|
||||
convertedCurrency: "USD",
|
||||
fiatConvertion: true,
|
||||
recoveryPhraseTestCompleted: false,
|
||||
sessionAutoshielded: true,
|
||||
userDefaults: .live()
|
||||
)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// UserPreferencesStorageMocks.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension UserPreferencesStorage {
|
||||
static let mock = UserPreferencesStorage(
|
||||
appSessionFrom: 1651039606.0,
|
||||
convertedCurrency: "USD",
|
||||
fiatConvertion: true,
|
||||
recoveryPhraseTestCompleted: false,
|
||||
sessionAutoshielded: true,
|
||||
userDefaults: .noOp
|
||||
)
|
||||
}
|
|
@ -35,10 +35,10 @@ struct WalletStorage {
|
|||
case unsupportedLanguage(MnemonicLanguageType)
|
||||
}
|
||||
|
||||
private let secItem: WrappedSecItem
|
||||
private let secItem: SecItemClient
|
||||
var zcashStoredWalletPrefix = ""
|
||||
|
||||
init(secItem: WrappedSecItem) {
|
||||
init(secItem: SecItemClient) {
|
||||
self.secItem = secItem
|
||||
}
|
||||
|
|
@ -1,21 +1,28 @@
|
|||
//
|
||||
// WrappedWalletStorage.swift
|
||||
// WalletStorageInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03/25/2022.
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import MnemonicSwift
|
||||
import ZcashLightClientKit
|
||||
|
||||
/// The `WrappedWalletStorage` is a wrapper around the `WalletStorage` type that allows for easy testing.
|
||||
extension DependencyValues {
|
||||
var walletStorage: WalletStorageClient {
|
||||
get { self[WalletStorageClient.self] }
|
||||
set { self[WalletStorageClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
/// The `WalletStorageClient` is a wrapper around the `WalletStorage` type that allows for easy testing.
|
||||
/// The `WalletStorage` Type is comprised of static functions that take and produce data. In order
|
||||
/// to easily produce test data, all of these static functions have been wrapped in function
|
||||
/// properties that live on the `WrappedWalletStorage` type. Because of this, you can instantiate
|
||||
/// the `WrappedWalletStorage` with your own implementation of these functions for testing purposes,
|
||||
/// or you can use one of the built in static versions of the `WrappedWalletStorage`.
|
||||
struct WrappedWalletStorage {
|
||||
/// properties that live on the `WalletStorageClient` type. Because of this, you can instantiate
|
||||
/// the `WalletStorageClient` with your own implementation of these functions for testing purposes,
|
||||
/// or you can use one of the built in static versions of the `WalletStorageClient`.
|
||||
struct WalletStorageClient {
|
||||
/// Store recovery phrase and optionally even birthday to the secured and persistent storage.
|
||||
/// This function creates an instance of `StoredWallet` and automatically handles versioning of the stored data.
|
||||
///
|
||||
|
@ -36,12 +43,12 @@ struct WrappedWalletStorage {
|
|||
/// - `WalletStorageError.uninitializedWallet`: when no wallet's data is found in the keychain.
|
||||
/// - `WalletStorageError.storageError` when some unrecognized error occured.
|
||||
/// - `WalletStorageError.unsupportedVersion` when wallet's version stored in the keychain is outdated.
|
||||
let exportWallet: () throws -> StoredWallet
|
||||
var exportWallet: () throws -> StoredWallet
|
||||
|
||||
/// Check if the wallet representation `StoredWallet` is present in the persistent storage.
|
||||
///
|
||||
/// - Returns: the information wheather some wallet is stored or is not available
|
||||
let areKeysPresent: () throws -> Bool
|
||||
var areKeysPresent: () throws -> Bool
|
||||
|
||||
/// Update the birthday in the securely stored wallet.
|
||||
///
|
||||
|
@ -65,52 +72,3 @@ struct WrappedWalletStorage {
|
|||
/// There's no fate but what we make for ourselves - Sarah Connor.
|
||||
let nukeWallet: () -> Void
|
||||
}
|
||||
|
||||
extension WrappedWalletStorage {
|
||||
public static func live(walletStorage: WalletStorage = WalletStorage(secItem: .live)) -> Self {
|
||||
Self(
|
||||
importWallet: { bip39, birthday, language, hasUserPassedPhraseBackupTest in
|
||||
try walletStorage.importWallet(
|
||||
bip39: bip39,
|
||||
birthday: birthday,
|
||||
language: language,
|
||||
hasUserPassedPhraseBackupTest: hasUserPassedPhraseBackupTest
|
||||
)
|
||||
},
|
||||
exportWallet: {
|
||||
try walletStorage.exportWallet()
|
||||
},
|
||||
areKeysPresent: {
|
||||
try walletStorage.areKeysPresent()
|
||||
},
|
||||
updateBirthday: { birthday in
|
||||
try walletStorage.updateBirthday(birthday)
|
||||
},
|
||||
markUserPassedPhraseBackupTest: {
|
||||
try walletStorage.markUserPassedPhraseBackupTest()
|
||||
},
|
||||
nukeWallet: {
|
||||
walletStorage.nukeWallet()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public static let throwing = WrappedWalletStorage(
|
||||
importWallet: { _, _, _, _ in
|
||||
throw WalletStorage.WalletStorageError.alreadyImported
|
||||
},
|
||||
exportWallet: {
|
||||
throw WalletStorage.WalletStorageError.uninitializedWallet
|
||||
},
|
||||
areKeysPresent: {
|
||||
throw WalletStorage.WalletStorageError.uninitializedWallet
|
||||
},
|
||||
updateBirthday: { _ in
|
||||
throw WalletStorage.KeychainError.encoding
|
||||
},
|
||||
markUserPassedPhraseBackupTest: {
|
||||
throw WalletStorage.KeychainError.encoding
|
||||
},
|
||||
nukeWallet: { }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// WalletStorageLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MnemonicSwift
|
||||
import ZcashLightClientKit
|
||||
import ComposableArchitecture
|
||||
|
||||
extension WalletStorageClient: DependencyKey {
|
||||
static let liveValue = WalletStorageClient.live()
|
||||
|
||||
static func live(walletStorage: WalletStorage = WalletStorage(secItem: .live)) -> Self {
|
||||
Self(
|
||||
importWallet: { bip39, birthday, language, hasUserPassedPhraseBackupTest in
|
||||
try walletStorage.importWallet(
|
||||
bip39: bip39,
|
||||
birthday: birthday,
|
||||
language: language,
|
||||
hasUserPassedPhraseBackupTest: hasUserPassedPhraseBackupTest
|
||||
)
|
||||
},
|
||||
exportWallet: {
|
||||
try walletStorage.exportWallet()
|
||||
},
|
||||
areKeysPresent: {
|
||||
try walletStorage.areKeysPresent()
|
||||
},
|
||||
updateBirthday: { birthday in
|
||||
try walletStorage.updateBirthday(birthday)
|
||||
},
|
||||
markUserPassedPhraseBackupTest: {
|
||||
try walletStorage.markUserPassedPhraseBackupTest()
|
||||
},
|
||||
nukeWallet: {
|
||||
walletStorage.nukeWallet()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// WalletStorageTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension WalletStorageClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
importWallet: XCTUnimplemented("\(Self.self).importWallet"),
|
||||
exportWallet: XCTUnimplemented("\(Self.self).exportWallet", placeholder: .placeholder),
|
||||
areKeysPresent: XCTUnimplemented("\(Self.self).areKeysPresent", placeholder: false),
|
||||
updateBirthday: XCTUnimplemented("\(Self.self).updateBirthday"),
|
||||
markUserPassedPhraseBackupTest: XCTUnimplemented("\(Self.self).markUserPassedPhraseBackupTest"),
|
||||
nukeWallet: XCTUnimplemented("\(Self.self).nukeWallet")
|
||||
)
|
||||
}
|
||||
|
||||
extension WalletStorageClient {
|
||||
static let noOp = Self(
|
||||
importWallet: { _, _, _, _ in },
|
||||
exportWallet: { .placeholder },
|
||||
areKeysPresent: { false },
|
||||
updateBirthday: { _ in },
|
||||
markUserPassedPhraseBackupTest: { },
|
||||
nukeWallet: { }
|
||||
)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// WalletStorageKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
private enum WalletStorageKey: DependencyKey {
|
||||
static let liveValue = WrappedWalletStorage.live()
|
||||
static let testValue = WrappedWalletStorage.throwing
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var walletStorage: WrappedWalletStorage {
|
||||
get { self[WalletStorageKey.self] }
|
||||
set { self[WalletStorageKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
//
|
||||
// ZCashSDKEnvironment.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ZcashLightClientKit
|
||||
import ComposableArchitecture
|
||||
|
||||
// swiftlint:disable:next private_over_fileprivate strict_fileprivate
|
||||
fileprivate enum ZcashSDKConstants {
|
||||
static let defaultBlockHeight = 1_629_724
|
||||
static let endpointMainnetAddress = "lightwalletd.electriccoin.co"
|
||||
static let endpointTestnetAddress = "lightwalletd.testnet.electriccoin.co"
|
||||
static let endpointPort = 9067
|
||||
static let mnemonicWordsMaxCount = 24
|
||||
static let requiredTransactionConfirmations = 10
|
||||
static let streamingCallTimeoutInMillis = Int64(10 * 60 * 60 * 1000) // ten hours
|
||||
}
|
||||
|
||||
struct ZCashSDKEnvironment {
|
||||
let defaultBirthday: BlockHeight
|
||||
let endpoint: LightWalletEndpoint
|
||||
let isMainnet: () -> Bool
|
||||
let lightWalletService: LightWalletService
|
||||
let memoCharLimit: Int
|
||||
let mnemonicWordsMaxCount: Int
|
||||
let network: ZcashNetwork
|
||||
let requiredTransactionConfirmations: Int
|
||||
let sdkVersion: String
|
||||
}
|
||||
|
||||
extension ZCashSDKEnvironment {
|
||||
static let mainnet = ZCashSDKEnvironment(
|
||||
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointMainnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
),
|
||||
isMainnet: { true },
|
||||
lightWalletService: LightWalletGRPCService(
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointMainnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
)
|
||||
),
|
||||
memoCharLimit: 512,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
network: ZcashNetworkBuilder.network(for: .mainnet),
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.16.5-beta"
|
||||
)
|
||||
|
||||
static let testnet = ZCashSDKEnvironment(
|
||||
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointTestnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
),
|
||||
isMainnet: { false },
|
||||
lightWalletService: LightWalletGRPCService(
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointTestnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
)
|
||||
),
|
||||
memoCharLimit: 512,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
network: ZcashNetworkBuilder.network(for: .testnet),
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.16.5-beta"
|
||||
)
|
||||
}
|
||||
|
||||
private enum ZCashSDKEnvironmentKey: DependencyKey {
|
||||
static let liveValue = ZCashSDKEnvironment.mainnet
|
||||
static let testValue = ZCashSDKEnvironment.testnet
|
||||
}
|
||||
|
||||
extension DependencyValues {
|
||||
var zcashSDKEnvironment: ZCashSDKEnvironment {
|
||||
get { self[ZCashSDKEnvironmentKey.self] }
|
||||
set { self[ZCashSDKEnvironmentKey.self] = newValue }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// ZcashSDKEnvironmentInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension DependencyValues {
|
||||
var zcashSDKEnvironment: ZcashSDKEnvironment {
|
||||
get { self[ZcashSDKEnvironment.self] }
|
||||
set { self[ZcashSDKEnvironment.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
extension ZcashSDKEnvironment {
|
||||
enum ZcashSDKConstants {
|
||||
static let defaultBlockHeight = 1_629_724
|
||||
static let endpointMainnetAddress = "lightwalletd.electriccoin.co"
|
||||
static let endpointTestnetAddress = "lightwalletd.testnet.electriccoin.co"
|
||||
static let endpointPort = 9067
|
||||
static let mnemonicWordsMaxCount = 24
|
||||
static let requiredTransactionConfirmations = 10
|
||||
static let streamingCallTimeoutInMillis = Int64(10 * 60 * 60 * 1000) // ten hours
|
||||
}
|
||||
}
|
||||
|
||||
struct ZcashSDKEnvironment {
|
||||
let defaultBirthday: BlockHeight
|
||||
let endpoint: LightWalletEndpoint
|
||||
let isMainnet: () -> Bool
|
||||
let lightWalletService: LightWalletService
|
||||
let memoCharLimit: Int
|
||||
let mnemonicWordsMaxCount: Int
|
||||
let network: ZcashNetwork
|
||||
let requiredTransactionConfirmations: Int
|
||||
let sdkVersion: String
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ZcashSDKEnvironmentLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension ZcashSDKEnvironment: DependencyKey {
|
||||
static let mainnet = ZcashSDKEnvironment.liveValue
|
||||
|
||||
static let liveValue = Self(
|
||||
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointMainnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
),
|
||||
isMainnet: { true },
|
||||
lightWalletService: LightWalletGRPCService(
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointMainnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
)
|
||||
),
|
||||
memoCharLimit: 512,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
network: ZcashNetworkBuilder.network(for: .mainnet),
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.16.5-beta"
|
||||
)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// ZcashSDKEnvironmentTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension ZcashSDKEnvironment: TestDependencyKey {
|
||||
static let testnet = ZcashSDKEnvironment.liveValue
|
||||
|
||||
static let testValue = Self(
|
||||
defaultBirthday: BlockHeight(ZcashSDKConstants.defaultBlockHeight),
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointTestnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
),
|
||||
isMainnet: { false },
|
||||
lightWalletService: LightWalletGRPCService(
|
||||
endpoint: LightWalletEndpoint(
|
||||
address: ZcashSDKConstants.endpointTestnetAddress,
|
||||
port: ZcashSDKConstants.endpointPort,
|
||||
secure: true,
|
||||
streamingCallTimeoutInMillis: ZcashSDKConstants.streamingCallTimeoutInMillis
|
||||
)
|
||||
),
|
||||
memoCharLimit: 512,
|
||||
mnemonicWordsMaxCount: ZcashSDKConstants.mnemonicWordsMaxCount,
|
||||
network: ZcashNetworkBuilder.network(for: .testnet),
|
||||
requiredTransactionConfirmations: ZcashSDKConstants.requiredTransactionConfirmations,
|
||||
sdkVersion: "0.16.5-beta"
|
||||
)
|
||||
}
|
|
@ -65,7 +65,7 @@ struct AppReducer: ReducerProtocol {
|
|||
@Dependency(\.derivationTool) var derivationTool
|
||||
@Dependency(\.mainQueue) var mainQueue
|
||||
@Dependency(\.mnemonic) var mnemonic
|
||||
@Dependency(\.randomPhrase) var randomPhrase
|
||||
@Dependency(\.randomRecoveryPhrase) var randomRecoveryPhrase
|
||||
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
|
||||
@Dependency(\.walletStorage) var walletStorage
|
||||
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
@ -105,7 +105,7 @@ struct AppReducer: ReducerProtocol {
|
|||
case .phraseValidation(.proceedToHome):
|
||||
state.route = .home
|
||||
|
||||
case .phraseValidation(.displayBackedUpPhrase), .phraseDisplay(.createPhrase):
|
||||
case .phraseValidation(.displayBackedUpPhrase):
|
||||
state.route = .phraseDisplay
|
||||
|
||||
case .phraseDisplay(.finishedPressed):
|
||||
|
@ -120,7 +120,7 @@ struct AppReducer: ReducerProtocol {
|
|||
|
||||
case .deeplink(let url):
|
||||
// get the latest synchronizer state
|
||||
var synchronizerStatus = WrappedSDKSynchronizerState.unknown
|
||||
var synchronizerStatus = SDKSynchronizerState.unknown
|
||||
_ = sdkSynchronizer.stateChanged.sink { synchronizerStatus = $0 }
|
||||
|
||||
// process the deeplink only if app is initialized and synchronizer synced
|
||||
|
@ -261,7 +261,7 @@ struct AppReducer: ReducerProtocol {
|
|||
|
||||
let recoveryPhrase = RecoveryPhrase(words: phraseWords)
|
||||
state.phraseDisplayState.phrase = recoveryPhrase
|
||||
state.phraseValidationState = randomPhrase.random(recoveryPhrase)
|
||||
state.phraseValidationState = randomRecoveryPhrase.random(recoveryPhrase)
|
||||
landingRoute = .phraseDisplay
|
||||
} catch {
|
||||
// TODO [#201]: - merge with issue 201 (https://github.com/zcash/secant-ios-wallet/issues/201) and its Error States
|
||||
|
@ -286,10 +286,10 @@ struct AppReducer: ReducerProtocol {
|
|||
try walletStorage.importWallet(newRandomPhrase, birthday, .english, false)
|
||||
|
||||
// start the backup phrase validation test
|
||||
let randomPhraseWords = try mnemonic.asWords(newRandomPhrase)
|
||||
let recoveryPhrase = RecoveryPhrase(words: randomPhraseWords)
|
||||
let randomRecoveryPhraseWords = try mnemonic.asWords(newRandomPhrase)
|
||||
let recoveryPhrase = RecoveryPhrase(words: randomRecoveryPhraseWords)
|
||||
state.phraseDisplayState.phrase = recoveryPhrase
|
||||
state.phraseValidationState = randomPhrase.random(recoveryPhrase)
|
||||
state.phraseValidationState = randomRecoveryPhrase.random(recoveryPhrase)
|
||||
|
||||
return .concatenate(
|
||||
Effect(value: .initializeSDK),
|
||||
|
@ -341,8 +341,8 @@ struct AppReducer: ReducerProtocol {
|
|||
extension AppReducer {
|
||||
static func walletInitializationState(
|
||||
databaseFiles: DatabaseFilesClient,
|
||||
walletStorage: WrappedWalletStorage,
|
||||
zcashSDKEnvironment: ZCashSDKEnvironment
|
||||
walletStorage: WalletStorageClient,
|
||||
zcashSDKEnvironment: ZcashSDKEnvironment
|
||||
) -> InitializationState {
|
||||
var keysPresent = false
|
||||
do {
|
||||
|
@ -388,8 +388,8 @@ extension AppReducer {
|
|||
birthday: BlockHeight,
|
||||
databaseFiles: DatabaseFilesClient,
|
||||
derivationTool: DerivationToolClient,
|
||||
mnemonic: WrappedMnemonic,
|
||||
zcashSDKEnvironment: ZCashSDKEnvironment
|
||||
mnemonic: MnemonicClient,
|
||||
zcashSDKEnvironment: ZcashSDKEnvironment
|
||||
) throws -> Initializer {
|
||||
do {
|
||||
let seedBytes = try mnemonic.toSeed(seedPhrase)
|
||||
|
|
|
@ -28,7 +28,7 @@ struct BalanceBreakdownReducer: ReducerProtocol {
|
|||
enum Action: Equatable {
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case synchronizerStateChanged(SDKSynchronizerState)
|
||||
case updateLatestBlock
|
||||
case updateSynchronizerStatus
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ struct HomeReducer: ReducerProtocol {
|
|||
case request(RequestReducer.Action)
|
||||
case send(SendFlowReducer.Action)
|
||||
case scan(ScanReducer.Action)
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case synchronizerStateChanged(SDKSynchronizerState)
|
||||
case walletEvents(WalletEventsFlowReducer.Action)
|
||||
case updateDrawer(DrawerOverlay)
|
||||
case updateRoute(HomeReducer.State.Route?)
|
||||
|
|
|
@ -17,22 +17,15 @@ struct RecoveryPhraseDisplayReducer: ReducerProtocol {
|
|||
}
|
||||
|
||||
enum Action: Equatable {
|
||||
case createPhrase
|
||||
case copyToBufferPressed
|
||||
case finishedPressed
|
||||
case phraseResponse(RecoveryPhrase)
|
||||
}
|
||||
|
||||
@Dependency(\.newRecoveryPhrase) var newRecoveryPhrase
|
||||
@Dependency(\.pasteboard) var pasteboard
|
||||
|
||||
func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
|
||||
switch action {
|
||||
case .createPhrase:
|
||||
return .run { send in
|
||||
await send(.phraseResponse(newRecoveryPhrase()))
|
||||
}
|
||||
|
||||
case .copyToBufferPressed:
|
||||
guard let phrase = state.phrase?.toString() else { return .none }
|
||||
pasteboard.setString(phrase)
|
||||
|
|
|
@ -53,13 +53,13 @@ struct RecoveryPhraseValidationFlowReducer: ReducerProtocol {
|
|||
@Dependency(\.feedbackGenerator) var feedbackGenerator
|
||||
@Dependency(\.mainQueue) var mainQueue
|
||||
@Dependency(\.pasteboard) var pasteboard
|
||||
@Dependency(\.randomPhrase) var randomPhrase
|
||||
@Dependency(\.randomRecoveryPhrase) var randomRecoveryPhrase
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> {
|
||||
switch action {
|
||||
case .reset:
|
||||
state = randomPhrase.random(state.phrase)
|
||||
state = randomRecoveryPhrase.random(state.phrase)
|
||||
state.route = .validation
|
||||
// FIXME [#186]: Resetting causes route to be nil = preamble screen, hence setting the .validation. The transition back is not animated
|
||||
// though
|
||||
|
@ -101,7 +101,7 @@ struct RecoveryPhraseValidationFlowReducer: ReducerProtocol {
|
|||
|
||||
case .updateRoute(let route):
|
||||
guard let route = route else {
|
||||
state = randomPhrase.random(state.phrase)
|
||||
state = randomRecoveryPhrase.random(state.phrase)
|
||||
return .none
|
||||
}
|
||||
state.route = route
|
||||
|
|
|
@ -80,7 +80,7 @@ struct SendFlowReducer: ReducerProtocol {
|
|||
case onDisappear
|
||||
case sendConfirmationPressed
|
||||
case sendTransactionResult(Result<TransactionState, NSError>)
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case synchronizerStateChanged(SDKSynchronizerState)
|
||||
case transactionAddressInput(TransactionAddressTextFieldReducer.Action)
|
||||
case transactionAmountInput(TransactionAmountTextFieldReducer.Action)
|
||||
case updateRoute(SendFlowReducer.State.Route?)
|
||||
|
|
|
@ -33,7 +33,7 @@ struct WalletEventsFlowReducer: ReducerProtocol {
|
|||
case openBlockExplorer(URL?)
|
||||
case updateRoute(WalletEventsFlowReducer.State.Route?)
|
||||
case replyTo(String)
|
||||
case synchronizerStateChanged(WrappedSDKSynchronizerState)
|
||||
case synchronizerStateChanged(SDKSynchronizerState)
|
||||
case updateWalletEvents([WalletEvent])
|
||||
case warnBeforeLeavingApp(URL?)
|
||||
}
|
||||
|
|
|
@ -18,3 +18,13 @@ struct StoredWallet: Codable, Equatable {
|
|||
var birthday: BlockHeight?
|
||||
var hasUserPassedPhraseBackupTest: Bool
|
||||
}
|
||||
|
||||
extension StoredWallet {
|
||||
static let placeholder = Self(
|
||||
language: .english,
|
||||
seedPhrase: "",
|
||||
version: 0,
|
||||
birthday: 0,
|
||||
hasUserPassedPhraseBackupTest: false
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// WrappedFeedbackGenerator.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.05.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
struct WrappedFeedbackGenerator {
|
||||
let generateSuccessFeedback: () -> Void
|
||||
let generateWarningFeedback: () -> Void
|
||||
let generateErrorFeedback: () -> Void
|
||||
}
|
||||
|
||||
extension WrappedFeedbackGenerator {
|
||||
static let haptic = WrappedFeedbackGenerator(
|
||||
generateSuccessFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.success) },
|
||||
generateWarningFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.warning) },
|
||||
generateErrorFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.error) }
|
||||
)
|
||||
|
||||
static let silent = WrappedFeedbackGenerator(
|
||||
generateSuccessFeedback: { },
|
||||
generateWarningFeedback: { },
|
||||
generateErrorFeedback: { }
|
||||
)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// WrappedNotificationCenter.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 04.05.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct WrappedNotificationCenter {
|
||||
let publisherFor: (Notification.Name) -> NotificationCenter.Publisher?
|
||||
}
|
||||
|
||||
extension WrappedNotificationCenter {
|
||||
static let live = WrappedNotificationCenter(
|
||||
publisherFor: { NotificationCenter.default.publisher(for: $0) }
|
||||
)
|
||||
|
||||
static let mock = WrappedNotificationCenter(
|
||||
publisherFor: { _ in nil }
|
||||
)
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// WrappedPasteboard.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.05.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
struct WrappedPasteboard {
|
||||
let setString: (String) -> Void
|
||||
let getString: () -> String?
|
||||
}
|
||||
|
||||
extension WrappedPasteboard {
|
||||
private struct TestPasteboard {
|
||||
static var general = TestPasteboard()
|
||||
var string: String?
|
||||
}
|
||||
|
||||
static let live = WrappedPasteboard(
|
||||
setString: { UIPasteboard.general.string = $0 },
|
||||
getString: { UIPasteboard.general.string }
|
||||
)
|
||||
|
||||
static let test = WrappedPasteboard(
|
||||
setString: { TestPasteboard.general.string = $0 },
|
||||
getString: { TestPasteboard.general.string }
|
||||
)
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//
|
||||
// WrappedRecoveryPhraseRandomizer.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 01.06.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct WrappedRecoveryPhraseRandomizer {
|
||||
let random: (RecoveryPhrase) -> RecoveryPhraseValidationFlowReducer.State
|
||||
}
|
||||
|
||||
extension WrappedRecoveryPhraseRandomizer {
|
||||
static let live = WrappedRecoveryPhraseRandomizer(
|
||||
random: { RecoveryPhraseRandomizer().random(phrase: $0) }
|
||||
)
|
||||
}
|
|
@ -1,533 +0,0 @@
|
|||
//
|
||||
// WrappedSDKSynchronizer.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ZcashLightClientKit
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
|
||||
enum WrappedSDKSynchronizerState: Equatable {
|
||||
case unknown
|
||||
case transactionsUpdated
|
||||
case started
|
||||
case progressUpdated
|
||||
case statusWillUpdate
|
||||
case synced
|
||||
case stopped
|
||||
case disconnected
|
||||
case syncing
|
||||
case downloading
|
||||
case validating
|
||||
case scanning
|
||||
case enhancing
|
||||
case fetching
|
||||
case minedTransaction
|
||||
case foundTransactions
|
||||
case failed
|
||||
case connectionStateChanged
|
||||
}
|
||||
|
||||
protocol WrappedSDKSynchronizer {
|
||||
var blockProcessor: CompactBlockProcessor? { get }
|
||||
var notificationCenter: WrappedNotificationCenter { get }
|
||||
var synchronizer: SDKSynchronizer? { get }
|
||||
var stateChanged: CurrentValueSubject<WrappedSDKSynchronizerState, Never> { get }
|
||||
var walletBirthday: BlockHeight? { get }
|
||||
var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState? { get }
|
||||
|
||||
func prepareWith(initializer: Initializer) throws
|
||||
func start(retry: Bool) throws
|
||||
func stop()
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?)
|
||||
func statusSnapshot() -> SyncStatusSnapshot
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws
|
||||
|
||||
func getShieldedBalance() -> WalletBalance?
|
||||
func getTransparentBalance() -> WalletBalance?
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never>
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never>
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never>
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress?
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress?
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never>
|
||||
}
|
||||
|
||||
extension WrappedSDKSynchronizer {
|
||||
func start() throws {
|
||||
try start(retry: false)
|
||||
}
|
||||
|
||||
func getTransparentAddress() -> TransparentAddress? {
|
||||
getTransparentAddress(account: 0)
|
||||
}
|
||||
|
||||
func getShieldedAddress() -> SaplingShieldedAddress? {
|
||||
getShieldedAddress(account: 0)
|
||||
}
|
||||
}
|
||||
|
||||
class LiveWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||
private var cancellables: [AnyCancellable] = []
|
||||
private(set) var blockProcessor: CompactBlockProcessor?
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<WrappedSDKSynchronizerState, Never>
|
||||
private(set) var notificationCenter: WrappedNotificationCenter
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: WrappedNotificationCenter = .live) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<WrappedSDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
deinit {
|
||||
synchronizer?.stop()
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws {
|
||||
synchronizer = try SDKSynchronizer(initializer: initializer)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerStarted)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.synchronizerStarted() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerSynced)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] output in
|
||||
let synchronizerState = output.userInfo?[SDKSynchronizer.NotificationKeys.synchronizerState] as? SDKSynchronizer.SynchronizerState
|
||||
self?.synchronizerSynced(synchronizerState)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerProgressUpdated)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.synchronizerProgressUpdated() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
notificationCenter.publisherFor(.synchronizerStopped)?
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in self?.synchronizerStopped() }
|
||||
.store(in: &cancellables)
|
||||
|
||||
try synchronizer?.prepare()
|
||||
blockProcessor = CompactBlockProcessor(initializer: initializer)
|
||||
walletBirthday = initializer.walletBirthday
|
||||
}
|
||||
|
||||
func start(retry: Bool) throws {
|
||||
try synchronizer?.start(retry: retry)
|
||||
}
|
||||
|
||||
func stop() {
|
||||
synchronizer?.stop()
|
||||
}
|
||||
|
||||
func synchronizerStarted() {
|
||||
stateChanged.send(.started)
|
||||
}
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) {
|
||||
stateChanged.send(.synced)
|
||||
latestScannedSynchronizerState = synchronizerState
|
||||
}
|
||||
|
||||
func synchronizerProgressUpdated() {
|
||||
stateChanged.send(.progressUpdated)
|
||||
}
|
||||
|
||||
func synchronizerStopped() {
|
||||
stateChanged.send(.stopped)
|
||||
}
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot {
|
||||
guard let synchronizer = synchronizer else {
|
||||
return .default
|
||||
}
|
||||
|
||||
return SyncStatusSnapshot.snapshotFor(state: synchronizer.status)
|
||||
}
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws {
|
||||
stop()
|
||||
|
||||
var height: BlockHeight?
|
||||
|
||||
switch policy {
|
||||
case .quick, .transaction:
|
||||
break
|
||||
|
||||
case .birthday:
|
||||
height = walletBirthday
|
||||
|
||||
case .height(let blockheight):
|
||||
height = blockheight
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try blockProcessor?.rewindTo(height)
|
||||
} catch {
|
||||
throw SynchronizerError.rewindError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? {
|
||||
latestScannedSynchronizerState?.shieldedBalance
|
||||
}
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? {
|
||||
latestScannedSynchronizerState?.transparentBalance
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let clearedTransactions = try? synchronizer?.allClearedTransactions() {
|
||||
return Effect(value: clearedTransactions.map {
|
||||
let transaction = TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let pendingTransactions = try? synchronizer?.allPendingTransactions(),
|
||||
let syncedBlockHeight = synchronizer?.latestScannedHeight {
|
||||
return Effect(value: pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
})
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
if let pendingTransactions = try? synchronizer?.allPendingTransactions(),
|
||||
let clearedTransactions = try? synchronizer?.allClearedTransactions(),
|
||||
let syncedBlockHeight = synchronizer?.latestScannedHeight {
|
||||
let clearedTxs: [WalletEvent] = clearedTransactions.map {
|
||||
let transaction = TransactionState.init(confirmedTransaction: $0, sent: ($0.toAddress != nil))
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
let pendingTxs: [WalletEvent] = pendingTransactions.map {
|
||||
let transaction = TransactionState.init(pendingTransaction: $0, latestBlockHeight: syncedBlockHeight)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
|
||||
let txs = clearedTxs.filter { cleared in
|
||||
pendingTxs.first { pending in
|
||||
pending.id == cleared.id
|
||||
} == nil
|
||||
}
|
||||
return .merge(
|
||||
Effect(value: txs),
|
||||
Effect(value: pendingTxs)
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? {
|
||||
synchronizer?.getTransparentAddress(accountIndex: account)
|
||||
}
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? {
|
||||
synchronizer?.getShieldedAddress(accountIndex: account)
|
||||
}
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
Deferred {
|
||||
Future { [weak self] promise in
|
||||
self?.synchronizer?.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: zatoshi,
|
||||
toAddress: recipientAddress,
|
||||
memo: memo,
|
||||
from: account) { result in
|
||||
switch result {
|
||||
case .failure(let error as NSError):
|
||||
promise(.failure(error))
|
||||
case .success(let pendingTx):
|
||||
promise(.success(TransactionState(pendingTransaction: pendingTx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.mapError { $0 as NSError }
|
||||
.catchToEffect()
|
||||
}
|
||||
}
|
||||
|
||||
class MockWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||
private var cancellables: [AnyCancellable] = []
|
||||
private(set) var blockProcessor: CompactBlockProcessor?
|
||||
private(set) var notificationCenter: WrappedNotificationCenter
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<WrappedSDKSynchronizerState, Never>
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: WrappedNotificationCenter = .mock) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<WrappedSDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
deinit {
|
||||
synchronizer?.stop()
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws {
|
||||
try synchronizer?.prepare()
|
||||
}
|
||||
|
||||
func start(retry: Bool) throws {
|
||||
try synchronizer?.start(retry: retry)
|
||||
}
|
||||
|
||||
func stop() {
|
||||
synchronizer?.stop()
|
||||
}
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) {
|
||||
stateChanged.send(.synced)
|
||||
}
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot {
|
||||
guard let synchronizer = synchronizer else {
|
||||
return .default
|
||||
}
|
||||
|
||||
return SyncStatusSnapshot.snapshotFor(state: synchronizer.status)
|
||||
}
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws { }
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? {
|
||||
WalletBalance(verified: Zatoshi(12345000), total: Zatoshi(12345000))
|
||||
}
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? {
|
||||
WalletBalance(verified: Zatoshi(12345000), total: Zatoshi(12345000))
|
||||
}
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "1"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "2"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "3"),
|
||||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(4), uuid: "4"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "5")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039606, amount: Zatoshi(6), status: .paid(success: false)),
|
||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(7)),
|
||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(8), status: .paid(success: true)),
|
||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(9))
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
return .merge(
|
||||
getAllClearedTransactions(),
|
||||
getAllPendingTransactions()
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
}
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? { nil }
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? { nil }
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
let transactionState = TransactionState(
|
||||
expirationHeight: 40,
|
||||
memo: memo,
|
||||
minedHeight: 50,
|
||||
shielded: true,
|
||||
zAddress: "tteafadlamnelkqe",
|
||||
fee: Zatoshi(10),
|
||||
id: "id",
|
||||
status: .paid(success: true),
|
||||
timestamp: 1234567,
|
||||
zecAmount: Zatoshi(10)
|
||||
)
|
||||
|
||||
return Effect(value: Result.success(transactionState))
|
||||
}
|
||||
}
|
||||
|
||||
class TestWrappedSDKSynchronizer: WrappedSDKSynchronizer {
|
||||
private(set) var blockProcessor: CompactBlockProcessor?
|
||||
private(set) var notificationCenter: WrappedNotificationCenter
|
||||
private(set) var synchronizer: SDKSynchronizer?
|
||||
private(set) var stateChanged: CurrentValueSubject<WrappedSDKSynchronizerState, Never>
|
||||
private(set) var walletBirthday: BlockHeight?
|
||||
private(set) var latestScannedSynchronizerState: SDKSynchronizer.SynchronizerState?
|
||||
|
||||
init(notificationCenter: WrappedNotificationCenter = .mock) {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.stateChanged = CurrentValueSubject<WrappedSDKSynchronizerState, Never>(.unknown)
|
||||
}
|
||||
|
||||
func prepareWith(initializer: Initializer) throws { }
|
||||
|
||||
func start(retry: Bool) throws { }
|
||||
|
||||
func stop() { }
|
||||
|
||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||
|
||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||
|
||||
func rewind(_ policy: RewindPolicy) throws { }
|
||||
|
||||
func getShieldedBalance() -> WalletBalance? { nil }
|
||||
|
||||
func getTransparentBalance() -> WalletBalance? { nil }
|
||||
|
||||
func getAllClearedTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "cc33"),
|
||||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(4), uuid: "dd44"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .send(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllPendingTransactions() -> Effect<[WalletEvent], Never> {
|
||||
let mocked: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(
|
||||
date: 1651039606,
|
||||
amount: Zatoshi(6),
|
||||
status: .paid(success: false),
|
||||
uuid: "ff66"
|
||||
),
|
||||
TransactionStateMockHelper(date: 1651039303, amount: Zatoshi(7), uuid: "gg77"),
|
||||
TransactionStateMockHelper(date: 1651039707, amount: Zatoshi(8), status: .paid(success: true), uuid: "hh88"),
|
||||
TransactionStateMockHelper(date: 1651039808, amount: Zatoshi(9), uuid: "ii99")
|
||||
]
|
||||
|
||||
return Effect(
|
||||
value:
|
||||
mocked.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
amount: $0.amount,
|
||||
fee: Zatoshi(10),
|
||||
shielded: $0.shielded,
|
||||
status: $0.amount.amount > 5 ? .pending : $0.status,
|
||||
timestamp: $0.date,
|
||||
uuid: $0.uuid
|
||||
)
|
||||
return WalletEvent(id: transaction.id, state: .pending(transaction), timestamp: transaction.timestamp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func getAllTransactions() -> Effect<[WalletEvent], Never> {
|
||||
return .merge(
|
||||
getAllClearedTransactions(),
|
||||
getAllPendingTransactions()
|
||||
)
|
||||
.flatMap(Publishers.Sequence.init(sequence:))
|
||||
.collect()
|
||||
.eraseToEffect()
|
||||
}
|
||||
|
||||
func getTransparentAddress(account: Int) -> TransparentAddress? { nil }
|
||||
|
||||
func getShieldedAddress(account: Int) -> SaplingShieldedAddress? { "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8" }
|
||||
|
||||
func sendTransaction(
|
||||
with spendingKey: String,
|
||||
zatoshi: Zatoshi,
|
||||
to recipientAddress: String,
|
||||
memo: String?,
|
||||
from account: Int
|
||||
) -> Effect<Result<TransactionState, NSError>, Never> {
|
||||
return Effect(value: Result.failure(SynchronizerError.criticalError as NSError))
|
||||
}
|
||||
|
||||
func updateStateChanged(_ newState: WrappedSDKSynchronizerState) {
|
||||
stateChanged = CurrentValueSubject<WrappedSDKSynchronizerState, Never>(newState)
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
//
|
||||
// WrappedUserDefaults.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 03.05.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct WrappedUserDefaults {
|
||||
let objectForKey: @Sendable (String) -> Any?
|
||||
let remove: @Sendable (String) async -> Void
|
||||
let setValue: @Sendable (Any?, String) async -> Void
|
||||
let synchronize: @Sendable () async -> Bool
|
||||
}
|
||||
|
||||
/// `UserDefaults` is thread-safe class. Because of that we can mark it as `Sendable` on our own. If it's marked as `Sendable` in `Foundation` in
|
||||
/// future we can simply remove this line and be ok. This is probably simpliest and easiest way how to fix warnings about `UserDefaults` not being
|
||||
/// sendable.
|
||||
extension UserDefaults: @unchecked Sendable { }
|
||||
|
||||
extension WrappedUserDefaults {
|
||||
static func live(
|
||||
userDefaults: UserDefaults = .standard
|
||||
) -> Self {
|
||||
Self(
|
||||
objectForKey: { userDefaults.object(forKey: $0) },
|
||||
remove: { userDefaults.removeObject(forKey: $0) },
|
||||
setValue: { userDefaults.set($0, forKey: $1) },
|
||||
synchronize: { userDefaults.synchronize() }
|
||||
)
|
||||
}
|
||||
|
||||
static let mock = WrappedUserDefaults(
|
||||
objectForKey: { _ in },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
synchronize: { true }
|
||||
)
|
||||
}
|
|
@ -10,14 +10,6 @@ import XCTest
|
|||
import ComposableArchitecture
|
||||
|
||||
class AppInitializationTests: XCTestCase {
|
||||
var storage = WalletStorage(secItem: .live)
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
storage.zcashStoredWalletPrefix = "test_app_"
|
||||
storage.deleteData(forKey: WalletStorage.Constants.zcashStoredWallet)
|
||||
}
|
||||
|
||||
/// This integration test starts with finishing the app launch and triggering bunch of initialization proceedures.
|
||||
/// 1. The app calls .checkWalletInitialization delayed by 0.02 seconds to ensure keychain is successfuly operational.
|
||||
/// 2. The .respondToWalletInitializationState is triggered to decide the state of the wallet.
|
||||
|
@ -25,13 +17,10 @@ class AppInitializationTests: XCTestCase {
|
|||
/// 4. The .checkBackupPhraseValidation is triggered to check the validation state.
|
||||
/// 5. The user hasn't finished the backup phrase test so the display phrase is presented.
|
||||
func testDidFinishLaunching_to_InitializedWallet() throws {
|
||||
// the test needs to pass the exportWallet() so we simulate some in the keychain
|
||||
try storage.importWallet(bip39: "one two three", birthday: nil)
|
||||
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let recoveryPhrase = RecoveryPhrase(words: try WrappedMnemonic.mock.randomMnemonicWords())
|
||||
let recoveryPhrase = RecoveryPhrase(words: try MnemonicClient.mock.randomMnemonicWords())
|
||||
|
||||
let phraseValidationState = RecoveryPhraseValidationFlowReducer.State(
|
||||
phrase: recoveryPhrase,
|
||||
|
@ -48,7 +37,7 @@ class AppInitializationTests: XCTestCase {
|
|||
route: nil
|
||||
)
|
||||
|
||||
let recoveryPhraseRandomizer = WrappedRecoveryPhraseRandomizer(
|
||||
let recoveryPhraseRandomizer = RecoveryPhraseRandomizerClient(
|
||||
random: { _ in
|
||||
let missingIndices = [2, 0, 3, 5]
|
||||
let missingWordChipKind = [
|
||||
|
@ -81,18 +70,6 @@ class AppInitializationTests: XCTestCase {
|
|||
}
|
||||
)
|
||||
|
||||
let emptyURL = URL(fileURLWithPath: "")
|
||||
let dbFiles = DatabaseFilesClient(
|
||||
documentsDirectory: { emptyURL },
|
||||
cacheDbURLFor: { _ in emptyURL },
|
||||
dataDbURLFor: { _ in emptyURL },
|
||||
outputParamsURLFor: { _ in emptyURL },
|
||||
pendingDbURLFor: { _ in emptyURL },
|
||||
spendParamsURLFor: { _ in emptyURL },
|
||||
areDbFilesPresentFor: { _ in true },
|
||||
nukeDbFilesFor: { _ in throw DatabaseFiles.DatabaseFilesError.nukeFiles }
|
||||
)
|
||||
|
||||
let appState = AppReducer.State(
|
||||
homeState: .placeholder,
|
||||
onboardingState: .init(
|
||||
|
@ -109,13 +86,16 @@ class AppInitializationTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: appState,
|
||||
reducer: AppReducer()
|
||||
.dependency(\.databaseFiles, dbFiles)
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.randomPhrase, recoveryPhraseRandomizer)
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
|
||||
store.dependencies.databaseFiles = .noOp
|
||||
store.dependencies.databaseFiles.areDbFilesPresentFor = { _ in true }
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.mnemonic = .mock
|
||||
store.dependencies.randomRecoveryPhrase = recoveryPhraseRandomizer
|
||||
store.dependencies.walletStorage.exportWallet = { .placeholder }
|
||||
store.dependencies.walletStorage.areKeysPresent = { true }
|
||||
|
||||
// Root of the test, the app finished the launch process and triggers the checks and initializations.
|
||||
store.send(.appDelegate(.didFinishLaunching))
|
||||
|
@ -133,8 +113,9 @@ class AppInitializationTests: XCTestCase {
|
|||
store.receive(.initializeSDK) { state in
|
||||
state.storedWallet = StoredWallet(
|
||||
language: .english,
|
||||
seedPhrase: "one two three",
|
||||
version: 1,
|
||||
seedPhrase: "",
|
||||
version: 0,
|
||||
birthday: 0,
|
||||
hasUserPassedPhraseBackupTest: false
|
||||
)
|
||||
}
|
||||
|
@ -160,26 +141,16 @@ class AppInitializationTests: XCTestCase {
|
|||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let emptyURL = URL(fileURLWithPath: "")
|
||||
let dbFiles = DatabaseFilesClient(
|
||||
documentsDirectory: { emptyURL },
|
||||
cacheDbURLFor: { _ in emptyURL },
|
||||
dataDbURLFor: { _ in emptyURL },
|
||||
outputParamsURLFor: { _ in emptyURL },
|
||||
pendingDbURLFor: { _ in emptyURL },
|
||||
spendParamsURLFor: { _ in emptyURL },
|
||||
areDbFilesPresentFor: { _ in true },
|
||||
nukeDbFilesFor: { _ in throw DatabaseFiles.DatabaseFilesError.nukeFiles }
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: AppReducer()
|
||||
.dependency(\.databaseFiles, dbFiles)
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
store.dependencies.databaseFiles = .noOp
|
||||
store.dependencies.databaseFiles.areDbFilesPresentFor = { _ in true }
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.walletStorage = .noOp
|
||||
|
||||
// Root of the test, the app finished the launch process and triggers the checks and initializations.
|
||||
store.send(.appDelegate(.didFinishLaunching))
|
||||
|
||||
|
@ -206,12 +177,12 @@ class AppInitializationTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: AppReducer()
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
store.dependencies.databaseFiles = .throwing
|
||||
|
||||
store.dependencies.databaseFiles = .noOp
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.walletStorage = .noOp
|
||||
|
||||
// Root of the test, the app finished the launch process and triggers the checks and initializations.
|
||||
store.send(.appDelegate(.didFinishLaunching))
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ class AppTests: XCTestCase {
|
|||
|
||||
func testWalletInitializationState_Uninitialized() throws {
|
||||
let walletState = AppReducer.walletInitializationState(
|
||||
databaseFiles: .throwing,
|
||||
walletStorage: .throwing,
|
||||
databaseFiles: .noOp,
|
||||
walletStorage: .noOp,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
|
@ -23,15 +23,15 @@ class AppTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testWalletInitializationState_FilesPresentKeysMissing() throws {
|
||||
let wfmMock = WrappedFileManager(
|
||||
url: { _, _, _, _ in URL(fileURLWithPath: "") },
|
||||
let wfmMock = FileManagerClient(
|
||||
url: { _, _, _, _ in .emptyURL },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in }
|
||||
)
|
||||
|
||||
let walletState = AppReducer.walletInitializationState(
|
||||
databaseFiles: .live(databaseFiles: DatabaseFiles(fileManager: wfmMock)),
|
||||
walletStorage: .throwing,
|
||||
walletStorage: .noOp,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
|
@ -39,15 +39,15 @@ class AppTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testWalletInitializationState_FilesMissingKeysMissing() throws {
|
||||
let wfmMock = WrappedFileManager(
|
||||
url: { _, _, _, _ in URL(fileURLWithPath: "") },
|
||||
let wfmMock = FileManagerClient(
|
||||
url: { _, _, _, _ in .emptyURL },
|
||||
fileExists: { _ in return false },
|
||||
removeItem: { _ in }
|
||||
)
|
||||
|
||||
let walletState = AppReducer.walletInitializationState(
|
||||
databaseFiles: .live(databaseFiles: DatabaseFiles(fileManager: wfmMock)),
|
||||
walletStorage: .throwing,
|
||||
walletStorage: .noOp,
|
||||
zcashSDKEnvironment: .testnet
|
||||
)
|
||||
|
||||
|
@ -62,10 +62,10 @@ class AppTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: AppReducer()
|
||||
.dependency(\.mainQueue, Self.testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
||||
|
||||
store.send(.respondToWalletInitializationState(.uninitialized))
|
||||
|
||||
Self.testScheduler.advance(by: 3)
|
||||
|
@ -93,6 +93,9 @@ class AppTests: XCTestCase {
|
|||
reducer: AppReducer()
|
||||
)
|
||||
|
||||
store.dependencies.walletStorage = .noOp
|
||||
store.dependencies.walletStorage.exportWallet = { throw "export failed" }
|
||||
|
||||
store.send(.respondToWalletInitializationState(.filesMissing)) { state in
|
||||
state.appInitializationState = .filesMissing
|
||||
}
|
||||
|
@ -111,6 +114,9 @@ class AppTests: XCTestCase {
|
|||
reducer: AppReducer()
|
||||
)
|
||||
|
||||
store.dependencies.walletStorage = .noOp
|
||||
store.dependencies.walletStorage.exportWallet = { throw "export failed" }
|
||||
|
||||
store.send(.respondToWalletInitializationState(.initialized))
|
||||
|
||||
store.receive(.initializeSDK) { state in
|
||||
|
|
|
@ -15,7 +15,9 @@ class RecoveryPhraseDisplayReducerTests: XCTestCase {
|
|||
initialState: RecoveryPhraseDisplayStore.test,
|
||||
reducer: RecoveryPhraseDisplayReducer()
|
||||
)
|
||||
|
||||
|
||||
store.dependencies.pasteboard = .testPasteboard
|
||||
|
||||
store.send(.copyToBufferPressed) {
|
||||
$0.phrase = .placeholder
|
||||
$0.showCopyToBufferAlert = true
|
||||
|
|
|
@ -12,19 +12,13 @@ import ZcashLightClientKit
|
|||
|
||||
class BalanceBreakdownTests: XCTestCase {
|
||||
func testOnAppear() throws {
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: BalanceBreakdownReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
store.send(.onAppear)
|
||||
|
||||
testScheduler.advance(by: 0.1)
|
||||
|
||||
// expected side effects as a result of .onAppear registration
|
||||
store.receive(.synchronizerStateChanged(.unknown))
|
||||
store.receive(.updateSynchronizerStatus)
|
||||
|
|
|
@ -84,17 +84,16 @@ class DeeplinkTests: XCTestCase {
|
|||
reducer: AppReducer()
|
||||
)
|
||||
|
||||
let synchronizer = TestWrappedSDKSynchronizer()
|
||||
synchronizer.updateStateChanged(.synced)
|
||||
store.dependencies.sdkSynchronizer = synchronizer
|
||||
|
||||
guard let url = URL(string: "zcash:///home") else {
|
||||
return XCTFail("Deeplink: 'testDeeplinkRequest_homeURL' URL is expected to be valid.")
|
||||
}
|
||||
|
||||
store.dependencies.deeplink = DeeplinkClient(
|
||||
resolveDeeplinkURL: { _, _ in Deeplink.Route.home }
|
||||
)
|
||||
let synchronizer = NoopSDKSynchronizer()
|
||||
synchronizer.updateStateChanged(.synced)
|
||||
store.dependencies.sdkSynchronizer = synchronizer
|
||||
|
||||
guard let url = URL(string: "zcash:///home") else {
|
||||
return XCTFail("Deeplink: 'testDeeplinkRequest_homeURL' URL is expected to be valid.")
|
||||
}
|
||||
|
||||
_ = await store.send(.deeplink(url))
|
||||
|
||||
|
@ -116,7 +115,7 @@ class DeeplinkTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDeeplinkRequest_Received_Send() async throws {
|
||||
let synchronizer = TestWrappedSDKSynchronizer()
|
||||
let synchronizer = NoopSDKSynchronizer()
|
||||
synchronizer.updateStateChanged(.synced)
|
||||
|
||||
var appState = AppReducer.State.placeholder
|
||||
|
@ -126,7 +125,6 @@ class DeeplinkTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: appState,
|
||||
reducer: AppReducer()
|
||||
.dependency(\.sdkSynchronizer, synchronizer)
|
||||
)
|
||||
|
||||
guard let url = URL(string: "zcash:///home/send?address=address&memo=some%20text&amount=123000000") else {
|
||||
|
@ -136,6 +134,7 @@ class DeeplinkTests: XCTestCase {
|
|||
store.dependencies.deeplink = DeeplinkClient(
|
||||
resolveDeeplinkURL: { _, _ in Deeplink.Route.send(amount: 123_000_000, address: "address", memo: "some text") }
|
||||
)
|
||||
store.dependencies.sdkSynchronizer = synchronizer
|
||||
|
||||
_ = await store.send(.deeplink(url))
|
||||
|
||||
|
|
|
@ -32,9 +32,11 @@ class HomeTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: HomeReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.sdkSynchronizer = SDKSynchronizerDependency.mock
|
||||
|
||||
store.send(.synchronizerStateChanged(.synced))
|
||||
|
||||
testScheduler.advance(by: 0.01)
|
||||
|
@ -44,11 +46,11 @@ class HomeTests: XCTestCase {
|
|||
|
||||
// ad 2.
|
||||
let transactionsHelper: [TransactionStateMockHelper] = [
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "1"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "2"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "3"),
|
||||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(4), uuid: "4"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "5")
|
||||
TransactionStateMockHelper(date: 1651039202, amount: Zatoshi(1), status: .paid(success: false), uuid: "aa11"),
|
||||
TransactionStateMockHelper(date: 1651039101, amount: Zatoshi(2), uuid: "bb22"),
|
||||
TransactionStateMockHelper(date: 1651039000, amount: Zatoshi(3), status: .paid(success: true), uuid: "cc33"),
|
||||
TransactionStateMockHelper(date: 1651039505, amount: Zatoshi(4), uuid: "dd44"),
|
||||
TransactionStateMockHelper(date: 1651039404, amount: Zatoshi(5), uuid: "ee55")
|
||||
]
|
||||
let walletEvents: [WalletEvent] = transactionsHelper.map {
|
||||
let transaction = TransactionState.placeholder(
|
||||
|
|
|
@ -26,9 +26,11 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.mnemonic.isValid = { _ in throw "invalid mnemonic" }
|
||||
|
||||
store.send(.binding(.set(\.$importedSeedPhrase, "one two three"))) { state in
|
||||
state.importedSeedPhrase = "one two three"
|
||||
state.wordsCount = 3
|
||||
|
@ -40,9 +42,11 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.mnemonic.isValid = { _ in throw "invalid mnemonic" }
|
||||
|
||||
store.send(.binding(.set(\.$importedSeedPhrase, "a a a a a a a a a a a a a a a a a a a a a a a a"))) { state in
|
||||
state.importedSeedPhrase = "a a a a a a a a a a a a a a a a a a a a a a a a"
|
||||
state.wordsCount = 24
|
||||
|
@ -55,9 +59,10 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
|
||||
store.send(
|
||||
.binding(
|
||||
.set(
|
||||
|
@ -142,9 +147,11 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.mnemonic.isValid = { _ in throw "invalid mnemonic" }
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1700000"))) { state in
|
||||
state.birthdayHeight = "1700000"
|
||||
state.birthdayHeightValue = 1_700_000
|
||||
|
@ -166,9 +173,11 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.mnemonic.isValid = { _ in throw "invalid mnemonic" }
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1600000"))) { state in
|
||||
state.birthdayHeight = "1600000"
|
||||
}
|
||||
|
@ -189,9 +198,10 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1600000"))) { state in
|
||||
state.birthdayHeight = "1600000"
|
||||
}
|
||||
|
@ -229,9 +239,10 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
|
||||
store.send(.binding(.set(\.$birthdayHeight, "1700000"))) { state in
|
||||
state.birthdayHeight = "1700000"
|
||||
state.birthdayHeightValue = 1_700_000
|
||||
|
@ -270,9 +281,10 @@ class ImportWalletTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
|
||||
store.send(
|
||||
.binding(
|
||||
.set(
|
||||
|
@ -303,10 +315,6 @@ class ImportWalletTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testRestoreWallet() throws {
|
||||
var storage = WalletStorage(secItem: .live)
|
||||
storage.zcashStoredWalletPrefix = "test_importWallet_"
|
||||
storage.deleteData(forKey: WalletStorage.Constants.zcashStoredWallet)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(
|
||||
alert: nil,
|
||||
|
@ -324,10 +332,11 @@ class ImportWalletTests: XCTestCase {
|
|||
birthdayHeightValue: 1_700_000
|
||||
),
|
||||
reducer: ImportWalletReducer()
|
||||
.dependency(\.mnemonic, .live)
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
)
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.walletStorage = .noOp
|
||||
|
||||
store.send(.restoreWallet) { state in
|
||||
state.alert = AlertState(
|
||||
title: TextState("Success"),
|
||||
|
|
|
@ -14,10 +14,10 @@ class ProfileTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: ProfileReducer()
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.appVersion = .mock
|
||||
store.dependencies.sdkSynchronizer = SDKSynchronizerDependency.mock
|
||||
|
||||
store.send(.onAppear) { state in
|
||||
state.address = "ff3927e1f83df9b1b0dc75540ddc59ee435eecebae914d2e6dfe8576fbedc9a8"
|
||||
|
|
|
@ -291,7 +291,6 @@ class RecoveryPhraseValidationTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: currentStep,
|
||||
reducer: RecoveryPhraseValidationFlowReducer()
|
||||
.dependency(\.mainQueue, RecoveryPhraseValidationTests.testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
let expectedMissingWordChips = [
|
||||
|
@ -308,6 +307,8 @@ class RecoveryPhraseValidationTests: XCTestCase {
|
|||
ValidationWord(groupIndex: 3, word: "pizza")
|
||||
]
|
||||
|
||||
store.dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
||||
|
||||
store.send(.move(wordChip: PhraseChip.Kind.unassigned(word: "pizza"), intoGroup: 3)) {
|
||||
$0.missingWordChips = expectedMissingWordChips
|
||||
$0.validationWords = expectedValidationWords
|
||||
|
@ -362,7 +363,6 @@ class RecoveryPhraseValidationTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: currentStep,
|
||||
reducer: RecoveryPhraseValidationFlowReducer()
|
||||
.dependency(\.mainQueue, RecoveryPhraseValidationTests.testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
let expectedMissingWordChips = [
|
||||
|
@ -379,6 +379,9 @@ class RecoveryPhraseValidationTests: XCTestCase {
|
|||
ValidationWord(groupIndex: 3, word: "pizza")
|
||||
]
|
||||
|
||||
store.dependencies.feedbackGenerator = .noOp
|
||||
store.dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
||||
|
||||
store.send(.move(wordChip: PhraseChip.Kind.unassigned(word: "pizza"), intoGroup: 3)) {
|
||||
$0.missingWordChips = expectedMissingWordChips
|
||||
$0.validationWords = expectedValidationWords
|
||||
|
|
|
@ -23,7 +23,7 @@ class ScanTests: XCTestCase {
|
|||
reducer: ScanReducer()
|
||||
)
|
||||
|
||||
store.dependencies.captureDevice = .noop
|
||||
store.dependencies.captureDevice = .noOp
|
||||
|
||||
store.send(.onAppear) { state in
|
||||
state.isTorchAvailable = false
|
||||
|
@ -39,7 +39,7 @@ class ScanTests: XCTestCase {
|
|||
reducer: ScanReducer()
|
||||
)
|
||||
|
||||
store.dependencies.captureDevice = .noop
|
||||
store.dependencies.captureDevice = .noOp
|
||||
|
||||
store.send(.torchPressed) { state in
|
||||
state.isTorchOn = true
|
||||
|
@ -54,7 +54,7 @@ class ScanTests: XCTestCase {
|
|||
reducer: ScanReducer()
|
||||
)
|
||||
|
||||
store.dependencies.captureDevice = .noop
|
||||
store.dependencies.captureDevice = .noOp
|
||||
|
||||
store.send(.torchPressed) { state in
|
||||
state.isTorchOn = false
|
||||
|
@ -67,6 +67,8 @@ class ScanTests: XCTestCase {
|
|||
reducer: ScanReducer()
|
||||
)
|
||||
|
||||
store.dependencies.uriParser.isValidURI = { _ in false }
|
||||
|
||||
store.send(.scan("test")) { state in
|
||||
state.scanStatus = .value("test")
|
||||
state.isValidValue = false
|
||||
|
@ -79,9 +81,11 @@ class ScanTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: ScanReducer.State(),
|
||||
reducer: ScanReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.uriParser.isValidURI = { _ in true }
|
||||
|
||||
store.send(.scan("t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po")) { state in
|
||||
state.scanStatus = .value("t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po")
|
||||
state.isValidValue = true
|
||||
|
|
|
@ -28,22 +28,21 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendSucceeded() throws {
|
||||
// the test needs to pass the exportWallet() so we simulate some in the keychain
|
||||
try storage.importWallet(bip39: "one two three", birthday: nil)
|
||||
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.deriveSpendingKeys = { _, _ in [""] }
|
||||
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.mnemonic = .mock
|
||||
store.dependencies.sdkSynchronizer = SDKSynchronizerDependency.mock
|
||||
store.dependencies.walletStorage.exportWallet = { .placeholder }
|
||||
|
||||
// simulate the sending confirmation button to be pressed
|
||||
store.send(.sendConfirmationPressed) { state in
|
||||
// once sending is confirmed, the attemts to try to send again by pressing the button
|
||||
|
@ -85,9 +84,6 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendSucceededWithoutMemo() throws {
|
||||
// the test needs to pass the exportWallet() so we simulate some in the keychain
|
||||
try storage.importWallet(bip39: "one two three", birthday: nil)
|
||||
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
|
@ -97,12 +93,14 @@ class SendTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: state,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.deriveSpendingKeys = { _, _ in [""] }
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.mnemonic = .mock
|
||||
store.dependencies.sdkSynchronizer = SDKSynchronizerDependency.mock
|
||||
store.dependencies.walletStorage.exportWallet = { .placeholder }
|
||||
|
||||
// simulate the sending confirmation button to be pressed
|
||||
store.send(.sendConfirmationPressed) { state in
|
||||
|
@ -145,22 +143,19 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSendFailed() throws {
|
||||
// the test needs to pass the exportWallet() so we simulate some in the keychain
|
||||
try storage.importWallet(bip39: "one two three", birthday: nil)
|
||||
|
||||
// setup the store and environment to be fully mocked
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: storage))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.deriveSpendingKeys = { _, _ in [""] }
|
||||
store.dependencies.mainQueue = testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.mnemonic = .mock
|
||||
store.dependencies.walletStorage.exportWallet = { .placeholder }
|
||||
|
||||
// simulate the sending confirmation button to be pressed
|
||||
store.send(.sendConfirmationPressed) { state in
|
||||
|
@ -190,17 +185,12 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testAddressValidation() throws {
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.isValidZcashAddress = { _ in false }
|
||||
|
||||
store.send(.transactionAddressInput(.textField(.set("3HRG769ii3HDSJV5vNknQPzXqtL2mTSGnr")))) { state in
|
||||
|
@ -231,16 +221,13 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testInvalidAmountFormatEmptyInput() throws {
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter = .noOp
|
||||
|
||||
// Checks the computed property `isInvalidAmountFormat` which controls the error message to be shown on the screen
|
||||
// With empty input it must be false
|
||||
store.send(.transactionAmountInput(.textField(.set(""))))
|
||||
|
@ -249,17 +236,12 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testInvalidAddressFormatEmptyInput() throws {
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
|
||||
// Checks the computed property `isInvalidAddressFormat` which controls the error message to be shown on the screen
|
||||
// With empty input it must be false
|
||||
|
@ -291,17 +273,15 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter = .noOp
|
||||
store.dependencies.numberFormatter.number = { _ in NSNumber(0.00501299) }
|
||||
|
||||
store.send(.transactionAmountInput(.textField(.set("0.00501299")))) { state in
|
||||
state.transactionAmountInputState.textFieldState.text = "0.00501299"
|
||||
state.transactionAmountInputState.textFieldState.valid = true
|
||||
|
@ -315,6 +295,8 @@ class SendTests: XCTestCase {
|
|||
state.transactionAmountInputState.amount = 501_299
|
||||
}
|
||||
|
||||
store.dependencies.numberFormatter.number = { _ in NSNumber(0.00501301) }
|
||||
|
||||
store.send(.transactionAmountInput(.textField(.set("0.00501301")))) { state in
|
||||
state.transactionAmountInputState.textFieldState.text = "0.00501301"
|
||||
state.transactionAmountInputState.textFieldState.valid = true
|
||||
|
@ -333,43 +315,19 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testDifferentAmountFormats() throws {
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .init(
|
||||
addMemoState: true,
|
||||
memoState: .placeholder,
|
||||
route: nil,
|
||||
transactionAddressInputState: .placeholder,
|
||||
transactionAmountInputState:
|
||||
TransactionAmountTextFieldReducer.State(
|
||||
currencySelectionState: CurrencySelectionReducer.State(),
|
||||
textFieldState:
|
||||
TCATextFieldReducer.State(
|
||||
validationType: .customFloatingPoint(usNumberFormatter),
|
||||
text: ""
|
||||
)
|
||||
)
|
||||
),
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
try amountFormatTest("1.234", true, 123_400_000, false, store)
|
||||
try amountFormatTest("1,234", true, 123_400_000_000, false, store)
|
||||
try amountFormatTest("1 234", true, 123_400_000_000, true, store)
|
||||
try amountFormatTest("1,234.567", true, 123_456_700_000, false, store)
|
||||
try amountFormatTest("1.", true, 100_000_000, false, store)
|
||||
try amountFormatTest("1..", false, 0, false, store)
|
||||
try amountFormatTest("1,.", false, 0, true, store)
|
||||
try amountFormatTest("1.,", false, 0, true, store)
|
||||
try amountFormatTest("1,,", false, 0, true, store)
|
||||
try amountFormatTest("1,23", false, 0, true, store)
|
||||
try amountFormatTest("1 23", false, 0, true, store)
|
||||
try amountFormatTest("1.2.3", false, 0, true, store)
|
||||
func testDifferentNumberFormats_LiveNumberFormatter() throws {
|
||||
try numberFormatTest("1.234", NSNumber(1.234))
|
||||
try numberFormatTest("1,234", NSNumber(1_234))
|
||||
try numberFormatTest("1 234", NSNumber(1_234))
|
||||
try numberFormatTest("1,234.567", NSNumber(1_234.567))
|
||||
try numberFormatTest("1.", NSNumber(1))
|
||||
try numberFormatTest("1..", nil)
|
||||
try numberFormatTest("1,.", nil)
|
||||
try numberFormatTest("1.,", nil)
|
||||
try numberFormatTest("1,,", nil)
|
||||
try numberFormatTest("1,23", nil)
|
||||
try numberFormatTest("1 23", nil)
|
||||
try numberFormatTest("1.2.3", nil)
|
||||
}
|
||||
|
||||
func testValidForm() throws {
|
||||
|
@ -389,18 +347,13 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.isValidZcashAddress = { _ in true }
|
||||
|
||||
store.send(.transactionAddressInput(.textField(.set("t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po")))) { state in
|
||||
|
@ -433,17 +386,12 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.isValidZcashAddress = { _ in true }
|
||||
|
||||
store.send(.transactionAddressInput(.textField(.set("t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po")))) { state in
|
||||
|
@ -475,18 +423,13 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .noop
|
||||
store.dependencies.derivationTool = .noOp
|
||||
|
||||
store.send(.transactionAddressInput(.textField(.set("3HRG769ii3HDSJV5vNknQPzXqtL2mTSGnr")))) { state in
|
||||
state.transactionAddressInputState.textFieldState.text = "3HRG769ii3HDSJV5vNknQPzXqtL2mTSGnr"
|
||||
|
@ -518,20 +461,16 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.dependencies.derivationTool = .liveValue
|
||||
|
||||
store.send(.transactionAddressInput(.textField(.set("t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po")))) { state in
|
||||
state.transactionAddressInputState.textFieldState.text = "t1gXqfSSQt6WfpwyuCU3Wi7sSVZ66DYQ3Po"
|
||||
store.dependencies.derivationTool = .noOp
|
||||
store.dependencies.derivationTool.isValidZcashAddress = { _ in true }
|
||||
|
||||
store.send(.transactionAddressInput(.textField(.set("tmGh6ttAnQRJra81moqYcedFadW9XtUT5Eq")))) { state in
|
||||
state.transactionAddressInputState.textFieldState.text = "tmGh6ttAnQRJra81moqYcedFadW9XtUT5Eq"
|
||||
// true is expected here because textField doesn't have any `validationType: String.ValidationType?`
|
||||
// isValid function returns true, `guard let validationType = validationType else { return true }`
|
||||
state.transactionAddressInputState.textFieldState.valid = true
|
||||
|
@ -569,17 +508,12 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
|
||||
store.send(.memo(.binding(.set(\.$text, "test")))) { state in
|
||||
state.memoState.text = "test"
|
||||
XCTAssertFalse(
|
||||
|
@ -606,14 +540,9 @@ class SendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
|
||||
let testScheduler = DispatchQueue.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: sendState,
|
||||
reducer: SendFlowReducer()
|
||||
.dependency(\.mainQueue, testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live(walletStorage: WalletStorage(secItem: .live)))
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
)
|
||||
|
||||
store.send(.onAppear) { state in
|
||||
|
@ -629,24 +558,15 @@ class SendTests: XCTestCase {
|
|||
}
|
||||
|
||||
private extension SendTests {
|
||||
func amountFormatTest(
|
||||
func numberFormatTest(
|
||||
_ amount: String,
|
||||
_ expectedValidationResult: Bool,
|
||||
_ expectedAmount: Int64,
|
||||
_ expectedToReceive: Bool,
|
||||
_ store: TestStore<SendFlowReducer.State, SendFlowReducer.Action, SendFlowReducer.State, SendFlowReducer.Action, Void>
|
||||
_ expectedResult: NSNumber?
|
||||
) throws {
|
||||
store.send(.transactionAmountInput(.textField(.set(amount)))) { state in
|
||||
state.transactionAmountInputState.textFieldState.text = amount
|
||||
state.transactionAmountInputState.textFieldState.valid = expectedValidationResult
|
||||
}
|
||||
|
||||
if expectedToReceive {
|
||||
store.receive(.transactionAmountInput(.updateAmount))
|
||||
if let number = NumberFormatterClient.liveValue.number(amount) {
|
||||
XCTAssertEqual(number, expectedResult)
|
||||
return
|
||||
} else {
|
||||
store.receive(.transactionAmountInput(.updateAmount)) { state in
|
||||
state.transactionAmountInputState.amount = expectedAmount
|
||||
}
|
||||
XCTAssertEqual(nil, expectedResult, "NumberFormatterClient.liveValue.number(\(amount)) unexpected result.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
)
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.setMax) { state in
|
||||
state.textFieldState.text = "0.00501301"
|
||||
}
|
||||
|
@ -83,9 +85,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
zecPrice: 1000.0
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.currencySelection(.swapCurrencyType)) { state in
|
||||
state.textFieldState.text = "1,000"
|
||||
state.currencySelectionState.currencyType = .usd
|
||||
|
@ -112,9 +116,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
zecPrice: 1000.0
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.currencySelection(.swapCurrencyType)) { state in
|
||||
state.textFieldState.text = "25,000,000"
|
||||
state.currencySelectionState.currencyType = .usd
|
||||
|
@ -141,9 +147,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
zecPrice: 1000.0
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.currencySelection(.swapCurrencyType)) { state in
|
||||
state.textFieldState.text = "1"
|
||||
state.currencySelectionState.currencyType = .zec
|
||||
|
@ -171,9 +179,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
zecPrice: 1000.0
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.textField(.set("1 000"))) { state in
|
||||
state.textFieldState.text = "1 000"
|
||||
state.textFieldState.valid = true
|
||||
|
@ -210,9 +220,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
zecPrice: 1000.0
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.setMax) { state in
|
||||
state.textFieldState.text = "2"
|
||||
}
|
||||
|
@ -239,9 +251,11 @@ class TransactionAmountTextFieldTests: XCTestCase {
|
|||
zecPrice: 1000.0
|
||||
),
|
||||
reducer: TransactionAmountTextFieldReducer()
|
||||
.dependency(\.numberFormatter, .live(numberFormatter: usNumberFormatter))
|
||||
)
|
||||
|
||||
store.dependencies.numberFormatter.string = { self.usNumberFormatter.string(from: $0) }
|
||||
store.dependencies.numberFormatter.number = { self.usNumberFormatter.number(from: $0) }
|
||||
|
||||
store.send(.setMax) { state in
|
||||
state.textFieldState.text = "2,000"
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class SettingsTests: XCTestCase {
|
|||
breeze blouse charge solid fish spread
|
||||
"""
|
||||
|
||||
let mockedWalletStorage = WrappedWalletStorage(
|
||||
let mockedWalletStorage = WalletStorageClient(
|
||||
importWallet: { _, _, _, _ in
|
||||
throw WalletStorage.WalletStorageError.alreadyImported
|
||||
},
|
||||
|
@ -47,11 +47,13 @@ class SettingsTests: XCTestCase {
|
|||
let store = TestStore(
|
||||
initialState: SettingsReducer.State(phraseDisplayState: RecoveryPhraseDisplayReducer.State(phrase: nil)),
|
||||
reducer: SettingsReducer()
|
||||
.dependency(\.walletStorage, mockedWalletStorage)
|
||||
)
|
||||
|
||||
store.dependencies.localAuthentication = .mockAuthenticationSucceeded
|
||||
|
||||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.mnemonic.asWords = { _ in mnemonic.components(separatedBy: " ") }
|
||||
store.dependencies.walletStorage = mockedWalletStorage
|
||||
|
||||
_ = await store.send(.backupWalletAccessRequest)
|
||||
|
||||
await store.receive(.backupWallet) { state in
|
||||
|
|
|
@ -12,7 +12,7 @@ import ComposableArchitecture
|
|||
|
||||
class HomeCircularProgressSnapshotTests: XCTestCase {
|
||||
func testCircularProgress_DownloadingInnerCircle() throws {
|
||||
class SnapshotTestWrappedSDKSynchronizer: TestWrappedSDKSynchronizer {
|
||||
class SnapshotNoopSDKSynchronizer: NoopSDKSynchronizer {
|
||||
// heights purposely set so we visually see 55% progress
|
||||
override func statusSnapshot() -> SyncStatusSnapshot {
|
||||
let blockProgress = BlockProgress(
|
||||
|
@ -40,15 +40,15 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
|
|||
walletEventsState: .emptyPlaceHolder
|
||||
),
|
||||
reducer: HomeReducer()
|
||||
.dependency(\.sdkSynchronizer, SnapshotTestWrappedSDKSynchronizer())
|
||||
.dependency(\.diskSpaceChecker, .mockEmptyDisk)
|
||||
.dependency(\.sdkSynchronizer, SnapshotNoopSDKSynchronizer())
|
||||
)
|
||||
|
||||
addAttachments(HomeView(store: store))
|
||||
}
|
||||
|
||||
func testCircularProgress_ScanningOuterCircle() throws {
|
||||
class SnapshotTestWrappedSDKSynchronizer: TestWrappedSDKSynchronizer {
|
||||
class SnapshotNoopSDKSynchronizer: NoopSDKSynchronizer {
|
||||
override func statusSnapshot() -> SyncStatusSnapshot {
|
||||
// heights purposely set so we visually see 72% progress
|
||||
let blockProgress = BlockProgress(
|
||||
|
@ -83,7 +83,7 @@ class HomeCircularProgressSnapshotTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testCircularProgress_UpToDateOnlyOuterCircle() throws {
|
||||
class SnapshotTestWrappedSDKSynchronizer: TestWrappedSDKSynchronizer {
|
||||
class SnapshotNoopSDKSynchronizer: NoopSDKSynchronizer {
|
||||
override func statusSnapshot() -> SyncStatusSnapshot {
|
||||
SyncStatusSnapshot.snapshotFor(state: .synced)
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ class ProfileSnapshotTests: XCTestCase {
|
|||
let store = Store(
|
||||
initialState: .placeholder,
|
||||
reducer: ProfileReducer()
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
.dependency(\.appVersion, .mock)
|
||||
.dependency(\.sdkSynchronizer, NoopSDKSynchronizer())
|
||||
)
|
||||
|
||||
ViewStore(store).send(.onAppear)
|
||||
|
|
|
@ -24,7 +24,8 @@ class RecoveryPhraseValidationFlowSnapshotTests: XCTestCase {
|
|||
let store = RecoveryPhraseValidationFlowStore(
|
||||
initialState: .placeholder,
|
||||
reducer: RecoveryPhraseValidationFlowReducer()
|
||||
.dependency(\.mainQueue, RecoveryPhraseValidationTests.testScheduler.eraseToAnyScheduler())
|
||||
.dependency(\.feedbackGenerator, .noOp)
|
||||
.dependency(\.mainQueue, DispatchQueue.test.eraseToAnyScheduler())
|
||||
)
|
||||
let viewStore = ViewStore(store)
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ class TransactionConfirmationSnapshotTests: XCTestCase {
|
|||
reducer: SendFlowReducer()
|
||||
.dependency(\.derivationTool, .live(derivationTool: DerivationTool(networkType: .testnet)))
|
||||
.dependency(\.mainQueue, DispatchQueue.main.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live())
|
||||
.dependency(\.numberFormatter, .live())
|
||||
.dependency(\.walletStorage, .live())
|
||||
)
|
||||
|
||||
ViewStore(store).send(.onAppear)
|
||||
|
@ -64,8 +64,8 @@ class TransactionConfirmationSnapshotTests: XCTestCase {
|
|||
reducer: SendFlowReducer()
|
||||
.dependency(\.derivationTool, .live(derivationTool: DerivationTool(networkType: .testnet)))
|
||||
.dependency(\.mainQueue, DispatchQueue.main.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live())
|
||||
.dependency(\.numberFormatter, .live())
|
||||
.dependency(\.walletStorage, .live())
|
||||
)
|
||||
|
||||
ViewStore(store).send(.onAppear)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// TransactionSendingTests.swift
|
||||
// TransactionSendingSnapshotTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Michal Fousek on 30.09.2022.
|
||||
|
@ -34,8 +34,8 @@ class TransactionSendingTests: XCTestCase {
|
|||
reducer: SendFlowReducer()
|
||||
.dependency(\.derivationTool, .live(derivationTool: DerivationTool(networkType: .testnet)))
|
||||
.dependency(\.mainQueue, DispatchQueue.main.eraseToAnyScheduler())
|
||||
.dependency(\.walletStorage, .live())
|
||||
.dependency(\.numberFormatter, .live())
|
||||
.dependency(\.walletStorage, .live())
|
||||
)
|
||||
|
||||
ViewStore(store).send(.onAppear)
|
|
@ -16,8 +16,8 @@ class SettingsSnapshotTests: XCTestCase {
|
|||
initialState: .placeholder,
|
||||
reducer: SettingsReducer()
|
||||
.dependency(\.localAuthentication, .mockAuthenticationFailed)
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
.dependency(\.walletStorage, .throwing)
|
||||
.dependency(\.sdkSynchronizer, NoopSDKSynchronizer())
|
||||
.dependency(\.walletStorage, .noOp)
|
||||
)
|
||||
|
||||
addAttachments(SettingsView(store: store))
|
||||
|
|
|
@ -30,7 +30,7 @@ class DatabaseFilesTests: XCTestCase {
|
|||
let network = ZcashNetworkBuilder.network(for: .testnet)
|
||||
|
||||
func testFailingDocumentsDirectory() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in throw "some error" },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in }
|
||||
|
@ -58,7 +58,7 @@ class DatabaseFilesTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testFailingDataDbURL() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in throw "some error" },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in }
|
||||
|
@ -86,8 +86,8 @@ class DatabaseFilesTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDatabaseFilesPresent() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
url: { _, _, _, _ in URL(fileURLWithPath: "") },
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in .emptyURL },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in }
|
||||
)
|
||||
|
@ -104,8 +104,8 @@ class DatabaseFilesTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDatabaseFilesNotPresent() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
url: { _, _, _, _ in URL(fileURLWithPath: "") },
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in .emptyURL },
|
||||
fileExists: { _ in return false },
|
||||
removeItem: { _ in }
|
||||
)
|
||||
|
@ -122,7 +122,7 @@ class DatabaseFilesTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDatabaseFilesPresentFailure() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in throw "some error" },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in }
|
||||
|
@ -150,8 +150,8 @@ class DatabaseFilesTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testNukeFiles_RemoveFileFailure() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
url: { _, _, _, _ in URL(fileURLWithPath: "") },
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in .emptyURL },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in throw "some error" }
|
||||
)
|
||||
|
@ -178,7 +178,7 @@ class DatabaseFilesTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testNukeFiles_URLFailure() throws {
|
||||
let mockedFileManager = WrappedFileManager(
|
||||
let mockedFileManager = FileManagerClient(
|
||||
url: { _, _, _, _ in throw "some error" },
|
||||
fileExists: { _ in return true },
|
||||
removeItem: { _ in }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// WrappedSecItemTests.swift
|
||||
// SecItemClientTests.swift
|
||||
// secantTests
|
||||
//
|
||||
// Created by Lukáš Korba on 12.04.2022.
|
||||
|
@ -20,9 +20,9 @@ extension WalletStorage.KeychainError {
|
|||
}
|
||||
}
|
||||
|
||||
class WrappedSecItemTests: XCTestCase {
|
||||
class SecItemClientTests: XCTestCase {
|
||||
func test_secItemAdd_KeychainErrorDuplicate() throws {
|
||||
let secItemDuplicate = WrappedSecItem(
|
||||
let secItemDuplicate = SecItemClient(
|
||||
copyMatching: { _, _ in errSecSuccess },
|
||||
add: { _, _ in errSecDuplicateItem },
|
||||
update: { _, _ in errSecSuccess },
|
||||
|
@ -34,10 +34,10 @@ class WrappedSecItemTests: XCTestCase {
|
|||
do {
|
||||
try walletStorage.setData(Data(), forKey: "")
|
||||
|
||||
XCTFail("WrappedSecItem: test_secItemAdd_KeychainErrorDuplicate expected to fail but passed.")
|
||||
XCTFail("SecItemClient: test_secItemAdd_KeychainErrorDuplicate expected to fail but passed.")
|
||||
} catch {
|
||||
guard let error = error as? WalletStorage.KeychainError else {
|
||||
XCTFail("WrappedSecItem: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
XCTFail("SecItemClient: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -45,13 +45,13 @@ class WrappedSecItemTests: XCTestCase {
|
|||
XCTAssertEqual(
|
||||
error.debugValue,
|
||||
WalletStorage.KeychainError.duplicate.debugValue,
|
||||
"WrappedSecItem: error must be .duplicate but it's \(error)."
|
||||
"SecItemClient: error must be .duplicate but it's \(error)."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func test_secItemAdd_KeychainErrorUnknown() throws {
|
||||
let secItemDuplicate = WrappedSecItem(
|
||||
let secItemDuplicate = SecItemClient(
|
||||
copyMatching: { _, _ in errSecSuccess },
|
||||
add: { _, _ in errSecCoreFoundationUnknown },
|
||||
update: { _, _ in errSecSuccess },
|
||||
|
@ -63,10 +63,10 @@ class WrappedSecItemTests: XCTestCase {
|
|||
do {
|
||||
try walletStorage.setData(Data(), forKey: "")
|
||||
|
||||
XCTFail("WrappedSecItem: test_secItemAdd_KeychainErrorUnknown expected to fail but passed.")
|
||||
XCTFail("SecItemClient: test_secItemAdd_KeychainErrorUnknown expected to fail but passed.")
|
||||
} catch {
|
||||
guard let error = error as? WalletStorage.KeychainError else {
|
||||
XCTFail("WrappedSecItem: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
XCTFail("SecItemClient: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -74,13 +74,13 @@ class WrappedSecItemTests: XCTestCase {
|
|||
XCTAssertEqual(
|
||||
error.debugValue,
|
||||
WalletStorage.KeychainError.unknown(0).debugValue,
|
||||
"WrappedSecItem: error must be .unknown but it's \(error)."
|
||||
"SecItemClient: error must be .unknown but it's \(error)."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func test_secItemUpdate_KeychainErrorNoDataFound() throws {
|
||||
let secItemDuplicate = WrappedSecItem(
|
||||
let secItemDuplicate = SecItemClient(
|
||||
copyMatching: { _, _ in errSecSuccess },
|
||||
add: { _, _ in errSecSuccess },
|
||||
update: { _, _ in errSecItemNotFound },
|
||||
|
@ -92,10 +92,10 @@ class WrappedSecItemTests: XCTestCase {
|
|||
do {
|
||||
try walletStorage.updateData(Data(), forKey: "")
|
||||
|
||||
XCTFail("WrappedSecItem: test_secItemUpdate_KeychainErrorNoDataFound expected to fail but passed.")
|
||||
XCTFail("SecItemClient: test_secItemUpdate_KeychainErrorNoDataFound expected to fail but passed.")
|
||||
} catch {
|
||||
guard let error = error as? WalletStorage.KeychainError else {
|
||||
XCTFail("WrappedSecItem: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
XCTFail("SecItemClient: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -103,13 +103,13 @@ class WrappedSecItemTests: XCTestCase {
|
|||
XCTAssertEqual(
|
||||
error.debugValue,
|
||||
WalletStorage.KeychainError.noDataFound.debugValue,
|
||||
"WrappedSecItem: error must be .noDataFound but it's \(error)."
|
||||
"SecItemClient: error must be .noDataFound but it's \(error)."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func test_secItemUpdate_KeychainErrorUnknown() throws {
|
||||
let secItemDuplicate = WrappedSecItem(
|
||||
let secItemDuplicate = SecItemClient(
|
||||
copyMatching: { _, _ in errSecSuccess },
|
||||
add: { _, _ in errSecSuccess },
|
||||
update: { _, _ in errSecCoreFoundationUnknown },
|
||||
|
@ -121,10 +121,10 @@ class WrappedSecItemTests: XCTestCase {
|
|||
do {
|
||||
try walletStorage.updateData(Data(), forKey: "")
|
||||
|
||||
XCTFail("WrappedSecItem: test_secItemUpdate_KeychainErrorUnknown expected to fail but passed.")
|
||||
XCTFail("SecItemClient: test_secItemUpdate_KeychainErrorUnknown expected to fail but passed.")
|
||||
} catch {
|
||||
guard let error = error as? WalletStorage.KeychainError else {
|
||||
XCTFail("WrappedSecItem: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
XCTFail("SecItemClient: the error is expected to be WalletStorage.KeychainError but it's \(error).")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -132,13 +132,13 @@ class WrappedSecItemTests: XCTestCase {
|
|||
XCTAssertEqual(
|
||||
error.debugValue,
|
||||
WalletStorage.KeychainError.unknown(0).debugValue,
|
||||
"WrappedSecItem: error must be .unknown but it's \(error)."
|
||||
"SecItemClient: error must be .unknown but it's \(error)."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func test_secItemDelete_Succeeded() throws {
|
||||
let secItemDuplicate = WrappedSecItem(
|
||||
let secItemDuplicate = SecItemClient(
|
||||
copyMatching: { _, _ in errSecSuccess },
|
||||
add: { _, _ in errSecSuccess },
|
||||
update: { _, _ in errSecSuccess },
|
||||
|
@ -153,7 +153,7 @@ class WrappedSecItemTests: XCTestCase {
|
|||
}
|
||||
|
||||
func test_secItemDelete_Failed() throws {
|
||||
let secItemDuplicate = WrappedSecItem(
|
||||
let secItemDuplicate = SecItemClient(
|
||||
copyMatching: { _, _ in errSecSuccess },
|
||||
add: { _, _ in errSecSuccess },
|
||||
update: { _, _ in errSecSuccess },
|
|
@ -94,7 +94,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
|||
// MARK: - Mocked user defaults vs. default values
|
||||
|
||||
func testAppSessionFrom_mocked() throws {
|
||||
let mockedUD = WrappedUserDefaults(
|
||||
let mockedUD = UserDefaultsClient(
|
||||
objectForKey: { _ in 87654321.0 },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
|
@ -114,7 +114,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testConvertedCurrency_mocked() throws {
|
||||
let mockedUD = WrappedUserDefaults(
|
||||
let mockedUD = UserDefaultsClient(
|
||||
objectForKey: { _ in "CZK" },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
|
@ -134,7 +134,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testFiatConvertion_mocked() throws {
|
||||
let mockedUD = WrappedUserDefaults(
|
||||
let mockedUD = UserDefaultsClient(
|
||||
objectForKey: { _ in false },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
|
@ -154,7 +154,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testRecoveryPhraseTestCompleted_mocked() throws {
|
||||
let mockedUD = WrappedUserDefaults(
|
||||
let mockedUD = UserDefaultsClient(
|
||||
objectForKey: { _ in false },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
|
@ -174,7 +174,7 @@ class UserPreferencesStorageTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSessionAutoshielded_mocked() throws {
|
||||
let mockedUD = WrappedUserDefaults(
|
||||
let mockedUD = UserDefaultsClient(
|
||||
objectForKey: { _ in true },
|
||||
remove: { _ in },
|
||||
setValue: { _, _ in },
|
||||
|
|
|
@ -76,10 +76,11 @@ class WalletEventsTests: XCTestCase {
|
|||
walletEvents: identifiedWalletEvents
|
||||
),
|
||||
reducer: WalletEventsFlowReducer()
|
||||
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
|
||||
.dependency(\.mainQueue, WalletEventsTests.testScheduler.eraseToAnyScheduler())
|
||||
)
|
||||
|
||||
store.dependencies.mainQueue = Self.testScheduler.eraseToAnyScheduler()
|
||||
store.dependencies.sdkSynchronizer = SDKSynchronizerDependency.mock
|
||||
|
||||
store.send(.synchronizerStateChanged(.synced))
|
||||
|
||||
Self.testScheduler.advance(by: 0.01)
|
||||
|
@ -98,8 +99,6 @@ class WalletEventsTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testCopyToPasteboard() throws {
|
||||
let pasteboard = WrappedPasteboard.test
|
||||
|
||||
let store = TestStore(
|
||||
initialState: WalletEventsFlowReducer.State(
|
||||
route: .latest,
|
||||
|
@ -108,10 +107,16 @@ class WalletEventsTests: XCTestCase {
|
|||
),
|
||||
reducer: WalletEventsFlowReducer()
|
||||
)
|
||||
|
||||
store.dependencies.pasteboard = .testPasteboard
|
||||
|
||||
let testText = "test text"
|
||||
store.send(.copyToPastboard(testText))
|
||||
|
||||
XCTAssertEqual(pasteboard.getString(), testText, "WalletEvetns: `testCopyToPasteboard` is expected to match the input `\(testText)`")
|
||||
XCTAssertEqual(
|
||||
store.dependencies.pasteboard.getString(),
|
||||
testText,
|
||||
"WalletEvetns: `testCopyToPasteboard` is expected to match the input `\(testText)`"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue