From 40760f270a1ddbaeab84e536573c61c22ff14126 Mon Sep 17 00:00:00 2001 From: David Perez Date: Thu, 13 Mar 2025 14:28:27 -0500 Subject: [PATCH] Use immutable map in debug menu (#4861) --- .../feature/debugmenu/DebugMenuScreen.kt | 6 ++++-- .../feature/debugmenu/DebugMenuViewModel.kt | 9 ++++++--- .../feature/debugmenu/DebugMenuScreenTest.kt | 17 ++++++++++------- .../feature/debugmenu/DebugMenuViewModelTest.kt | 6 ++++-- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreen.kt index ba669c53b3..9a47b7806f 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreen.kt @@ -38,6 +38,8 @@ import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter import com.x8bit.bitwarden.ui.platform.feature.debugmenu.components.ListItemContent import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentMapOf /** * Top level screen for the debug menu. @@ -136,7 +138,7 @@ fun DebugMenuScreen( @Composable private fun FeatureFlagContent( - featureFlagMap: Map, Any>, + featureFlagMap: ImmutableMap, Any>, onValueChange: (key: FlagKey, value: Any) -> Unit, onResetValues: () -> Unit, modifier: Modifier = Modifier, @@ -238,7 +240,7 @@ private fun OnboardingOverrideContent( private fun FeatureFlagContent_preview() { BitwardenTheme { FeatureFlagContent( - featureFlagMap = mapOf( + featureFlagMap = persistentMapOf( FlagKey.EmailVerification to true, FlagKey.OnboardingCarousel to true, FlagKey.OnboardingFlow to false, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModel.kt index 97580e23d6..eca9c602cb 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModel.kt @@ -7,6 +7,9 @@ import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepository import com.x8bit.bitwarden.ui.platform.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.Job import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn @@ -25,7 +28,7 @@ class DebugMenuViewModel @Inject constructor( private val debugMenuRepository: DebugMenuRepository, private val authRepository: AuthRepository, ) : BaseViewModel( - initialState = DebugMenuState(featureFlags = emptyMap()), + initialState = DebugMenuState(featureFlags = persistentMapOf()), ) { private var featureFlagResetJob: Job? = null @@ -81,7 +84,7 @@ class DebugMenuViewModel @Inject constructor( private fun handleUpdateFeatureFlagMap(action: DebugMenuAction.Internal.UpdateFeatureFlagMap) { mutableStateFlow.update { - it.copy(featureFlags = action.newMap) + it.copy(featureFlags = action.newMap.toImmutableMap()) } } @@ -94,7 +97,7 @@ class DebugMenuViewModel @Inject constructor( * State for the [DebugMenuViewModel] */ data class DebugMenuState( - val featureFlags: Map, Any>, + val featureFlags: ImmutableMap, Any>, ) /** diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreenTest.kt index be47ca9a7a..cde67e2e8f 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuScreenTest.kt @@ -14,6 +14,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest import io.mockk.every import io.mockk.mockk import io.mockk.verify +import kotlinx.collections.immutable.persistentMapOf import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Assert.assertTrue import org.junit.Before @@ -22,7 +23,9 @@ import org.junit.Test class DebugMenuScreenTest : BaseComposeTest() { private var onNavigateBackCalled = false private val mutableEventFlow = bufferedMutableSharedFlow() - private val mutableStateFlow = MutableStateFlow(DebugMenuState(featureFlags = emptyMap())) + private val mutableStateFlow = MutableStateFlow( + value = DebugMenuState(featureFlags = persistentMapOf()), + ) private val viewModel = mockk(relaxed = true) { every { stateFlow } returns mutableStateFlow every { eventFlow } returns mutableEventFlow @@ -65,7 +68,7 @@ class DebugMenuScreenTest : BaseComposeTest() { fun `feature flag content should display if the state is not empty`() { mutableStateFlow.tryEmit( DebugMenuState( - featureFlags = mapOf( + featureFlags = persistentMapOf( FlagKey.EmailVerification to true, ), ), @@ -80,7 +83,7 @@ class DebugMenuScreenTest : BaseComposeTest() { fun `boolean feature flag content should send action when clicked`() { mutableStateFlow.tryEmit( DebugMenuState( - featureFlags = mapOf( + featureFlags = persistentMapOf( FlagKey.EmailVerification to true, ), ), @@ -113,7 +116,7 @@ class DebugMenuScreenTest : BaseComposeTest() { fun `restart onboarding should send action when enabled and clicked`() { mutableStateFlow.tryEmit( DebugMenuState( - featureFlags = mapOf( + featureFlags = persistentMapOf( FlagKey.OnboardingFlow to true, ), ), @@ -131,7 +134,7 @@ class DebugMenuScreenTest : BaseComposeTest() { fun `restart onboarding should not send action when not enabled`() { mutableStateFlow.tryEmit( DebugMenuState( - featureFlags = mapOf( + featureFlags = persistentMapOf( FlagKey.OnboardingFlow to false, ), ), @@ -150,7 +153,7 @@ class DebugMenuScreenTest : BaseComposeTest() { fun `Show onboarding carousel should send action when enabled and clicked`() { mutableStateFlow.tryEmit( DebugMenuState( - featureFlags = mapOf( + featureFlags = persistentMapOf( FlagKey.OnboardingCarousel to true, ), ), @@ -168,7 +171,7 @@ class DebugMenuScreenTest : BaseComposeTest() { fun `show onboarding carousel should not send action when not enabled`() { mutableStateFlow.tryEmit( DebugMenuState( - featureFlags = mapOf( + featureFlags = persistentMapOf( FlagKey.OnboardingCarousel to false, ), ), diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt index 1a2f94a893..28b1c37cbf 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/debugmenu/DebugMenuViewModelTest.kt @@ -13,6 +13,8 @@ import io.mockk.just import io.mockk.mockk import io.mockk.runs import io.mockk.verify +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentMapOf import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals @@ -117,7 +119,7 @@ class DebugMenuViewModelTest : BaseViewModelTest() { ) } -private val DEFAULT_MAP_VALUE: Map, Any> = mapOf( +private val DEFAULT_MAP_VALUE: ImmutableMap, Any> = persistentMapOf( FlagKey.AuthenticatorSync to true, FlagKey.EmailVerification to true, FlagKey.OnboardingCarousel to true, @@ -139,7 +141,7 @@ private val DEFAULT_MAP_VALUE: Map, Any> = mapOf( FlagKey.MobileErrorReporting to true, ) -private val UPDATED_MAP_VALUE: Map, Any> = mapOf( +private val UPDATED_MAP_VALUE: ImmutableMap, Any> = persistentMapOf( FlagKey.AuthenticatorSync to false, FlagKey.EmailVerification to false, FlagKey.OnboardingCarousel to true,