From 533bbc770c5248915bdbe42caa047354fa78f777 Mon Sep 17 00:00:00 2001 From: bug-factory Date: Fri, 9 Oct 2026 13:41:33 -0500 Subject: [PATCH] =?UTF-8?q?[PM-41952]=20fix:=20[Defect]=20Android=20-=20If?= =?UTF-8?q?=20a=20Passkey=20is=20attached=20to=20a=20Cipher=20that=20has?= =?UTF-8?q?=20a=E2=80=A6=20[bug-factory=20poc]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated fix from the AI-49 bug factory. Proof: ./gradlew :app:testStandardDebugUnitTest --tests "com.x8bit.bitwarden.ui.vault.feature.exportitems.reviewexport.ReviewExportViewModelTest" must fail on base and pass with the fix. --- .../reviewexport/ReviewExportViewModel.kt | 2 +- .../reviewexport/ReviewExportViewModelTest.kt | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModel.kt index 2c18c0a9eb..517a6ac90e 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModel.kt @@ -245,9 +245,9 @@ class ReviewExportViewModel @Inject constructor( ?.filter { it.isActive } .orEmpty() .forEach { + if (it.isActiveWithFido2Credentials) passkeyItemCount++ when { it.isActiveWithCopyablePassword -> passwordItemCount++ - it.isActiveWithFido2Credentials -> passkeyItemCount++ it.type is CipherListViewType.Identity -> identityItemCount++ it.card != null -> cardItemCount++ it.type is CipherListViewType.SecureNote -> secureNoteItemCount++ diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt index f1d9347889..658c974b7c 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt @@ -25,6 +25,7 @@ import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCardListView import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherListView import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockDecryptCipherListResult +import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginListView import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkPolicy import com.x8bit.bitwarden.data.vault.repository.VaultRepository import io.mockk.awaits @@ -101,6 +102,67 @@ class ReviewExportViewModelTest : BaseViewModelTest() { assertEquals(expectedState, awaitItem()) } } + + @Suppress("MaxLineLength") + @Test + fun `State should count login with both password and passkey in passwords and passkeys`() = + runTest { + decryptCipherListResultFlow.value = DataState.Loaded( + data = DecryptCipherListResult( + successes = listOf( + createMockCipherListView( + number = 1, + type = CipherListViewType.Login( + createMockLoginListView(number = 1, hasFido2 = true), + ), + ), + ), + failures = emptyList(), + ), + ) + val expectedState = DEFAULT_STATE.copy( + viewState = DEFAULT_CONTENT_VIEW_STATE.copy( + itemTypeCounts = DEFAULT_CONTENT_VIEW_STATE.itemTypeCounts.copy( + passwordCount = 1, + passkeyCount = 1, + ), + ), + ) + val viewModel = createViewModel() + viewModel.stateFlow.test { + assertEquals(expectedState, awaitItem()) + } + } + + @Test + fun `State should count passkey-only login only in passkeys`() = runTest { + decryptCipherListResultFlow.value = DataState.Loaded( + data = DecryptCipherListResult( + successes = listOf( + createMockCipherListView( + number = 1, + type = CipherListViewType.Login( + createMockLoginListView(number = 1, hasFido2 = true), + ), + copyableFields = emptyList(), + ), + ), + failures = emptyList(), + ), + ) + val expectedState = DEFAULT_STATE.copy( + viewState = DEFAULT_CONTENT_VIEW_STATE.copy( + itemTypeCounts = DEFAULT_CONTENT_VIEW_STATE.itemTypeCounts.copy( + passwordCount = 0, + passkeyCount = 1, + ), + ), + ) + val viewModel = createViewModel() + viewModel.stateFlow.test { + assertEquals(expectedState, awaitItem()) + } + } } @Nested