diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt index fddd153073..e76597dccd 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt @@ -50,7 +50,8 @@ class CipherManagerImpl( private val activeUserId: String? get() = authDiskSource.userState?.activeUserId override suspend fun createCipher(cipherView: CipherView): CreateCipherResult { - val userId = activeUserId ?: return CreateCipherResult.Error + val userId = activeUserId + ?: return CreateCipherResult.Error(error = NoActiveUserException()) return vaultSdkSource .encryptCipher( userId = userId, @@ -59,7 +60,7 @@ class CipherManagerImpl( .flatMap { ciphersService.createCipher(body = it.toEncryptedNetworkCipher()) } .onSuccess { vaultDiskSource.saveCipher(userId = userId, cipher = it) } .fold( - onFailure = { CreateCipherResult.Error }, + onFailure = { CreateCipherResult.Error(error = it) }, onSuccess = { reviewPromptManager.registerAddCipherAction() CreateCipherResult.Success @@ -71,7 +72,8 @@ class CipherManagerImpl( cipherView: CipherView, collectionIds: List, ): CreateCipherResult { - val userId = activeUserId ?: return CreateCipherResult.Error + val userId = activeUserId + ?: return CreateCipherResult.Error(error = NoActiveUserException()) return vaultSdkSource .encryptCipher( userId = userId, @@ -92,7 +94,7 @@ class CipherManagerImpl( ) } .fold( - onFailure = { CreateCipherResult.Error }, + onFailure = { CreateCipherResult.Error(error = it) }, onSuccess = { reviewPromptManager.registerAddCipherAction() CreateCipherResult.Success @@ -101,13 +103,14 @@ class CipherManagerImpl( } override suspend fun hardDeleteCipher(cipherId: String): DeleteCipherResult { - val userId = activeUserId ?: return DeleteCipherResult.Error + val userId = activeUserId + ?: return DeleteCipherResult.Error(error = NoActiveUserException()) return ciphersService .hardDeleteCipher(cipherId = cipherId) .onSuccess { vaultDiskSource.deleteCipher(userId = userId, cipherId = cipherId) } .fold( onSuccess = { DeleteCipherResult.Success }, - onFailure = { DeleteCipherResult.Error }, + onFailure = { DeleteCipherResult.Error(error = it) }, ) } @@ -115,7 +118,8 @@ class CipherManagerImpl( cipherId: String, cipherView: CipherView, ): DeleteCipherResult { - val userId = activeUserId ?: return DeleteCipherResult.Error + val userId = activeUserId + ?: return DeleteCipherResult.Error(error = NoActiveUserException()) return cipherView .encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherId) .flatMap { cipher -> @@ -137,7 +141,7 @@ class CipherManagerImpl( } .fold( onSuccess = { DeleteCipherResult.Success }, - onFailure = { DeleteCipherResult.Error }, + onFailure = { DeleteCipherResult.Error(error = it) }, ) } @@ -188,7 +192,8 @@ class CipherManagerImpl( cipherId: String, cipherView: CipherView, ): RestoreCipherResult { - val userId = activeUserId ?: return RestoreCipherResult.Error + val userId = activeUserId + ?: return RestoreCipherResult.Error(error = NoActiveUserException()) return ciphersService .restoreCipher(cipherId = cipherId) .onSuccess { @@ -199,7 +204,7 @@ class CipherManagerImpl( } .fold( onSuccess = { RestoreCipherResult.Success }, - onFailure = { RestoreCipherResult.Error }, + onFailure = { RestoreCipherResult.Error(error = it) }, ) } @@ -207,7 +212,8 @@ class CipherManagerImpl( cipherId: String, cipherView: CipherView, ): UpdateCipherResult { - val userId = activeUserId ?: return UpdateCipherResult.Error(errorMessage = null) + val userId = activeUserId + ?: return UpdateCipherResult.Error(errorMessage = null, error = NoActiveUserException()) return vaultSdkSource .encryptCipher( userId = userId, @@ -222,7 +228,7 @@ class CipherManagerImpl( .map { response -> when (response) { is UpdateCipherResponseJson.Invalid -> { - UpdateCipherResult.Error(errorMessage = response.message) + UpdateCipherResult.Error(errorMessage = response.message, error = null) } is UpdateCipherResponseJson.Success -> { @@ -235,7 +241,7 @@ class CipherManagerImpl( } } .fold( - onFailure = { UpdateCipherResult.Error(errorMessage = null) }, + onFailure = { UpdateCipherResult.Error(errorMessage = null, error = it) }, onSuccess = { it }, ) } @@ -246,7 +252,7 @@ class CipherManagerImpl( cipherView: CipherView, collectionIds: List, ): ShareCipherResult { - val userId = activeUserId ?: return ShareCipherResult.Error + val userId = activeUserId ?: return ShareCipherResult.Error(error = NoActiveUserException()) return migrateAttachments(userId = userId, cipherView = cipherView) .flatMap { vaultSdkSource.moveToOrganization( @@ -272,7 +278,7 @@ class CipherManagerImpl( ) } .fold( - onFailure = { ShareCipherResult.Error }, + onFailure = { ShareCipherResult.Error(error = it) }, onSuccess = { ShareCipherResult.Success }, ) } @@ -282,7 +288,7 @@ class CipherManagerImpl( cipherView: CipherView, collectionIds: List, ): ShareCipherResult { - val userId = activeUserId ?: return ShareCipherResult.Error + val userId = activeUserId ?: return ShareCipherResult.Error(error = NoActiveUserException()) return ciphersService .updateCipherCollections( cipherId = cipherId, @@ -302,7 +308,7 @@ class CipherManagerImpl( } .fold( onSuccess = { ShareCipherResult.Success }, - onFailure = { ShareCipherResult.Error }, + onFailure = { ShareCipherResult.Error(error = it) }, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateCipherResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateCipherResult.kt index a224d3660e..129aba101a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateCipherResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateCipherResult.kt @@ -13,5 +13,5 @@ sealed class CreateCipherResult { /** * Generic error while creating cipher. */ - data object Error : CreateCipherResult() + data class Error(val error: Throwable) : CreateCipherResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteCipherResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteCipherResult.kt index ad63a25a56..2ad981fd27 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteCipherResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteCipherResult.kt @@ -13,5 +13,5 @@ sealed class DeleteCipherResult { /** * Generic error while deleting a cipher. */ - data object Error : DeleteCipherResult() + data class Error(val error: Throwable) : DeleteCipherResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RestoreCipherResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RestoreCipherResult.kt index 076e818d18..50af6e50be 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RestoreCipherResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RestoreCipherResult.kt @@ -13,5 +13,5 @@ sealed class RestoreCipherResult { /** * Generic error while restoring a cipher. */ - data object Error : RestoreCipherResult() + data class Error(val error: Throwable) : RestoreCipherResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/ShareCipherResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/ShareCipherResult.kt index 2a5c976d37..0722fcb737 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/ShareCipherResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/ShareCipherResult.kt @@ -12,5 +12,5 @@ sealed class ShareCipherResult { /** * Generic error while sharing cipher. */ - data object Error : ShareCipherResult() + data class Error(val error: Throwable) : ShareCipherResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateCipherResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateCipherResult.kt index 9fe61ffe3d..23fcb43ad3 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateCipherResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateCipherResult.kt @@ -14,5 +14,5 @@ sealed class UpdateCipherResult { * Generic error while updating cipher. The optional [errorMessage] may be displayed directly in * the UI when present. */ - data class Error(val errorMessage: String?) : UpdateCipherResult() + data class Error(val errorMessage: String?, val error: Throwable?) : UpdateCipherResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt index dd42d09e92..8f7ec24cf9 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt @@ -546,6 +546,7 @@ class SearchViewModel @Inject constructor( title = null, message = result.errorMessage?.asText() ?: R.string.generic_error_message.asText(), + throwable = result.error, ), ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index 8d929394ac..9ad74a6e48 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -1554,9 +1554,14 @@ class VaultAddEditViewModel @Inject constructor( ) { clearDialogState() - when (action.createCipherResult) { + when (val result = action.createCipherResult) { is CreateCipherResult.Error -> { - showGenericErrorDialog() + showDialog( + dialogState = VaultAddEditState.DialogState.Generic( + message = R.string.generic_error_message.asText(), + error = result.error, + ), + ) } is CreateCipherResult.Success -> { @@ -1581,11 +1586,15 @@ class VaultAddEditViewModel @Inject constructor( clearDialogState() when (val result = action.updateCipherResult) { is UpdateCipherResult.Error -> { - showGenericErrorDialog( - message = result - .errorMessage - ?.asText() - ?: R.string.generic_error_message.asText(), + showDialog( + dialogState = VaultAddEditState.DialogState.Generic( + title = R.string.an_error_has_occurred.asText(), + message = result + .errorMessage + ?.asText() + ?: R.string.generic_error_message.asText(), + error = result.error, + ), ) } @@ -1602,11 +1611,12 @@ class VaultAddEditViewModel @Inject constructor( } private fun handleDeleteCipherReceive(action: VaultAddEditAction.Internal.DeleteCipherReceive) { - when (action.result) { - DeleteCipherResult.Error -> { + when (val result = action.result) { + is DeleteCipherResult.Error -> { showDialog( dialogState = VaultAddEditState.DialogState.Generic( message = R.string.generic_error_message.asText(), + error = result.error, ), ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt index dfe7be63f5..186b00f12b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt @@ -1245,11 +1245,12 @@ class VaultItemViewModel @Inject constructor( } private fun handleDeleteCipherReceive(action: VaultItemAction.Internal.DeleteCipherReceive) { - when (action.result) { - DeleteCipherResult.Error -> { + when (val result = action.result) { + is DeleteCipherResult.Error -> { updateDialogState( VaultItemState.DialogState.Generic( message = R.string.generic_error_message.asText(), + error = result.error, ), ) } @@ -1271,11 +1272,12 @@ class VaultItemViewModel @Inject constructor( } private fun handleRestoreCipherReceive(action: VaultItemAction.Internal.RestoreCipherReceive) { - when (action.result) { - RestoreCipherResult.Error -> { + when (val result = action.result) { + is RestoreCipherResult.Error -> { updateDialogState( VaultItemState.DialogState.Generic( message = R.string.generic_error_message.asText(), + error = result.error, ), ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationScreen.kt index ab3629396a..fa1b848cde 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationScreen.kt @@ -85,6 +85,7 @@ private fun VaultMoveToOrganizationScaffold( title = stringResource(id = R.string.an_error_has_occurred), message = dialog.message(), onDismissRequest = dismissClick, + throwable = dialog.throwable, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModel.kt index e0dab914c7..fe6d69c0c5 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModel.kt @@ -151,12 +151,13 @@ class VaultMoveToOrganizationViewModel @Inject constructor( action: VaultMoveToOrganizationAction.Internal.ShareCipherResultReceive, ) { mutableStateFlow.update { it.copy(dialogState = null) } - when (action.shareCipherResult) { + when (val result = action.shareCipherResult) { is ShareCipherResult.Error -> { mutableStateFlow.update { it.copy( dialogState = VaultMoveToOrganizationState.DialogState.Error( message = R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -358,6 +359,7 @@ data class VaultMoveToOrganizationState( @Parcelize data class Error( val message: Text, + val throwable: Throwable? = null, ) : DialogState() /** diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt index ed20488695..d2328fc568 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt @@ -115,7 +115,7 @@ class CipherManagerTest { val result = cipherManager.createCipher(cipherView = mockk()) - assertEquals(CreateCipherResult.Error, result) + assertEquals(CreateCipherResult.Error(error = NoActiveUserException()), result) } @Test @@ -124,16 +124,17 @@ class CipherManagerTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val mockCipherView = createMockCipherView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptCipher( userId = userId, cipherView = mockCipherView, ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = cipherManager.createCipher(cipherView = mockCipherView) - assertEquals(CreateCipherResult.Error, result) + assertEquals(CreateCipherResult.Error(error = error), result) } @Test @@ -143,6 +144,7 @@ class CipherManagerTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val mockCipherView = createMockCipherView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptCipher( userId = userId, @@ -153,11 +155,11 @@ class CipherManagerTest { ciphersService.createCipher( body = createMockCipherJsonRequest(number = 1, hasNullUri = true), ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = cipherManager.createCipher(cipherView = mockCipherView) - assertEquals(CreateCipherResult.Error, result) + assertEquals(CreateCipherResult.Error(error = error), result) } @Test @@ -197,7 +199,7 @@ class CipherManagerTest { collectionIds = mockk(), ) - assertEquals(CreateCipherResult.Error, result) + assertEquals(CreateCipherResult.Error(error = NoActiveUserException()), result) } @Test @@ -207,19 +209,20 @@ class CipherManagerTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val mockCipherView = createMockCipherView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptCipher( userId = userId, cipherView = mockCipherView, ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = cipherManager.createCipherInOrganization( cipherView = mockCipherView, collectionIds = mockk(), ) - assertEquals(CreateCipherResult.Error, result) + assertEquals(CreateCipherResult.Error(error = error), result) } @Test @@ -229,6 +232,7 @@ class CipherManagerTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val mockCipherView = createMockCipherView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptCipher( userId = userId, @@ -242,14 +246,14 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ), ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = cipherManager.createCipherInOrganization( cipherView = mockCipherView, collectionIds = listOf("mockId-1"), ) - assertEquals(CreateCipherResult.Error, result) + assertEquals(CreateCipherResult.Error(error = error), result) } @Test @@ -299,7 +303,10 @@ class CipherManagerTest { cipherView = mockk(), ) - assertEquals(UpdateCipherResult.Error(errorMessage = null), result) + assertEquals( + UpdateCipherResult.Error(errorMessage = null, error = NoActiveUserException()), + result, + ) } @Test @@ -309,19 +316,20 @@ class CipherManagerTest { val userId = "mockId-1" val cipherId = "cipherId1234" val mockCipherView = createMockCipherView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptCipher( userId = userId, cipherView = mockCipherView, ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = cipherManager.updateCipher( cipherId = cipherId, cipherView = mockCipherView, ) - assertEquals(UpdateCipherResult.Error(errorMessage = null), result) + assertEquals(UpdateCipherResult.Error(errorMessage = null, error = error), result) } @Test @@ -332,6 +340,7 @@ class CipherManagerTest { val userId = "mockId-1" val cipherId = "cipherId1234" val mockCipherView = createMockCipherView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptCipher( userId = userId, @@ -343,14 +352,14 @@ class CipherManagerTest { cipherId = cipherId, body = createMockCipherJsonRequest(number = 1, hasNullUri = true), ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = cipherManager.updateCipher( cipherId = cipherId, cipherView = mockCipherView, ) - assertEquals(UpdateCipherResult.Error(errorMessage = null), result) + assertEquals(UpdateCipherResult.Error(errorMessage = null, error = error), result) } @Test @@ -385,7 +394,10 @@ class CipherManagerTest { ) assertEquals( - UpdateCipherResult.Error(errorMessage = "You do not have permission to edit this."), + UpdateCipherResult.Error( + errorMessage = "You do not have permission to edit this.", + error = null, + ), result, ) } @@ -436,7 +448,7 @@ class CipherManagerTest { cipherId = "cipherId", ) - assertEquals(DeleteCipherResult.Error, result) + assertEquals(DeleteCipherResult.Error(error = NoActiveUserException()), result) } @Suppress("MaxLineLength") @@ -445,13 +457,14 @@ class CipherManagerTest { runTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val cipherId = "mockId-1" + val error = Throwable("Fail") coEvery { ciphersService.hardDeleteCipher(cipherId = cipherId) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() val result = cipherManager.hardDeleteCipher(cipherId) - assertEquals(DeleteCipherResult.Error, result) + assertEquals(DeleteCipherResult.Error(error = error), result) } @Suppress("MaxLineLength") @@ -478,7 +491,7 @@ class CipherManagerTest { cipherView = mockk(), ) - assertEquals(DeleteCipherResult.Error, result) + assertEquals(DeleteCipherResult.Error(error = NoActiveUserException()), result) } @Suppress("MaxLineLength") @@ -490,19 +503,20 @@ class CipherManagerTest { val cipherId = "mockId-1" val cipherView = createMockCipherView(number = 1) val cipher = createMockSdkCipher(number = 1) + val error = Throwable("Fail") coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView) } returns cipher.asSuccess() coEvery { ciphersService.softDeleteCipher(cipherId = cipherId) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() val result = cipherManager.softDeleteCipher( cipherId = cipherId, cipherView = cipherView, ) - assertEquals(DeleteCipherResult.Error, result) + assertEquals(DeleteCipherResult.Error(error = error), result) } @Suppress("MaxLineLength") @@ -700,7 +714,7 @@ class CipherManagerTest { cipherView = createMockCipherView(number = 1), ) - assertEquals(RestoreCipherResult.Error, result) + assertEquals(RestoreCipherResult.Error(error = NoActiveUserException()), result) } @Suppress("MaxLineLength") @@ -710,16 +724,17 @@ class CipherManagerTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val cipherId = "mockId-1" val cipherView = createMockCipherView(number = 1) + val error = Throwable("Fail") coEvery { ciphersService.restoreCipher(cipherId = cipherId) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() val result = cipherManager.restoreCipher( cipherId = cipherId, cipherView = cipherView, ) - assertEquals(RestoreCipherResult.Error, result) + assertEquals(RestoreCipherResult.Error(error = error), result) } @Suppress("MaxLineLength") @@ -758,7 +773,7 @@ class CipherManagerTest { collectionIds = emptyList(), ) - assertEquals(ShareCipherResult.Error, result) + assertEquals(ShareCipherResult.Error(error = NoActiveUserException()), result) } @Test @@ -968,6 +983,7 @@ class CipherManagerTest { coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView) } returns createMockSdkCipher(number = 1, clock = clock).asSuccess() + val error = Throwable("Fail") coEvery { ciphersService.shareCipher( cipherId = "mockId-1", @@ -976,7 +992,7 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ), ) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() coEvery { vaultDiskSource.saveCipher(userId, createMockCipher(number = 1)) } just runs val result = cipherManager.shareCipher( @@ -986,7 +1002,7 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ) - assertEquals(ShareCipherResult.Error, result) + assertEquals(ShareCipherResult.Error(error = error), result) } @Test @@ -996,13 +1012,14 @@ class CipherManagerTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val organizationId = "organizationId" + val error = Throwable("Fail") coEvery { vaultSdkSource.moveToOrganization( userId = userId, organizationId = organizationId, cipherView = createMockCipherView(number = 1), ) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() coEvery { ciphersService.shareCipher( cipherId = "mockId-1", @@ -1021,7 +1038,7 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ) - assertEquals(ShareCipherResult.Error, result) + assertEquals(ShareCipherResult.Error(error = error), result) } @Test @@ -1035,7 +1052,7 @@ class CipherManagerTest { collectionIds = emptyList(), ) - assertEquals(ShareCipherResult.Error, result) + assertEquals(ShareCipherResult.Error(error = NoActiveUserException()), result) } @Test @@ -1083,6 +1100,7 @@ class CipherManagerTest { cipherView = createMockCipherView(number = 1), ) } returns createMockSdkCipher(number = 1, clock = clock).asSuccess() + val error = Throwable("Fail") coEvery { ciphersService.updateCipherCollections( cipherId = "mockId-1", @@ -1090,7 +1108,7 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ), ) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() coEvery { vaultDiskSource.saveCipher(userId, any()) } just runs val result = cipherManager.updateCipherCollections( @@ -1101,7 +1119,7 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ) - assertEquals(ShareCipherResult.Error, result) + assertEquals(ShareCipherResult.Error(error = error), result) } @Test @@ -1110,12 +1128,13 @@ class CipherManagerTest { runTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" + val error = Throwable("Fail") coEvery { vaultSdkSource.encryptCipher( userId = userId, cipherView = createMockCipherView(number = 1), ) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() coEvery { ciphersService.updateCipherCollections( cipherId = "mockId-1", @@ -1134,7 +1153,7 @@ class CipherManagerTest { collectionIds = listOf("mockId-1"), ) - assertEquals(ShareCipherResult.Error, result) + assertEquals(ShareCipherResult.Error(error = error), result) } @Test diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt index f2c3db6e25..2dce826164 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt @@ -275,6 +275,7 @@ class SearchViewModelTest : BaseViewModelTest() { val cipherView = setupForAutofill() val cipherId = CIPHER_ID val errorMessage = "Server error" + val error = Throwable("Oof") val updatedCipherView = cipherView.copy( login = createMockLoginView(number = 1, clock = clock).copy( uris = listOf(createMockUriView(number = 1)) + @@ -291,7 +292,7 @@ class SearchViewModelTest : BaseViewModelTest() { cipherId = cipherId, cipherView = updatedCipherView, ) - } returns UpdateCipherResult.Error(errorMessage) + } returns UpdateCipherResult.Error(errorMessage = errorMessage, error = error) viewModel.stateFlow.test { assertEquals(INITIAL_STATE_FOR_AUTOFILL, awaitItem()) @@ -314,6 +315,7 @@ class SearchViewModelTest : BaseViewModelTest() { dialogState = SearchState.DialogState.Error( title = null, message = errorMessage.asText(), + throwable = error, ), ), awaitItem(), diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt index 04b6ba3f02..f93de5ff54 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt @@ -592,12 +592,13 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ), ) + val error = Throwable("Oh dang.") coEvery { vaultRepository.softDeleteCipher( cipherId = "mockId-1", cipherView = cipherView, ) - } returns DeleteCipherResult.Error + } returns DeleteCipherResult.Error(error = error) viewModel.trySendAction(VaultAddEditAction.Common.ConfirmDeleteClick) @@ -606,6 +607,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { vaultAddEditType = vaultAddEditType, dialogState = VaultAddEditState.DialogState.Generic( message = R.string.generic_error_message.asText(), + error = error, ), commonContentViewState = createCommonContentViewState( name = "mockName-1", @@ -1638,7 +1640,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { coEvery { vaultRepository.createCipherInOrganization(any(), any()) - } returns CreateCipherResult.Error + } returns CreateCipherResult.Error(error = Throwable("Oh dang")) viewModel.trySendAction(VaultAddEditAction.Common.SaveClick) assertEquals( @@ -1772,9 +1774,10 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { canAssignToCollections = true, ) } returns stateWithName.viewState + val error = Throwable("Oh dang.") coEvery { vaultRepository.updateCipher(DEFAULT_EDIT_ITEM_ID, any()) - } returns UpdateCipherResult.Error(errorMessage = null) + } returns UpdateCipherResult.Error(errorMessage = null, error = error) mutableVaultDataFlow.value = DataState.Loaded( data = createVaultData(cipherView = cipherView), ) @@ -1794,6 +1797,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { dialog = VaultAddEditState.DialogState.Generic( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + error = error, ), ), viewModel.stateFlow.value, @@ -1839,7 +1843,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { } returns stateWithName.viewState coEvery { vaultRepository.updateCipher(DEFAULT_EDIT_ITEM_ID, any()) - } returns UpdateCipherResult.Error(errorMessage = errorMessage) + } returns UpdateCipherResult.Error(errorMessage = errorMessage, error = null) mutableVaultDataFlow.value = DataState.Loaded( createVaultData(cipherView = cipherView), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt index 638648bdaf..9aba65bb44 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt @@ -400,12 +400,13 @@ class VaultItemViewModelTest : BaseViewModelTest() { mutableFoldersStateFlow.value = DataState.Loaded(emptyList()) val viewModel = createViewModel(state = DEFAULT_STATE) + val error = Throwable("Oh dang.") coEvery { vaultRepo.softDeleteCipher( cipherId = VAULT_ITEM_ID, cipherView = createMockCipherView(number = 1), ) - } returns DeleteCipherResult.Error + } returns DeleteCipherResult.Error(error = error) viewModel.trySendAction(VaultItemAction.Common.ConfirmDeleteClick) @@ -414,6 +415,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { viewState = loginViewState, dialog = VaultItemState.DialogState.Generic( message = R.string.generic_error_message.asText(), + error = error, ), ), viewModel.stateFlow.value, @@ -624,12 +626,13 @@ class VaultItemViewModelTest : BaseViewModelTest() { mutableFoldersStateFlow.value = DataState.Loaded(emptyList()) val viewModel = createViewModel(state = DEFAULT_STATE) + val error = Throwable("Fail") coEvery { vaultRepo.restoreCipher( cipherId = VAULT_ITEM_ID, cipherView = createMockCipherView(number = 1), ) - } returns RestoreCipherResult.Error + } returns RestoreCipherResult.Error(error = error) viewModel.trySendAction(VaultItemAction.Common.ConfirmRestoreClick) @@ -638,6 +641,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { viewState = DEFAULT_VIEW_STATE, dialog = VaultItemState.DialogState.Generic( message = R.string.generic_error_message.asText(), + error = error, ), ), viewModel.stateFlow.value, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt index abaad2e4de..dbfdf6e45e 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt @@ -303,6 +303,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() mutableCollectionFlow.tryEmit(value = DataState.Loaded(DEFAULT_COLLECTIONS)) mutableVaultItemFlow.tryEmit(value = DataState.Loaded(createMockCipherView(number = 1))) + val error = Throwable("Fail") coEvery { vaultRepository.shareCipher( cipherId = "mockCipherId", @@ -310,7 +311,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() { cipherView = createMockCipherView(number = 1), collectionIds = listOf("mockId-1"), ) - } returns ShareCipherResult.Error + } returns ShareCipherResult.Error(error = error) viewModel.stateFlow.test { assertEquals( initialState.copy( @@ -340,6 +341,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() { initialState.copy( dialogState = VaultMoveToOrganizationState.DialogState.Error( message = R.string.generic_error_message.asText(), + throwable = error, ), viewState = VaultMoveToOrganizationState.ViewState.Content( organizations = createMockOrganizationList(),