mirror of
https://github.com/bitwarden/android.git
synced 2026-05-31 09:46:08 -05:00
BIT-1057: Vault item listing functionality (#379)
This commit is contained in:
@@ -18,9 +18,17 @@ import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
|
||||
/**
|
||||
* Create a mock [CipherView] with a given [number].
|
||||
* Create a mock [CipherView].
|
||||
*
|
||||
* @param number the number to create the cipher with.
|
||||
* @param isDeleted whether or not the cipher has been deleted.
|
||||
* @param cipherType the type of cipher to create.
|
||||
*/
|
||||
fun createMockCipherView(number: Int): CipherView =
|
||||
fun createMockCipherView(
|
||||
number: Int,
|
||||
isDeleted: Boolean = true,
|
||||
cipherType: CipherType = CipherType.LOGIN,
|
||||
): CipherView =
|
||||
CipherView(
|
||||
id = "mockId-$number",
|
||||
organizationId = "mockOrganizationId-$number",
|
||||
@@ -29,14 +37,18 @@ fun createMockCipherView(number: Int): CipherView =
|
||||
key = "mockKey-$number",
|
||||
name = "mockName-$number",
|
||||
notes = "mockNotes-$number",
|
||||
type = CipherType.LOGIN,
|
||||
type = cipherType,
|
||||
login = createMockLoginView(number = number),
|
||||
creationDate = LocalDateTime
|
||||
.parse("2023-10-27T12:00:00")
|
||||
.toInstant(ZoneOffset.UTC),
|
||||
deletedDate = LocalDateTime
|
||||
.parse("2023-10-27T12:00:00")
|
||||
.toInstant(ZoneOffset.UTC),
|
||||
deletedDate = if (isDeleted) {
|
||||
LocalDateTime
|
||||
.parse("2023-10-27T12:00:00")
|
||||
.toInstant(ZoneOffset.UTC)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
revisionDate = LocalDateTime
|
||||
.parse("2023-10-27T12:00:00")
|
||||
.toInstant(ZoneOffset.UTC),
|
||||
|
||||
@@ -2,15 +2,33 @@ package com.x8bit.bitwarden.ui.vault.feature.itemlisting
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.concat
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.createMockItemListingDisplayItem
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val mutableVaultDataStateFlow =
|
||||
MutableStateFlow<DataState<VaultData>>(DataState.Loading)
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { vaultDataStateFlow } returns mutableVaultDataStateFlow
|
||||
every { sync() } returns Unit
|
||||
}
|
||||
private val initialState = createVaultItemListingState()
|
||||
private val initialSavedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
||||
vaultItemListingType = VaultItemListingType.Login,
|
||||
@@ -63,15 +81,330 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RefreshClick should emit ShowToast`() = runTest {
|
||||
fun `RefreshClick should sync`() = runTest {
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(VaultItemListingsAction.RefreshClick)
|
||||
viewModel.actionChannel.trySend(VaultItemListingsAction.RefreshClick)
|
||||
verify { vaultRepository.sync() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loaded with items should update ViewState to Content`() =
|
||||
runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(
|
||||
createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
),
|
||||
),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingEvent.ShowToast("Not yet implemented".asText()),
|
||||
awaitItem(),
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
displayItemList = listOf(
|
||||
createMockItemListingDisplayItem(number = 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loaded with empty items should update ViewState to NoItems`() =
|
||||
runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = emptyList(),
|
||||
folderViewList = emptyList(),
|
||||
),
|
||||
),
|
||||
)
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
assertEquals(
|
||||
createVaultItemListingState(viewState = VaultItemListingState.ViewState.NoItems),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loaded with trash items should update ViewState to NoItems`() =
|
||||
runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loading should update state to Loading`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(value = DataState.Loading)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(viewState = VaultItemListingState.ViewState.Loading),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Pending with data should update state to Content`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Pending(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = false)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
displayItemList = listOf(
|
||||
createMockItemListingDisplayItem(number = 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Pending with empty data should update state to NoItems`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Pending(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(viewState = VaultItemListingState.ViewState.NoItems),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Pending with trash data should update state to NoItems`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Pending(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(viewState = VaultItemListingState.ViewState.NoItems),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Error without data should update state to Error`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Error(
|
||||
error = IllegalStateException(),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Error(
|
||||
message = R.string.generic_error_message.asText(),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Error with data should update state to Content`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Error(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = false)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
error = IllegalStateException(),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
displayItemList = listOf(
|
||||
createMockItemListingDisplayItem(number = 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Error with empty data should update state to NoItems`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Error(
|
||||
data = VaultData(
|
||||
cipherViewList = emptyList(),
|
||||
folderViewList = emptyList(),
|
||||
),
|
||||
error = IllegalStateException(),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Error with trash data should update state to NoItems`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.Error(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = true)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
error = IllegalStateException(),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow NoNetwork without data should update state to Error`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.NoNetwork(),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Error(
|
||||
message = R.string.internet_connection_required_title
|
||||
.asText()
|
||||
.concat(R.string.internet_connection_required_message.asText()),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow NoNetwork with data should update state to Content`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.NoNetwork(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = false)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
)),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
displayItemList = listOf(
|
||||
createMockItemListingDisplayItem(number = 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow NoNetwork with empty data should update state to NoItems`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.NoNetwork(
|
||||
data = VaultData(
|
||||
cipherViewList = emptyList(),
|
||||
folderViewList = emptyList(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow NoNetwork with trash data should update state to NoItems`() = runTest {
|
||||
mutableVaultDataStateFlow.tryEmit(
|
||||
value = DataState.NoNetwork(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = true)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSavedStateHandleWithVaultItemListingType(
|
||||
@@ -103,9 +436,11 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private fun createVaultItemListingViewModel(
|
||||
savedStateHandle: SavedStateHandle = initialSavedStateHandle,
|
||||
vaultRepository: VaultRepository = this.vaultRepository,
|
||||
): VaultItemListingViewModel =
|
||||
VaultItemListingViewModel(
|
||||
savedStateHandle = savedStateHandle,
|
||||
vaultRepository = vaultRepository,
|
||||
)
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util
|
||||
|
||||
import com.bitwarden.core.CipherType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class VaultItemListingDataExtensionsTest {
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for non trash Login cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.LOGIN,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to true,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to false,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to true,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for trash Login cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.LOGIN,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to true,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to false,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for non trash Card cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.CARD,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to true,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to false,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to true,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for trash Card cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.CARD,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to true,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to false,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for non trash Identity cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.IDENTITY,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to true,
|
||||
VaultItemListingState.ItemListingType.Trash to false,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to true,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for trash Identity cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.IDENTITY,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to true,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to false,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for non trash SecureNote cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.SECURE_NOTE,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to true,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to false,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to true,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `determineListingPredicate should return the correct predicate for trash SecureNote cipherView`() {
|
||||
val cipherView = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.SECURE_NOTE,
|
||||
)
|
||||
|
||||
mapOf(
|
||||
VaultItemListingState.ItemListingType.Login to false,
|
||||
VaultItemListingState.ItemListingType.Card to false,
|
||||
VaultItemListingState.ItemListingType.SecureNote to false,
|
||||
VaultItemListingState.ItemListingType.Identity to false,
|
||||
VaultItemListingState.ItemListingType.Trash to true,
|
||||
VaultItemListingState.ItemListingType.Folder(folderId = "mockId-1") to false,
|
||||
)
|
||||
.forEach { (type, expected) ->
|
||||
val result = cipherView.determineListingPredicate(
|
||||
itemListingType = type,
|
||||
)
|
||||
assertEquals(
|
||||
expected,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toViewState should transform a list of CipherViews into a ViewState`() {
|
||||
val cipherViewList = listOf(
|
||||
createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.LOGIN,
|
||||
),
|
||||
createMockCipherView(
|
||||
number = 2,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.CARD,
|
||||
),
|
||||
createMockCipherView(
|
||||
number = 3,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.SECURE_NOTE,
|
||||
),
|
||||
createMockCipherView(
|
||||
number = 4,
|
||||
isDeleted = false,
|
||||
cipherType = CipherType.IDENTITY,
|
||||
),
|
||||
)
|
||||
|
||||
val result = cipherViewList.toViewState()
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingState.ViewState.Content(
|
||||
displayItemList = listOf(
|
||||
createMockItemListingDisplayItem(
|
||||
number = 1,
|
||||
cipherType = CipherType.LOGIN,
|
||||
),
|
||||
createMockItemListingDisplayItem(
|
||||
number = 2,
|
||||
cipherType = CipherType.CARD,
|
||||
),
|
||||
createMockItemListingDisplayItem(
|
||||
number = 3,
|
||||
cipherType = CipherType.SECURE_NOTE,
|
||||
),
|
||||
createMockItemListingDisplayItem(
|
||||
number = 4,
|
||||
cipherType = CipherType.IDENTITY,
|
||||
),
|
||||
),
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateWithAdditionalDataIfNecessary should update a folder itemListingType`() {
|
||||
val folderViewList = listOf(
|
||||
createMockFolderView(number = 1),
|
||||
createMockFolderView(number = 2),
|
||||
createMockFolderView(number = 3),
|
||||
)
|
||||
|
||||
val result = VaultItemListingState.ItemListingType.Folder(
|
||||
folderId = "mockId-1",
|
||||
folderName = "wrong name",
|
||||
)
|
||||
.updateWithAdditionalDataIfNecessary(folderList = folderViewList)
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingState.ItemListingType.Folder(
|
||||
folderId = "mockId-1",
|
||||
folderName = "mockName-1",
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateWithAdditionalDataIfNecessary should not change a non folder itemListingType`() {
|
||||
val folderViewList = listOf(
|
||||
createMockFolderView(number = 1),
|
||||
createMockFolderView(number = 2),
|
||||
createMockFolderView(number = 3),
|
||||
)
|
||||
|
||||
val result = VaultItemListingState.ItemListingType.Login
|
||||
.updateWithAdditionalDataIfNecessary(folderList = folderViewList)
|
||||
|
||||
assertEquals(
|
||||
VaultItemListingState.ItemListingType.Login,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util
|
||||
|
||||
import com.bitwarden.core.CipherType
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState
|
||||
|
||||
/**
|
||||
* Create a mock [VaultItemListingState.DisplayItem] with a given [number].
|
||||
*/
|
||||
fun createMockItemListingDisplayItem(
|
||||
number: Int,
|
||||
cipherType: CipherType = CipherType.LOGIN,
|
||||
): VaultItemListingState.DisplayItem =
|
||||
when (cipherType) {
|
||||
CipherType.LOGIN -> {
|
||||
VaultItemListingState.DisplayItem(
|
||||
id = "mockId-$number",
|
||||
title = "mockName-$number",
|
||||
subtitle = "mockUsername-$number",
|
||||
iconRes = R.drawable.ic_login_item,
|
||||
uri = "mockUri-$number",
|
||||
)
|
||||
}
|
||||
|
||||
CipherType.SECURE_NOTE -> {
|
||||
VaultItemListingState.DisplayItem(
|
||||
id = "mockId-$number",
|
||||
title = "mockName-$number",
|
||||
subtitle = null,
|
||||
iconRes = R.drawable.ic_secure_note_item,
|
||||
uri = null,
|
||||
)
|
||||
}
|
||||
|
||||
CipherType.CARD -> {
|
||||
VaultItemListingState.DisplayItem(
|
||||
id = "mockId-$number",
|
||||
title = "mockName-$number",
|
||||
subtitle = "er-$number",
|
||||
iconRes = R.drawable.ic_card_item,
|
||||
uri = null,
|
||||
)
|
||||
}
|
||||
|
||||
CipherType.IDENTITY -> {
|
||||
VaultItemListingState.DisplayItem(
|
||||
id = "mockId-$number",
|
||||
title = "mockName-$number",
|
||||
subtitle = "mockFirstName-${number}mockLastName-$number",
|
||||
iconRes = R.drawable.ic_identity_item,
|
||||
uri = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user