mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-15 10:46:12 -04:00
feat(reactions): Move reaction settings to per-device profiles
Migrate reaction toggles (auto-play, auto-pause, auto-connect, popups) from global ReactionSettings singleton to per-profile fields on AppleDeviceProfile. Each paired device can now have independent reaction behavior. Extract ReactionConfig snapshot to decouple PodDevice from AppleDeviceProfile — reaction consumers read device.reactions instead of device.profile. Remove auto-connect from upgrade benefits (now free). Add LegacyReactionSettingsReader for one-shot DataStore migration.
This commit is contained in:
+14
@@ -4,10 +4,12 @@ import eu.darken.capod.common.bluetooth.BluetoothAddress
|
||||
import eu.darken.capod.common.bluetooth.BluetoothDevice2
|
||||
import eu.darken.capod.common.bluetooth.BluetoothManager2
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
import eu.darken.capod.monitor.core.DeviceMonitor
|
||||
import eu.darken.capod.monitor.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.aap.AapConnectionManager
|
||||
import eu.darken.capod.pods.core.apple.aap.protocol.AapCommand
|
||||
import eu.darken.capod.profiles.core.DeviceProfilesRepo
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.types.shouldBeInstanceOf
|
||||
import io.mockk.Called
|
||||
@@ -46,6 +48,8 @@ class DeviceSettingsViewModelTest : BaseTest() {
|
||||
private lateinit var aapManager: AapConnectionManager
|
||||
private lateinit var upgradeRepo: UpgradeRepo
|
||||
private lateinit var bluetoothManager: BluetoothManager2
|
||||
private lateinit var profilesRepo: DeviceProfilesRepo
|
||||
private lateinit var generalSettings: GeneralSettings
|
||||
|
||||
private lateinit var devicesFlow: MutableStateFlow<List<PodDevice>>
|
||||
private lateinit var upgradeInfoFlow: MutableStateFlow<UpgradeRepo.Info>
|
||||
@@ -63,8 +67,14 @@ class DeviceSettingsViewModelTest : BaseTest() {
|
||||
every { it.isPro } returns false
|
||||
})
|
||||
|
||||
// Synthesize a PodDevice for forceConnect/sendInternal lookups (currentAddress()).
|
||||
val syntheticDevice = mockk<PodDevice>().also {
|
||||
every { it.profileId } returns testAddress
|
||||
every { it.address } returns testAddress
|
||||
}
|
||||
deviceMonitor = mockk<DeviceMonitor>().also {
|
||||
every { it.devices } returns devicesFlow
|
||||
coEvery { it.getDeviceForProfile(testAddress) } returns syntheticDevice
|
||||
}
|
||||
aapManager = mockk(relaxed = true)
|
||||
upgradeRepo = mockk<UpgradeRepo>().also {
|
||||
@@ -74,6 +84,8 @@ class DeviceSettingsViewModelTest : BaseTest() {
|
||||
every { isNudgeAvailable } returns true
|
||||
every { bondedDevices() } returns flowOf(emptySet())
|
||||
}
|
||||
profilesRepo = mockk(relaxed = true)
|
||||
generalSettings = mockk(relaxed = true)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -87,6 +99,8 @@ class DeviceSettingsViewModelTest : BaseTest() {
|
||||
aapManager = aapManager,
|
||||
upgradeRepo = upgradeRepo,
|
||||
bluetoothManager = bluetoothManager,
|
||||
profilesRepo = profilesRepo,
|
||||
generalSettings = generalSettings,
|
||||
)
|
||||
|
||||
@Test
|
||||
|
||||
@@ -312,7 +312,7 @@ class DeviceMonitorTest : BaseTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDeviceForProfile no BLE no cache no AAP - returns null`() = runTest(testDispatcher) {
|
||||
fun `getDeviceForProfile no BLE no cache no AAP - returns synthesized bare device`() = runTest(testDispatcher) {
|
||||
val monitor = createMonitor(
|
||||
ble = emptyList(),
|
||||
aap = emptyMap(),
|
||||
@@ -323,6 +323,27 @@ class DeviceMonitorTest : BaseTest() {
|
||||
|
||||
val device = monitor.getDeviceForProfile(testProfile.id)
|
||||
|
||||
// Pristine profile must still be reachable so the Reactions section in
|
||||
// DeviceSettings can be edited even before the device has ever been observed.
|
||||
device shouldNotBe null
|
||||
device!!.profileId shouldBe testProfile.id
|
||||
device.reactions shouldBe testProfile.reactionConfig
|
||||
device.ble shouldBe null
|
||||
device.isLive shouldBe false
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDeviceForProfile profile not in repo - returns null`() = runTest(testDispatcher) {
|
||||
val monitor = createMonitor(
|
||||
ble = emptyList(),
|
||||
aap = emptyMap(),
|
||||
cache = emptyMap(),
|
||||
profiles = emptyList(),
|
||||
scope = backgroundScope,
|
||||
)
|
||||
|
||||
val device = monitor.getDeviceForProfile("nonexistent-profile-id")
|
||||
|
||||
device shouldBe null
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ class DeviceProfilesRepoReorderTest : BaseTest() {
|
||||
val settings = mockk<DeviceProfilesSettings> {
|
||||
every { profiles } returns fakeProfiles.mock
|
||||
every { defaultProfileCreated } returns FakeDataStoreValue(true).mock
|
||||
every { reactionMigrationDone } returns FakeDataStoreValue(true).mock
|
||||
}
|
||||
|
||||
val repo = DeviceProfilesRepo(
|
||||
@@ -29,6 +30,7 @@ class DeviceProfilesRepoReorderTest : BaseTest() {
|
||||
generalSettings = mockk(relaxed = true),
|
||||
settings = settings,
|
||||
deviceStateCache = mockk(relaxed = true),
|
||||
json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true },
|
||||
)
|
||||
|
||||
return repo to fakeProfiles
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package eu.darken.capod.profiles.core
|
||||
|
||||
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.junit.jupiter.api.Test
|
||||
import testhelpers.BaseTest
|
||||
|
||||
/**
|
||||
* Verifies the legacy reaction DataStore key names and JSON serialization format.
|
||||
* A key-name mismatch would silently zero all reaction settings for upgrading users.
|
||||
*/
|
||||
class LegacyReactionSettingsReaderTest : BaseTest() {
|
||||
|
||||
/**
|
||||
* The keys that were used by the now-deleted `ReactionSettings` class.
|
||||
* If any of these change in `LegacyReactionSettingsReader`, upgrading users lose their settings.
|
||||
* This test acts as a frozen snapshot — DO NOT update these values to "fix" the test.
|
||||
*/
|
||||
@Test
|
||||
fun `legacy key names match the deleted ReactionSettings class`() {
|
||||
// Boolean keys — frozen snapshot of the old ReactionSettings key names.
|
||||
// If LegacyReactionSettingsReader keys change, upgrading users silently lose settings.
|
||||
LegacyReactionSettingsReader.AUTO_PAUSE_KEY.name shouldBe "reaction.autopause.enabled"
|
||||
LegacyReactionSettingsReader.AUTO_PLAY_KEY.name shouldBe "reaction.autoplay.enabled"
|
||||
LegacyReactionSettingsReader.AUTO_CONNECT_KEY.name shouldBe "reaction.autoconnect.enabled"
|
||||
LegacyReactionSettingsReader.POPUP_CASE_OPEN_KEY.name shouldBe "reaction.popup.caseopen"
|
||||
LegacyReactionSettingsReader.POPUP_CONNECTED_KEY.name shouldBe "reaction.popup.connected"
|
||||
LegacyReactionSettingsReader.ONE_POD_KEY.name shouldBe "reaction.onepod.enabled"
|
||||
|
||||
// String key for serialized enum
|
||||
LegacyReactionSettingsReader.CONDITION_KEY.name shouldBe "reaction.autoconnect.condition"
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the project Json can round-trip AutoConnectCondition enum values using their
|
||||
* @SerialName annotations. The legacy DataStore stored these as JSON strings.
|
||||
*/
|
||||
@Test
|
||||
fun `AutoConnectCondition round-trips through project Json`() {
|
||||
val projectJson = Json {
|
||||
ignoreUnknownKeys = true
|
||||
encodeDefaults = true
|
||||
explicitNulls = false
|
||||
classDiscriminator = "type"
|
||||
}
|
||||
|
||||
for (condition in AutoConnectCondition.entries) {
|
||||
val encoded = projectJson.encodeToString(condition)
|
||||
val decoded = projectJson.decodeFromString<AutoConnectCondition>(encoded)
|
||||
decoded shouldBe condition
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the serialized form matches what the deleted ReactionSettings class stored.
|
||||
* The old class used `createValue(key, default, json, onErrorFallbackToDefault = true)`
|
||||
* which serializes the enum to its @SerialName value as a JSON string.
|
||||
*/
|
||||
@Test
|
||||
fun `AutoConnectCondition serialized format matches legacy storage`() {
|
||||
val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
encodeDefaults = true
|
||||
explicitNulls = false
|
||||
classDiscriminator = "type"
|
||||
}
|
||||
|
||||
json.encodeToString(AutoConnectCondition.WHEN_SEEN) shouldBe "\"autoconnect.condition.seen\""
|
||||
json.encodeToString(AutoConnectCondition.CASE_OPEN) shouldBe "\"autoconnect.condition.case\""
|
||||
json.encodeToString(AutoConnectCondition.IN_EAR) shouldBe "\"autoconnect.condition.inear\""
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,6 @@ class AutoConnectLogicTest : BaseTest() {
|
||||
bluetoothManager = mockk(relaxed = true),
|
||||
deviceMonitor = mockk(relaxed = true),
|
||||
generalSettings = mockk(relaxed = true),
|
||||
reactionSettings = mockk(relaxed = true),
|
||||
deviceProfilesRepo = mockk(relaxed = true),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ class PlayPauseLogicTest : BaseTest() {
|
||||
playPause = PlayPause(
|
||||
deviceMonitor = mockk(relaxed = true),
|
||||
bluetoothManager = mockk(relaxed = true),
|
||||
reactionSettings = mockk(relaxed = true),
|
||||
mediaControl = mockk(relaxed = true)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ class PopUpReactionLogicTest : BaseTest() {
|
||||
fun setup() {
|
||||
popUpReaction = PopUpReaction(
|
||||
deviceMonitor = mockk(relaxed = true),
|
||||
reactionSettings = mockk(relaxed = true),
|
||||
bluetoothManager = mockk(relaxed = true),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
package eu.darken.capod.reaction.ui
|
||||
|
||||
import eu.darken.capod.common.navigation.Nav
|
||||
import eu.darken.capod.common.navigation.NavEvent
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
import eu.darken.capod.main.core.MonitorMode
|
||||
import eu.darken.capod.reaction.core.ReactionSettings
|
||||
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import testhelpers.BaseTest
|
||||
import testhelpers.coroutine.TestDispatcherProvider
|
||||
import testhelpers.datastore.FakeDataStoreValue
|
||||
import testhelpers.livedata.InstantExecutorExtension
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@ExtendWith(InstantExecutorExtension::class)
|
||||
class ReactionSettingsViewModelTest : BaseTest() {
|
||||
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
|
||||
private lateinit var upgradeInfoFlow: MutableStateFlow<UpgradeRepo.Info>
|
||||
private lateinit var upgradeRepo: UpgradeRepo
|
||||
private lateinit var reactionSettings: ReactionSettings
|
||||
private lateinit var generalSettings: GeneralSettings
|
||||
|
||||
private lateinit var fakeOnePodMode: FakeDataStoreValue<Boolean>
|
||||
private lateinit var fakeAutoPlay: FakeDataStoreValue<Boolean>
|
||||
private lateinit var fakeAutoPause: FakeDataStoreValue<Boolean>
|
||||
private lateinit var fakeAutoConnect: FakeDataStoreValue<Boolean>
|
||||
private lateinit var fakeAutoConnectCondition: FakeDataStoreValue<AutoConnectCondition>
|
||||
private lateinit var fakeShowPopUpOnCaseOpen: FakeDataStoreValue<Boolean>
|
||||
private lateinit var fakeShowPopUpOnConnection: FakeDataStoreValue<Boolean>
|
||||
private lateinit var fakeMonitorMode: FakeDataStoreValue<MonitorMode>
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
|
||||
upgradeInfoFlow = MutableStateFlow(mockUpgradeInfo(isPro = false))
|
||||
upgradeRepo = mockk<UpgradeRepo>().also {
|
||||
every { it.upgradeInfo } returns upgradeInfoFlow
|
||||
}
|
||||
|
||||
fakeOnePodMode = FakeDataStoreValue(false)
|
||||
fakeAutoPlay = FakeDataStoreValue(false)
|
||||
fakeAutoPause = FakeDataStoreValue(false)
|
||||
fakeAutoConnect = FakeDataStoreValue(false)
|
||||
fakeAutoConnectCondition = FakeDataStoreValue(AutoConnectCondition.WHEN_SEEN)
|
||||
fakeShowPopUpOnCaseOpen = FakeDataStoreValue(false)
|
||||
fakeShowPopUpOnConnection = FakeDataStoreValue(false)
|
||||
|
||||
reactionSettings = mockk<ReactionSettings>().also {
|
||||
every { it.onePodMode } returns fakeOnePodMode.mock
|
||||
every { it.autoPlay } returns fakeAutoPlay.mock
|
||||
every { it.autoPause } returns fakeAutoPause.mock
|
||||
every { it.autoConnect } returns fakeAutoConnect.mock
|
||||
every { it.autoConnectCondition } returns fakeAutoConnectCondition.mock
|
||||
every { it.showPopUpOnCaseOpen } returns fakeShowPopUpOnCaseOpen.mock
|
||||
every { it.showPopUpOnConnection } returns fakeShowPopUpOnConnection.mock
|
||||
}
|
||||
|
||||
fakeMonitorMode = FakeDataStoreValue(MonitorMode.AUTOMATIC)
|
||||
generalSettings = mockk<GeneralSettings>().also {
|
||||
every { it.monitorMode } returns fakeMonitorMode.mock
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun teardown() {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
|
||||
private fun createViewModel() = ReactionSettingsViewModel(
|
||||
dispatcherProvider = TestDispatcherProvider(testDispatcher),
|
||||
reactionSettings = reactionSettings,
|
||||
generalSettings = generalSettings,
|
||||
upgradeRepo = upgradeRepo,
|
||||
)
|
||||
|
||||
private fun mockUpgradeInfo(isPro: Boolean): UpgradeRepo.Info = mockk<UpgradeRepo.Info>().also {
|
||||
every { it.isPro } returns isPro
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class StateTests {
|
||||
|
||||
@Test
|
||||
fun `state combines all flows correctly`() = runTest(testDispatcher) {
|
||||
fakeAutoPlay.value = true
|
||||
fakeAutoPause.value = true
|
||||
fakeAutoConnect.value = true
|
||||
fakeOnePodMode.value = true
|
||||
fakeShowPopUpOnCaseOpen.value = true
|
||||
fakeShowPopUpOnConnection.value = true
|
||||
fakeAutoConnectCondition.value = AutoConnectCondition.CASE_OPEN
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = true)
|
||||
|
||||
val vm = createViewModel()
|
||||
val state = vm.state.first()
|
||||
|
||||
state.isPro shouldBe true
|
||||
state.autoPlay shouldBe true
|
||||
state.autoPause shouldBe true
|
||||
state.autoConnect shouldBe true
|
||||
state.onePodMode shouldBe true
|
||||
state.showPopUpOnCaseOpen shouldBe true
|
||||
state.showPopUpOnConnection shouldBe true
|
||||
state.autoConnectCondition shouldBe AutoConnectCondition.CASE_OPEN
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class AutoPlayTests {
|
||||
|
||||
@Test
|
||||
fun `setAutoPlay true when pro - sets setting`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = true)
|
||||
val vm = createViewModel()
|
||||
vm.state.first() // ensure state is initialized
|
||||
|
||||
vm.setAutoPlay(true)
|
||||
|
||||
fakeAutoPlay.value shouldBe true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoPlay true when not pro - navigates to upgrade, does NOT change setting`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = false)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoPlay(true)
|
||||
|
||||
fakeAutoPlay.value shouldBe false
|
||||
val event = vm.navEvents.first()
|
||||
(event as NavEvent.GoTo).destination shouldBe Nav.Main.Upgrade
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoPlay false - always sets (no pro check)`() = runTest(testDispatcher) {
|
||||
fakeAutoPlay.value = true
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoPlay(false)
|
||||
|
||||
fakeAutoPlay.value shouldBe false
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class AutoPauseTests {
|
||||
|
||||
@Test
|
||||
fun `setAutoPause true when pro - sets setting`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = true)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoPause(true)
|
||||
|
||||
fakeAutoPause.value shouldBe true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoPause true when not pro - navigates to upgrade`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = false)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoPause(true)
|
||||
|
||||
fakeAutoPause.value shouldBe false
|
||||
val event = vm.navEvents.first()
|
||||
(event as NavEvent.GoTo).destination shouldBe Nav.Main.Upgrade
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoPause false - always sets`() = runTest(testDispatcher) {
|
||||
fakeAutoPause.value = true
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoPause(false)
|
||||
|
||||
fakeAutoPause.value shouldBe false
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class AutoConnectTests {
|
||||
|
||||
@Test
|
||||
fun `setAutoConnect true when pro - sets setting AND sets monitorMode to ALWAYS`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = true)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoConnect(true)
|
||||
|
||||
fakeAutoConnect.value shouldBe true
|
||||
fakeMonitorMode.value shouldBe MonitorMode.ALWAYS
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoConnect true when not pro - navigates to upgrade`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = false)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoConnect(true)
|
||||
|
||||
fakeAutoConnect.value shouldBe false
|
||||
val event = vm.navEvents.first()
|
||||
(event as NavEvent.GoTo).destination shouldBe Nav.Main.Upgrade
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoConnect false - sets setting, does NOT change monitorMode`() = runTest(testDispatcher) {
|
||||
fakeAutoConnect.value = true
|
||||
fakeMonitorMode.value = MonitorMode.ALWAYS
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setAutoConnect(false)
|
||||
|
||||
fakeAutoConnect.value shouldBe false
|
||||
fakeMonitorMode.value shouldBe MonitorMode.ALWAYS
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class PopUpTests {
|
||||
|
||||
@Test
|
||||
fun `setShowPopUpOnCaseOpen true when pro - sets setting`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = true)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setShowPopUpOnCaseOpen(true)
|
||||
|
||||
fakeShowPopUpOnCaseOpen.value shouldBe true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setShowPopUpOnCaseOpen true when not pro - navigates to upgrade`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = false)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setShowPopUpOnCaseOpen(true)
|
||||
|
||||
fakeShowPopUpOnCaseOpen.value shouldBe false
|
||||
val event = vm.navEvents.first()
|
||||
(event as NavEvent.GoTo).destination shouldBe Nav.Main.Upgrade
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setShowPopUpOnConnection true when pro - sets setting`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = true)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setShowPopUpOnConnection(true)
|
||||
|
||||
fakeShowPopUpOnConnection.value shouldBe true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setShowPopUpOnConnection true when not pro - navigates to upgrade`() = runTest(testDispatcher) {
|
||||
upgradeInfoFlow.value = mockUpgradeInfo(isPro = false)
|
||||
val vm = createViewModel()
|
||||
vm.state.first()
|
||||
|
||||
vm.setShowPopUpOnConnection(true)
|
||||
|
||||
fakeShowPopUpOnConnection.value shouldBe false
|
||||
val event = vm.navEvents.first()
|
||||
(event as NavEvent.GoTo).destination shouldBe Nav.Main.Upgrade
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class DirectSettingTests {
|
||||
|
||||
@Test
|
||||
fun `setOnePodMode - direct assignment (no pro check)`() = runTest(testDispatcher) {
|
||||
val vm = createViewModel()
|
||||
|
||||
vm.setOnePodMode(true)
|
||||
|
||||
fakeOnePodMode.value shouldBe true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setAutoConnectCondition - direct assignment (no pro check)`() = runTest(testDispatcher) {
|
||||
val vm = createViewModel()
|
||||
|
||||
vm.setAutoConnectCondition(AutoConnectCondition.IN_EAR)
|
||||
|
||||
fakeAutoConnectCondition.value shouldBe AutoConnectCondition.IN_EAR
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user