#3810 Convert DepictedImagesFragment to use Pagination - rename base classes to better reflect usage

This commit is contained in:
Sean Mac Gillicuddy 2020-06-17 10:40:20 +01:00
parent 181a63a233
commit 310c29c2bd
25 changed files with 104 additions and 103 deletions

View file

@ -1,12 +1,12 @@
package fr.free.nrw.commons.depictions.Media
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.explore.SearchFragmentContract
import fr.free.nrw.commons.explore.PagingContract
/**
* Contract with which DepictedImagesFragment and its presenter will talk to each other
*/
interface DepictedImagesContract {
interface View : SearchFragmentContract.View<Media>
interface Presenter : SearchFragmentContract.Presenter<Media>
interface View : PagingContract.View<Media>
interface Presenter : PagingContract.Presenter<Media>
}

View file

@ -10,12 +10,12 @@ class DepictedImagesFragment : PageableMediaFragment(), DepictedImagesContract.V
@Inject
lateinit var presenter: DepictedImagesContract.Presenter
override val injectedPresenter: DepictedImagesContract.Presenter
override val injectedPresenter
get() = presenter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
injectedPresenter.onQueryUpdated(arguments!!.getString("entityId")!!)
onQueryUpdated(arguments!!.getString("entityId")!!)
}
override fun onItemClicked(position: Int) {

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.depictions.Media
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.di.CommonsApplicationModule
import fr.free.nrw.commons.explore.BaseSearchPresenter
import fr.free.nrw.commons.explore.BasePagingPresenter
import io.reactivex.Scheduler
import javax.inject.Inject
import javax.inject.Named
@ -13,5 +13,5 @@ import javax.inject.Named
class DepictedImagesPresenter @Inject constructor(
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
dataSourceFactory: PageableDepictedMediaDataSource
) : BaseSearchPresenter<Media>(mainThreadScheduler, dataSourceFactory),
) : BasePagingPresenter<Media>(mainThreadScheduler, dataSourceFactory),
DepictedImagesContract.Presenter

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.depictions.Media
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.explore.LiveDataConverter
import fr.free.nrw.commons.explore.PageableDataSource
import fr.free.nrw.commons.explore.PageableBaseDataSource
import fr.free.nrw.commons.explore.depictions.LoadFunction
import fr.free.nrw.commons.media.MediaClient
import javax.inject.Inject
@ -10,7 +10,7 @@ import javax.inject.Inject
class PageableDepictedMediaDataSource @Inject constructor(
liveDataConverter: LiveDataConverter,
private val mediaClient: MediaClient
) : PageableDataSource<Media>(liveDataConverter) {
) : PageableBaseDataSource<Media>(liveDataConverter) {
override val loadFunction: LoadFunction<Media> = { loadSize: Int, startPosition: Int ->
mediaClient.fetchImagesForDepictedItem(query, loadSize, startPosition).blockingGet()
}

View file

@ -19,11 +19,11 @@ import fr.free.nrw.commons.utils.ViewUtil
import kotlinx.android.synthetic.main.fragment_search_paginated.*
abstract class BaseSearchFragment<T> : CommonsDaggerSupportFragment(),
SearchFragmentContract.View<T> {
abstract class BasePagingFragment<T> : CommonsDaggerSupportFragment(),
PagingContract.View<T> {
abstract val pagedListAdapter: PagedListAdapter<T, *>
abstract val injectedPresenter: SearchFragmentContract.Presenter<T>
abstract val injectedPresenter: PagingContract.Presenter<T>
abstract val errorTextId: Int
private val loadingAdapter by lazy { FooterAdapter { injectedPresenter.retryFailedRequest() } }
private val mergeAdapter by lazy { MergeAdapter(pagedListAdapter, loadingAdapter) }
@ -47,11 +47,12 @@ abstract class BaseSearchFragment<T> : CommonsDaggerSupportFragment(),
)
}
override fun observeSearchResults(searchResults: LiveData<PagedList<T>>) {
override fun observePagingResults(searchResults: LiveData<PagedList<T>>) {
this.searchResults?.removeObservers(viewLifecycleOwner)
this.searchResults = searchResults
searchResults.observe(viewLifecycleOwner, Observer {
pagedListAdapter.submitList(it) })
pagedListAdapter.submitList(it)
})
}
override fun onAttach(context: Context) {
@ -85,7 +86,7 @@ abstract class BaseSearchFragment<T> : CommonsDaggerSupportFragment(),
contentNotFound.visibility = View.VISIBLE
}
abstract fun getEmptyText(query: String):String
abstract fun getEmptyText(query: String): String
override fun hideEmptyText() {
contentNotFound.visibility = View.GONE

View file

@ -7,25 +7,25 @@ import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
abstract class BaseSearchPresenter<T>(
abstract class BasePagingPresenter<T>(
val mainThreadScheduler: Scheduler,
val pageableDataSource: PageableDataSource<T>
) : SearchFragmentContract.Presenter<T> {
val pageableBaseDataSource: PageableBaseDataSource<T>
) : PagingContract.Presenter<T> {
private val DUMMY: SearchFragmentContract.View<T> = proxy()
private var view: SearchFragmentContract.View<T> = DUMMY
private val DUMMY: PagingContract.View<T> = proxy()
private var view: PagingContract.View<T> = DUMMY
private val compositeDisposable = CompositeDisposable()
override val listFooterData = MutableLiveData<List<FooterItem>>().apply { value = emptyList() }
override fun onAttachView(view: SearchFragmentContract.View<T>) {
override fun onAttachView(view: PagingContract.View<T>) {
this.view = view
compositeDisposable.addAll(
pageableDataSource.searchResults.subscribe(view::observeSearchResults),
pageableDataSource.loadingStates
pageableBaseDataSource.pagingResults.subscribe(view::observePagingResults),
pageableBaseDataSource.loadingStates
.observeOn(mainThreadScheduler)
.subscribe(::onLoadingState, Timber::e),
pageableDataSource.noItemsLoadedQueries.subscribe(view::showEmptyText)
pageableBaseDataSource.noItemsLoadedQueries.subscribe(view::showEmptyText)
)
}
@ -50,7 +50,7 @@ abstract class BaseSearchPresenter<T>(
}
override fun retryFailedRequest() {
pageableDataSource.retryFailedRequest()
pageableBaseDataSource.retryFailedRequest()
}
override fun onDetachView() {
@ -59,7 +59,7 @@ abstract class BaseSearchPresenter<T>(
}
override fun onQueryUpdated(query: String) {
pageableDataSource.onQueryUpdated(query)
pageableBaseDataSource.onQueryUpdated(query)
}
}

View file

@ -4,10 +4,10 @@ import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import fr.free.nrw.commons.BasePresenter
interface SearchFragmentContract {
interface PagingContract {
interface View<T> {
fun showSnackbar()
fun observeSearchResults(searchResults: LiveData<PagedList<T>>)
fun observePagingResults(searchResults: LiveData<PagedList<T>>)
fun showInitialLoadInProgress()
fun hideInitialLoadProgress()
fun showEmptyText(query: String)

View file

@ -14,25 +14,25 @@ import javax.inject.Inject
private const val PAGE_SIZE = 50
private const val INITIAL_LOAD_SIZE = 50
abstract class PageableDataSource<T>(private val liveDataConverter: LiveDataConverter) {
abstract class PageableBaseDataSource<T>(private val liveDataConverter: LiveDataConverter) {
lateinit var query: String
private val dataSourceFactoryFactory: () -> SearchDataSourceFactory<T> = {
private val dataSourceFactoryFactory: () -> PagingDataSourceFactory<T> = {
dataSourceFactory(_loadingStates, loadFunction)
}
private val _loadingStates = PublishProcessor.create<LoadingState>()
val loadingStates: Flowable<LoadingState> = _loadingStates
private val _searchResults = PublishProcessor.create<LiveData<PagedList<T>>>()
val searchResults: Flowable<LiveData<PagedList<T>>> = _searchResults
private val _pagingResults = PublishProcessor.create<LiveData<PagedList<T>>>()
val pagingResults: Flowable<LiveData<PagedList<T>>> = _pagingResults
private val _noItemsLoadedEvent = PublishProcessor.create<String>()
val noItemsLoadedQueries: Flowable<String> = _noItemsLoadedEvent
private var currentFactory: SearchDataSourceFactory<T>? = null
private var currentFactory: PagingDataSourceFactory<T>? = null
abstract val loadFunction: LoadFunction<T>
fun onQueryUpdated(query: String) {
this.query = query
_searchResults.offer(
_pagingResults.offer(
liveDataConverter.convert(dataSourceFactoryFactory().also { currentFactory = it }) {
_noItemsLoadedEvent.offer(query)
}
@ -46,7 +46,7 @@ abstract class PageableDataSource<T>(private val liveDataConverter: LiveDataConv
class LiveDataConverter @Inject constructor() {
fun <T> convert(
dataSourceFactory: SearchDataSourceFactory<T>,
dataSourceFactory: PagingDataSourceFactory<T>,
zeroItemsLoadedFunction: () -> Unit
): LiveData<PagedList<T>> {
return dataSourceFactory.toLiveData(
@ -65,7 +65,7 @@ class LiveDataConverter @Inject constructor() {
}
abstract class SearchDataSourceFactory<T>(val loadingStates: LoadingStates) :
abstract class PagingDataSourceFactory<T>(val loadingStates: LoadingStates) :
DataSource.Factory<Int, T>() {
private var currentDataSource: SearchDataSource<T>? = null
abstract val loadFunction: LoadFunction<T>
@ -80,7 +80,7 @@ abstract class SearchDataSourceFactory<T>(val loadingStates: LoadingStates) :
}
fun <T> dataSourceFactory(loadingStates: LoadingStates, loadFunction: LoadFunction<T>) =
object : SearchDataSourceFactory<T>(loadingStates) {
object : PagingDataSourceFactory<T>(loadingStates) {
override val loadFunction: LoadFunction<T> = loadFunction
}

View file

@ -10,5 +10,5 @@ import javax.inject.Named
class SearchCategoriesFragmentPresenter @Inject constructor(
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
dataSourceFactory: PageableCategoriesDataSource
) : BaseSearchPresenter<String>(mainThreadScheduler, dataSourceFactory),
) : BasePagingPresenter<String>(mainThreadScheduler, dataSourceFactory),
SearchCategoriesFragmentContract.Presenter

View file

@ -2,13 +2,13 @@ package fr.free.nrw.commons.explore.categories
import fr.free.nrw.commons.category.CategoryClient
import fr.free.nrw.commons.explore.LiveDataConverter
import fr.free.nrw.commons.explore.PageableDataSource
import fr.free.nrw.commons.explore.PageableBaseDataSource
import javax.inject.Inject
class PageableCategoriesDataSource @Inject constructor(
liveDataConverter: LiveDataConverter,
val categoryClient: CategoryClient
) : PageableDataSource<String>(liveDataConverter) {
) : PageableBaseDataSource<String>(liveDataConverter) {
override val loadFunction = { loadSize: Int, startPosition: Int ->
categoryClient.searchCategories(query, loadSize, startPosition).blockingFirst()

View file

@ -1,8 +1,8 @@
package fr.free.nrw.commons.explore.categories
import fr.free.nrw.commons.explore.SearchFragmentContract
import fr.free.nrw.commons.explore.PagingContract
interface SearchCategoriesFragmentContract {
interface View : SearchFragmentContract.View<String>
interface Presenter : SearchFragmentContract.Presenter<String>
interface View : PagingContract.View<String>
interface Presenter : PagingContract.Presenter<String>
}

View file

@ -2,20 +2,20 @@ package fr.free.nrw.commons.explore.categories
import fr.free.nrw.commons.R
import fr.free.nrw.commons.category.CategoryDetailsActivity
import fr.free.nrw.commons.explore.BaseSearchFragment
import fr.free.nrw.commons.explore.SearchFragmentContract
import fr.free.nrw.commons.explore.BasePagingFragment
import fr.free.nrw.commons.explore.PagingContract
import javax.inject.Inject
/**
* Displays the category search screen.
*/
class SearchCategoryFragment : BaseSearchFragment<String>() {
class SearchCategoryFragment : BasePagingFragment<String>() {
@Inject
lateinit var presenter: SearchCategoriesFragmentContract.Presenter
override val errorTextId: Int = R.string.error_loading_categories
override val injectedPresenter: SearchFragmentContract.Presenter<String>
override val injectedPresenter
get() = presenter
override val pagedListAdapter by lazy {

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.explore.depictions
import fr.free.nrw.commons.explore.LiveDataConverter
import fr.free.nrw.commons.explore.LoadingState
import fr.free.nrw.commons.explore.PageableDataSource
import fr.free.nrw.commons.explore.PageableBaseDataSource
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import io.reactivex.processors.PublishProcessor
import javax.inject.Inject
@ -13,7 +13,7 @@ typealias LoadingStates = PublishProcessor<LoadingState>
class PageableDepictionsDataSource @Inject constructor(
liveDataConverter: LiveDataConverter,
val depictsClient: DepictsClient
) : PageableDataSource<DepictedItem>(liveDataConverter) {
) : PageableBaseDataSource<DepictedItem>(liveDataConverter) {
override val loadFunction = { loadSize: Int, startPosition: Int ->
depictsClient.searchForDepictions(query, loadSize, startPosition).blockingGet()

View file

@ -2,21 +2,21 @@ package fr.free.nrw.commons.explore.depictions
import fr.free.nrw.commons.R
import fr.free.nrw.commons.depictions.WikidataItemDetailsActivity
import fr.free.nrw.commons.explore.BaseSearchFragment
import fr.free.nrw.commons.explore.BasePagingFragment
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import javax.inject.Inject
/**
* Display depictions in search fragment
*/
class SearchDepictionsFragment : BaseSearchFragment<DepictedItem>(),
class SearchDepictionsFragment : BasePagingFragment<DepictedItem>(),
SearchDepictionsFragmentContract.View {
@Inject
lateinit var presenter: SearchDepictionsFragmentContract.Presenter
override val errorTextId: Int = R.string.error_loading_depictions
override val injectedPresenter: SearchDepictionsFragmentContract.Presenter
override val injectedPresenter
get() = presenter
override val pagedListAdapter by lazy {

View file

@ -1,12 +1,12 @@
package fr.free.nrw.commons.explore.depictions
import fr.free.nrw.commons.explore.SearchFragmentContract
import fr.free.nrw.commons.explore.PagingContract
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
/**
* The contract with with SearchDepictionsFragment and its presenter would talk to each other
*/
interface SearchDepictionsFragmentContract {
interface View : SearchFragmentContract.View<DepictedItem>
interface Presenter : SearchFragmentContract.Presenter<DepictedItem>
interface View : PagingContract.View<DepictedItem>
interface Presenter : PagingContract.Presenter<DepictedItem>
}

View file

@ -1,7 +1,7 @@
package fr.free.nrw.commons.explore.depictions
import fr.free.nrw.commons.di.CommonsApplicationModule
import fr.free.nrw.commons.explore.BaseSearchPresenter
import fr.free.nrw.commons.explore.BasePagingPresenter
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import io.reactivex.Scheduler
import javax.inject.Inject
@ -13,5 +13,5 @@ import javax.inject.Named
class SearchDepictionsFragmentPresenter @Inject constructor(
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
dataSourceFactory: PageableDepictionsDataSource
) : BaseSearchPresenter<DepictedItem>(mainThreadScheduler, dataSourceFactory),
) : BasePagingPresenter<DepictedItem>(mainThreadScheduler, dataSourceFactory),
SearchDepictionsFragmentContract.Presenter

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.explore.media
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.explore.LiveDataConverter
import fr.free.nrw.commons.explore.PageableDataSource
import fr.free.nrw.commons.explore.PageableBaseDataSource
import fr.free.nrw.commons.explore.depictions.LoadFunction
import fr.free.nrw.commons.media.MediaClient
import javax.inject.Inject
@ -10,7 +10,7 @@ import javax.inject.Inject
class PageableMediaDataSource @Inject constructor(
liveDataConverter: LiveDataConverter,
private val mediaClient: MediaClient
) : PageableDataSource<Media>(liveDataConverter) {
) : PageableBaseDataSource<Media>(liveDataConverter) {
override val loadFunction: LoadFunction<Media> = { loadSize: Int, startPosition: Int ->
mediaClient.getMediaListFromSearch(query, loadSize, startPosition).blockingGet()
}

View file

@ -4,11 +4,11 @@ import android.os.Bundle
import android.view.View
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.explore.BaseSearchFragment
import fr.free.nrw.commons.explore.BasePagingFragment
import kotlinx.android.synthetic.main.fragment_search_paginated.*
abstract class PageableMediaFragment : BaseSearchFragment<Media>() {
abstract class PageableMediaFragment : BasePagingFragment<Media>() {
override val pagedListAdapter by lazy { PagedMediaAdapter(::onItemClicked) }
override val errorTextId: Int = R.string.error_loading_images

View file

@ -11,7 +11,7 @@ class SearchMediaFragment : PageableMediaFragment(), SearchMediaFragmentContract
@Inject
lateinit var presenter: SearchMediaFragmentContract.Presenter
override val injectedPresenter: SearchMediaFragmentContract.Presenter
override val injectedPresenter
get() = presenter
override fun onItemClicked(position: Int) {

View file

@ -1,10 +1,10 @@
package fr.free.nrw.commons.explore.media
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.explore.SearchFragmentContract
import fr.free.nrw.commons.explore.PagingContract
interface SearchMediaFragmentContract {
interface View : SearchFragmentContract.View<Media>
interface Presenter : SearchFragmentContract.Presenter<Media>
interface View : PagingContract.View<Media>
interface Presenter : PagingContract.Presenter<Media>
}

View file

@ -2,7 +2,7 @@ package fr.free.nrw.commons.explore.media
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.di.CommonsApplicationModule
import fr.free.nrw.commons.explore.BaseSearchPresenter
import fr.free.nrw.commons.explore.BasePagingPresenter
import io.reactivex.Scheduler
import javax.inject.Inject
import javax.inject.Named
@ -10,5 +10,5 @@ import javax.inject.Named
class SearchMediaFragmentPresenter @Inject constructor(
@Named(CommonsApplicationModule.MAIN_THREAD) mainThreadScheduler: Scheduler,
dataSourceFactory: PageableMediaDataSource
) : BaseSearchPresenter<Media>(mainThreadScheduler, dataSourceFactory),
) : BasePagingPresenter<Media>(mainThreadScheduler, dataSourceFactory),
SearchMediaFragmentContract.Presenter

View file

@ -15,21 +15,21 @@ import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class BaseSearchPresenterTest {
class BasePagingPresenterTest {
@Rule
@JvmField
var instantTaskExecutorRule = InstantTaskExecutorRule()
@Mock
internal lateinit var view: SearchFragmentContract.View<String>
internal lateinit var view: PagingContract.View<String>
private lateinit var baseSearchPresenter: BaseSearchPresenter<String>
private lateinit var basePagingPresenter: BasePagingPresenter<String>
private lateinit var testScheduler: TestScheduler
@Mock
private lateinit var pageableDataSource: PageableDataSource<String>
private lateinit var pageableBaseDataSource: PageableBaseDataSource<String>
private var loadingStates: PublishProcessor<LoadingState> = PublishProcessor.create()
@ -42,34 +42,34 @@ class BaseSearchPresenterTest {
@Throws(Exception::class)
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(pageableDataSource.searchResults).thenReturn(searchResults)
whenever(pageableDataSource.loadingStates).thenReturn(loadingStates)
whenever(pageableDataSource.noItemsLoadedQueries)
whenever(pageableBaseDataSource.pagingResults).thenReturn(searchResults)
whenever(pageableBaseDataSource.loadingStates).thenReturn(loadingStates)
whenever(pageableBaseDataSource.noItemsLoadedQueries)
.thenReturn(noItemLoadedQueries)
testScheduler = TestScheduler()
baseSearchPresenter =
object : BaseSearchPresenter<String>(testScheduler, pageableDataSource) {}
baseSearchPresenter.onAttachView(view)
basePagingPresenter =
object : BasePagingPresenter<String>(testScheduler, pageableBaseDataSource) {}
basePagingPresenter.onAttachView(view)
}
@Test
fun `searchResults emission updates the view`() {
val pagedListLiveData = mock<LiveData<PagedList<String>>>()
searchResults.offer(pagedListLiveData)
verify(view).observeSearchResults(pagedListLiveData)
verify(view).observePagingResults(pagedListLiveData)
}
@Test
fun `Loading offers a loading list item`() {
onLoadingState(LoadingState.Loading)
verify(view).hideEmptyText()
baseSearchPresenter.listFooterData.test().assertValue(listOf(FooterItem.LoadingItem))
basePagingPresenter.listFooterData.test().assertValue(listOf(FooterItem.LoadingItem))
}
@Test
fun `Complete offers an empty list item and hides initial loader`() {
onLoadingState(LoadingState.Complete)
baseSearchPresenter.listFooterData.test()
basePagingPresenter.listFooterData.test()
.assertValue(emptyList())
verify(view).hideInitialLoadProgress()
}
@ -83,11 +83,11 @@ class BaseSearchPresenterTest {
@Test
fun `Error offers a refresh list item, hides initial loader and shows error with a set text`() {
baseSearchPresenter.onQueryUpdated("test")
basePagingPresenter.onQueryUpdated("test")
onLoadingState(LoadingState.Error)
verify(view).showSnackbar()
verify(view).hideInitialLoadProgress()
baseSearchPresenter.listFooterData.test().assertValue(listOf(FooterItem.RefreshItem))
basePagingPresenter.listFooterData.test().assertValue(listOf(FooterItem.RefreshItem))
}
@Test
@ -98,21 +98,21 @@ class BaseSearchPresenterTest {
@Test
fun `retryFailedRequest calls retry`() {
baseSearchPresenter.retryFailedRequest()
verify(pageableDataSource).retryFailedRequest()
basePagingPresenter.retryFailedRequest()
verify(pageableBaseDataSource).retryFailedRequest()
}
@Test
fun `onDetachView stops subscriptions`() {
baseSearchPresenter.onDetachView()
basePagingPresenter.onDetachView()
onLoadingState(LoadingState.Loading)
baseSearchPresenter.listFooterData.test().assertValue(emptyList())
basePagingPresenter.listFooterData.test().assertValue(emptyList())
}
@Test
fun `onQueryUpdated updates dataSourceFactory`() {
baseSearchPresenter.onQueryUpdated("test")
verify(pageableDataSource).onQueryUpdated("test")
basePagingPresenter.onQueryUpdated("test")
verify(pageableBaseDataSource).onQueryUpdated("test")
}
private fun onLoadingState(loadingState: LoadingState) {

View file

@ -10,17 +10,17 @@ import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class PageableDataSourceTest {
class PageableBaseDataSourceTest {
@Mock
private lateinit var liveDataConverter: LiveDataConverter
private lateinit var pageableDataSource: PageableDataSource<String>
private lateinit var pageableBaseDataSource: PageableBaseDataSource<String>
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
pageableDataSource = object: PageableDataSource<String>(liveDataConverter){
pageableBaseDataSource = object: PageableBaseDataSource<String>(liveDataConverter){
override val loadFunction: LoadFunction<String>
get() = mock()
@ -30,16 +30,16 @@ class PageableDataSourceTest {
@Test
fun `onQueryUpdated emits new liveData`() {
val (_, liveData) = expectNewLiveData()
pageableDataSource.searchResults.test()
.also { pageableDataSource.onQueryUpdated("test") }
pageableBaseDataSource.pagingResults.test()
.also { pageableBaseDataSource.onQueryUpdated("test") }
.assertValue(liveData)
}
@Test
fun `onQueryUpdated invokes livedatconverter with no items emitter`() {
val (zeroItemsFuncCaptor, _) = expectNewLiveData()
pageableDataSource.onQueryUpdated("test")
pageableDataSource.noItemsLoadedQueries.test()
pageableBaseDataSource.onQueryUpdated("test")
pageableBaseDataSource.noItemsLoadedQueries.test()
.also { zeroItemsFuncCaptor.firstValue.invoke() }
.assertValue("test")
}
@ -49,22 +49,22 @@ class PageableDataSourceTest {
* */
@Test
fun `retryFailedRequest does nothing without a factory`() {
pageableDataSource.retryFailedRequest()
pageableBaseDataSource.retryFailedRequest()
}
@Test
@Ignore("Rewrite with Mockk constructor mocks")
fun `retryFailedRequest retries with a factory`() {
val (_, _, dataSourceFactoryCaptor) = expectNewLiveData()
pageableDataSource.onQueryUpdated("test")
pageableBaseDataSource.onQueryUpdated("test")
val dataSourceFactory = spy(dataSourceFactoryCaptor.firstValue)
pageableDataSource.retryFailedRequest()
pageableBaseDataSource.retryFailedRequest()
verify(dataSourceFactory).retryFailedRequest()
}
private fun expectNewLiveData(): Triple<KArgumentCaptor<() -> Unit>, LiveData<PagedList<String>>, KArgumentCaptor<SearchDataSourceFactory<String>>> {
private fun expectNewLiveData(): Triple<KArgumentCaptor<() -> Unit>, LiveData<PagedList<String>>, KArgumentCaptor<PagingDataSourceFactory<String>>> {
val captor = argumentCaptor<() -> Unit>()
val dataSourceFactoryCaptor = argumentCaptor<SearchDataSourceFactory<String>>()
val dataSourceFactoryCaptor = argumentCaptor<PagingDataSourceFactory<String>>()
val liveData: LiveData<PagedList<String>> = mock()
whenever(liveDataConverter.convert(dataSourceFactoryCaptor.capture(), captor.capture()))
.thenReturn(liveData)

View file

@ -14,21 +14,21 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
class SearchDataSourceFactoryTest {
class PagingDataSourceFactoryTest {
@Mock
private lateinit var depictsClient: DepictsClient
@Mock
private lateinit var loadingStates: PublishProcessor<LoadingState>
private lateinit var factory: SearchDataSourceFactory<String>
private lateinit var factory: PagingDataSourceFactory<String>
private var function: (Int, Int) -> List<String> = mock()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
factory = object : SearchDataSourceFactory<String>(loadingStates) {
factory = object : PagingDataSourceFactory<String>(loadingStates) {
override val loadFunction get() = function
}
}