Skip to content

Commit

Permalink
Add statemachine test cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaskioko committed Jun 9, 2023
1 parent 6841784 commit 750895e
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import com.thomaskioko.tvmaniac.traktauth.api.TraktAuthRepository
import com.thomaskioko.tvmaniac.traktauth.api.TraktAuthState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

class FakeTraktAuthRepository : TraktAuthRepository {

override fun observeState(): StateFlow<TraktAuthState> =
MutableStateFlow(TraktAuthState.LOGGED_OUT)
private val state = MutableStateFlow(TraktAuthState.LOGGED_OUT)

suspend fun setAuthState(authState: TraktAuthState) {
state.emit(authState)
}

override fun observeState(): StateFlow<TraktAuthState> = state.asStateFlow()

override fun updateAuthState(authState: AuthState) {
// no-op
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ package com.thomaskioko.tvmaniac.trakt.profile.testing

import com.thomaskioko.tvmaniac.core.db.User
import com.thomaskioko.tvmaniac.profile.api.ProfileRepository
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.receiveAsFlow
import org.mobilenativefoundation.store.store5.StoreReadResponse
import org.mobilenativefoundation.store.store5.StoreReadResponseOrigin

class FakeProfileRepository : ProfileRepository {

private val user = User(
slug = "me",
user_name = "silly_eyes",
full_name = "Stranger Danger",
profile_picture = "",
is_me = true,
)
private val userFlow: Channel<StoreReadResponse<User>> = Channel(Channel.UNLIMITED)

suspend fun setUserData(response: StoreReadResponse<User>) {
userFlow.send(response)
}

override fun observeProfile(slug: String): Flow<StoreReadResponse<User>> =
flowOf(
StoreReadResponse.Data(
value = user,
origin = StoreReadResponseOrigin.Cache,
),
)
userFlow.receiveAsFlow()

override suspend fun clearProfile() {
// no-op
}
}

val user = User(
slug = "me",
user_name = "silly_eyes",
full_name = "Stranger Danger",
profile_picture = null,
is_me = true,
)
5 changes: 3 additions & 2 deletions presentation/profile/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ kotlin {
}

sourceSets["commonTest"].dependencies {
implementation(projects.data.episodeimages.testing)
implementation(projects.data.seasondetails.testing)
implementation(projects.core.datastore.testing)
implementation(projects.data.profile.testing)
implementation(projects.core.traktAuth.testing)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.thomaskioko.tvmaniac.presentation.profile

import app.cash.turbine.test
import com.thomaskioko.tvmaniac.datastore.testing.FakeDatastoreRepository
import com.thomaskioko.tvmaniac.datastore.testing.authenticatedAuthState
import com.thomaskioko.tvmaniac.trakt.profile.testing.FakeProfileRepository
import com.thomaskioko.tvmaniac.trakt.profile.testing.user
import com.thomaskioko.tvmaniac.traktauth.api.TraktAuthState
import com.thomaskioko.tvmaniac.traktauth.testing.FakeTraktAuthRepository
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.test.runTest
import org.mobilenativefoundation.store.store5.StoreReadResponse
import org.mobilenativefoundation.store.store5.StoreReadResponseOrigin
import kotlin.test.Test

class ProfileStateMachineTest {

private val datastoreRepository = FakeDatastoreRepository()
private val profileRepository = FakeProfileRepository()
private val traktAuthRepository = FakeTraktAuthRepository()

private val stateMachine = ProfileStateMachine(
datastoreRepository = datastoreRepository,
profileRepository = profileRepository,
traktAuthRepository = traktAuthRepository,
)

@Test
fun initial_state_emits_expected_result() = runTest {
stateMachine.state.test {
awaitItem() shouldBe LoggedOutContent()
}
}

@Test
fun given_ShowTraktDialog_andUserIsAuthenticated_expectedResultIsEmitted() = runTest {
stateMachine.state.test {
awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE // Initial State

stateMachine.dispatch(ShowTraktDialog)

awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE
.copy(
showTraktDialog = true,
)

stateMachine.dispatch(TraktLoginClicked)

awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE
.copy(
showTraktDialog = false,
)

traktAuthRepository.setAuthState(TraktAuthState.LOGGED_IN)
datastoreRepository.setAuthState(authenticatedAuthState)
profileRepository.setUserData(
StoreReadResponse.Data(
value = user,
origin = StoreReadResponseOrigin.Cache,
),
)

awaitItem() shouldBe LoggedInContent()
awaitItem() shouldBe LoggedInContent()
.copy(
errorMessage = null,
userInfo = UserInfo(
slug = user.slug,
userName = user.user_name,
fullName = user.full_name,
userPicUrl = user.profile_picture,
),
)
}
}

@Test
fun given_TraktLoginClicked_andErrorOccurs_expectedResultIsEmitted() = runTest {
stateMachine.state.test {
val errorMessage = "Something happened"

awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE

stateMachine.dispatch(ShowTraktDialog)

awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE.copy(
showTraktDialog = true,
)

stateMachine.dispatch(TraktLoginClicked)

awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE.copy(
showTraktDialog = false,
)

traktAuthRepository.setAuthState(TraktAuthState.LOGGED_IN)
datastoreRepository.setAuthState(authenticatedAuthState)
profileRepository.setUserData(
StoreReadResponse.Error.Exception(
error = Throwable(errorMessage),
origin = StoreReadResponseOrigin.Cache,
),
)

awaitItem() shouldBe LoggedInContent()
awaitItem() shouldBe LoggedInContent()
.copy(
errorMessage = errorMessage,
)
}
}

@Test
fun given_TraktLogoutClicked_expectedResultIsEmitted() = runTest {
stateMachine.state.test {
awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE

traktAuthRepository.setAuthState(TraktAuthState.LOGGED_IN)
datastoreRepository.setAuthState(authenticatedAuthState)
profileRepository.setUserData(
StoreReadResponse.Data(
value = user,
origin = StoreReadResponseOrigin.Cache,
),
)

awaitItem() shouldBe LoggedInContent()
awaitItem() shouldBe LoggedInContent()
.copy(
errorMessage = null,
userInfo = UserInfo(
slug = user.slug,
userName = user.user_name,
fullName = user.full_name,
userPicUrl = user.profile_picture,
),
)

stateMachine.dispatch(TraktLogoutClicked)

awaitItem() shouldBe LoggedOutContent.DEFAULT_STATE
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.thomaskioko.tvmaniac.datastore.testing.FakeDatastoreRepository
import com.thomaskioko.tvmaniac.datastore.testing.authenticatedAuthState
import com.thomaskioko.tvmaniac.trakt.profile.testing.FakeProfileRepository
import com.thomaskioko.tvmaniac.trakt.profile.testing.user
import com.thomaskioko.tvmaniac.traktauth.api.TraktAuthState
import com.thomaskioko.tvmaniac.traktauth.testing.FakeTraktAuthRepository
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.test.runTest
Expand Down Expand Up @@ -112,6 +113,7 @@ class SettingsStateMachineTest {
showTraktDialog = false,
)

traktAuthRepository.setAuthState(TraktAuthState.LOGGED_IN)
datastoreRepository.setAuthState(authenticatedAuthState)
profileRepository.setUserData(
StoreReadResponse.Data(
Expand Down Expand Up @@ -153,6 +155,7 @@ class SettingsStateMachineTest {
showTraktDialog = false,
)

traktAuthRepository.setAuthState(TraktAuthState.LOGGED_IN)
datastoreRepository.setAuthState(authenticatedAuthState)
profileRepository.setUserData(
StoreReadResponse.Error.Exception(
Expand All @@ -174,6 +177,7 @@ class SettingsStateMachineTest {
stateMachine.state.test {
awaitItem() shouldBe Default.EMPTY // Initial State

traktAuthRepository.setAuthState(TraktAuthState.LOGGED_IN)
datastoreRepository.setAuthState(authenticatedAuthState)
profileRepository.setUserData(
StoreReadResponse.Data(
Expand Down

0 comments on commit 750895e

Please sign in to comment.