[PM-33394] debt: Add userFriendlyMessage extension and errorMessage to result types (#6642)

This commit is contained in:
Patrick Honkonen
2026-03-12 09:56:49 -04:00
committed by GitHub
parent 04bcd35776
commit 9068307928
12 changed files with 105 additions and 20 deletions

View File

@@ -0,0 +1,13 @@
package com.x8bit.bitwarden.data.platform.util
import com.bitwarden.network.exception.CookieRedirectException
/**
* Returns a user-friendly error message if this [Throwable] is an allow-listed
* exception type that carries one, or `null` otherwise.
*/
val Throwable.userFriendlyMessage: String?
get() = when (this) {
is CookieRedirectException -> message
else -> null
}

View File

@@ -11,7 +11,11 @@ sealed class ArchiveCipherResult {
data object Success : ArchiveCipherResult()
/**
* Generic error while archiving a cipher.
* Generic error while archiving a cipher. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : ArchiveCipherResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : ArchiveCipherResult()
}

View File

@@ -13,7 +13,11 @@ sealed class CreateFolderResult {
data class Success(val folderView: FolderView) : CreateFolderResult()
/**
* Generic error while creating a folder.
* Generic error while creating a folder. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : CreateFolderResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : CreateFolderResult()
}

View File

@@ -11,7 +11,11 @@ sealed class DeleteAttachmentResult {
data object Success : DeleteAttachmentResult()
/**
* Generic error while deleting an attachment.
* Generic error while deleting an attachment. The optional [errorMessage] may be
* displayed directly in the UI when present.
*/
data class Error(val error: Throwable) : DeleteAttachmentResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : DeleteAttachmentResult()
}

View File

@@ -11,7 +11,11 @@ sealed class DeleteCipherResult {
data object Success : DeleteCipherResult()
/**
* Generic error while deleting a cipher.
* Generic error while deleting a cipher. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : DeleteCipherResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : DeleteCipherResult()
}

View File

@@ -11,7 +11,11 @@ sealed class DeleteFolderResult {
data object Success : DeleteFolderResult()
/**
* Generic error while deleting a folder.
* Generic error while deleting a folder. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : DeleteFolderResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : DeleteFolderResult()
}

View File

@@ -11,7 +11,11 @@ sealed class DeleteSendResult {
data object Success : DeleteSendResult()
/**
* Generic error while deleting a send.
* Generic error while deleting a send. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : DeleteSendResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : DeleteSendResult()
}

View File

@@ -22,9 +22,13 @@ sealed class ImportCredentialsResult {
data class SyncFailed(val error: Throwable) : ImportCredentialsResult()
/**
* Indicates there was an error importing the vault data.
* Indicates there was an error importing the vault data. The optional [errorMessage] may be
* displayed directly in the UI when present.
*
* @param error The error that occurred during import.
*/
data class Error(val error: Throwable) : ImportCredentialsResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : ImportCredentialsResult()
}

View File

@@ -11,7 +11,11 @@ sealed class RestoreCipherResult {
data object Success : RestoreCipherResult()
/**
* Generic error while restoring a cipher.
* Generic error while restoring a cipher. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : RestoreCipherResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : RestoreCipherResult()
}

View File

@@ -10,7 +10,11 @@ sealed class ShareCipherResult {
data object Success : ShareCipherResult()
/**
* Generic error while sharing cipher.
* Generic error while sharing cipher. The optional [errorMessage] may be displayed
* directly in the UI when present.
*/
data class Error(val error: Throwable) : ShareCipherResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : ShareCipherResult()
}

View File

@@ -11,7 +11,11 @@ sealed class UnarchiveCipherResult {
data object Success : UnarchiveCipherResult()
/**
* Generic error while unarchiving a cipher.
* Generic error while unarchiving a cipher. The optional [errorMessage] may be
* displayed directly in the UI when present.
*/
data class Error(val error: Throwable) : UnarchiveCipherResult()
data class Error(
val error: Throwable,
val errorMessage: String? = null,
) : UnarchiveCipherResult()
}

View File

@@ -0,0 +1,32 @@
package com.x8bit.bitwarden.data.platform.util
import com.bitwarden.network.exception.CookieRedirectException
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import java.io.IOException
class ThrowableExtensionsTest {
@Test
fun `userFriendlyMessage should return message for CookieRedirectException`() {
val exception = CookieRedirectException(hostname = "example.com")
assertEquals(
"Your request was interrupted because the app needed to " +
"re-authenticate. Please try again.",
exception.userFriendlyMessage,
)
}
@Test
fun `userFriendlyMessage should return null for IOException`() {
val exception = IOException("io error")
assertNull(exception.userFriendlyMessage)
}
@Test
fun `userFriendlyMessage should return null for RuntimeException`() {
val exception = RuntimeException("runtime error")
assertNull(exception.userFriendlyMessage)
}
}