fixing broken settings view model tests and handling file opening errors

This commit is contained in:
Adam Brown 2022-09-04 14:13:36 +01:00
parent ef2a2c5624
commit f973e01a4e
4 changed files with 34 additions and 21 deletions

View File

@ -158,6 +158,7 @@ internal fun SettingsScreen(viewModel: SettingsViewModel, onSignOut: () -> Unit,
ImportResult.Error.Type.NoKeysFound -> "No keys found in the file"
ImportResult.Error.Type.UnexpectedDecryptionOutput -> "Unable to decrypt file, double check your passphrase"
is ImportResult.Error.Type.Unknown -> "${type.cause::class.java.simpleName}: ${type.cause.message}"
ImportResult.Error.Type.UnableToOpenFile -> "Unable to open file"
}
Text(text = "Import failed\n$message", textAlign = TextAlign.Center)

View File

@ -4,7 +4,6 @@ import android.content.ContentResolver
import android.net.Uri
import androidx.lifecycle.viewModelScope
import app.dapk.st.core.Lce
import app.dapk.st.core.LceWithProgress
import app.dapk.st.design.components.SpiderPage
import app.dapk.st.domain.StoreCleaner
import app.dapk.st.matrix.crypto.CryptoService
@ -127,22 +126,30 @@ internal class SettingsViewModel(
updatePageState<Page.ImportRoomKey> { copy(importProgress = ImportResult.Update(0)) }
viewModelScope.launch {
with(cryptoService) {
contentResolver.openInputStream(file)?.importRoomKeys(passphrase)
?.onEach {
updatePageState<Page.ImportRoomKey> { copy(importProgress = it) }
when (it) {
is ImportResult.Error -> {
// do nothing
}
is ImportResult.Update -> {
// do nothing
}
is ImportResult.Success -> {
syncService.forceManualRefresh(it.roomIds.toList())
}
runCatching { contentResolver.openInputStream(file)!! }
.fold(
onSuccess = { fileStream ->
fileStream.importRoomKeys(passphrase)
.onEach {
updatePageState<Page.ImportRoomKey> { copy(importProgress = it) }
when (it) {
is ImportResult.Error -> {
// do nothing
}
is ImportResult.Update -> {
// do nothing
}
is ImportResult.Success -> {
syncService.forceManualRefresh(it.roomIds.toList())
}
}
}
.launchIn(viewModelScope)
},
onFailure = {
updatePageState<Page.ImportRoomKey> { copy(importProgress = ImportResult.Error(ImportResult.Error.Type.UnableToOpenFile)) }
}
}
?.launchIn(viewModelScope)
)
}
}
}

View File

@ -3,6 +3,7 @@ package app.dapk.st.settings
import ViewModelTest
import app.dapk.st.core.Lce
import app.dapk.st.design.components.SpiderPage
import app.dapk.st.matrix.crypto.ImportResult
import fake.*
import fixture.FakeStoreCleaner
import fixture.aRoomId
@ -10,6 +11,7 @@ import internalfake.FakeSettingsItemFactory
import internalfake.FakeUriFilenameResolver
import internalfixture.aImportRoomKeysPage
import internalfixture.aSettingTextItem
import kotlinx.coroutines.flow.flowOf
import org.junit.Test
private const val APP_PRIVACY_POLICY_URL = "https://ouchadam.github.io/small-talk/privacy/"
@ -21,6 +23,8 @@ private val A_IMPORT_ROOM_KEYS_PAGE_WITH_SELECTION = aImportRoomKeysPage(
state = Page.ImportRoomKey(selectedFile = NamedUri(A_FILENAME, A_URI.instance))
)
private val A_LIST_OF_ROOM_IDS = listOf(aRoomId())
private val AN_IMPORT_SUCCESS = ImportResult.Success(A_LIST_OF_ROOM_IDS.toSet(), totalImportedKeysCount = 5)
private val AN_IMPORT_FILE_ERROR = ImportResult.Error(ImportResult.Error.Type.UnableToOpenFile)
private val AN_INPUT_STREAM = FakeInputStream()
private const val A_PASSPHRASE = "passphrase"
private val AN_ERROR = RuntimeException()
@ -166,15 +170,15 @@ internal class SettingsViewModelTest {
fun `given success when importing room keys, then emits progress`() = runViewModelTest {
fakeSyncService.expectUnit { it.forceManualRefresh(A_LIST_OF_ROOM_IDS) }
fakeContentResolver.givenFile(A_URI.instance).returns(AN_INPUT_STREAM.instance)
fakeCryptoService.givenImportKeys(AN_INPUT_STREAM.instance, A_PASSPHRASE).returns(A_LIST_OF_ROOM_IDS)
fakeCryptoService.givenImportKeys(AN_INPUT_STREAM.instance, A_PASSPHRASE).returns(flowOf(AN_IMPORT_SUCCESS))
viewModel
.test(initialState = SettingsScreenState(A_IMPORT_ROOM_KEYS_PAGE_WITH_SELECTION))
.importFromFileKeys(A_URI.instance, A_PASSPHRASE)
assertStates<SettingsScreenState>(
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = Lce.Loading()) }) },
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = Lce.Content(Unit)) }) },
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = ImportResult.Update(0L)) }) },
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = AN_IMPORT_SUCCESS) }) },
)
assertNoEvents<SettingsEvent>()
verifyExpects()
@ -189,8 +193,8 @@ internal class SettingsViewModelTest {
.importFromFileKeys(A_URI.instance, A_PASSPHRASE)
assertStates<SettingsScreenState>(
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = Lce.Loading()) }) },
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = Lce.Error(AN_ERROR)) }) },
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = ImportResult.Update(0L)) }) },
{ copy(page = page.updateState<Page.ImportRoomKey> { copy(importProgress = AN_IMPORT_FILE_ERROR) }) },
)
assertNoEvents<SettingsEvent>()
}

View File

@ -169,6 +169,7 @@ sealed interface ImportResult {
data class Unknown(val cause: Throwable): Type
object NoKeysFound: Type
object UnexpectedDecryptionOutput: Type
object UnableToOpenFile: Type
}
}