Merge main into feat-155-yahoo-app-password
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
package org.libremail.data.settings
|
||||
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.core.preferencesOf
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
/**
|
||||
* The user-chosen default account (#163), covered at the `toAppSettings()` mapping layer:
|
||||
* [SettingsRepository] itself needs a real `Context` for its DataStore, so (as with [AppSettingsTest]'s
|
||||
* coverage of [FetchPolicy]) the JVM-testable seam is the plain `Preferences` -> [AppSettings] mapping
|
||||
* that [SettingsRepository.setDefaultAccountId] and [SettingsRepository.clearDefaultAccountId] are
|
||||
* ultimately read back through.
|
||||
*/
|
||||
class SettingsRepositoryTest {
|
||||
|
||||
private val defaultAccountIdKey = stringPreferencesKey("default_account_id")
|
||||
|
||||
@Test
|
||||
fun `in-memory default has no default account`() {
|
||||
assertNull(AppSettings().defaultAccountId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a persisted default account id round-trips`() {
|
||||
val prefs = preferencesOf(defaultAccountIdKey to "imap:me@example.org")
|
||||
|
||||
assertEquals("imap:me@example.org", prefs.toAppSettings().defaultAccountId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an absent key reads back as no default (the cleared state)`() {
|
||||
// setDefaultAccountId(null) and clearDefaultAccountId both remove the key rather than store a
|
||||
// sentinel value, so "cleared" and "never set" are indistinguishable and both map to null here.
|
||||
assertNull(emptyPreferences().toAppSettings().defaultAccountId)
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import io.mockk.slot
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -18,6 +19,8 @@ import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.libremail.data.settings.AccountSettingsRepository
|
||||
import org.libremail.data.settings.AppSettings
|
||||
import org.libremail.data.settings.SettingsRepository
|
||||
import org.libremail.data.settings.SignatureRepository
|
||||
import org.libremail.domain.model.Account
|
||||
import org.libremail.domain.model.AccountSettings
|
||||
@@ -66,6 +69,7 @@ class ComposeViewModelTest {
|
||||
signatures: Map<String, Signature> = emptyMap(),
|
||||
settings: Map<String, AccountSettings> = emptyMap(),
|
||||
mailRepository: MailRepository = mockk(relaxed = true),
|
||||
defaultAccountId: String? = null,
|
||||
): ComposeViewModel {
|
||||
val accountRepository = mockk<AccountRepository>()
|
||||
every { accountRepository.observeAccounts() } returns MutableStateFlow(accounts)
|
||||
@@ -76,6 +80,8 @@ class ComposeViewModelTest {
|
||||
}
|
||||
val signatureRepository = mockk<SignatureRepository>()
|
||||
coEvery { signatureRepository.getDefault(any()) } answers { signatures[firstArg<String>()] }
|
||||
val settingsRepository = mockk<SettingsRepository>()
|
||||
every { settingsRepository.settings } returns flowOf(AppSettings(defaultAccountId = defaultAccountId))
|
||||
return ComposeViewModel(
|
||||
savedStateHandle = savedState,
|
||||
mailRepository = mailRepository,
|
||||
@@ -83,6 +89,7 @@ class ComposeViewModelTest {
|
||||
contactsRepository = mockk(relaxed = true),
|
||||
accountSettingsRepository = accountSettingsRepository,
|
||||
signatureRepository = signatureRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -120,6 +127,40 @@ class ComposeViewModelTest {
|
||||
assertEquals("\n\n-- \nBest, Bob", vm.state.value.body)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `uses the persisted default account when no explicit from-account is given`() = runTest(testDispatcher) {
|
||||
val vm = viewModel(accounts = listOf(alice, bob), defaultAccountId = bob.id)
|
||||
|
||||
assertEquals(bob.id, vm.state.value.fromAccountId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `falls back to the first account when the persisted default no longer exists`() = runTest(testDispatcher) {
|
||||
// Simulates a default that outlived its account (deletion, or a Backup restore onto a device
|
||||
// that never had it) — must fall back to the incidental first-alphabetically account, not crash.
|
||||
val vm = viewModel(accounts = listOf(alice, bob), defaultAccountId = "imap:deleted-account")
|
||||
|
||||
assertEquals(alice.id, vm.state.value.fromAccountId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `falls back to the first account when no default is set`() = runTest(testDispatcher) {
|
||||
val vm = viewModel(accounts = listOf(alice, bob), defaultAccountId = null)
|
||||
|
||||
assertEquals(alice.id, vm.state.value.fromAccountId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an explicit from-account wins over the persisted default`() = runTest(testDispatcher) {
|
||||
val vm = viewModel(
|
||||
accounts = listOf(alice, bob),
|
||||
savedState = SavedStateHandle(mapOf(Routes.COMPOSE_ARG_FROM to alice.id)),
|
||||
defaultAccountId = bob.id,
|
||||
)
|
||||
|
||||
assertEquals(alice.id, vm.state.value.fromAccountId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `does not append a signature when the account disabled it`() = runTest(testDispatcher) {
|
||||
val vm = viewModel(
|
||||
|
||||
Reference in New Issue
Block a user