From 88a3ccc71155e6a649298fe9816517fb3dc5b90f Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 16 Jan 2024 20:30:55 +0700 Subject: [PATCH 1/3] chore: ios: Add unit tests for network setting details, verifier certificate, sign specs list (#2289) --- ios/PolkadotVault.xcodeproj/project.pbxproj | 34 +++ .../SignSpecs/SignSpecsListView.swift | 4 +- .../VerifierCertificateView.swift | 6 +- .../NetworkSettingDetailsViewModelTests.swift | 226 ++++++++++++++++++ .../SignSpecsListViewModelTests.swift | 207 ++++++++++++++++ .../VerifierCertificateViewModelTests.swift | 120 ++++++++++ 6 files changed, 592 insertions(+), 5 deletions(-) create mode 100644 ios/PolkadotVaultTests/Screens/Settings/Subview/NetworkSelectionSettings/NetworkSettingDetailsViewModelTests.swift create mode 100644 ios/PolkadotVaultTests/Screens/Settings/Subview/SignSpecs/SignSpecsListViewModelTests.swift create mode 100644 ios/PolkadotVaultTests/Screens/Settings/Subview/VerifierCertificate/VerifierCertificateViewModelTests.swift diff --git a/ios/PolkadotVault.xcodeproj/project.pbxproj b/ios/PolkadotVault.xcodeproj/project.pbxproj index 9a03bc8963..7b14bb6d55 100644 --- a/ios/PolkadotVault.xcodeproj/project.pbxproj +++ b/ios/PolkadotVault.xcodeproj/project.pbxproj @@ -173,6 +173,11 @@ 6D80EB522B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB512B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift */; }; 6D80EB542B4EB0C8009C544B /* MAddressCard+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB532B4EB0C8009C544B /* MAddressCard+Generate.swift */; }; 6D80EB492B4CF582009C544B /* BananaSplitService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB482B4CF582009C544B /* BananaSplitService.swift */; }; + 6D80EB4B2B4E7034009C544B /* NetworkSettingDetailsActionModalViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB4A2B4E7034009C544B /* NetworkSettingDetailsActionModalViewModelTests.swift */; }; + 6D80EB502B4EAD3E009C544B /* VerifierCertificateViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB4F2B4EAD3E009C544B /* VerifierCertificateViewModelTests.swift */; }; + 6D80EB522B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB512B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift */; }; + 6D80EB542B4EB0C8009C544B /* MAddressCard+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB532B4EB0C8009C544B /* MAddressCard+Generate.swift */; }; + 6D80EB572B4EB117009C544B /* SignSpecsListViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D80EB562B4EB117009C544B /* SignSpecsListViewModelTests.swift */; }; 6D84442428D3424F0072FBAC /* HiddenScrollContainerModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D84442328D3424F0072FBAC /* HiddenScrollContainerModifier.swift */; }; 6D850BDE292F7B4D00BA9017 /* EnterPasswordModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D850BDD292F7B4D00BA9017 /* EnterPasswordModal.swift */; }; 6D850BE2292F85F200BA9017 /* SecuredTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D850BE1292F85F200BA9017 /* SecuredTextField.swift */; }; @@ -231,6 +236,7 @@ 6DB2E7C82B4BBEB0002387DE /* NetworkSelectionSettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB2E7C72B4BBEB0002387DE /* NetworkSelectionSettingsViewModelTests.swift */; }; 6DB2E7CA2B4BBF6E002387DE /* MmNetwork+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB2E7C92B4BBF6E002387DE /* MmNetwork+Generate.swift */; }; 6DB2E7CC2B4BBF78002387DE /* MNetworkDetails+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB2E7CB2B4BBF78002387DE /* MNetworkDetails+Generate.swift */; }; + 6DB2E7CE2B4BC7F6002387DE /* NetworkSettingDetailsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB2E7CD2B4BC7F6002387DE /* NetworkSettingDetailsViewModelTests.swift */; }; 6DB39AA42A4579E0004B8FAA /* AddDerivedKeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB39AA32A4579E0004B8FAA /* AddDerivedKeysView.swift */; }; 6DB39AA92A45C909004B8FAA /* TransparentHelpBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB39AA82A45C909004B8FAA /* TransparentHelpBox.swift */; }; 6DB99039295E95E9001101DC /* NetworkCapsuleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB99038295E95E9001101DC /* NetworkCapsuleView.swift */; }; @@ -561,6 +567,11 @@ 6D80EB512B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSufficientCryptoReady+Generate.swift"; sourceTree = ""; }; 6D80EB532B4EB0C8009C544B /* MAddressCard+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MAddressCard+Generate.swift"; sourceTree = ""; }; 6D80EB482B4CF582009C544B /* BananaSplitService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BananaSplitService.swift; sourceTree = ""; }; + 6D80EB4A2B4E7034009C544B /* NetworkSettingDetailsActionModalViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkSettingDetailsActionModalViewModelTests.swift; sourceTree = ""; }; + 6D80EB4F2B4EAD3E009C544B /* VerifierCertificateViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifierCertificateViewModelTests.swift; sourceTree = ""; }; + 6D80EB512B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MSufficientCryptoReady+Generate.swift"; sourceTree = ""; }; + 6D80EB532B4EB0C8009C544B /* MAddressCard+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MAddressCard+Generate.swift"; sourceTree = ""; }; + 6D80EB562B4EB117009C544B /* SignSpecsListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignSpecsListViewModelTests.swift; sourceTree = ""; }; 6D84442328D3424F0072FBAC /* HiddenScrollContainerModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenScrollContainerModifier.swift; sourceTree = ""; }; 6D850BDD292F7B4D00BA9017 /* EnterPasswordModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnterPasswordModal.swift; sourceTree = ""; }; 6D850BE1292F85F200BA9017 /* SecuredTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecuredTextField.swift; sourceTree = ""; }; @@ -618,6 +629,7 @@ 6DB2E7C72B4BBEB0002387DE /* NetworkSelectionSettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkSelectionSettingsViewModelTests.swift; sourceTree = ""; }; 6DB2E7C92B4BBF6E002387DE /* MmNetwork+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MmNetwork+Generate.swift"; sourceTree = ""; }; 6DB2E7CB2B4BBF78002387DE /* MNetworkDetails+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MNetworkDetails+Generate.swift"; sourceTree = ""; }; + 6DB2E7CD2B4BC7F6002387DE /* NetworkSettingDetailsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkSettingDetailsViewModelTests.swift; sourceTree = ""; }; 6DB39AA32A4579E0004B8FAA /* AddDerivedKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddDerivedKeysView.swift; sourceTree = ""; }; 6DB39AA82A45C909004B8FAA /* TransparentHelpBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransparentHelpBox.swift; sourceTree = ""; }; 6DB99038295E95E9001101DC /* NetworkCapsuleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkCapsuleView.swift; sourceTree = ""; }; @@ -1530,6 +1542,22 @@ path = QRCode; sourceTree = ""; }; + 6D80EB4E2B4EAD34009C544B /* VerifierCertificate */ = { + isa = PBXGroup; + children = ( + 6D80EB4F2B4EAD3E009C544B /* VerifierCertificateViewModelTests.swift */, + ); + path = VerifierCertificate; + sourceTree = ""; + }; + 6D80EB552B4EB10D009C544B /* SignSpecs */ = { + isa = PBXGroup; + children = ( + 6D80EB562B4EB117009C544B /* SignSpecsListViewModelTests.swift */, + ); + path = SignSpecs; + sourceTree = ""; + }; 6D84442228D342430072FBAC /* Modifiers */ = { isa = PBXGroup; children = ( @@ -1721,6 +1749,8 @@ 6DB2E7C22B4BBC12002387DE /* Subview */ = { isa = PBXGroup; children = ( + 6D80EB552B4EB10D009C544B /* SignSpecs */, + 6D80EB4E2B4EAD34009C544B /* VerifierCertificate */, 6DB2E7C62B4BBEA0002387DE /* NetworkSelectionSettings */, 6DB2E7C32B4BBC19002387DE /* Backup */, ); @@ -1739,6 +1769,7 @@ isa = PBXGroup; children = ( 6DB2E7C72B4BBEB0002387DE /* NetworkSelectionSettingsViewModelTests.swift */, + 6DB2E7CD2B4BC7F6002387DE /* NetworkSettingDetailsViewModelTests.swift */, 6D80EB4A2B4E7034009C544B /* NetworkSettingDetailsActionModalViewModelTests.swift */, ); path = NetworkSelectionSettings; @@ -2685,9 +2716,11 @@ 6DE48E922B1F0B96003094D5 /* AutoMockable+T.generated.swift in Sources */, 6DE48E892B1F0B96003094D5 /* AutoMockable+M.generated.swift in Sources */, 6DE48E7F2B1F0B96003094D5 /* AutoMockable+Z.generated.swift in Sources */, + 6D80EB572B4EB117009C544B /* SignSpecsListViewModelTests.swift in Sources */, 6DAFCAF82B0A360600DDD165 /* CameraPermissionHandlerTests.swift in Sources */, 6DE48E952B1F0B96003094D5 /* AutoMockable+Q.generated.swift in Sources */, 6DE48E802B1F0B96003094D5 /* AutoMockable+P.generated.swift in Sources */, + 6D80EB502B4EAD3E009C544B /* VerifierCertificateViewModelTests.swift in Sources */, 6D80EB522B4EB0B8009C544B /* MSufficientCryptoReady+Generate.swift in Sources */, 6DE48E8C2B1F0B96003094D5 /* AutoMockable+R.generated.swift in Sources */, 6D5801E5289937BA006C41D8 /* ConnectivityMonitoringAssemblerTests.swift in Sources */, @@ -2702,6 +2735,7 @@ 6DE48E972B1F0B96003094D5 /* AutoMockable+L.generated.swift in Sources */, 6DE48E852B1F0B96003094D5 /* AutoMockable+U.generated.swift in Sources */, 6DAFCAFA2B0AE5C000DDD165 /* KeychainAccessAdapterTests.swift in Sources */, + 6DB2E7CE2B4BC7F6002387DE /* NetworkSettingDetailsViewModelTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/PolkadotVault/Screens/Settings/Subviews/SignSpecs/SignSpecsListView.swift b/ios/PolkadotVault/Screens/Settings/Subviews/SignSpecs/SignSpecsListView.swift index 81a5e38d47..12cec2d2d7 100644 --- a/ios/PolkadotVault/Screens/Settings/Subviews/SignSpecs/SignSpecsListView.swift +++ b/ios/PolkadotVault/Screens/Settings/Subviews/SignSpecs/SignSpecsListView.swift @@ -117,7 +117,7 @@ extension SignSpecsListView { final class ViewModel: ObservableObject { private let networkKey: String private let seedsMediator: SeedsMediating - private let service: ManageNetworkDetailsService + private let service: ManageNetworkDetailsServicing let type: SpecSignType @Published var detailsContent: MSufficientCryptoReady! @Published var content: MSignSufficientCrypto? @@ -137,7 +137,7 @@ extension SignSpecsListView { networkKey: String, type: SpecSignType, seedsMediator: SeedsMediating = ServiceLocator.seedsMediator, - service: ManageNetworkDetailsService = ManageNetworkDetailsService() + service: ManageNetworkDetailsServicing = ManageNetworkDetailsService() ) { self.networkKey = networkKey self.type = type diff --git a/ios/PolkadotVault/Screens/Settings/Subviews/VerifierCertificate/VerifierCertificateView.swift b/ios/PolkadotVault/Screens/Settings/Subviews/VerifierCertificate/VerifierCertificateView.swift index 6645763a27..41149a031b 100644 --- a/ios/PolkadotVault/Screens/Settings/Subviews/VerifierCertificate/VerifierCertificateView.swift +++ b/ios/PolkadotVault/Screens/Settings/Subviews/VerifierCertificate/VerifierCertificateView.swift @@ -96,7 +96,7 @@ extension VerifierCertificateView { @Published var isPresentingError: Bool = false @Published var presentableError: ErrorBottomModalViewModel = .alertError(message: "") private let onboardingMediator: OnboardingMediating - private let service: GeneralVerifierService + private let service: GeneralVerifierServicing var dismissViewRequest: AnyPublisher { dismissRequest.eraseToAnyPublisher() } @@ -105,7 +105,7 @@ extension VerifierCertificateView { init( onboardingMediator: OnboardingMediating = ServiceLocator.onboardingMediator, - service: GeneralVerifierService = GeneralVerifierService() + service: GeneralVerifierServicing = GeneralVerifierService() ) { self.onboardingMediator = onboardingMediator self.service = service @@ -122,7 +122,7 @@ extension VerifierCertificateView { dismissRequest.send() } - func loadData() { + private func loadData() { service.getGeneralVerifier { result in switch result { case let .success(content): diff --git a/ios/PolkadotVaultTests/Screens/Settings/Subview/NetworkSelectionSettings/NetworkSettingDetailsViewModelTests.swift b/ios/PolkadotVaultTests/Screens/Settings/Subview/NetworkSelectionSettings/NetworkSettingDetailsViewModelTests.swift new file mode 100644 index 0000000000..e60b988ffc --- /dev/null +++ b/ios/PolkadotVaultTests/Screens/Settings/Subview/NetworkSelectionSettings/NetworkSettingDetailsViewModelTests.swift @@ -0,0 +1,226 @@ +// +// NetworkSettingDetailsViewModelTests.swift +// PolkadotVaultTests +// +// Created by Krzysztof Rodak on 12/01/2024. +// + +import Combine +import Foundation +@testable import PolkadotVault +import XCTest + +final class NetworkSettingsDetailsViewModelTests: XCTestCase { + private var viewModel: NetworkSettingsDetails.ViewModel! + private var manageNetworkDetailsServiceMock: ManageNetworkDetailsServicingMock! + private var cancelBag: CancelBag! + private var onCompleteCalled = false + private var onCompleteReceivedResult: NetworkSettingsDetails.OnCompletionAction! + private var networkDetails: MNetworkDetails! + + override func setUp() { + super.setUp() + cancelBag = CancelBag() + manageNetworkDetailsServiceMock = ManageNetworkDetailsServicingMock() + networkDetails = .generate() + viewModel = NetworkSettingsDetails.ViewModel( + networkKey: "testKey", + networkDetails: networkDetails, + networkDetailsService: manageNetworkDetailsServiceMock, + onCompletion: { onCompleteResult in + self.onCompleteCalled = true + self.onCompleteReceivedResult = onCompleteResult + } + ) + } + + override func tearDown() { + viewModel = nil + manageNetworkDetailsServiceMock = nil + cancelBag = nil + super.tearDown() + } + + func testOnAppearUpdatesView() { + // Given + let networkDetails = MNetworkDetails.generate() + + // When + viewModel.onAppear() + manageNetworkDetailsServiceMock.getNetworkDetailsReceivedCompletion.first?(.success(networkDetails)) + + // Then + XCTAssertEqual(viewModel.networkDetails, networkDetails) + } + + func testOnAppearWhenFailurePresentsError() { + // Given + let error = ServiceError(message: "Error") + let updatedNetworkDetails = MNetworkDetails.generate(name: "New name") + let expectedPresentableError: ErrorBottomModalViewModel = .alertError(message: error.localizedDescription) + + // When + viewModel.onAppear() + manageNetworkDetailsServiceMock.getNetworkDetailsReceivedCompletion.first?(.failure(error)) + + // Then + XCTAssertNotEqual(viewModel.networkDetails, updatedNetworkDetails) + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, expectedPresentableError) + } + + func testRemoveMetadataSuccess() { + // Given + let metadataRecord = MMetadataRecord.generate() + viewModel.didTapDelete(metadataRecord) + + // When + viewModel.removeMetadata() + manageNetworkDetailsServiceMock.deleteNetworkMetadataReceivedCompletion.first?(.success(())) + + // Then + XCTAssertFalse(viewModel.isPresentingRemoveMetadataConfirmation) + XCTAssertTrue(viewModel.isSnackbarPresented) + } + + func testRemoveMetadataFailure() { + // Given + let error = ServiceError(message: "Error") + viewModel.didTapDelete(.generate()) + let expectedPresentableError: ErrorBottomModalViewModel = .alertError(message: error.localizedDescription) + + // When + viewModel.removeMetadata() + manageNetworkDetailsServiceMock.deleteNetworkMetadataReceivedCompletion.first?(.failure(error)) + + // Then + XCTAssertFalse(viewModel.isPresentingRemoveMetadataConfirmation) + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, expectedPresentableError) + } + + func testRemoveNetworkSuccess() { + // When + viewModel.removeNetwork() + manageNetworkDetailsServiceMock.deleteNetworkReceivedCompletion.first?(.success(())) + + // Then + XCTAssertTrue(onCompleteCalled) + XCTAssertEqual(onCompleteReceivedResult, .networkDeleted(networkDetails.title)) + } + + func testRemoveNetworkFailure() { + // Given + let error = ServiceError(message: "Error") + let expectedPresentableError: ErrorBottomModalViewModel = .alertError(message: error.localizedDescription) + + // When + viewModel.removeNetwork() + manageNetworkDetailsServiceMock.deleteNetworkReceivedCompletion.first?(.failure(error)) + + // Then + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, expectedPresentableError) + } + + func testOnTapDeleteTriggersConfirmation() { + // Given + let metadata = MMetadataRecord.generate() + + // When + viewModel.didTapDelete(metadata) + + // Then + XCTAssertTrue(viewModel.isPresentingRemoveMetadataConfirmation) + } + + func testCancelMetadataRemovalResetsState() { + // When + viewModel.cancelMetadataRemoval() + + // Then + XCTAssertFalse(viewModel.isPresentingRemoveMetadataConfirmation) + } + + func testOnAddTapOpensQRScanner() { + // When + viewModel.onAddTap() + + // Then + XCTAssertTrue(viewModel.isShowingQRScanner) + } + + func testOnQRScannerDismissUpdatesView() { + // When + viewModel.onQRScannerDismiss() + + // Then + XCTAssertEqual(manageNetworkDetailsServiceMock.getNetworkDetailsCallsCount, 1) + } + + func testOnMoreMenuTapOpensActionSheet() { + // When + viewModel.onMoreMenuTap() + + // Then + XCTAssertTrue(viewModel.isShowingActionSheet) + } + + func testOnMoreActionSheetDismissalWithSignSpecs() { + // Given + viewModel.shouldSignSpecs = true + + // When + viewModel.onMoreActionSheetDismissal() + + // Then + XCTAssertTrue(viewModel.isPresentingSignSpecList) + XCTAssertEqual(viewModel.specSignType, .network) + } + + func testOnMoreActionSheetDismissalWithRemoveNetworkConfirmation() { + // Given + viewModel.shouldPresentRemoveNetworkConfirmation = true + + // When + viewModel.onMoreActionSheetDismissal() + + // Then + XCTAssertTrue(viewModel.isPresentingRemoveNetworkConfirmation) + XCTAssertFalse(viewModel.shouldPresentRemoveNetworkConfirmation) + } + + func testCancelNetworkRemovalResetsState() { + // Given + viewModel.isPresentingRemoveNetworkConfirmation = true + + // When + viewModel.cancelNetworkRemoval() + + // Then + XCTAssertFalse(viewModel.isPresentingRemoveNetworkConfirmation) + } + + func testDidTapSignOpensSignSpecList() { + // Given + let metadata = MMetadataRecord.generate() + + // When + viewModel.didTapSign(metadata) + + // Then + XCTAssertTrue(viewModel.isPresentingSignSpecList) + XCTAssertEqual(viewModel.specSignType, .metadata(metadataSpecsVersion: metadata.specsVersion)) + } + + func testListenToNavigationUpdatesReflectsView() { + // Given + viewModel.isPresentingSignSpecList = true + + // When + viewModel.isPresentingSignSpecList = false + + // Then + XCTAssertEqual(manageNetworkDetailsServiceMock.getNetworkDetailsCallsCount, 1) + } +} diff --git a/ios/PolkadotVaultTests/Screens/Settings/Subview/SignSpecs/SignSpecsListViewModelTests.swift b/ios/PolkadotVaultTests/Screens/Settings/Subview/SignSpecs/SignSpecsListViewModelTests.swift new file mode 100644 index 0000000000..64ec1f9641 --- /dev/null +++ b/ios/PolkadotVaultTests/Screens/Settings/Subview/SignSpecs/SignSpecsListViewModelTests.swift @@ -0,0 +1,207 @@ +// +// SignSpecsListViewModelTests.swift +// PolkadotVaultTests +// +// Created by Krzysztof Rodak on 15/01/2024. +// + +import Combine +import Foundation +@testable import PolkadotVault +import XCTest + +final class SignSpecsListViewViewModelTests: XCTestCase { + private var viewModel: SignSpecsListView.ViewModel! + private var seedsMediatorMock: SeedsMediatingMock! + private var manageNetworkDetailsServiceMock: ManageNetworkDetailsServicingMock! + private var cancellables: Set! + + override func setUp() { + super.setUp() + seedsMediatorMock = SeedsMediatingMock() + manageNetworkDetailsServiceMock = ManageNetworkDetailsServicingMock() + viewModel = SignSpecsListView.ViewModel( + networkKey: "networkKey", + type: .network, + seedsMediator: seedsMediatorMock, + service: manageNetworkDetailsServiceMock + ) + cancellables = [] + } + + override func tearDown() { + viewModel = nil + seedsMediatorMock = nil + manageNetworkDetailsServiceMock = nil + cancellables = nil + super.tearDown() + } + + func testViewModelOnAppearLoadsData() { + // Given + let expectedContent = MSignSufficientCrypto.generate() + + // When + viewModel.onAppear() + manageNetworkDetailsServiceMock.signSpecListReceivedCompletion.first?(.success(expectedContent)) + + // Then + XCTAssertEqual(manageNetworkDetailsServiceMock.signSpecListCallsCount, 1) + XCTAssertEqual(viewModel.content, expectedContent) + } + + func testPresentErrorOnFailedOnAppear() { + // Given + let error: ServiceError = .init(message: "Error") + let expectedPresentableError: ErrorBottomModalViewModel = .alertError(message: error.localizedDescription) + + // When + viewModel.onAppear() + manageNetworkDetailsServiceMock.signSpecListReceivedCompletion.first?(.failure(error)) + + // Then + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, expectedPresentableError) + } + + func testViewModelOnRecordTapWithPassword() { + // Given + let keyRecord = MRawKey.generate(address: .generate(hasPwd: true)) + seedsMediatorMock.getSeedSeedNameReturnValue = "passwordProtectedSeed" + + // When + viewModel.onRecordTap(keyRecord) + + // Then + XCTAssertEqual(viewModel.selectedKeyRecord, keyRecord) + XCTAssertTrue(viewModel.isPresentingEnterPassword) + } + + func testOnRecordTap_AttemptSigningWithoutPassword() { + // Given + let keyRecordWithoutPassword = MRawKey.generate() + seedsMediatorMock.getSeedSeedNameReturnValue = "SeedPhrase" + + // When + viewModel.onRecordTap(keyRecordWithoutPassword) + manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordReceivedCompletion + .first?(.success(MSufficientCryptoReady.generate())) + + // Then + XCTAssertEqual(seedsMediatorMock.getSeedSeedNameCallsCount, 1) + XCTAssertEqual(seedsMediatorMock.getSeedSeedNameReceivedSeedName, [keyRecordWithoutPassword.address.seedName]) + XCTAssertEqual(manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordCallsCount, 1) + XCTAssertTrue(viewModel.isPresentingDetails) + XCTAssertNotNil(viewModel.detailsContent) + } + + func testOnRecordTap_AttemptSigningWithoutPassword_whenError_presentsError() { + // Given + let error: ServiceError = .init(message: "Error") + let expectedPresentableError: ErrorBottomModalViewModel = .alertError(message: error.localizedDescription) + let keyRecordWithoutPassword = MRawKey.generate() + seedsMediatorMock.getSeedSeedNameReturnValue = "SeedPhrase" + + // When + viewModel.onRecordTap(keyRecordWithoutPassword) + manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordReceivedCompletion + .first?(.failure(.error(error))) + + // Then + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, expectedPresentableError) + } + + func testViewModelOnPasswordModalDoneWithSuccess() { + // Given + let keyRecord = MRawKey.generate() + let detailsContent = MSufficientCryptoReady.generate() + let modalViewModel = SignSpecEnterPasswordModal.ViewModel( + isPresented: .constant(true), + selectedKeyRecord: keyRecord, + onDoneTapAction: { _ in } + ) + seedsMediatorMock.getSeedSeedNameReturnValue = "seedPhrase" + + // When + viewModel.onPasswordModalDoneTapAction(modalViewModel) + manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordReceivedCompletion + .first?(.success(detailsContent)) + + // Then + XCTAssertEqual(manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordCallsCount, 1) + XCTAssertEqual(viewModel.detailsContent, detailsContent) + XCTAssertTrue(viewModel.isPresentingDetails) + } + + func testViewModelOnPasswordModalDoneWithError() { + // Given + let keyRecord = MRawKey.generate() + let modalViewModel = SignSpecEnterPasswordModal.ViewModel( + isPresented: .constant(true), + selectedKeyRecord: keyRecord, + onDoneTapAction: { _ in } + ) + let error: SpecSignError = .error(.init(message: "Error")) + + seedsMediatorMock.getSeedSeedNameReturnValue = "seedPhrase" + + // When + viewModel.onPasswordModalDoneTapAction(modalViewModel) + manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordReceivedCompletion + .first?(.failure(error)) + + // Then + XCTAssertEqual(manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordCallsCount, 1) + XCTAssertFalse(viewModel.isPresentingDetails) + XCTAssertTrue(viewModel.isPresentingError) + } + + func testAttemptSigningWithEmptySeedPhrase() { + // Given + let keyRecord = MRawKey.generate() + seedsMediatorMock.getSeedSeedNameReturnValue = "" + + // When + viewModel.onRecordTap(keyRecord) + + // Then + XCTAssertEqual(seedsMediatorMock.getSeedSeedNameCallsCount, 1) + XCTAssertNil(viewModel.detailsContent) + XCTAssertFalse(viewModel.isPresentingDetails) + } + + func testAttemptSigningWithValidSeedPhrase() { + // Given + let keyRecord = MRawKey.generate() + seedsMediatorMock.getSeedSeedNameReturnValue = "" + + // When + viewModel.onRecordTap(keyRecord) + + // Then + XCTAssertEqual(seedsMediatorMock.getSeedSeedNameCallsCount, 1) + XCTAssertNil(viewModel.detailsContent) + XCTAssertFalse(viewModel.isPresentingDetails) + } + + func testOnPasswordModalDoneTapAction_WrongPasswordError() { + // Given + let expectedKeyRecord = MRawKey.generate() + let modalViewModel = SignSpecEnterPasswordModal.ViewModel( + isPresented: .constant(true), + selectedKeyRecord: expectedKeyRecord, + onDoneTapAction: { _ in } + ) + viewModel.selectedKeyRecord = expectedKeyRecord + seedsMediatorMock.getSeedSeedNameReturnValue = "SomeSeedPhrase" + + // When + viewModel.onPasswordModalDoneTapAction(modalViewModel) + manageNetworkDetailsServiceMock.signSpecSigningAddressKeySeedPhrasePasswordReceivedCompletion + .first?(.failure(.wrongPassword)) + + // Then + XCTAssertFalse(modalViewModel.isValid) + } +} diff --git a/ios/PolkadotVaultTests/Screens/Settings/Subview/VerifierCertificate/VerifierCertificateViewModelTests.swift b/ios/PolkadotVaultTests/Screens/Settings/Subview/VerifierCertificate/VerifierCertificateViewModelTests.swift new file mode 100644 index 0000000000..71508b3707 --- /dev/null +++ b/ios/PolkadotVaultTests/Screens/Settings/Subview/VerifierCertificate/VerifierCertificateViewModelTests.swift @@ -0,0 +1,120 @@ +// +// VerifierCertificateViewModelTests.swift +// PolkadotVaultTests +// +// Created by Krzysztof Rodak on 12/01/2024. +// + +import Combine +import Foundation +@testable import PolkadotVault +import XCTest + +final class VerifierCertificateViewModelTests: XCTestCase { + private var viewModel: VerifierCertificateView.ViewModel! + private var onboardingMediatorMock: OnboardingMediatingMock! + private var generalVerifierServiceMock: GeneralVerifierServicingMock! + private var cancelBag: CancelBag! + + override func setUp() { + super.setUp() + cancelBag = CancelBag() + onboardingMediatorMock = OnboardingMediatingMock() + generalVerifierServiceMock = GeneralVerifierServicingMock() + } + + override func tearDown() { + cancelBag = nil + viewModel = nil + onboardingMediatorMock = nil + generalVerifierServiceMock = nil + super.tearDown() + } + + func testInit_whenLoadDataSuccess_callsService_loadsContent() { + // Given + let verifierDetails = MVerifierDetails.generate() + + // When + viewModel = VerifierCertificateView.ViewModel( + onboardingMediator: onboardingMediatorMock, + service: generalVerifierServiceMock + ) + generalVerifierServiceMock.getGeneralVerifierReceivedCompletion.first?(.success(verifierDetails)) + + // Then + XCTAssertEqual(generalVerifierServiceMock.getGeneralVerifierCallsCount, 1) + XCTAssertEqual(viewModel.content, verifierDetails) + } + + func testInit_whenLoadDataFails_callsService_presentsError_contentNil() { + // Given + let error = ServiceError(message: "Error occurred") + + // When + viewModel = VerifierCertificateView.ViewModel( + onboardingMediator: onboardingMediatorMock, + service: generalVerifierServiceMock + ) + generalVerifierServiceMock.getGeneralVerifierReceivedCompletion.first?(.failure(error)) + + // Then + XCTAssertEqual(generalVerifierServiceMock.getGeneralVerifierCallsCount, 1) + XCTAssertTrue(viewModel.isPresentingError) + XCTAssertEqual(viewModel.presentableError, .alertError(message: error.localizedDescription)) + XCTAssertNil(viewModel.content) + } + + func testOnRemoveTap() { + // Given + viewModel = VerifierCertificateView.ViewModel( + onboardingMediator: onboardingMediatorMock, + service: generalVerifierServiceMock + ) + + // When + viewModel.onRemoveTap() + + // Then + XCTAssertTrue(viewModel.isPresentingRemoveConfirmation) + } + + func testOnRemoveConfirmationTap() { + // Given + viewModel = VerifierCertificateView.ViewModel( + onboardingMediator: onboardingMediatorMock, + service: generalVerifierServiceMock + ) + + // When + viewModel.onRemoveConfirmationTap() + + // Then + XCTAssertEqual(onboardingMediatorMock.onboardVerifierRemovedCallsCount, 1) + XCTAssertTrue(onboardingMediatorMock.onboardVerifierRemovedReceivedVerifierRemoved.contains(true)) + XCTAssertFalse(viewModel.isPresentingRemoveConfirmation) + } + + func testDismissRequestIsSentOnRemoveConfirmation() { + // Given + viewModel = VerifierCertificateView.ViewModel( + onboardingMediator: onboardingMediatorMock, + service: generalVerifierServiceMock + ) + let expectation = XCTestExpectation(description: "Dismiss request should be sent") + var dismissRequestTriggered = false + + viewModel.dismissViewRequest.sink { + dismissRequestTriggered = true + expectation.fulfill() + } + .store(in: cancelBag) + + // When + viewModel.onRemoveConfirmationTap() + + // Then + wait(for: [expectation], timeout: 1.0) + XCTAssertTrue(dismissRequestTriggered, "Dismiss request should be triggered on remove confirmation") + } +} From 4e3d1ef22a82efb13cacc7126c85318b4964a141 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:24:14 +0000 Subject: [PATCH 2/3] chore(deps): bump opencv from 0.88.6 to 0.88.7 in /rust (#2280) --- rust/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 7b23a7ccbe..b691dc537c 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2396,9 +2396,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "opencv" -version = "0.88.6" +version = "0.88.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc7d90a679ddd02190fc621ee1592b96b299122fac4b65aa669143317bd4b6a" +checksum = "461ace7d1fd13b846ef1096dc7cac0f2ac39e8803360953eb869a42e8e1e5baa" dependencies = [ "cc", "dunce", @@ -2415,9 +2415,9 @@ dependencies = [ [[package]] name = "opencv-binding-generator" -version = "0.83.0" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f66d4e88785bc4748e65aeaffcaa457d1b0df4e6cd0a5dbe15b5bd53514fb0" +checksum = "6e842c276fd00b26100de550e2b47f6ded4f06213c62f0575cb7242aecde2efd" dependencies = [ "clang", "clang-sys", From a221c555097a4c691f9bc1982f5069765adde0f8 Mon Sep 17 00:00:00 2001 From: Dmitry Borodin <11879032+Dmitry-Borodin@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:16:37 -0500 Subject: [PATCH 3/3] feat: migration togs to Timber so we won't post logs in release app (#2283) --- android/build.gradle | 1 + .../java/io/parity/signer/PolkadotVaultApp.kt | 10 ++++++++-- .../main/java/io/parity/signer/domain/Helpers.kt | 4 ++-- .../io/parity/signer/domain/MainFlowViewModel.kt | 4 ++-- .../java/io/parity/signer/domain/Navigation.kt | 4 ++-- .../io/parity/signer/domain/NavigationLogger.kt | 4 ++-- .../main/java/io/parity/signer/domain/Utils.kt | 4 ++-- .../signer/domain/storage/SeedRepository.kt | 16 ++++++++-------- .../parity/signer/domain/storage/SeedStorage.kt | 6 +++--- .../DerivationCreateViewModel.kt | 6 +++--- .../signer/screens/initial/UnlockScreen.kt | 2 +- .../screenlock/SetScreenLockScreen.kt | 4 ++-- .../keysetdetails/KeySetDetailsViewModel.kt | 4 ++-- .../keysets/create/NewKeysetNameScreen.kt | 2 +- .../keysetname/KeysetRecoverNameScreen.kt | 2 +- .../parity/signer/screens/scan/ScanViewModel.kt | 16 ++++++++-------- .../signer/screens/scan/camera/CameraView.kt | 4 ++-- .../screens/scan/camera/CameraViewModel.kt | 10 +++++----- .../screens/settings/logs/LogsViewModel.kt | 10 +++++----- .../settings/logs/comment/AddLogCommentScreen.kt | 4 ++-- .../settings/logs/logdetails/LogDetails.kt | 4 ++-- .../logs/logdetails/LogsDetailsViewModel.kt | 4 ++-- .../screens/settings/logs/logslist/LogsMenu.kt | 2 +- .../settings/logs/logslist/LogsScreenFull.kt | 4 ++-- .../networks/signspecs/SignSpecsViewModel.kt | 4 ++-- .../ui/rootnavigation/MainScreensAppFlow.kt | 4 ++-- 26 files changed, 73 insertions(+), 66 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 354087198b..ded585b042 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -116,6 +116,7 @@ dependencies { implementation "com.appmattus.crypto:cryptohash:0.10.1" //black2b hash for dot icon implementation "io.coil-kt:coil-compose:$coilVersion" implementation "io.coil-kt:coil-svg:$coilVersion" + implementation 'com.jakewharton.timber:timber:5.0.1' testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-core:5.8.0" testImplementation "androidx.test:core:1.5.0" diff --git a/android/src/main/java/io/parity/signer/PolkadotVaultApp.kt b/android/src/main/java/io/parity/signer/PolkadotVaultApp.kt index 806543c504..0c68982bcb 100644 --- a/android/src/main/java/io/parity/signer/PolkadotVaultApp.kt +++ b/android/src/main/java/io/parity/signer/PolkadotVaultApp.kt @@ -1,13 +1,15 @@ package io.parity.signer import android.app.Application -import android.util.Log import io.parity.signer.dependencygraph.ServiceLocator import io.parity.signer.domain.submitErrorState import io.parity.signer.uniffi.ErrorDisplayed import io.parity.signer.uniffi.initLogging +import timber.log.Timber +import timber.log.Timber.* import java.lang.Thread.UncaughtExceptionHandler + class PolkadotVaultApp : Application() { override fun onCreate() { super.onCreate() @@ -16,6 +18,10 @@ class PolkadotVaultApp : Application() { initLogging("SIGNER_RUST_LOG") + if (BuildConfig.DEBUG) { + Timber.plant(DebugTree()) + } + val defaultHandler = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler( RootExceptionHandler(defaultHandler) @@ -34,7 +40,7 @@ class RootExceptionHandler( override fun uncaughtException(t: Thread, e: Throwable) { val rustStr = findErrorDisplayedStr(e) if (rustStr != null) { - Log.e(TAG, "Rust caused ErrorDisplay message was: ${rustStr.s}") + Timber.e(TAG, "Rust caused ErrorDisplay message was: ${rustStr.s}") submitErrorState("rust error not handled, fix it!") } else { defaultHandler?.uncaughtException(t, e) ?: throw e diff --git a/android/src/main/java/io/parity/signer/domain/Helpers.kt b/android/src/main/java/io/parity/signer/domain/Helpers.kt index 601555be68..87d5688abb 100644 --- a/android/src/main/java/io/parity/signer/domain/Helpers.kt +++ b/android/src/main/java/io/parity/signer/domain/Helpers.kt @@ -1,12 +1,12 @@ package io.parity.signer.domain -import android.util.Log +import timber.log.Timber import io.parity.signer.BuildConfig import io.parity.signer.uniffi.ErrorDisplayed import java.lang.RuntimeException fun submitErrorState(message: String) { - Log.e("error state", message) + Timber.e("error state", message) if (BuildConfig.DEBUG) { throw RuntimeException(message) } diff --git a/android/src/main/java/io/parity/signer/domain/MainFlowViewModel.kt b/android/src/main/java/io/parity/signer/domain/MainFlowViewModel.kt index 2b5ca7b4cc..ab7e18eac3 100644 --- a/android/src/main/java/io/parity/signer/domain/MainFlowViewModel.kt +++ b/android/src/main/java/io/parity/signer/domain/MainFlowViewModel.kt @@ -2,7 +2,7 @@ package io.parity.signer.domain import android.annotation.SuppressLint import android.content.* -import android.util.Log +import timber.log.Timber import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -34,7 +34,7 @@ class MainFlowViewModel() : ViewModel() { AuthResult.AuthError, AuthResult.AuthFailed, AuthResult.AuthUnavailable -> { - Log.e("Signer", "Auth failed, not unlocked") + Timber.e("Signer", "Auth failed, not unlocked") } } } diff --git a/android/src/main/java/io/parity/signer/domain/Navigation.kt b/android/src/main/java/io/parity/signer/domain/Navigation.kt index dd417b8c37..a3fab98df7 100644 --- a/android/src/main/java/io/parity/signer/domain/Navigation.kt +++ b/android/src/main/java/io/parity/signer/domain/Navigation.kt @@ -1,7 +1,7 @@ package io.parity.signer.domain import android.content.Context -import android.util.Log +import timber.log.Timber import android.widget.Toast import io.parity.signer.R import io.parity.signer.dependencygraph.ServiceLocator @@ -44,7 +44,7 @@ class FakeNavigator : Navigator { try { backendAction(action, details, seedPhrase) } catch (e: ErrorDisplayed) { - Log.e("fake navigation error", e.message ?: e.toString()) + Timber.e("fake navigation error", e.message ?: e.toString()) } //do nothing with result } diff --git a/android/src/main/java/io/parity/signer/domain/NavigationLogger.kt b/android/src/main/java/io/parity/signer/domain/NavigationLogger.kt index 6d7fecc170..4250bcf82e 100644 --- a/android/src/main/java/io/parity/signer/domain/NavigationLogger.kt +++ b/android/src/main/java/io/parity/signer/domain/NavigationLogger.kt @@ -1,7 +1,7 @@ package io.parity.signer.domain import android.os.Bundle -import android.util.Log +import timber.log.Timber import androidx.navigation.NavController import androidx.navigation.NavDestination import androidx.navigation.NavHostController @@ -19,7 +19,7 @@ private class NavLogger(val tag: String) : destination: NavDestination, arguments: Bundle? ) { - Log.d(tag, "destination is " + destination.route) + Timber.d(tag, "destination is " + destination.route) } } diff --git a/android/src/main/java/io/parity/signer/domain/Utils.kt b/android/src/main/java/io/parity/signer/domain/Utils.kt index 2f37edaf07..91407da4e2 100644 --- a/android/src/main/java/io/parity/signer/domain/Utils.kt +++ b/android/src/main/java/io/parity/signer/domain/Utils.kt @@ -2,7 +2,7 @@ package io.parity.signer.domain import android.content.Context import android.graphics.BitmapFactory -import android.util.Log +import timber.log.Timber import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap import kotlinx.coroutines.CoroutineScope @@ -65,7 +65,7 @@ fun List.intoImageBitmap(): ImageBitmap { return try { BitmapFactory.decodeByteArray(picture, 0, picture.size).asImageBitmap() } catch (e: java.lang.Exception) { - Log.d("image decoding error", e.toString()) + Timber.d("image decoding error", e.toString()) ImageBitmap(1, 1) } } diff --git a/android/src/main/java/io/parity/signer/domain/storage/SeedRepository.kt b/android/src/main/java/io/parity/signer/domain/storage/SeedRepository.kt index e4389d031c..bb2a049d16 100644 --- a/android/src/main/java/io/parity/signer/domain/storage/SeedRepository.kt +++ b/android/src/main/java/io/parity/signer/domain/storage/SeedRepository.kt @@ -1,7 +1,7 @@ package io.parity.signer.domain.storage import android.security.keystore.UserNotAuthenticatedException -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.fragment.app.FragmentActivity import io.parity.signer.domain.AuthResult @@ -67,7 +67,7 @@ class SeedRepository( } } } catch (e: java.lang.Exception) { - Log.d("get seed failure", e.toString()) + Timber.d("get seed failure", e.toString()) Toast.makeText(activity, "get seed failure: $e", Toast.LENGTH_LONG).show() RepoResult.Failure(RuntimeException("Unexpected Exception", e)) } @@ -111,7 +111,7 @@ class SeedRepository( } } } catch (e: java.lang.Exception) { - Log.d("get seed failure", e.toString()) + Timber.d("get seed failure", e.toString()) Toast.makeText(activity, "get seed failure: $e", Toast.LENGTH_LONG).show() RepoResult.Failure(RuntimeException("Unexpected Exception", e)) } @@ -141,12 +141,12 @@ class SeedRepository( AuthResult.AuthError, AuthResult.AuthFailed, AuthResult.AuthUnavailable -> { - Log.e(TAG, "auth error - $authResult") + Timber.e(TAG, "auth error - $authResult") false } } } catch (e: java.lang.Exception) { - Log.e(TAG, e.toString()) + Timber.e(TAG, e.toString()) return false } } @@ -181,7 +181,7 @@ class SeedRepository( is UniffiResult.Success -> OperationResult.Ok(Unit) } } catch (e: java.lang.Exception) { - Log.d("remove seed error", e.toString()) + Timber.d("remove seed error", e.toString()) OperationResult.Err(e) } } @@ -189,7 +189,7 @@ class SeedRepository( AuthResult.AuthError, AuthResult.AuthFailed, AuthResult.AuthUnavailable -> { - Log.d("remove seed auth error ", authResult.toString()) + Timber.d("remove seed auth error ", authResult.toString()) OperationResult.Err(Exception("remove seed auth error $authResult")) } } @@ -223,7 +223,7 @@ class SeedRepository( AuthResult.AuthError, AuthResult.AuthFailed, AuthResult.AuthUnavailable -> { - Log.e(TAG, "auth error - $authResult") + Timber.e(TAG, "auth error - $authResult") false } } diff --git a/android/src/main/java/io/parity/signer/domain/storage/SeedStorage.kt b/android/src/main/java/io/parity/signer/domain/storage/SeedStorage.kt index 9aa2157ac0..7924c9c7c4 100644 --- a/android/src/main/java/io/parity/signer/domain/storage/SeedStorage.kt +++ b/android/src/main/java/io/parity/signer/domain/storage/SeedStorage.kt @@ -5,7 +5,7 @@ import android.content.SharedPreferences import android.content.pm.PackageManager import android.os.Build import android.security.keystore.UserNotAuthenticatedException -import android.util.Log +import timber.log.Timber import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey import io.parity.signer.domain.FeatureFlags @@ -51,7 +51,7 @@ class SeedStorage { false } - Log.d("strongbox available:", hasStrongbox.toString()) + Timber.d("strongbox available:", hasStrongbox.toString()) // Init crypto for seeds: // https://developer.android.com/training/articles/keystore @@ -74,7 +74,7 @@ class SeedStorage { .build() } - Log.e("ENCRY", "$appContext $KEYSTORE_NAME $masterKey") + Timber.e("ENCRY", "$appContext $KEYSTORE_NAME $masterKey") //we need to be authenticated for this sharedPreferences = if (FeatureFlags.isEnabled(FeatureOption.SKIP_UNLOCK_FOR_DEVELOPMENT)) { diff --git a/android/src/main/java/io/parity/signer/screens/createderivation/DerivationCreateViewModel.kt b/android/src/main/java/io/parity/signer/screens/createderivation/DerivationCreateViewModel.kt index fc83edaa01..fd810c037a 100644 --- a/android/src/main/java/io/parity/signer/screens/createderivation/DerivationCreateViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/createderivation/DerivationCreateViewModel.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.createderivation import android.content.Context -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.lifecycle.ViewModel import io.parity.signer.R @@ -157,10 +157,10 @@ class DerivationCreateViewModel : ViewModel() { } } } else { - Log.e(TAG, "Seed phrase received but it's empty") + Timber.e(TAG, "Seed phrase received but it's empty") } } catch (e: java.lang.Exception) { - Log.e(TAG, e.toString()) + Timber.e(TAG, e.toString()) } } diff --git a/android/src/main/java/io/parity/signer/screens/initial/UnlockScreen.kt b/android/src/main/java/io/parity/signer/screens/initial/UnlockScreen.kt index f82b313f5c..9dfac6fb61 100644 --- a/android/src/main/java/io/parity/signer/screens/initial/UnlockScreen.kt +++ b/android/src/main/java/io/parity/signer/screens/initial/UnlockScreen.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.initial import android.content.res.Configuration -import android.util.Log +import timber.log.Timber import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.material.MaterialTheme diff --git a/android/src/main/java/io/parity/signer/screens/initial/eachstartchecks/screenlock/SetScreenLockScreen.kt b/android/src/main/java/io/parity/signer/screens/initial/eachstartchecks/screenlock/SetScreenLockScreen.kt index 5e585b0d22..72e276a346 100644 --- a/android/src/main/java/io/parity/signer/screens/initial/eachstartchecks/screenlock/SetScreenLockScreen.kt +++ b/android/src/main/java/io/parity/signer/screens/initial/eachstartchecks/screenlock/SetScreenLockScreen.kt @@ -3,7 +3,7 @@ package io.parity.signer.screens.initial.eachstartchecks.screenlock import android.content.Intent import android.content.res.Configuration import android.provider.Settings -import android.util.Log +import timber.log.Timber import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.material.MaterialTheme @@ -83,7 +83,7 @@ fun SetScreenLockScreen() { null ) } else { - Log.e("screen lock", "Settings activity not found") + Timber.e("screen lock", "Settings activity not found") } } } diff --git a/android/src/main/java/io/parity/signer/screens/keysetdetails/KeySetDetailsViewModel.kt b/android/src/main/java/io/parity/signer/screens/keysetdetails/KeySetDetailsViewModel.kt index 06e7bd1df5..7767c7008c 100644 --- a/android/src/main/java/io/parity/signer/screens/keysetdetails/KeySetDetailsViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/keysetdetails/KeySetDetailsViewModel.kt @@ -1,6 +1,6 @@ package io.parity.signer.screens.keysetdetails -import android.util.Log +import timber.log.Timber import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import io.parity.signer.dependencygraph.ServiceLocator @@ -104,7 +104,7 @@ class KeySetDetailsViewModel : ViewModel() { return when (result) { null, is OperationResult.Err -> { - Log.d( + Timber.d( "Keyset", "wrong seed name requested or wrong last known seed getting another one" ) diff --git a/android/src/main/java/io/parity/signer/screens/keysets/create/NewKeysetNameScreen.kt b/android/src/main/java/io/parity/signer/screens/keysets/create/NewKeysetNameScreen.kt index 4d421be335..596c77bfc6 100644 --- a/android/src/main/java/io/parity/signer/screens/keysets/create/NewKeysetNameScreen.kt +++ b/android/src/main/java/io/parity/signer/screens/keysets/create/NewKeysetNameScreen.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.keysets.create import android.content.res.Configuration -import android.util.Log +import timber.log.Timber import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize diff --git a/android/src/main/java/io/parity/signer/screens/keysets/restore/keysetname/KeysetRecoverNameScreen.kt b/android/src/main/java/io/parity/signer/screens/keysets/restore/keysetname/KeysetRecoverNameScreen.kt index 05d1b76ec7..c102aa3d9b 100644 --- a/android/src/main/java/io/parity/signer/screens/keysets/restore/keysetname/KeysetRecoverNameScreen.kt +++ b/android/src/main/java/io/parity/signer/screens/keysets/restore/keysetname/KeysetRecoverNameScreen.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.keysets.restore.keysetname import android.content.res.Configuration -import android.util.Log +import timber.log.Timber import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize diff --git a/android/src/main/java/io/parity/signer/screens/scan/ScanViewModel.kt b/android/src/main/java/io/parity/signer/screens/scan/ScanViewModel.kt index 546ba661a1..80f34bad4a 100644 --- a/android/src/main/java/io/parity/signer/screens/scan/ScanViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/scan/ScanViewModel.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.scan import android.content.Context -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -76,7 +76,7 @@ class ScanViewModel : ViewModel() { suspend fun performTransactionPayload(payload: String, context: Context) { val fakeNavigator = FakeNavigator() if (transactionIsInProgress.value) { - Log.e(TAG, "started transaction while it was in progress, ignoring") + Timber.e(TAG, "started transaction while it was in progress, ignoring") return } transactionIsInProgress.value = true @@ -92,7 +92,7 @@ class ScanViewModel : ViewModel() { val screenData = navigateResponse.result.screenData val transactions: List = (screenData as? ScreenData.Transaction)?.f ?: run { - Log.e( + Timber.e( TAG, "Error in getting transaction from qr payload, " + "screenData is $screenData, navigation resp is $navigateResponse" ) @@ -224,7 +224,7 @@ class ScanViewModel : ViewModel() { ) { when (val phrases = seedRepository.getAllSeeds()) { is RepoResult.Failure -> { - Log.e( + Timber.e( TAG, "cannot get seeds to show import dynamic derivations ${phrases.error}" ) @@ -255,7 +255,7 @@ class ScanViewModel : ViewModel() { ) { when (val phrases = seedRepository.getAllSeeds()) { is RepoResult.Failure -> { - Log.e( + Timber.e( TAG, "cannot get seeds to show import dynamic derivations ${phrases.error}" ) @@ -435,7 +435,7 @@ class ScanViewModel : ViewModel() { ): ActionResult? { return when (val phrases = seedRepository.getSeedPhrases(seedNames)) { is RepoResult.Failure -> { - Log.w(TAG, "signature transactions failure ${phrases.error}") + Timber.w(TAG, "signature transactions failure ${phrases.error}") null } @@ -453,7 +453,7 @@ class ScanViewModel : ViewModel() { scanFlowInteractor.handlePasswordEntered(password) val actionResult = (navigateResponse as? OperationResult.Ok)?.result ?: run { - Log.e( + Timber.e( TAG, "Error in entering password for a key, " + "navigation resp is $navigateResponse" ) @@ -478,7 +478,7 @@ class ScanViewModel : ViewModel() { } //ignore the rest modals else -> { - Log.e( + Timber.e( TAG, "Password is entered for transaction, but neither new password or signature is passed! Should not happen" + "actionResult is $actionResult" ) diff --git a/android/src/main/java/io/parity/signer/screens/scan/camera/CameraView.kt b/android/src/main/java/io/parity/signer/screens/scan/camera/CameraView.kt index 17366141fe..84c9e2f0c8 100644 --- a/android/src/main/java/io/parity/signer/screens/scan/camera/CameraView.kt +++ b/android/src/main/java/io/parity/signer/screens/scan/camera/CameraView.kt @@ -1,6 +1,6 @@ package io.parity.signer.screens.scan.camera -import android.util.Log +import timber.log.Timber import android.util.Rational import android.util.Size import android.view.ViewGroup @@ -120,7 +120,7 @@ internal fun CameraViewInternal(viewModel: CameraViewModel) { }.build() camera.cameraControl.startFocusAndMetering(autoFocusAction) } catch (e: CameraInfoUnavailableException) { - Log.d("ERROR", "cannot access camera", e) + Timber.d("ERROR", "cannot access camera", e) } } }, executor) diff --git a/android/src/main/java/io/parity/signer/screens/scan/camera/CameraViewModel.kt b/android/src/main/java/io/parity/signer/screens/scan/camera/CameraViewModel.kt index 49da5c2453..fcaee92acd 100644 --- a/android/src/main/java/io/parity/signer/screens/scan/camera/CameraViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/scan/camera/CameraViewModel.kt @@ -2,7 +2,7 @@ package io.parity.signer.screens.scan.camera import android.annotation.SuppressLint import android.os.Trace -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.camera.core.ImageProxy import androidx.lifecycle.ViewModel @@ -86,7 +86,7 @@ class CameraViewModel() : ViewModel() { _total.value = proposeTotal } } catch (e: java.lang.Exception) { - Log.e("scanVM", "QR sequence length estimation $e") + Timber.e("scanVM", "QR sequence length estimation $e") } } else { currentMultiQrTransaction += payloadString @@ -95,14 +95,14 @@ class CameraViewModel() : ViewModel() { } else { _captured.value = currentMultiQrTransaction.size } - Log.d("scanVM", "captured " + captured.value.toString()) + Timber.d("scanVM", "captured " + captured.value.toString()) } } } Trace.endSection() } .addOnFailureListener { - Log.e("scanVM", "Scan failed " + it.message.toString()) + Timber.e("scanVM", "Scan failed " + it.message.toString()) } .addOnCompleteListener { Trace.endSection() @@ -150,7 +150,7 @@ class CameraViewModel() : ViewModel() { } } catch (e: Exception) { - Log.e("scanVM", "Single frame decode failed $e") + Timber.e("scanVM", "Single frame decode failed $e") } } diff --git a/android/src/main/java/io/parity/signer/screens/settings/logs/LogsViewModel.kt b/android/src/main/java/io/parity/signer/screens/settings/logs/LogsViewModel.kt index 9a2ab8a488..05c879f9cc 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/logs/LogsViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/logs/LogsViewModel.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.settings.logs import android.content.Context -import android.util.Log +import timber.log.Timber import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -37,7 +37,7 @@ class LogsViewModel() : ViewModel() { withContext(Dispatchers.IO) { uniffiInteractor.getLogs() }) { is UniffiResult.Error -> { val error = result.error.getDebugDetailedDescriptionString() - Log.e(TAG, "Unexpected error getLogs, $error") + Timber.e(TAG, "Unexpected error getLogs, $error") _logsState.value = CompletableResult.Err(error) } is UniffiResult.Success -> { @@ -51,7 +51,7 @@ class LogsViewModel() : ViewModel() { withContext(Dispatchers.IO) { uniffiInteractor.addCommentToLogs(logNote) }) { is UniffiResult.Error -> { val error = result.error.getDebugDetailedDescriptionString() - Log.e(TAG, "Unexpected error addNote, $error") + Timber.e(TAG, "Unexpected error addNote, $error") OperationResult.Err(error) } is UniffiResult.Success -> { @@ -71,7 +71,7 @@ class LogsViewModel() : ViewModel() { AuthResult.AuthError, AuthResult.AuthFailed, AuthResult.AuthUnavailable -> { - Log.d("Vault", "Can't remove logs without authentication") + Timber.d("Vault", "Can't remove logs without authentication") } } } @@ -81,7 +81,7 @@ class LogsViewModel() : ViewModel() { withContext(Dispatchers.IO) { uniffiInteractor.clearLogHistory() }) { is UniffiResult.Error -> { val error = result.error.getDebugDetailedDescriptionString() - Log.e(TAG, "Unexpected error clear logs, $error") + Timber.e(TAG, "Unexpected error clear logs, $error") OperationResult.Err(error) } is UniffiResult.Success -> { diff --git a/android/src/main/java/io/parity/signer/screens/settings/logs/comment/AddLogCommentScreen.kt b/android/src/main/java/io/parity/signer/screens/settings/logs/comment/AddLogCommentScreen.kt index e007a136c8..d2a105903b 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/logs/comment/AddLogCommentScreen.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/logs/comment/AddLogCommentScreen.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.settings.logs.comment import android.content.res.Configuration -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardActions @@ -45,7 +45,7 @@ internal fun AddLogCommentScreen(onBack: Callback) { viewModel.viewModelScope.launch { when (val postResult = viewModel.addLogNote(note)) { is OperationResult.Err -> { - Log.e(TAG, "log note not added, error ${postResult.error}") + Timber.e(TAG, "log note not added, error ${postResult.error}") Toast.makeText( context, context.getString( diff --git a/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogDetails.kt b/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogDetails.kt index 57bfe5f165..fa3fb2e5c8 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogDetails.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogDetails.kt @@ -1,6 +1,6 @@ package io.parity.signer.screens.settings.logs.logdetails -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -41,7 +41,7 @@ fun LogDetailsScreen(navController: NavController, logDetailsId: UInt) { ) { when (logsCurrentValue) { is CompletableResult.Err -> { - Log.e(TAG, "error in getting log details ${logsCurrentValue.error}") + Timber.e(TAG, "error in getting log details ${logsCurrentValue.error}") Toast.makeText(context, logsCurrentValue.error, Toast.LENGTH_LONG) .show() viewModel.resetValues() diff --git a/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogsDetailsViewModel.kt b/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogsDetailsViewModel.kt index 367bb2233c..2ad47e61e5 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogsDetailsViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/logs/logdetails/LogsDetailsViewModel.kt @@ -1,6 +1,6 @@ package io.parity.signer.screens.settings.logs.logdetails -import android.util.Log +import timber.log.Timber import androidx.lifecycle.ViewModel import io.parity.signer.domain.backend.CompletableResult import io.parity.signer.domain.backend.UniffiResult @@ -29,7 +29,7 @@ class LogsDetailsViewModel(): ViewModel() { }) { is UniffiResult.Error -> { val error = result.error.getDebugDetailedDescriptionString() - Log.e(TAG, "Unexpected error getLogs, $error") + Timber.e(TAG, "Unexpected error getLogs, $error") _logsState.value = CompletableResult.Err(error) } is UniffiResult.Success -> { diff --git a/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsMenu.kt b/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsMenu.kt index 362c3d6f34..550f77f718 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsMenu.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsMenu.kt @@ -1,7 +1,7 @@ package io.parity.signer.screens.settings.logs.logslist import android.content.res.Configuration -import android.util.Log +import timber.log.Timber import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth diff --git a/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsScreenFull.kt b/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsScreenFull.kt index 3445cad56a..1ac214f14a 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsScreenFull.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/logs/logslist/LogsScreenFull.kt @@ -1,6 +1,6 @@ package io.parity.signer.screens.settings.logs.logslist -import android.util.Log +import timber.log.Timber import android.widget.Toast import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer @@ -39,7 +39,7 @@ fun LogsScreenFull( Box(Modifier.statusBarsPadding()) { when (logsCurrentValue) { is CompletableResult.Err -> { - Log.e(TAG, "error in getting logs ${logsCurrentValue.error}") + Timber.e(TAG, "error in getting logs ${logsCurrentValue.error}") Toast.makeText(context, logsCurrentValue.error, Toast.LENGTH_LONG) .show() viewModel.resetValues() diff --git a/android/src/main/java/io/parity/signer/screens/settings/networks/signspecs/SignSpecsViewModel.kt b/android/src/main/java/io/parity/signer/screens/settings/networks/signspecs/SignSpecsViewModel.kt index 06b2e8795c..ea9d9c8e2f 100644 --- a/android/src/main/java/io/parity/signer/screens/settings/networks/signspecs/SignSpecsViewModel.kt +++ b/android/src/main/java/io/parity/signer/screens/settings/networks/signspecs/SignSpecsViewModel.kt @@ -1,6 +1,6 @@ package io.parity.signer.screens.settings.networks.signspecs -import android.util.Log +import timber.log.Timber import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import io.parity.signer.R @@ -50,7 +50,7 @@ class SignSpecsViewModel : ViewModel() { when (val seedResult = seedRepo.getSeedPhraseForceAuth(keyModel.seedName)) { is RepoResult.Failure -> { - Log.d( + Timber.d( "sufficient crypto", "failed to get seed to sign sufficient crypto" ) diff --git a/android/src/main/java/io/parity/signer/ui/rootnavigation/MainScreensAppFlow.kt b/android/src/main/java/io/parity/signer/ui/rootnavigation/MainScreensAppFlow.kt index 049b35494b..caf862dc03 100644 --- a/android/src/main/java/io/parity/signer/ui/rootnavigation/MainScreensAppFlow.kt +++ b/android/src/main/java/io/parity/signer/ui/rootnavigation/MainScreensAppFlow.kt @@ -1,7 +1,7 @@ package io.parity.signer.ui.rootnavigation import android.os.Build -import android.util.Log +import timber.log.Timber import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.captionBarPadding import androidx.compose.foundation.layout.navigationBarsPadding @@ -50,7 +50,7 @@ fun NavGraphBuilder.mainSignerAppFlow(globalNavController: NavHostController) { } else -> {} } -Log.e("TAGG", Build.VERSION.SECURITY_PATCH) +Timber.e("TAGG", Build.VERSION.SECURITY_PATCH) } else { UnlockAppAuthScreen(onUnlockClicked = mainFlowViewModel::onUnlockClicked) }