Fix Next Up channel launch sign in (#1886)
## Description When parsing intents, not every path for authentication was checked, so launching via the "Next Up" OS channel wouldn't check for a profile PIN. This PR fixes that. Additionally, the "Next Up" OS channel launch wasn't checking the correct parameter to ensure the back stack was written properly. ### Related issues Fixes #1883 ### Testing I manually test on the emulator with these test cases: - No profile PIN, cold start - No profile PIN, hot start - Profile PIN, cold start - Profile PIN, hot start - No profile PIN, launch via "Next Up" channel - No profile PIN, launch via intent - Profile PIN, launch via "Next Up" channel - Profile PIN, launch via intent Also added unit tests for intent-based and regular launching which covers those cases and more. ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
39523aa6e2
commit
4b927e6b7b
5 changed files with 736 additions and 34 deletions
|
|
@ -0,0 +1,222 @@
|
|||
package com.github.damontecres.wholphin.services
|
||||
|
||||
import android.content.Intent
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.preferences.update
|
||||
import com.github.damontecres.wholphin.test.currentUser
|
||||
import com.github.damontecres.wholphin.test.server
|
||||
import com.github.damontecres.wholphin.test.user
|
||||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class IntentServiceTest {
|
||||
private val api: ApiClient = mockk()
|
||||
private val serverRepository: ServerRepository = mockk()
|
||||
private val userPreferencesService: UserPreferencesService = mockk()
|
||||
|
||||
lateinit var intentService: IntentService
|
||||
|
||||
private val serverId = UUID.randomUUID()
|
||||
private val userId = UUID.randomUUID()
|
||||
private val currentUser = currentUser(serverId, userId)
|
||||
|
||||
private val protectedCurrentUser =
|
||||
CurrentUser(
|
||||
server(serverId),
|
||||
user(serverId, userId).copy(pin = "1234"),
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
intentService = IntentService(api, serverRepository, userPreferencesService)
|
||||
}
|
||||
|
||||
private fun setupPreferences(block: AppPreferences.Builder.() -> Unit) {
|
||||
every { userPreferencesService.flow } returns
|
||||
flow {
|
||||
emit(
|
||||
UserPreferences(
|
||||
AppPreferences.getDefaultInstance().update(block),
|
||||
null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in with unprotected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertNull(result)
|
||||
|
||||
coVerify { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign disabled in with unprotected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = false
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in, hot load, with protected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(protectedCurrentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in, cold load, with protected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in, no current user`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
// coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test user specified with unprotected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.serverDao.getUser(serverId, userId) } returns currentUser.user
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
putExtra(IntentService.INTENT_SERVER_ID, serverId.toServerString())
|
||||
putExtra(IntentService.INTENT_USER_ID, userId.toServerString())
|
||||
}
|
||||
val result = intentService.prepare(intent)
|
||||
assertNull(result)
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test user specified with protected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.serverDao.getUser(serverId, userId) } returns protectedCurrentUser.user
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
putExtra(IntentService.INTENT_SERVER_ID, serverId.toServerString())
|
||||
putExtra(IntentService.INTENT_USER_ID, userId.toServerString())
|
||||
}
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test user specified does not exist`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.serverDao.getUser(serverId, userId) } returns null
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns null
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
putExtra(IntentService.INTENT_SERVER_ID, serverId.toServerString())
|
||||
putExtra(IntentService.INTENT_USER_ID, userId.toServerString())
|
||||
}
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,415 @@
|
|||
package com.github.damontecres.wholphin.test
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.github.damontecres.wholphin.MainActivityViewModel
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinServerUsers
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.update
|
||||
import com.github.damontecres.wholphin.services.AppUpgradeHandler
|
||||
import com.github.damontecres.wholphin.services.BackdropService
|
||||
import com.github.damontecres.wholphin.services.DeviceProfileService
|
||||
import com.github.damontecres.wholphin.services.IntentResult
|
||||
import com.github.damontecres.wholphin.services.IntentService
|
||||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.SetupDestination
|
||||
import com.github.damontecres.wholphin.services.SetupNavigationManager
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.util.WholphinDispatchers
|
||||
import com.github.damontecres.wholphin.util.configure
|
||||
import com.github.damontecres.wholphin.util.reset
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.slot
|
||||
import io.mockk.unmockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class TestMainActivityViewModel {
|
||||
private val testDispatcher = StandardTestDispatcher()
|
||||
|
||||
private val context: Context = mockk()
|
||||
private val preferences: DataStore<AppPreferences> = mockk()
|
||||
private val serverRepository: ServerRepository = mockk()
|
||||
private val setupNavigationManager: SetupNavigationManager = mockk(relaxed = true)
|
||||
private val navigationManager: NavigationManager = mockk(relaxed = true)
|
||||
private val deviceProfileService: DeviceProfileService = mockk()
|
||||
private val backdropService: BackdropService = mockk(relaxed = true)
|
||||
private val appUpgradeHandler: AppUpgradeHandler = mockk()
|
||||
private val intentService: IntentService = mockk()
|
||||
private val serverDao: JellyfinServerDao = mockk()
|
||||
|
||||
val viewModel =
|
||||
MainActivityViewModel(
|
||||
context,
|
||||
preferences,
|
||||
serverRepository,
|
||||
setupNavigationManager,
|
||||
navigationManager,
|
||||
deviceProfileService,
|
||||
backdropService,
|
||||
appUpgradeHandler,
|
||||
intentService,
|
||||
)
|
||||
|
||||
private val serverId = UUID.randomUUID()
|
||||
private val userId = UUID.randomUUID()
|
||||
private val currentUser = currentUser(serverId, userId)
|
||||
|
||||
private val protectedCurrentUser =
|
||||
CurrentUser(
|
||||
server(serverId),
|
||||
user(serverId, userId).copy(pin = "1234"),
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
WholphinDispatchers.configure(testDispatcher)
|
||||
every { appUpgradeHandler.needUpgrade() } returns false
|
||||
every { appUpgradeHandler.copySubfont(any()) } returns Unit
|
||||
every { serverRepository.serverDao } returns serverDao
|
||||
coEvery { serverDao.getServer(serverId) } returns
|
||||
JellyfinServerUsers(
|
||||
currentUser.server,
|
||||
// User list is unused
|
||||
emptyList(),
|
||||
)
|
||||
mockkStatic(Toast::class)
|
||||
val mockToast = mockk<Toast>()
|
||||
every { Toast.makeText(any(), any<CharSequence>(), any()) } returns mockToast
|
||||
every { mockToast.show() } returns Unit
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
WholphinDispatchers.reset()
|
||||
unmockkStatic(Toast::class)
|
||||
}
|
||||
|
||||
private fun setupPreferences(block: AppPreferences.Builder.() -> Unit) {
|
||||
every { preferences.data } returns
|
||||
flow {
|
||||
emit(
|
||||
AppPreferences.getDefaultInstance().update(block),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in with unprotected profile`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign disabled in with current server`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = false
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
// coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(exactly = 1) { serverDao.getServer(serverId) }
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(any(), any()) }
|
||||
val args = mutableListOf<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(args)) }
|
||||
assertEquals(2, args.size)
|
||||
args[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.Loading)
|
||||
}
|
||||
args[1].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in, hot load, with protected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(protectedCurrentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
verify { serverDao.getServer(serverId) }
|
||||
val args = mutableListOf<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(args)) }
|
||||
assertEquals(2, args.size)
|
||||
args[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.Loading)
|
||||
}
|
||||
args[1].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in, cold load, with protected profile`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(serverId, userId) }
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test auto sign in, no current user`() =
|
||||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreSession(null, null) } returns null
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(null, null) }
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.ServerList)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is noop`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns IntentResult.NoOp
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is error, has server`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns IntentResult.Error("Error")
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is error, does not have server`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns IntentResult.Error("Error")
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.ServerList)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is target, has server`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns
|
||||
IntentResult.Target(
|
||||
destinations = listOf(Destination.Favorites),
|
||||
addHomeToBackStack = true,
|
||||
)
|
||||
val backstack = mutableListOf<Destination>()
|
||||
every { navigationManager.backStack } returns backstack
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
verify { navigationManager.reloadHome() }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
}
|
||||
// Note: navigation manager internally handles Home destination, so it won't be in this list
|
||||
assertEquals(1, backstack.size)
|
||||
backstack[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is Destination.Favorites)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is target, has server, no home backstack`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns
|
||||
IntentResult.Target(
|
||||
destinations = listOf(Destination.Favorites),
|
||||
addHomeToBackStack = false,
|
||||
)
|
||||
val backstack = mutableListOf<Destination>()
|
||||
every { navigationManager.backStack } returns backstack
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
verify(exactly = 0) { navigationManager.reloadHome() }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
}
|
||||
assertEquals(1, backstack.size)
|
||||
backstack[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is Destination.Favorites)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is target, has no server`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns
|
||||
IntentResult.Target(
|
||||
destinations = listOf(Destination.Favorites),
|
||||
addHomeToBackStack = true,
|
||||
)
|
||||
val backstack = mutableListOf<Destination>()
|
||||
every { navigationManager.backStack } returns backstack
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
verify(exactly = 0) { navigationManager.reloadHome() }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.ServerList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
package com.github.damontecres.wholphin.test
|
||||
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinServer
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinUser
|
||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||
import io.mockk.MockKMatcherScope
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.NameGuidPair
|
||||
import org.jellyfin.sdk.model.api.UserDto
|
||||
|
||||
fun MockKMatcherScope.nonBlankString() = match<String> { it.isNotNullOrBlank() }
|
||||
|
||||
|
|
@ -75,3 +79,35 @@ fun playlist(
|
|||
seriesId = null,
|
||||
genreItems = genres,
|
||||
)
|
||||
|
||||
fun server(serverId: UUID = UUID.randomUUID()) = JellyfinServer(serverId, "test server", "http://localhost:8096", "10.11.11")
|
||||
|
||||
fun user(
|
||||
serverId: UUID,
|
||||
userId: UUID = UUID.randomUUID(),
|
||||
) = JellyfinUser(
|
||||
rowId = 1,
|
||||
id = userId,
|
||||
serverId = serverId,
|
||||
name = "test-user",
|
||||
accessToken = "token",
|
||||
pin = null,
|
||||
)
|
||||
|
||||
fun userDto(userId: UUID) =
|
||||
UserDto(
|
||||
id = userId,
|
||||
name = "test-user",
|
||||
serverName = "test server",
|
||||
hasPassword = true,
|
||||
hasConfiguredPassword = true,
|
||||
hasConfiguredEasyPassword = false,
|
||||
)
|
||||
|
||||
fun currentUser(
|
||||
serverId: UUID = UUID.randomUUID(),
|
||||
userId: UUID = UUID.randomUUID(),
|
||||
) = CurrentUser(
|
||||
server(serverId),
|
||||
user(userId),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue