initial commit
This commit is contained in:
parent
85ef73b2ba
commit
90a9426b7d
221 changed files with 7611 additions and 0 deletions
|
|
@ -0,0 +1,51 @@
|
|||
package org.fnives.test.showcase.core.content
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class AddContentToFavouriteUseCaseTest {
|
||||
|
||||
private lateinit var sut: AddContentToFavouriteUseCase
|
||||
private lateinit var mockFavouriteContentLocalStorage: FavouriteContentLocalStorage
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockFavouriteContentLocalStorage = mock()
|
||||
sut = AddContentToFavouriteUseCase(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_nothing_happens_THEN_the_storage_is_not_touched() {
|
||||
verifyZeroInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_contentId_WHEN_called_THEN_storage_is_called() = runBlockingTest {
|
||||
sut.invoke(ContentId("a"))
|
||||
|
||||
verify(mockFavouriteContentLocalStorage, times(1)).markAsFavourite(ContentId("a"))
|
||||
verifyNoMoreInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_thrown() = runBlockingTest {
|
||||
whenever(mockFavouriteContentLocalStorage.markAsFavourite(ContentId("a"))).doThrow(RuntimeException())
|
||||
|
||||
assertThrows(RuntimeException::class.java) {
|
||||
runBlocking { sut.invoke(ContentId("a")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
package org.fnives.test.showcase.core.content
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.fnives.test.showcase.core.shared.UnexpectedException
|
||||
import org.fnives.test.showcase.model.content.Content
|
||||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.fnives.test.showcase.model.content.ImageUrl
|
||||
import org.fnives.test.showcase.model.shared.Resource
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSource
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.doSuspendableAnswer
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class ContentRepositoryTest {
|
||||
|
||||
private lateinit var sut: ContentRepository
|
||||
private lateinit var mockContentRemoteSource: ContentRemoteSource
|
||||
private lateinit var testDispatcher: TestCoroutineDispatcher
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
testDispatcher = TestCoroutineDispatcher()
|
||||
mockContentRemoteSource = mock()
|
||||
sut = ContentRepository(mockContentRemoteSource)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_no_interaction_THEN_remote_source_is_not_called() {
|
||||
verifyNoMoreInteractions(mockContentRemoteSource)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_no_response_from_remote_source_WHEN_content_observed_THEN_loading_is_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
val expected = Resource.Loading<List<Content>>()
|
||||
val suspendedRequest = CompletableDeferred<Unit>()
|
||||
whenever(mockContentRemoteSource.get()).doSuspendableAnswer {
|
||||
suspendedRequest.await()
|
||||
emptyList()
|
||||
}
|
||||
val actual = sut.contents.take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
suspendedRequest.complete(Unit)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_content_response_WHEN_content_observed_THEN_loading_AND_data_is_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Success(listOf(Content(ContentId("a"), "", "", ImageUrl(""))))
|
||||
)
|
||||
whenever(mockContentRemoteSource.get())
|
||||
.doReturn(listOf(Content(ContentId("a"), "", "", ImageUrl(""))))
|
||||
|
||||
val actual = sut.contents.take(2).toList()
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_content_error_WHEN_content_observed_THEN_loading_AND_data_is_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
val exception = RuntimeException()
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Error<List<Content>>(UnexpectedException(exception))
|
||||
)
|
||||
whenever(mockContentRemoteSource.get()).doThrow(exception)
|
||||
|
||||
val actual = sut.contents.take(2).toList()
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_content_response_THEN_error_WHEN_fetched_THEN_returned_states_are_loading_data_loading_error() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
val exception = RuntimeException()
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Success(emptyList()),
|
||||
Resource.Loading(),
|
||||
Resource.Error<List<Content>>(UnexpectedException(exception))
|
||||
)
|
||||
var first = true
|
||||
whenever(mockContentRemoteSource.get()).doAnswer {
|
||||
if (first) emptyList<Content>().also { first = false } else throw exception
|
||||
}
|
||||
|
||||
val actual = async(testDispatcher) { sut.contents.take(4).toList() }
|
||||
testDispatcher.advanceUntilIdle()
|
||||
sut.fetch()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_content_response_THEN_error_WHEN_fetched_THEN_only_4_items_are_emitted() {
|
||||
Assertions.assertThrows(IllegalStateException::class.java) {
|
||||
runBlockingTest(testDispatcher) {
|
||||
val exception = RuntimeException()
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Success(emptyList()),
|
||||
Resource.Loading(),
|
||||
Resource.Error<List<Content>>(UnexpectedException(exception))
|
||||
)
|
||||
var first = true
|
||||
whenever(mockContentRemoteSource.get()).doAnswer {
|
||||
if (first) emptyList<Content>().also { first = false } else throw exception
|
||||
}
|
||||
|
||||
val actual = async(testDispatcher) { sut.contents.take(5).toList() }
|
||||
testDispatcher.advanceUntilIdle()
|
||||
sut.fetch()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_saved_cache_WHEN_collected_THEN_cache_is_returned() = runBlockingTest {
|
||||
val content = Content(ContentId("1"), "", "", ImageUrl(""))
|
||||
val expected = listOf(Resource.Success(listOf(content)))
|
||||
whenever(mockContentRemoteSource.get()).doReturn(listOf(content))
|
||||
sut.contents.take(2).toList()
|
||||
|
||||
val actual = sut.contents.take(1).toList()
|
||||
|
||||
verify(mockContentRemoteSource, times(1)).get()
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package org.fnives.test.showcase.core.content
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class FetchContentUseCaseTest {
|
||||
|
||||
private lateinit var sut: FetchContentUseCase
|
||||
private lateinit var mockContentRepository: ContentRepository
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockContentRepository = mock()
|
||||
sut = FetchContentUseCase(mockContentRepository)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_nothing_happens_THEN_the_storage_is_not_touched() {
|
||||
verifyZeroInteractions(mockContentRepository)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_called_THEN_repository_is_called() = runBlockingTest {
|
||||
sut.invoke()
|
||||
|
||||
verify(mockContentRepository, times(1)).fetch()
|
||||
verifyNoMoreInteractions(mockContentRepository)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_thrown() = runBlockingTest {
|
||||
whenever(mockContentRepository.fetch()).doThrow(RuntimeException())
|
||||
|
||||
assertThrows(RuntimeException::class.java) {
|
||||
runBlocking { sut.invoke() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
package org.fnives.test.showcase.core.content
|
||||
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||
import org.fnives.test.showcase.model.content.Content
|
||||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.fnives.test.showcase.model.content.FavouriteContent
|
||||
import org.fnives.test.showcase.model.content.ImageUrl
|
||||
import org.fnives.test.showcase.model.shared.Resource
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class GetAllContentUseCaseTest {
|
||||
|
||||
private lateinit var sut: GetAllContentUseCase
|
||||
private lateinit var mockContentRepository: ContentRepository
|
||||
private lateinit var mockFavouriteContentLocalStorage: FavouriteContentLocalStorage
|
||||
private lateinit var contentFlow: MutableStateFlow<Resource<List<Content>>>
|
||||
private lateinit var favouriteContentIdFlow: MutableStateFlow<List<ContentId>>
|
||||
private lateinit var testDispatcher: TestCoroutineDispatcher
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
testDispatcher = TestCoroutineDispatcher()
|
||||
mockFavouriteContentLocalStorage = mock()
|
||||
mockContentRepository = mock()
|
||||
favouriteContentIdFlow = MutableStateFlow(emptyList())
|
||||
contentFlow = MutableStateFlow(Resource.Loading())
|
||||
whenever(mockFavouriteContentLocalStorage.observeFavourites()).doReturn(favouriteContentIdFlow)
|
||||
whenever(mockContentRepository.contents).doReturn(contentFlow)
|
||||
sut = GetAllContentUseCase(mockContentRepository, mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loading_AND_empty_favourite_WHEN_observed_THEN_loading_is_shown() = runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
contentFlow.value = Resource.Loading()
|
||||
val expected = Resource.Loading<List<FavouriteContent>>()
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loading_AND_listOfFavourite_WHEN_observed_THEN_loading_is_shown() = runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
contentFlow.value = Resource.Loading()
|
||||
val expected = Resource.Loading<List<FavouriteContent>>()
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_error_AND_empty_favourite_WHEN_observed_THEN_error_is_shown() = runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
val exception = Throwable()
|
||||
contentFlow.value = Resource.Error(exception)
|
||||
val expected = Resource.Error<List<FavouriteContent>>(exception)
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_error_AND_listOfFavourite_WHEN_observed_THEN_error_is_shown() = runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("b"))
|
||||
val exception = Throwable()
|
||||
contentFlow.value = Resource.Error(exception)
|
||||
val expected = Resource.Error<List<FavouriteContent>>(exception)
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_listOfContent_AND_empty_favourite_WHEN_observed_THEN_favourites_are_returned() = runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
contentFlow.value = Resource.Success(listOf(content))
|
||||
val items = listOf(
|
||||
FavouriteContent(content, false)
|
||||
)
|
||||
val expected = Resource.Success(items)
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_listOfContent_AND_other_favourite_id_WHEN_observed_THEN_favourites_are_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("x"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
contentFlow.value = Resource.Success(listOf(content))
|
||||
val items = listOf(
|
||||
FavouriteContent(content, false)
|
||||
)
|
||||
val expected = Resource.Success(items)
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_listOfContent_AND_same_favourite_id_WHEN_observed_THEN_favourites_are_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
contentFlow.value = Resource.Success(listOf(content))
|
||||
val items = listOf(
|
||||
FavouriteContent(content, true)
|
||||
)
|
||||
val expected = Resource.Success(items)
|
||||
|
||||
val actual = sut.get().take(1).toList()
|
||||
|
||||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_then_added_favourite_WHEN_observed_THEN_loading_then_correct_favourites_are_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
contentFlow.value = Resource.Loading()
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Success(listOf(FavouriteContent(content, false))),
|
||||
Resource.Success(listOf(FavouriteContent(content, true)))
|
||||
)
|
||||
|
||||
val actual = async(testDispatcher) {
|
||||
sut.get().take(3).toList()
|
||||
}
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
contentFlow.value = Resource.Success(listOf(content))
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_then_removed_favourite_WHEN_observed_THEN_loading_then_correct_favourites_are_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
contentFlow.value = Resource.Loading()
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Success(listOf(FavouriteContent(content, true))),
|
||||
Resource.Success(listOf(FavouriteContent(content, false)))
|
||||
)
|
||||
|
||||
val actual = async(testDispatcher) {
|
||||
sut.get().take(3).toList()
|
||||
}
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
contentFlow.value = Resource.Success(listOf(content))
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_then_loading_WHEN_observed_THEN_loading_then_correct_favourites_then_loadingare_returned() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
contentFlow.value = Resource.Loading()
|
||||
val expected = listOf(
|
||||
Resource.Loading(),
|
||||
Resource.Success(listOf(FavouriteContent(content, true))),
|
||||
Resource.Loading()
|
||||
)
|
||||
|
||||
val actual = async(testDispatcher) {
|
||||
sut.get().take(3).toList()
|
||||
}
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
contentFlow.value = Resource.Success(listOf(content))
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
contentFlow.value = Resource.Loading()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package org.fnives.test.showcase.core.content
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class RemoveContentFromFavouritesUseCaseTest {
|
||||
|
||||
private lateinit var sut: RemoveContentFromFavouritesUseCase
|
||||
private lateinit var mockFavouriteContentLocalStorage: FavouriteContentLocalStorage
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockFavouriteContentLocalStorage = mock()
|
||||
sut = RemoveContentFromFavouritesUseCase(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_nothing_happens_THEN_the_storage_is_not_touched() {
|
||||
verifyZeroInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_contentId_WHEN_called_THEN_storage_is_called() = runBlockingTest {
|
||||
sut.invoke(ContentId("a"))
|
||||
|
||||
verify(mockFavouriteContentLocalStorage, times(1)).deleteAsFavourite(ContentId("a"))
|
||||
verifyNoMoreInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_thrown() = runBlockingTest {
|
||||
whenever(mockFavouriteContentLocalStorage.deleteAsFavourite(ContentId("a"))).doThrow(RuntimeException())
|
||||
|
||||
Assertions.assertThrows(RuntimeException::class.java) {
|
||||
runBlocking { sut.invoke(ContentId("a")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package org.fnives.test.showcase.core.login
|
||||
|
||||
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class IsUserLoggedInUseCaseTest {
|
||||
|
||||
private lateinit var sut: IsUserLoggedInUseCase
|
||||
private lateinit var mockUserDataLocalStorage: UserDataLocalStorage
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockUserDataLocalStorage = mock()
|
||||
sut = IsUserLoggedInUseCase(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_nothing_is_called_THEN_storage_is_not_called() {
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_session_data_saved_WHEN_is_user_logged_in_checked_THEN_true_is_returned() {
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(Session("a", "b"))
|
||||
|
||||
val actual = sut.invoke()
|
||||
|
||||
Assertions.assertEquals(true, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_no_session_data_saved_WHEN_is_user_logged_in_checked_THEN_false_is_returned() {
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(null)
|
||||
|
||||
val actual = sut.invoke()
|
||||
|
||||
Assertions.assertEquals(false, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_no_session_THEN_session_THEN_no_session_WHEN_is_user_logged_in_checked_over_again_THEN_every_return_is_correct() {
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(null)
|
||||
val actual1 = sut.invoke()
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(Session("", ""))
|
||||
val actual2 = sut.invoke()
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(null)
|
||||
val actual3 = sut.invoke()
|
||||
|
||||
Assertions.assertEquals(false, actual1)
|
||||
Assertions.assertEquals(true, actual2)
|
||||
Assertions.assertEquals(false, actual3)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package org.fnives.test.showcase.core.login
|
||||
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.fnives.test.showcase.core.shared.UnexpectedException
|
||||
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.model.auth.LoginStatus
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.fnives.test.showcase.model.shared.Answer
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSource
|
||||
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class LoginUseCaseTest {
|
||||
|
||||
private lateinit var sut: LoginUseCase
|
||||
private lateinit var mockLoginRemoteSource: LoginRemoteSource
|
||||
private lateinit var mockUserDataLocalStorage: UserDataLocalStorage
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockLoginRemoteSource = mock()
|
||||
mockUserDataLocalStorage = mock()
|
||||
sut = LoginUseCase(mockLoginRemoteSource, mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_empty_username_WHEN_trying_to_login_THEN_invalid_username_is_returned() = runBlockingTest {
|
||||
val expected = Answer.Success(LoginStatus.INVALID_USERNAME)
|
||||
|
||||
val actual = sut.invoke(LoginCredentials("", "a"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
verifyZeroInteractions(mockLoginRemoteSource)
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_empty_password_WHEN_trying_to_login_THEN_invalid_password_is_returned() = runBlockingTest {
|
||||
val expected = Answer.Success(LoginStatus.INVALID_PASSWORD)
|
||||
|
||||
val actual = sut.invoke(LoginCredentials("a", ""))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
verifyZeroInteractions(mockLoginRemoteSource)
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_login_invalid_credentials_response_WHEN_trying_to_login_THEN_invalid_credentials_is_returned() = runBlockingTest {
|
||||
val expected = Answer.Success(LoginStatus.INVALID_CREDENTIALS)
|
||||
whenever(mockLoginRemoteSource.login(LoginCredentials("a", "b")))
|
||||
.doReturn(LoginStatusResponses.InvalidCredentials)
|
||||
|
||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_valid_login_response_WHEN_trying_to_login_THEN_Success_is_returned() = runBlockingTest {
|
||||
val expected = Answer.Success(LoginStatus.SUCCESS)
|
||||
whenever(mockLoginRemoteSource.login(LoginCredentials("a", "b")))
|
||||
.doReturn(LoginStatusResponses.Success(Session("c", "d")))
|
||||
|
||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
verify(mockUserDataLocalStorage, times(1)).session = Session("c", "d")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_throwing_remote_source_WHEN_trying_to_login_THEN_error_is_returned() = runBlockingTest {
|
||||
val exception = RuntimeException()
|
||||
val expected = Answer.Error<LoginStatus>(UnexpectedException(exception))
|
||||
whenever(mockLoginRemoteSource.login(LoginCredentials("a", "b")))
|
||||
.doThrow(exception)
|
||||
|
||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package org.fnives.test.showcase.core.login
|
||||
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.fnives.test.showcase.core.content.ContentRepository
|
||||
import org.fnives.test.showcase.core.di.createCoreModule
|
||||
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.core.context.stopKoin
|
||||
import org.koin.test.KoinTest
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class LogoutUseCaseTest : KoinTest {
|
||||
|
||||
private lateinit var sut: LogoutUseCase
|
||||
private lateinit var mockUserDataLocalStorage: UserDataLocalStorage
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockUserDataLocalStorage = mock()
|
||||
sut = LogoutUseCase(mockUserDataLocalStorage)
|
||||
startKoin {
|
||||
modules(
|
||||
createCoreModule(
|
||||
baseUrl = BaseUrl("https://a.b.com"),
|
||||
enableNetworkLogging = true,
|
||||
favouriteContentLocalStorageProvider = { mock() },
|
||||
sessionExpirationListenerProvider = { mock() },
|
||||
userDataLocalStorageProvider = { mock() }
|
||||
).toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
stopKoin()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_no_call_THEN_storage_is_not_interacted() {
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_logout_invoked_THEN_storage_is_cleared() = runBlockingTest {
|
||||
val repositoryBefore = getKoin().get<ContentRepository>()
|
||||
|
||||
sut.invoke()
|
||||
|
||||
val repositoryAfter = getKoin().get<ContentRepository>()
|
||||
verify(mockUserDataLocalStorage, times(1)).session = null
|
||||
verifyNoMoreInteractions(mockUserDataLocalStorage)
|
||||
Assertions.assertNotSame(repositoryBefore, repositoryAfter)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package org.fnives.test.showcase.core.session
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class SessionExpirationAdapterTest {
|
||||
|
||||
private lateinit var sut: SessionExpirationAdapter
|
||||
private lateinit var mockSessionExpirationListener: SessionExpirationListener
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockSessionExpirationListener = mock()
|
||||
sut = SessionExpirationAdapter(mockSessionExpirationListener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_onSessionExpired_is_called_THEN_its_delegated() {
|
||||
sut.onSessionExpired()
|
||||
|
||||
verify(mockSessionExpirationListener, times(1)).onSessionExpired()
|
||||
verifyNoMoreInteractions(mockSessionExpirationListener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_nothing_is_changed_THEN_delegate_is_not_touched() {
|
||||
verifyZeroInteractions(mockSessionExpirationListener)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package org.fnives.test.showcase.core.shared
|
||||
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.shared.Answer
|
||||
import org.fnives.test.showcase.model.shared.Resource
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class AnswerUtilsKtTest {
|
||||
|
||||
@Test
|
||||
fun GIVEN_network_exception_thrown_WHEN_wrapped_into_answer_THEN_answer_error_is_returned() = runBlocking {
|
||||
val exception = NetworkException(Throwable())
|
||||
val expected = Answer.Error<Unit>(exception)
|
||||
|
||||
val actual = wrapIntoAnswer<Unit> { throw exception }
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_parsing_exception_thrown_WHEN_wrapped_into_answer_THEN_answer_error_is_returned() = runBlocking {
|
||||
val exception = ParsingException(Throwable())
|
||||
val expected = Answer.Error<Unit>(exception)
|
||||
|
||||
val actual = wrapIntoAnswer<Unit> { throw exception }
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_parsing_throwable_thrown_WHEN_wrapped_into_answer_THEN_answer_error_is_returned() = runBlocking {
|
||||
val exception = Throwable()
|
||||
val expected = Answer.Error<Unit>(UnexpectedException(exception))
|
||||
|
||||
val actual = wrapIntoAnswer<Unit> { throw exception }
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_string_WHEN_wrapped_into_answer_THEN_string_answer_is_returned() = runBlocking {
|
||||
val expected = Answer.Success("banan")
|
||||
|
||||
val actual = wrapIntoAnswer { "banan" }
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_cancellation_exception_WHEN_wrapped_into_answer_THEN_cancellation_exception_is_thrown() {
|
||||
Assertions.assertThrows(CancellationException::class.java) {
|
||||
runBlocking { wrapIntoAnswer { throw CancellationException() } }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_success_answer_WHEN_converted_into_resource_THEN_Resource_success_is_returned() {
|
||||
val expected = Resource.Success("alma")
|
||||
|
||||
val actual = Answer.Success("alma").mapIntoResource()
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_error_answer_WHEN_converted_into_resource_THEN_Resource_error_is_returned() {
|
||||
val exception = Throwable()
|
||||
val expected = Resource.Error<Unit>(exception)
|
||||
|
||||
val actual = Answer.Error<Unit>(exception).mapIntoResource()
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package org.fnives.test.showcase.core.storage
|
||||
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class NetworkSessionLocalStorageAdapterTest {
|
||||
|
||||
private lateinit var sut: NetworkSessionLocalStorageAdapter
|
||||
private lateinit var mockUserDataLocalStorage: UserDataLocalStorage
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockUserDataLocalStorage = mock()
|
||||
sut = NetworkSessionLocalStorageAdapter(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_null_as_session_WHEN_saved_THEN_its_delegated() {
|
||||
sut.session = null
|
||||
|
||||
verify(mockUserDataLocalStorage, times(1)).session = null
|
||||
verifyNoMoreInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun GIVEN_session_WHEN_saved_THEN_its_delegated() {
|
||||
val expected = Session("a", "b")
|
||||
|
||||
sut.session = Session("a", "b")
|
||||
|
||||
verify(mockUserDataLocalStorage, times(1)).session = expected
|
||||
verifyNoMoreInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun WHEN_session_requested_THEN_its_returned_from_delegated() {
|
||||
val expected = Session("a", "b")
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(expected)
|
||||
|
||||
val actual = sut.session
|
||||
|
||||
Assertions.assertSame(expected, actual)
|
||||
verify(mockUserDataLocalStorage, times(1)).session
|
||||
verifyNoMoreInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
mock-maker-inline
|
||||
Loading…
Add table
Add a link
Reference in a new issue