refactor: Provide TestScope as ApplicationScope in tests (#364)
Previously some tests had to manually create dependencies (instead of injecting them) because the dependency required the `TestScope` `CoroutineScope` as one of its dependencies. Resolve this with a `FakeCoroutineScopeModule` that provides `TestScope` as `@ApplicationScope`. The tests can now inject their dependencies, which will use `TestScope`. To inject `AccountPreferenceDataStore` it has been updated to use the current active account when reading or writing preferences.
This commit is contained in:
parent
993b74691a
commit
aaf8cf57f3
|
@ -3,7 +3,6 @@ package app.pachli.settings
|
|||
import androidx.preference.PreferenceDataStore
|
||||
import app.pachli.core.accounts.AccountManager
|
||||
import app.pachli.core.common.di.ApplicationScope
|
||||
import app.pachli.core.database.model.AccountEntity
|
||||
import app.pachli.core.preferences.PrefKeys
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -17,18 +16,18 @@ class AccountPreferenceDataStore @Inject constructor(
|
|||
/** Flow of key/values that have been updated in the preferences */
|
||||
val changes = MutableSharedFlow<Pair<String, Boolean>>()
|
||||
|
||||
private val account: AccountEntity = accountManager.activeAccount!!
|
||||
|
||||
override fun getBoolean(key: String, defValue: Boolean): Boolean {
|
||||
return when (key) {
|
||||
PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA -> account.alwaysShowSensitiveMedia
|
||||
PrefKeys.ALWAYS_OPEN_SPOILER -> account.alwaysOpenSpoiler
|
||||
PrefKeys.MEDIA_PREVIEW_ENABLED -> account.mediaPreviewEnabled
|
||||
PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA -> accountManager.activeAccount!!.alwaysShowSensitiveMedia
|
||||
PrefKeys.ALWAYS_OPEN_SPOILER -> accountManager.activeAccount!!.alwaysOpenSpoiler
|
||||
PrefKeys.MEDIA_PREVIEW_ENABLED -> accountManager.activeAccount!!.mediaPreviewEnabled
|
||||
else -> defValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun putBoolean(key: String, value: Boolean) {
|
||||
val account = accountManager.activeAccount!!
|
||||
|
||||
when (key) {
|
||||
PrefKeys.ALWAYS_SHOW_SENSITIVE_MEDIA -> account.alwaysShowSensitiveMedia = value
|
||||
PrefKeys.ALWAYS_OPEN_SPOILER -> account.alwaysOpenSpoiler = value
|
||||
|
|
|
@ -29,8 +29,6 @@ import app.pachli.core.network.model.TimelineKind
|
|||
import app.pachli.core.network.retrofit.MastodonApi
|
||||
import app.pachli.core.preferences.SharedPreferencesRepository
|
||||
import app.pachli.core.testing.rules.MainCoroutineRule
|
||||
import app.pachli.network.ServerCapabilitiesRepository
|
||||
import app.pachli.settings.AccountPreferenceDataStore
|
||||
import app.pachli.usecase.TimelineCases
|
||||
import app.pachli.util.StatusDisplayOptionsRepository
|
||||
import at.connyduck.calladapter.networkresult.NetworkResult
|
||||
|
@ -41,7 +39,6 @@ import dagger.hilt.android.testing.HiltAndroidTest
|
|||
import java.time.Instant
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import okhttp3.ResponseBody
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.Before
|
||||
|
@ -85,9 +82,10 @@ abstract class CachedTimelineViewModelTestBase {
|
|||
@Inject
|
||||
lateinit var cachedTimelineRepository: CachedTimelineRepository
|
||||
|
||||
private lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
|
||||
@Inject
|
||||
lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
|
||||
protected lateinit var timelineCases: TimelineCases
|
||||
private lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
protected lateinit var viewModel: TimelineViewModel
|
||||
|
||||
private val eventHub = EventHub()
|
||||
|
@ -127,27 +125,8 @@ abstract class CachedTimelineViewModelTestBase {
|
|||
),
|
||||
)
|
||||
|
||||
accountPreferenceDataStore = AccountPreferenceDataStore(
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
timelineCases = mock()
|
||||
|
||||
val serverCapabilitiesRepository = ServerCapabilitiesRepository(
|
||||
mastodonApi,
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
statusDisplayOptionsRepository = StatusDisplayOptionsRepository(
|
||||
sharedPreferencesRepository,
|
||||
serverCapabilitiesRepository,
|
||||
accountManager,
|
||||
accountPreferenceDataStore,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
viewModel = CachedTimelineViewModel(
|
||||
SavedStateHandle(mapOf(TimelineViewModel.TIMELINE_KIND_TAG to TimelineKind.Home)),
|
||||
cachedTimelineRepository,
|
||||
|
|
|
@ -28,9 +28,8 @@ import app.pachli.core.network.model.TimelineKind
|
|||
import app.pachli.core.network.retrofit.MastodonApi
|
||||
import app.pachli.core.preferences.SharedPreferencesRepository
|
||||
import app.pachli.core.testing.rules.MainCoroutineRule
|
||||
import app.pachli.network.ServerCapabilitiesRepository
|
||||
import app.pachli.settings.AccountPreferenceDataStore
|
||||
import app.pachli.usecase.TimelineCases
|
||||
import app.pachli.util.HiltTestApplication_Application
|
||||
import app.pachli.util.StatusDisplayOptionsRepository
|
||||
import at.connyduck.calladapter.networkresult.NetworkResult
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
|
@ -38,7 +37,6 @@ import dagger.hilt.android.testing.HiltAndroidTest
|
|||
import java.time.Instant
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import okhttp3.ResponseBody
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.Before
|
||||
|
@ -77,9 +75,10 @@ abstract class NetworkTimelineViewModelTestBase {
|
|||
@Inject
|
||||
lateinit var networkTimelineRepository: NetworkTimelineRepository
|
||||
|
||||
private lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
|
||||
@Inject
|
||||
lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
|
||||
protected lateinit var timelineCases: TimelineCases
|
||||
private lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
protected lateinit var viewModel: TimelineViewModel
|
||||
|
||||
private val eventHub = EventHub()
|
||||
|
@ -119,27 +118,8 @@ abstract class NetworkTimelineViewModelTestBase {
|
|||
),
|
||||
)
|
||||
|
||||
accountPreferenceDataStore = AccountPreferenceDataStore(
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
timelineCases = mock()
|
||||
|
||||
val serverCapabilitiesRepository = ServerCapabilitiesRepository(
|
||||
mastodonApi,
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
statusDisplayOptionsRepository = StatusDisplayOptionsRepository(
|
||||
sharedPreferencesRepository,
|
||||
serverCapabilitiesRepository,
|
||||
accountManager,
|
||||
accountPreferenceDataStore,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
viewModel = NetworkTimelineViewModel(
|
||||
SavedStateHandle(mapOf(TimelineViewModel.TIMELINE_KIND_TAG to TimelineKind.Bookmarks)),
|
||||
networkTimelineRepository,
|
||||
|
|
|
@ -20,8 +20,6 @@ import app.pachli.core.network.model.Account
|
|||
import app.pachli.core.network.model.StatusContext
|
||||
import app.pachli.core.network.retrofit.MastodonApi
|
||||
import app.pachli.core.preferences.SharedPreferencesRepository
|
||||
import app.pachli.network.ServerCapabilitiesRepository
|
||||
import app.pachli.settings.AccountPreferenceDataStore
|
||||
import app.pachli.usecase.TimelineCases
|
||||
import app.pachli.util.StatusDisplayOptionsRepository
|
||||
import at.connyduck.calladapter.networkresult.NetworkResult
|
||||
|
@ -36,7 +34,6 @@ import java.util.Date
|
|||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
|
@ -113,9 +110,8 @@ class ViewThreadViewModelTest {
|
|||
@BindValue @JvmField
|
||||
val filtersRepository: FiltersRepository = mock()
|
||||
|
||||
private lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
|
||||
|
||||
private lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
@Inject
|
||||
lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
|
||||
private lateinit var viewModel: ViewThreadViewModel
|
||||
|
||||
|
@ -158,30 +154,11 @@ class ViewThreadViewModelTest {
|
|||
),
|
||||
)
|
||||
|
||||
accountPreferenceDataStore = AccountPreferenceDataStore(
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
val cachedTimelineRepository: CachedTimelineRepository = mock {
|
||||
onBlocking { getStatusViewData(any()) } doReturn emptyMap()
|
||||
onBlocking { getStatusTranslations(any()) } doReturn emptyMap()
|
||||
}
|
||||
|
||||
val serverCapabilitiesRepository = ServerCapabilitiesRepository(
|
||||
mastodonApi,
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
statusDisplayOptionsRepository = StatusDisplayOptionsRepository(
|
||||
sharedPreferencesRepository,
|
||||
serverCapabilitiesRepository,
|
||||
accountManager,
|
||||
accountPreferenceDataStore,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
viewModel = ViewThreadViewModel(
|
||||
mastodonApi,
|
||||
timelineCases,
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.di
|
||||
|
||||
import app.pachli.core.common.di.ApplicationScope
|
||||
import app.pachli.core.common.di.CoroutineScopeModule
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.hilt.testing.TestInstallIn
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
|
||||
@TestInstallIn(
|
||||
components = [SingletonComponent::class],
|
||||
replaces = [CoroutineScopeModule::class],
|
||||
)
|
||||
@Module
|
||||
object FakeCoroutineScopeModule {
|
||||
@ApplicationScope
|
||||
@Provides
|
||||
fun providesApplicationScope(): CoroutineScope = TestScope()
|
||||
}
|
|
@ -21,14 +21,12 @@ import androidx.core.content.edit
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import app.cash.turbine.test
|
||||
import app.pachli.PachliApplication
|
||||
import app.pachli.components.compose.HiltTestApplication_Application
|
||||
import app.pachli.core.accounts.AccountManager
|
||||
import app.pachli.core.network.model.Account
|
||||
import app.pachli.core.network.retrofit.MastodonApi
|
||||
import app.pachli.core.preferences.PrefKeys
|
||||
import app.pachli.core.preferences.SharedPreferencesRepository
|
||||
import app.pachli.core.testing.rules.MainCoroutineRule
|
||||
import app.pachli.network.ServerCapabilitiesRepository
|
||||
import app.pachli.settings.AccountPreferenceDataStore
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import dagger.hilt.android.testing.CustomTestApplication
|
||||
|
@ -38,7 +36,6 @@ import java.time.Instant
|
|||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
|
@ -72,11 +69,11 @@ class StatusDisplayOptionsRepositoryTest {
|
|||
@Inject
|
||||
lateinit var sharedPreferencesRepository: SharedPreferencesRepository
|
||||
|
||||
// Not injected as it expects an active account, so constructed by hand in setup()
|
||||
private lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
|
||||
@Inject
|
||||
lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
|
||||
|
||||
// Not injected, as it depends on accountPreferenceDataStore
|
||||
private lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
@Inject
|
||||
lateinit var statusDisplayOptionsRepository: StatusDisplayOptionsRepository
|
||||
|
||||
private val defaultStatusDisplayOptions = StatusDisplayOptions()
|
||||
|
||||
|
@ -102,25 +99,6 @@ class StatusDisplayOptionsRepositoryTest {
|
|||
header = "",
|
||||
),
|
||||
)
|
||||
|
||||
accountPreferenceDataStore = AccountPreferenceDataStore(
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
val serverCapabilitiesRepository = ServerCapabilitiesRepository(
|
||||
mastodonApi,
|
||||
accountManager,
|
||||
TestScope(),
|
||||
)
|
||||
|
||||
statusDisplayOptionsRepository = StatusDisplayOptionsRepository(
|
||||
sharedPreferencesRepository,
|
||||
serverCapabilitiesRepository,
|
||||
accountManager,
|
||||
accountPreferenceDataStore,
|
||||
TestScope(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue