diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index 97d2f4d467..4177625e6d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -21,6 +21,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.toUpdatedUserStateJson import com.x8bit.bitwarden.data.auth.repository.util.userSwitchingChangesFlow import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource import com.x8bit.bitwarden.data.platform.datasource.network.util.isNoConnectionError +import com.x8bit.bitwarden.data.platform.error.NoActiveUserException import com.x8bit.bitwarden.data.platform.manager.DatabaseSchemeManager import com.x8bit.bitwarden.data.platform.manager.PushManager import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager @@ -622,7 +623,8 @@ class VaultRepositoryImpl( sendView: SendView, fileUri: Uri?, ): CreateSendResult { - val userId = activeUserId ?: return CreateSendResult.Error(message = null) + val userId = activeUserId + ?: return CreateSendResult.Error(message = null, error = NoActiveUserException()) return vaultSdkSource .encryptSend( userId = userId, @@ -639,6 +641,7 @@ class VaultRepositoryImpl( is CreateSendJsonResponse.Invalid -> { return CreateSendResult.Error( message = createSendResponse.firstValidationErrorMessage, + error = null, ) } @@ -656,7 +659,7 @@ class VaultRepositoryImpl( ) } .fold( - onFailure = { CreateSendResult.Error(message = null) }, + onFailure = { CreateSendResult.Error(message = null, error = it) }, onSuccess = { reviewPromptManager.registerCreateSendAction() CreateSendResult.Success(it) @@ -668,7 +671,11 @@ class VaultRepositoryImpl( sendId: String, sendView: SendView, ): UpdateSendResult { - val userId = activeUserId ?: return UpdateSendResult.Error(null) + val userId = activeUserId + ?: return UpdateSendResult.Error( + errorMessage = null, + error = NoActiveUserException(), + ) return vaultSdkSource .encryptSend( userId = userId, @@ -681,11 +688,11 @@ class VaultRepositoryImpl( ) } .fold( - onFailure = { UpdateSendResult.Error(errorMessage = null) }, + onFailure = { UpdateSendResult.Error(errorMessage = null, error = it) }, onSuccess = { response -> when (response) { is UpdateSendResponseJson.Invalid -> { - UpdateSendResult.Error(errorMessage = response.message) + UpdateSendResult.Error(errorMessage = response.message, error = null) } is UpdateSendResponseJson.Success -> { @@ -695,9 +702,12 @@ class VaultRepositoryImpl( userId = userId, send = response.send.toEncryptedSdkSend(), ) - .getOrNull() - ?.let { UpdateSendResult.Success(sendView = it) } - ?: UpdateSendResult.Error(errorMessage = null) + .fold( + onSuccess = { UpdateSendResult.Success(sendView = it) }, + onFailure = { + UpdateSendResult.Error(errorMessage = null, error = it) + }, + ) } } }, @@ -705,14 +715,21 @@ class VaultRepositoryImpl( } override suspend fun removePasswordSend(sendId: String): RemovePasswordSendResult { - val userId = activeUserId ?: return RemovePasswordSendResult.Error(null) + val userId = activeUserId + ?: return RemovePasswordSendResult.Error( + errorMessage = null, + error = NoActiveUserException(), + ) return sendsService .removeSendPassword(sendId = sendId) .fold( onSuccess = { response -> when (response) { is UpdateSendResponseJson.Invalid -> { - RemovePasswordSendResult.Error(errorMessage = response.message) + RemovePasswordSendResult.Error( + errorMessage = response.message, + error = null, + ) } is UpdateSendResponseJson.Success -> { @@ -722,24 +739,30 @@ class VaultRepositoryImpl( userId = userId, send = response.send.toEncryptedSdkSend(), ) - .getOrNull() - ?.let { RemovePasswordSendResult.Success(sendView = it) } - ?: RemovePasswordSendResult.Error(errorMessage = null) + .fold( + onSuccess = { RemovePasswordSendResult.Success(sendView = it) }, + onFailure = { + RemovePasswordSendResult.Error( + errorMessage = null, + error = it, + ) + }, + ) } } }, - onFailure = { RemovePasswordSendResult.Error(errorMessage = null) }, + onFailure = { RemovePasswordSendResult.Error(errorMessage = null, error = it) }, ) } override suspend fun deleteSend(sendId: String): DeleteSendResult { - val userId = activeUserId ?: return DeleteSendResult.Error + val userId = activeUserId ?: return DeleteSendResult.Error(error = NoActiveUserException()) return sendsService .deleteSend(sendId) .onSuccess { vaultDiskSource.deleteSend(userId, sendId) } .fold( onSuccess = { DeleteSendResult.Success }, - onFailure = { DeleteSendResult.Error }, + onFailure = { DeleteSendResult.Error(error = it) }, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt index c4a321e028..18c7a4ac87 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateSendResult.kt @@ -15,5 +15,5 @@ sealed class CreateSendResult { /** * Generic error while creating a send. */ - data class Error(val message: String?) : CreateSendResult() + data class Error(val message: String?, val error: Throwable?) : CreateSendResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteSendResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteSendResult.kt index fe297923ec..c2aa01df7e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteSendResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/DeleteSendResult.kt @@ -13,5 +13,5 @@ sealed class DeleteSendResult { /** * Generic error while deleting a send. */ - data object Error : DeleteSendResult() + data class Error(val error: Throwable) : DeleteSendResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RemovePasswordSendResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RemovePasswordSendResult.kt index 5b96fe37b9..eef1cd93e4 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RemovePasswordSendResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/RemovePasswordSendResult.kt @@ -17,5 +17,5 @@ sealed class RemovePasswordSendResult { * Generic error while removing the password protection from a send. The optional * [errorMessage] may be displayed directly in the UI when present. */ - data class Error(val errorMessage: String?) : RemovePasswordSendResult() + data class Error(val errorMessage: String?, val error: Throwable?) : RemovePasswordSendResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateSendResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateSendResult.kt index 60ab1f8ce5..c0c3e42303 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateSendResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/UpdateSendResult.kt @@ -16,5 +16,5 @@ sealed class UpdateSendResult { * Generic error while updating a send. The optional [errorMessage] may be displayed directly * in the UI when present. */ - data class Error(val errorMessage: String?) : UpdateSendResult() + data class Error(val errorMessage: String?, val error: Throwable?) : UpdateSendResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreen.kt index 3a36a1ca43..a76733f233 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreen.kt @@ -186,6 +186,7 @@ private fun SearchDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = onDismissRequest, + throwable = dialogState.throwable, ) is SearchState.DialogState.Loading -> BitwardenLoadingDialog( 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 f1d3f0fdd9..dd42d09e92 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 @@ -474,13 +474,14 @@ class SearchViewModel @Inject constructor( private fun handleDeleteSendResultReceive( action: SearchAction.Internal.DeleteSendResultReceive, ) { - when (action.result) { - DeleteSendResult.Error -> { + when (val result = action.result) { + is DeleteSendResult.Error -> { mutableStateFlow.update { it.copy( dialogState = SearchState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -857,6 +858,7 @@ data class SearchState( data class Error( val title: Text?, val message: Text, + val throwable: Throwable? = null, ) : DialogState() /** diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt index fa763dff0a..6ec405d91a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt @@ -212,6 +212,7 @@ private fun SendDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = onDismissRequest, + throwable = dialogState.throwable, ) is SendState.DialogState.Loading -> BitwardenLoadingDialog( diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt index 92d2519689..037a0ae827 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt @@ -140,13 +140,14 @@ class SendViewModel @Inject constructor( } private fun handleDeleteSendResultReceive(action: SendAction.Internal.DeleteSendResultReceive) { - when (action.result) { - DeleteSendResult.Error -> { + when (val result = action.result) { + is DeleteSendResult.Error -> { mutableStateFlow.update { it.copy( dialogState = SendState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -465,6 +466,7 @@ data class SendState( data class Error( val title: Text?, val message: Text, + val throwable: Throwable? = null, ) : DialogState() /** diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt index e8d65b5a46..1e1a23b8be 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendScreen.kt @@ -255,6 +255,7 @@ private fun AddSendDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = onDismissRequest, + throwable = dialogState.throwable, ) is AddSendState.DialogState.Loading -> BitwardenLoadingDialog( diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt index 19711b4cfd..e5573bf07a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModel.kt @@ -192,6 +192,7 @@ class AddSendViewModel @Inject constructor( title = R.string.an_error_has_occurred.asText(), message = result.message?.asText() ?: R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -222,6 +223,7 @@ class AddSendViewModel @Inject constructor( .errorMessage ?.asText() ?: R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -242,13 +244,14 @@ class AddSendViewModel @Inject constructor( private fun handleDeleteSendResultReceive( action: AddSendAction.Internal.DeleteSendResultReceive, ) { - when (action.result) { + when (val result = action.result) { is DeleteSendResult.Error -> { mutableStateFlow.update { it.copy( dialogState = AddSendState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -275,6 +278,7 @@ class AddSendViewModel @Inject constructor( .errorMessage ?.asText() ?: R.string.generic_error_message.asText(), + result.error, ), ) } @@ -836,6 +840,7 @@ data class AddSendState( data class Error( val title: Text?, val message: Text, + val throwable: Throwable? = null, ) : DialogState() /** diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index aea4026ead..be5a597847 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -317,6 +317,7 @@ private fun VaultItemListingDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = onDismissRequest, + throwable = dialogState.throwable, ) is VaultItemListingState.DialogState.Loading -> BitwardenLoadingDialog( diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 0069774c8d..9423c5726c 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -1206,13 +1206,14 @@ class VaultItemListingViewModel @Inject constructor( private fun handleDeleteSendResultReceive( action: VaultItemListingsAction.Internal.DeleteSendResultReceive, ) { - when (action.result) { - DeleteSendResult.Error -> { + when (val result = action.result) { + is DeleteSendResult.Error -> { mutableStateFlow.update { it.copy( dialogState = VaultItemListingState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -1238,6 +1239,7 @@ class VaultItemListingViewModel @Inject constructor( .errorMessage ?.asText() ?: R.string.generic_error_message.asText(), + throwable = result.error, ), ) } @@ -1310,6 +1312,8 @@ class VaultItemListingViewModel @Inject constructor( dialogState = VaultItemListingState.DialogState.Error( title = null, message = R.string.generic_error_message.asText(), + // TODO PM-19425 update ValidatePasswordResult to propagate error. + throwable = null, ), ) } @@ -1322,6 +1326,8 @@ class VaultItemListingViewModel @Inject constructor( dialogState = VaultItemListingState.DialogState.Error( title = null, message = R.string.invalid_master_password.asText(), + // TODO PM-19425 update ValidatePasswordResult to propagate error. + throwable = null, ), ) } @@ -2025,6 +2031,7 @@ data class VaultItemListingState( data class Error( val title: Text?, val message: Text, + val throwable: Throwable? = null, ) : DialogState() /** diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index 8efaf1486f..60ddb0b372 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -25,6 +25,7 @@ import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource +import com.x8bit.bitwarden.data.platform.error.NoActiveUserException import com.x8bit.bitwarden.data.platform.manager.DatabaseSchemeManager import com.x8bit.bitwarden.data.platform.manager.PushManager import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager @@ -109,8 +110,10 @@ import io.mockk.coVerify import io.mockk.every import io.mockk.just import io.mockk.mockk +import io.mockk.mockkConstructor import io.mockk.mockkStatic import io.mockk.runs +import io.mockk.unmockkConstructor import io.mockk.unmockkStatic import io.mockk.verify import kotlinx.coroutines.flow.Flow @@ -248,6 +251,10 @@ class VaultRepositoryTest { mockkStatic(Uri::class) mockkStatic(MessageDigest::class) mockkStatic(Base64::class) + mockkConstructor(NoActiveUserException::class) + every { + anyConstructed() == any() + } returns true } @AfterEach @@ -256,6 +263,7 @@ class VaultRepositoryTest { unmockkStatic(Uri::class) unmockkStatic(MessageDigest::class) unmockkStatic(Base64::class) + unmockkConstructor(NoActiveUserException::class) } @Test @@ -2116,7 +2124,7 @@ class VaultRepositoryTest { ) assertEquals( - CreateSendResult.Error(message = null), + CreateSendResult.Error(message = null, error = NoActiveUserException()), result, ) } @@ -2127,13 +2135,14 @@ class VaultRepositoryTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val mockSendView = createMockSendView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = null) - assertEquals(CreateSendResult.Error(message = null), result) + assertEquals(CreateSendResult.Error(message = null, error = error), result) } @Test @@ -2143,6 +2152,7 @@ class VaultRepositoryTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val userId = "mockId-1" val mockSendView = createMockSendView(number = 1, type = SendType.TEXT) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns createMockSdkSend(number = 1, type = SendType.TEXT).asSuccess() @@ -2151,11 +2161,11 @@ class VaultRepositoryTest { body = createMockSendJsonRequest(number = 1, type = SendTypeJson.TEXT) .copy(fileLength = null), ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = null) - assertEquals(CreateSendResult.Error(IllegalStateException().message), result) + assertEquals(CreateSendResult.Error(message = error.message, error = error), result) } @Suppress("MaxLineLength") @@ -2219,13 +2229,14 @@ class VaultRepositoryTest { destinationFilePath = "mockAbsolutePath", ) } returns encryptedFile.asSuccess() + val error = IllegalStateException() coEvery { sendsService.createFileSend(body = createMockSendJsonRequest(number = 1)) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri) - assertEquals(CreateSendResult.Error(IllegalStateException().message), result) + assertEquals(CreateSendResult.Error(message = error.message, error = error), result) } @Test @@ -2254,6 +2265,7 @@ class VaultRepositoryTest { type = SendTypeJson.FILE, ), ) + val error = Throwable() coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() @@ -2284,11 +2296,11 @@ class VaultRepositoryTest { sendFileResponse = sendFileResponse.createFileJsonResponse, encryptedFile = encryptedFile, ) - } returns Throwable().asFailure() + } returns error.asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri) - assertEquals(CreateSendResult.Error(null), result) + assertEquals(CreateSendResult.Error(message = null, error = error), result) } @Test @@ -2301,14 +2313,15 @@ class VaultRepositoryTest { val uri = setupMockUri(url = url) val mockSendView = createMockSendView(number = 1) val mockSdkSend = createMockSdkSend(number = 1) + val error = Throwable() coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() - coEvery { fileManager.writeUriToCache(any()) } returns Throwable().asFailure() + coEvery { fileManager.writeUriToCache(any()) } returns error.asFailure() val result = vaultRepository.createSend(sendView = mockSendView, fileUri = uri) - assertEquals(CreateSendResult.Error(message = null), result) + assertEquals(CreateSendResult.Error(message = null, error = error), result) } @Test @@ -2381,7 +2394,7 @@ class VaultRepositoryTest { ) assertEquals( - UpdateSendResult.Error(null), + UpdateSendResult.Error(errorMessage = null, error = NoActiveUserException()), result, ) } @@ -2393,16 +2406,17 @@ class VaultRepositoryTest { val userId = "mockId-1" val sendId = "sendId1234" val mockSendView = createMockSendView(number = 1) + val error = IllegalStateException() coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = vaultRepository.updateSend( sendId = sendId, sendView = mockSendView, ) - assertEquals(UpdateSendResult.Error(errorMessage = null), result) + assertEquals(UpdateSendResult.Error(errorMessage = null, error = error), result) } @Test @@ -2416,20 +2430,21 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns createMockSdkSend(number = 1, type = SendType.TEXT).asSuccess() + val error = IllegalStateException() coEvery { sendsService.updateSend( sendId = sendId, body = createMockSendJsonRequest(number = 1, type = SendTypeJson.TEXT) .copy(fileLength = null), ) - } returns IllegalStateException().asFailure() + } returns error.asFailure() val result = vaultRepository.updateSend( sendId = sendId, sendView = mockSendView, ) - assertEquals(UpdateSendResult.Error(errorMessage = null), result) + assertEquals(UpdateSendResult.Error(errorMessage = null, error = error), result) } @Test @@ -2464,6 +2479,7 @@ class VaultRepositoryTest { assertEquals( UpdateSendResult.Error( errorMessage = "You do not have permission to edit this.", + error = null, ), result, ) @@ -2488,11 +2504,12 @@ class VaultRepositoryTest { .copy(fileLength = null), ) } returns UpdateSendResponseJson.Success(send = mockSend).asSuccess() + val error = Throwable("Fail") coEvery { vaultSdkSource.decryptSend( userId = userId, send = createMockSdkSend(number = 1, type = SendType.TEXT), ) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() coEvery { vaultDiskSource.saveSend(userId = userId, send = mockSend) } just runs val result = vaultRepository.updateSend( @@ -2500,7 +2517,7 @@ class VaultRepositoryTest { sendView = mockSendView, ) - assertEquals(UpdateSendResult.Error(errorMessage = null), result) + assertEquals(UpdateSendResult.Error(errorMessage = null, error = error), result) } @Test @@ -2549,7 +2566,10 @@ class VaultRepositoryTest { ) assertEquals( - RemovePasswordSendResult.Error(null), + RemovePasswordSendResult.Error( + errorMessage = null, + error = NoActiveUserException(), + ), result, ) } @@ -2560,13 +2580,14 @@ class VaultRepositoryTest { runTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val sendId = "sendId1234" + val error = Throwable("Fail") coEvery { sendsService.removeSendPassword(sendId = sendId) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() val result = vaultRepository.removePasswordSend(sendId = sendId) - assertEquals(RemovePasswordSendResult.Error(errorMessage = null), result) + assertEquals(RemovePasswordSendResult.Error(errorMessage = null, error = error), result) } @Test @@ -2577,17 +2598,18 @@ class VaultRepositoryTest { val userId = "mockId-1" val sendId = "sendId1234" val mockSend = createMockSend(number = 1) + val error = Throwable("Fail") coEvery { sendsService.removeSendPassword(sendId = sendId) } returns UpdateSendResponseJson.Success(send = mockSend).asSuccess() coEvery { vaultSdkSource.decryptSend(userId = userId, send = createMockSdkSend(number = 1)) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() coEvery { vaultDiskSource.saveSend(userId = userId, send = mockSend) } just runs val result = vaultRepository.removePasswordSend(sendId = sendId) - assertEquals(RemovePasswordSendResult.Error(errorMessage = null), result) + assertEquals(RemovePasswordSendResult.Error(errorMessage = null, error = error), result) } @Test @@ -2622,7 +2644,7 @@ class VaultRepositoryTest { ) assertEquals( - DeleteSendResult.Error, + DeleteSendResult.Error(error = NoActiveUserException()), result, ) } @@ -2632,13 +2654,14 @@ class VaultRepositoryTest { runTest { fakeAuthDiskSource.userState = MOCK_USER_STATE val sendId = "mockId-1" + val error = Throwable("Fail") coEvery { sendsService.deleteSend(sendId = sendId) - } returns Throwable("Fail").asFailure() + } returns error.asFailure() val result = vaultRepository.deleteSend(sendId) - assertEquals(DeleteSendResult.Error, result) + assertEquals(DeleteSendResult.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 09666e2ffc..f2c3db6e25 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 @@ -715,8 +715,11 @@ class SearchViewModelTest : BaseViewModelTest() { @Test fun `OverflowOptionClick Send DeleteClick with deleteSend error should display error dialog`() = runTest { + val error = Throwable("Ahhh") val sendId = "sendId1234" - coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error + coEvery { + vaultRepository.deleteSend(sendId) + } returns DeleteSendResult.Error(error = error) val viewModel = createViewModel() viewModel.stateFlow.test { @@ -739,6 +742,7 @@ class SearchViewModelTest : BaseViewModelTest() { dialogState = SearchState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = error, ), ), awaitItem(), @@ -787,7 +791,7 @@ class SearchViewModelTest : BaseViewModelTest() { val sendId = "sendId1234" coEvery { vaultRepository.removePasswordSend(sendId) - } returns RemovePasswordSendResult.Error(errorMessage = null) + } returns RemovePasswordSendResult.Error(errorMessage = null, error = null) val viewModel = createViewModel() viewModel.stateFlow.test { diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt index 003e291e33..292867e6a9 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt @@ -138,7 +138,8 @@ class SendViewModelTest : BaseViewModelTest() { val sendItem = mockk { every { id } returns sendId } - coEvery { vaultRepo.deleteSend(sendId) } returns DeleteSendResult.Error + val error = Throwable("Oops") + coEvery { vaultRepo.deleteSend(sendId) } returns DeleteSendResult.Error(error = error) val viewModel = createViewModel() viewModel.stateFlow.test { @@ -155,6 +156,7 @@ class SendViewModelTest : BaseViewModelTest() { dialogState = SendState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = error, ), ), awaitItem(), @@ -186,7 +188,7 @@ class SendViewModelTest : BaseViewModelTest() { } coEvery { vaultRepo.removePasswordSend(sendId) - } returns RemovePasswordSendResult.Error(errorMessage = null) + } returns RemovePasswordSendResult.Error(errorMessage = null, error = null) val viewModel = createViewModel() viewModel.stateFlow.test { diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt index 84c95903ad..03bceb9959 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/addsend/AddSendViewModelTest.kt @@ -242,7 +242,7 @@ class AddSendViewModelTest : BaseViewModelTest() { every { viewState.toSendView(clock) } returns mockSendView coEvery { vaultRepository.createSend(sendView = mockSendView, fileUri = null) - } returns CreateSendResult.Error("Fail") + } returns CreateSendResult.Error(message = "Fail", error = null) val viewModel = createViewModel(initialState) viewModel.stateFlow.test { @@ -337,7 +337,7 @@ class AddSendViewModelTest : BaseViewModelTest() { every { viewState.toSendView(clock) } returns mockSendView coEvery { vaultRepository.updateSend(sendId = sendId, sendView = mockSendView) - } returns UpdateSendResult.Error(errorMessage = errorMessage) + } returns UpdateSendResult.Error(errorMessage = errorMessage, error = null) mutableSendDataStateFlow.value = DataState.Loaded(mockSendView) val viewModel = createViewModel(initialState, AddSendType.EditItem(sendId)) @@ -493,7 +493,7 @@ class AddSendViewModelTest : BaseViewModelTest() { val sendId = "mockId-1" coEvery { vaultRepository.removePasswordSend(sendId) - } returns RemovePasswordSendResult.Error(errorMessage = null) + } returns RemovePasswordSendResult.Error(errorMessage = null, error = null) val initialState = DEFAULT_STATE.copy( addSendType = AddSendType.EditItem(sendItemId = sendId), ) @@ -542,7 +542,7 @@ class AddSendViewModelTest : BaseViewModelTest() { val errorMessage = "Fail" coEvery { vaultRepository.removePasswordSend(sendId) - } returns RemovePasswordSendResult.Error(errorMessage = errorMessage) + } returns RemovePasswordSendResult.Error(errorMessage = errorMessage, error = null) val mockSendView = createMockSendView(number = 1) every { mockSendView.toViewState( @@ -608,8 +608,11 @@ class AddSendViewModelTest : BaseViewModelTest() { @Test fun `DeleteClick vaultRepository deleteSend Error should show error dialog`() = runTest { + val error = Throwable("Ooops") val sendId = "mockId-1" - coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error + coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error( + error = error, + ) val initialState = DEFAULT_STATE.copy( addSendType = AddSendType.EditItem(sendItemId = sendId), ) @@ -643,6 +646,7 @@ class AddSendViewModelTest : BaseViewModelTest() { dialogState = AddSendState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = error, ), ), awaitItem(), diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index fb818ce532..c24bfb4b54 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -1232,7 +1232,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { fun `OverflowOptionClick Send DeleteClick with deleteSend error should display error dialog`() = runTest { val sendId = "sendId1234" - coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error + val error = Throwable("Oops") + coEvery { vaultRepository.deleteSend(sendId) } returns DeleteSendResult.Error( + error = error, + ) val viewModel = createVaultItemListingViewModel() viewModel.stateFlow.test { @@ -1255,6 +1258,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { dialogState = VaultItemListingState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = error, ), ), awaitItem(), @@ -1301,9 +1305,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { fun `OverflowOptionClick Send RemovePasswordClick with removePasswordSend error should display error dialog`() = runTest { val sendId = "sendId1234" + val error = Throwable("Oops") coEvery { vaultRepository.removePasswordSend(sendId) - } returns RemovePasswordSendResult.Error(errorMessage = null) + } returns RemovePasswordSendResult.Error(errorMessage = null, error = error) val viewModel = createVaultItemListingViewModel() viewModel.stateFlow.test { @@ -1326,6 +1331,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { dialogState = VaultItemListingState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), message = R.string.generic_error_message.asText(), + throwable = error, ), ), awaitItem(),