diff --git a/app/src/test/java/com/example/tvschedule/MainDispatcherRule.kt b/app/src/test/java/com/example/tvschedule/MainDispatcherRule.kt index bb0f3bd..4ee9d23 100644 --- a/app/src/test/java/com/example/tvschedule/MainDispatcherRule.kt +++ b/app/src/test/java/com/example/tvschedule/MainDispatcherRule.kt @@ -9,15 +9,15 @@ import kotlinx.coroutines.test.setMain import org.junit.rules.TestWatcher import org.junit.runner.Description -class MainDispatcherRule @OptIn(ExperimentalCoroutinesApi::class) constructor( - val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule constructor( + private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), ) : TestWatcher() { - @OptIn(ExperimentalCoroutinesApi::class) + override fun starting(description: Description) { Dispatchers.setMain(testDispatcher) } - @OptIn(ExperimentalCoroutinesApi::class) override fun finished(description: Description) { Dispatchers.resetMain() } diff --git a/app/src/test/java/com/example/tvschedule/data/show_details/repository/ShowDetailsRepositoryTest.kt b/app/src/test/java/com/example/tvschedule/data/show_details/repository/ShowDetailsRepositoryTest.kt new file mode 100644 index 0000000..94d38be --- /dev/null +++ b/app/src/test/java/com/example/tvschedule/data/show_details/repository/ShowDetailsRepositoryTest.kt @@ -0,0 +1,47 @@ +package com.example.tvschedule.data.show_details.repository + +import com.example.tvschedule.data.search.mapper.ShowMapper +import com.example.tvschedule.data.show_details.api.ShowDetailsApi +import com.example.tvschedule.data.util.ModelUtil +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.mockito.Mockito +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + + +class ShowDetailsRepositoryTest { + + private val api = mock() + + private val showMapper = mock() + + private val showDetailsRepository = ShowDetailsRepositoryImpl( + api = api, + showMapper = showMapper + ) + + @Test + fun `get show details success`() = runTest { + whenever(api.getShowDetails(ModelUtil.showId)).thenReturn(ModelUtil.showResponse) + whenever(showMapper.map(ModelUtil.showResponse)).thenReturn(ModelUtil.show) + val result = showDetailsRepository.getShowDetails(ModelUtil.showId) + verify(api, Mockito.times(1)).getShowDetails(ModelUtil.showId) + verify(showMapper, Mockito.times(1)).map(ModelUtil.showResponse) + assertThat(result).isEqualTo(ModelUtil.show) + } + + @Test + fun `get show details failed`() = runTest { + val exception = IllegalStateException("Failed to get show details") + whenever(api.getShowDetails(ModelUtil.showId)).thenThrow(exception) + runCatching { + showDetailsRepository.getShowDetails(ModelUtil.showId) + }.onFailure { e -> + verify(api, Mockito.times(1)).getShowDetails(ModelUtil.showId) + assertThat(e).isEqualTo(exception) + } + } +} diff --git a/app/src/test/java/com/example/tvschedule/data/util/ModelUtil.kt b/app/src/test/java/com/example/tvschedule/data/util/ModelUtil.kt index 3400cce..dcc2d81 100644 --- a/app/src/test/java/com/example/tvschedule/data/util/ModelUtil.kt +++ b/app/src/test/java/com/example/tvschedule/data/util/ModelUtil.kt @@ -17,6 +17,7 @@ import com.example.tvschedule.domain.schedule.model.Schedule import com.example.tvschedule.domain.show_details.model.Cast import com.example.tvschedule.domain.show_details.model.Season import com.example.tvschedule.domain.show_details.model.Show +import com.example.tvschedule.domain.show_details.model.ShowDetails import java.time.LocalDate object ModelUtil { @@ -30,6 +31,8 @@ object ModelUtil { const val showAverageRuntime = 30 val showGenres = listOf("Comedy", "Drama", "Thriller") + const val searchQuery = "query" + const val castId = 43L const val castFullName = "John Gold" const val castCharacterName = "Peter" @@ -204,6 +207,11 @@ object ModelUtil { seasons = seasons ) + val showDetails = ShowDetails( + show = show, + isFavorite = true + ) + val showFromEntity = Show( id = showId, showName = showName, diff --git a/app/src/test/java/com/example/tvschedule/presentation/favorite/FavoriteViewModelTest.kt b/app/src/test/java/com/example/tvschedule/presentation/favorite/FavoriteViewModelTest.kt new file mode 100644 index 0000000..bdd5f8a --- /dev/null +++ b/app/src/test/java/com/example/tvschedule/presentation/favorite/FavoriteViewModelTest.kt @@ -0,0 +1,114 @@ +package com.example.tvschedule.presentation.favorite + +import com.example.tvschedule.MainDispatcherRule +import com.example.tvschedule.data.util.ModelUtil +import com.example.tvschedule.domain.favorite.use_case.GetFavoritesUseCase +import com.example.tvschedule.domain.favorite.use_case.RemoveFromFavoritesUseCase +import com.example.tvschedule.presentation.favorite.model.FavoriteUiEvent +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test +import org.mockito.Mockito.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + + +class FavoriteViewModelTest { + + private val getFavoritesUseCase = mock() + + private val removeFromFavoritesUseCase = mock() + + private lateinit var viewModel : FavoriteViewModel + + @get:Rule + val mainCoroutineRule = MainDispatcherRule() + + @Test + fun `get favorite shows success`() = runTest { + val flow = flow { emit(listOf(ModelUtil.show)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + viewModel = FavoriteViewModel( + getFavoritesUseCase = getFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isEmpty() + assertThat(state.shows).isNotEmpty() + } + + @Test + fun `get favorite shows failed`() = runTest { + whenever(getFavoritesUseCase.invoke()) + .thenReturn(Result.failure(IllegalStateException("Failed to get favorites"))) + viewModel = FavoriteViewModel( + getFavoritesUseCase = getFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isTrue() + assertThat(state.searchQuery).isEmpty() + assertThat(state.shows).isEmpty() + } + + @Test + fun `remove from favorite shows success`() = runTest { + val flow = flow { emit(listOf(ModelUtil.show)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(removeFromFavoritesUseCase.invoke(ModelUtil.showId)) + .thenReturn(Result.success(Unit)) + viewModel = FavoriteViewModel( + getFavoritesUseCase = getFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(FavoriteUiEvent.OnFavoriteClick(ModelUtil.showId)) + verify(removeFromFavoritesUseCase, times(1)).invoke(ModelUtil.showId) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isEmpty() + assertThat(state.shows).isNotEmpty() + } + + @Test + fun `handle retry event success`() = runTest { + val flow = flow { emit(listOf(ModelUtil.show)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + viewModel = FavoriteViewModel( + getFavoritesUseCase = getFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + whenever(viewModel.setEvent(FavoriteUiEvent.Retry)).thenReturn(Unit) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isEmpty() + assertThat(state.shows).isNotEmpty() + } + + @Test + fun `handle query change event success`() = runTest { + val flow = flow { emit(listOf(ModelUtil.show)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + viewModel = FavoriteViewModel( + getFavoritesUseCase = getFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + whenever(viewModel.setEvent(FavoriteUiEvent.OnQueryChange(ModelUtil.searchQuery))) + .thenReturn(Unit) + verify(getFavoritesUseCase, times(0)).invoke() + val state = viewModel.viewState.value + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isNotEmpty() + } +} diff --git a/app/src/test/java/com/example/tvschedule/presentation/schedule/ScheduleViewModelTest.kt b/app/src/test/java/com/example/tvschedule/presentation/schedule/ScheduleViewModelTest.kt new file mode 100644 index 0000000..2babed3 --- /dev/null +++ b/app/src/test/java/com/example/tvschedule/presentation/schedule/ScheduleViewModelTest.kt @@ -0,0 +1,78 @@ +package com.example.tvschedule.presentation.schedule + +import com.example.tvschedule.MainDispatcherRule +import com.example.tvschedule.data.util.ModelUtil +import com.example.tvschedule.domain.schedule.use_case.GetScheduleUseCase +import com.example.tvschedule.presentation.schedule.model.ScheduleUiEvent +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + + +class ScheduleViewModelTest { + + private val getScheduleUseCase = mock() + + private lateinit var viewModel: ScheduleViewModel + + @get:Rule + val mainCoroutineRule = MainDispatcherRule() + + @Test + fun `load schedule success`() = runTest { + whenever(getScheduleUseCase.invoke(any())) + .thenReturn(Result.success(ModelUtil.schedules)) + viewModel = ScheduleViewModel(getScheduleUseCase) + verify(getScheduleUseCase, times(1)).invoke(any()) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.schedule).isNotEmpty() + } + + @Test + fun `load schedule failed`() = runTest { + whenever(getScheduleUseCase.invoke(any())) + .thenReturn(Result.failure(IllegalStateException("Failed to load schedule"))) + viewModel = ScheduleViewModel(getScheduleUseCase) + verify(getScheduleUseCase, times(1)).invoke(any()) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isTrue() + assertThat(state.schedule).isEmpty() + } + + @Test + fun `handle select date event success`() = runTest { + whenever(getScheduleUseCase.invoke(any())) + .thenReturn(Result.success(ModelUtil.schedules)) + viewModel = ScheduleViewModel(getScheduleUseCase) + whenever(viewModel.setEvent(ScheduleUiEvent.SelectDate(ModelUtil.scheduleDate))) + .thenReturn(Unit) + verify(getScheduleUseCase, times(1)).invoke(any()) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.schedule).isNotEmpty() + assertThat(state.selectedDate).isEqualTo(ModelUtil.scheduleDate) + } + + @Test + fun `handle retry event success`() = runTest { + whenever(getScheduleUseCase.invoke(any())) + .thenReturn(Result.success(ModelUtil.schedules)) + viewModel = ScheduleViewModel(getScheduleUseCase) + whenever(viewModel.setEvent(ScheduleUiEvent.Retry)).thenReturn(Unit) + verify(getScheduleUseCase, times(1)).invoke(any()) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.schedule).isNotEmpty() + } +} diff --git a/app/src/test/java/com/example/tvschedule/presentation/search/SearchViewModelTest.kt b/app/src/test/java/com/example/tvschedule/presentation/search/SearchViewModelTest.kt new file mode 100644 index 0000000..8bc24aa --- /dev/null +++ b/app/src/test/java/com/example/tvschedule/presentation/search/SearchViewModelTest.kt @@ -0,0 +1,162 @@ +package com.example.tvschedule.presentation.search + +import com.example.tvschedule.MainDispatcherRule +import com.example.tvschedule.data.util.ModelUtil +import com.example.tvschedule.domain.favorite.use_case.AddToFavoritesUseCase +import com.example.tvschedule.domain.favorite.use_case.GetFavoritesUseCase +import com.example.tvschedule.domain.favorite.use_case.RemoveFromFavoritesUseCase +import com.example.tvschedule.domain.search.use_case.SearchShowUseCase +import com.example.tvschedule.domain.show_details.model.Show +import com.example.tvschedule.presentation.search.model.SearchUiEvent +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + + +@OptIn(ExperimentalCoroutinesApi::class) +class SearchViewModelTest { + private val searchShowUseCase = mock() + private val getFavoritesUseCase = mock() + private val addToFavoritesUseCase = mock() + private val removeFromFavoritesUseCase = mock() + + private lateinit var viewModel : SearchViewModel + + @get:Rule + val mainCoroutineRule = MainDispatcherRule() + + @Test + fun `get favorite shows success`() = runTest { + val flow = flow { emit(listOf(ModelUtil.show)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + viewModel = SearchViewModel( + searchShowUseCase = searchShowUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isEmpty() + } + + @Test + fun `get favorite shows failed`() = runTest { + whenever(getFavoritesUseCase.invoke()) + .thenReturn(Result.failure(IllegalStateException("Failed to get favorites"))) + viewModel = SearchViewModel( + searchShowUseCase = searchShowUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isTrue() + assertThat(state.searchQuery).isEmpty() + assertThat(state.shows).isEmpty() + } + + @Test + fun `search shows success`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(searchShowUseCase.invoke(ModelUtil.searchQuery)) + .thenReturn(Result.success(ModelUtil.shows)) + viewModel = SearchViewModel( + searchShowUseCase = searchShowUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(SearchUiEvent.OnQueryChange(ModelUtil.searchQuery)) + advanceUntilIdle() + verify(getFavoritesUseCase, times(1)).invoke() + verify(searchShowUseCase, times(1)).invoke(ModelUtil.searchQuery) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isNotEmpty() + assertThat(state.shows).isNotEmpty() + } + + @Test + fun `search shows failed`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(searchShowUseCase.invoke(ModelUtil.searchQuery)) + .thenReturn(Result.failure(IllegalStateException("Failed to search shows"))) + viewModel = SearchViewModel( + searchShowUseCase = searchShowUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(SearchUiEvent.OnQueryChange(ModelUtil.searchQuery)) + advanceUntilIdle() + verify(getFavoritesUseCase, times(1)).invoke() + verify(searchShowUseCase, times(1)).invoke(ModelUtil.searchQuery) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isTrue() + assertThat(state.searchQuery).isNotEmpty() + assertThat(state.shows).isEmpty() + } + + @Test + fun `remove from favorite shows success`() = runTest { + val flow = flow { emit(listOf(ModelUtil.show)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(removeFromFavoritesUseCase.invoke(ModelUtil.showId)) + .thenReturn(Result.success(Unit)) + viewModel = SearchViewModel( + searchShowUseCase = searchShowUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(SearchUiEvent.OnFavoriteClick(ModelUtil.showId, false)) + verify(removeFromFavoritesUseCase, times(1)).invoke(ModelUtil.showId) + verify(getFavoritesUseCase, times(1)).invoke() + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isEmpty() + } + + @Test + fun `add to favorite shows success`() = runTest { + val flow = flow { emit(emptyList()) } + whenever(searchShowUseCase.invoke(any())).thenReturn(Result.success(ModelUtil.shows)) + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(addToFavoritesUseCase.invoke(ModelUtil.show)).thenReturn(Result.success(Unit)) + viewModel = SearchViewModel( + searchShowUseCase = searchShowUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(SearchUiEvent.Retry) + advanceUntilIdle() + viewModel.setEvent(SearchUiEvent.OnFavoriteClick(ModelUtil.showId, true)) + verify(searchShowUseCase, times(1)).invoke(any()) + verify(getFavoritesUseCase, times(1)).invoke() + verify(addToFavoritesUseCase, times(1)).invoke(ModelUtil.show) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.searchQuery).isEmpty() + } +} diff --git a/app/src/test/java/com/example/tvschedule/presentation/show_details/ShowDetailsViewModelTest.kt b/app/src/test/java/com/example/tvschedule/presentation/show_details/ShowDetailsViewModelTest.kt new file mode 100644 index 0000000..2ee3ef4 --- /dev/null +++ b/app/src/test/java/com/example/tvschedule/presentation/show_details/ShowDetailsViewModelTest.kt @@ -0,0 +1,177 @@ +package com.example.tvschedule.presentation.show_details + +import androidx.lifecycle.SavedStateHandle +import com.example.tvschedule.MainDispatcherRule +import com.example.tvschedule.data.util.ModelUtil +import com.example.tvschedule.domain.favorite.use_case.AddToFavoritesUseCase +import com.example.tvschedule.domain.favorite.use_case.GetFavoritesUseCase +import com.example.tvschedule.domain.favorite.use_case.RemoveFromFavoritesUseCase +import com.example.tvschedule.domain.show_details.model.Show +import com.example.tvschedule.domain.show_details.use_case.GetShowDetailsUseCase +import com.example.tvschedule.presentation.model.Screen +import com.example.tvschedule.presentation.show_details.model.ShowDetailsUiEvent +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + + +class ShowDetailsViewModelTest { + + private val savedStateHandle = mock() + private val getShowDetailsUseCase = mock() + private val getFavoritesUseCase = mock() + private val addToFavoritesUseCase = mock() + private val removeFromFavoritesUseCase = mock() + + private lateinit var viewModel: ShowDetailsViewModel + + @get:Rule + val mainCoroutineRule = MainDispatcherRule() + + @Test + fun `get favorite show success`() = runTest { + val flow = flow { emit(emptyList()) } + val detailsFlow = flow { emit(ModelUtil.showDetails) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(getShowDetailsUseCase.invoke(ModelUtil.showId)).thenReturn(detailsFlow) + whenever(savedStateHandle.get(Screen.SHOW_ID) as? Long).thenReturn(ModelUtil.showId) + viewModel = ShowDetailsViewModel( + savedStateHandle = savedStateHandle, + getShowDetailsUseCase = getShowDetailsUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + verify(savedStateHandle, times(1)).get(Screen.SHOW_ID) as? Long + verify(getFavoritesUseCase, times(1)).invoke() + verify(getShowDetailsUseCase, times(1)).invoke(ModelUtil.showId) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + assertThat(state.isFavorite).isTrue() + } + + @Test + fun `get favorite show failed`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(getShowDetailsUseCase.invoke(ModelUtil.showId)) + .thenReturn(flow { throw RuntimeException("Failed to get favorite show") }) + whenever(savedStateHandle.get(Screen.SHOW_ID) as? Long).thenReturn(ModelUtil.showId) + viewModel = ShowDetailsViewModel( + savedStateHandle = savedStateHandle, + getShowDetailsUseCase = getShowDetailsUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + verify(savedStateHandle, times(1)).get(Screen.SHOW_ID) as? Long + verify(getFavoritesUseCase, times(1)).invoke() + verify(getShowDetailsUseCase, times(1)).invoke(ModelUtil.showId) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isTrue() + assertThat(state.isFavorite).isTrue() + } + + @Test + fun `add to favorites success`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + val detailsFlow = flow { emit(ModelUtil.showDetails.copy(isFavorite = false)) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(getShowDetailsUseCase.invoke(ModelUtil.showId)).thenReturn(detailsFlow) + whenever(addToFavoritesUseCase.invoke(ModelUtil.show)).thenReturn(Result.success(Unit)) + whenever(savedStateHandle.get(Screen.SHOW_ID) as? Long).thenReturn(ModelUtil.showId) + viewModel = ShowDetailsViewModel( + savedStateHandle = savedStateHandle, + getShowDetailsUseCase = getShowDetailsUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(ShowDetailsUiEvent.OnFavoriteClick) + verify(savedStateHandle, times(1)).get(Screen.SHOW_ID) as? Long + verify(getFavoritesUseCase, times(1)).invoke() + verify(getShowDetailsUseCase, times(1)).invoke(ModelUtil.showId) + verify(addToFavoritesUseCase, times(1)).invoke(ModelUtil.show) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + } + + @Test + fun `remove from favorites success`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + val detailsFlow = flow { emit(ModelUtil.showDetails.copy()) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(getShowDetailsUseCase.invoke(ModelUtil.showId)).thenReturn(detailsFlow) + whenever(removeFromFavoritesUseCase.invoke(ModelUtil.showId)) + .thenReturn(Result.success(Unit)) + whenever(savedStateHandle.get(Screen.SHOW_ID) as? Long).thenReturn(ModelUtil.showId) + viewModel = ShowDetailsViewModel( + savedStateHandle = savedStateHandle, + getShowDetailsUseCase = getShowDetailsUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(ShowDetailsUiEvent.OnFavoriteClick) + verify(savedStateHandle, times(1)).get(Screen.SHOW_ID) as? Long + verify(getFavoritesUseCase, times(1)).invoke() + verify(getShowDetailsUseCase, times(1)).invoke(ModelUtil.showId) + verify(removeFromFavoritesUseCase, times(1)).invoke(ModelUtil.showId) + val state = viewModel.viewState.value + assertThat(state.isLoading).isFalse() + assertThat(state.isError).isFalse() + } + + @Test + fun `show all casts success`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + val detailsFlow = flow { emit(ModelUtil.showDetails) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(getShowDetailsUseCase.invoke(ModelUtil.showId)).thenReturn(detailsFlow) + whenever(savedStateHandle.get(Screen.SHOW_ID) as? Long).thenReturn(ModelUtil.showId) + viewModel = ShowDetailsViewModel( + savedStateHandle = savedStateHandle, + getShowDetailsUseCase = getShowDetailsUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(ShowDetailsUiEvent.OnShowAllCastClick) + verify(savedStateHandle, times(1)).get(Screen.SHOW_ID) as? Long + verify(getFavoritesUseCase, times(1)).invoke() + verify(getShowDetailsUseCase, times(1)).invoke(ModelUtil.showId) + val state = viewModel.viewState.value + assertThat(state.isViewAllCastButtonVisible).isFalse() + } + + @Test + fun `show all seasons success`() = runTest { + val flow = flow { emit(ModelUtil.shows) } + val detailsFlow = flow { emit(ModelUtil.showDetails) } + whenever(getFavoritesUseCase.invoke()).thenReturn(Result.success(flow)) + whenever(getShowDetailsUseCase.invoke(ModelUtil.showId)).thenReturn(detailsFlow) + whenever(savedStateHandle.get(Screen.SHOW_ID) as? Long).thenReturn(ModelUtil.showId) + viewModel = ShowDetailsViewModel( + savedStateHandle = savedStateHandle, + getShowDetailsUseCase = getShowDetailsUseCase, + getFavoritesUseCase = getFavoritesUseCase, + addToFavoritesUseCase = addToFavoritesUseCase, + removeFromFavoritesUseCase = removeFromFavoritesUseCase + ) + viewModel.setEvent(ShowDetailsUiEvent.OnShowAllSeasonsClick) + verify(savedStateHandle, times(1)).get(Screen.SHOW_ID) as? Long + verify(getFavoritesUseCase, times(1)).invoke() + verify(getShowDetailsUseCase, times(1)).invoke(ModelUtil.showId) + val state = viewModel.viewState.value + assertThat(state.isViewAllSeasonsButtonVisible).isFalse() + } +}