#3818 Convert SubDepictionListFragment to use Pagination (#3819)

This commit is contained in:
Seán Mac Gillicuddy 2020-06-25 10:08:15 +01:00 committed by GitHub
parent 34ab6f581b
commit 0e5ba98c2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
82 changed files with 474 additions and 1480 deletions

View file

@ -1,70 +0,0 @@
package fr.free.nrw.commons.depictions
import fr.free.nrw.commons.depictions.subClass.SubDepictionListContract
import fr.free.nrw.commons.depictions.subClass.SubDepictionListPresenter
import fr.free.nrw.commons.explore.depictions.DepictsClient
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import io.reactivex.Observable
import io.reactivex.schedulers.TestScheduler
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
class SubDepictionListPresenterTest {
@Mock
internal lateinit var view: SubDepictionListContract.View
lateinit var subDepictionListPresenter: SubDepictionListPresenter
lateinit var testScheduler: TestScheduler
@Mock
internal lateinit var recentSearchesDao: RecentSearchesDao
@Mock
internal lateinit var depictsClient: DepictsClient
@Mock
internal lateinit var okHttpJsonApiClient: OkHttpJsonApiClient
var testObservable: Observable<List<DepictedItem>>? = null
@Mock
lateinit var depictedItem: DepictedItem
val depictedItems: ArrayList<DepictedItem> = ArrayList()
@Before
@Throws(Exception::class)
fun setUp() {
MockitoAnnotations.initMocks(this)
testScheduler = TestScheduler()
depictedItems.add(depictedItem)
testObservable = Observable.just(depictedItems)
subDepictionListPresenter = SubDepictionListPresenter(recentSearchesDao, depictsClient, okHttpJsonApiClient, testScheduler, testScheduler)
subDepictionListPresenter.onAttachView(view)
}
@Test
fun initSubDepictionListForParentClass() {
Mockito.`when`(okHttpJsonApiClient.getParentQIDs(ArgumentMatchers.anyString())).thenReturn(testObservable)
subDepictionListPresenter.initSubDepictionList("Q9394", true)
testScheduler.triggerActions()
verify(view)?.onSuccess(depictedItems)
}
@Test
fun initSubDepictionListForChildClass() {
Mockito.`when`(okHttpJsonApiClient.getChildQIDs(ArgumentMatchers.anyString())).thenReturn(testObservable)
subDepictionListPresenter.initSubDepictionList("Q9394", false)
testScheduler.triggerActions()
verify(view)?.onSuccess(depictedItems)
}
}

View file

@ -7,6 +7,7 @@ import com.jraska.livedata.test
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.explore.paging.*
import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.TestScheduler
import org.junit.Before

View file

@ -3,7 +3,10 @@ package fr.free.nrw.commons.explore
import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import com.nhaarman.mockitokotlin2.*
import fr.free.nrw.commons.explore.depictions.LoadFunction
import fr.free.nrw.commons.explore.depictions.search.LoadFunction
import fr.free.nrw.commons.explore.paging.LiveDataConverter
import fr.free.nrw.commons.explore.paging.PageableBaseDataSource
import fr.free.nrw.commons.explore.paging.PagingDataSourceFactory
import org.junit.Before
import org.junit.Ignore
import org.junit.Test

View file

@ -4,6 +4,9 @@ import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.spy
import com.nhaarman.mockitokotlin2.verify
import fr.free.nrw.commons.explore.depictions.DepictsClient
import fr.free.nrw.commons.explore.paging.LoadingState
import fr.free.nrw.commons.explore.paging.PagingDataSource
import fr.free.nrw.commons.explore.paging.PagingDataSourceFactory
import io.reactivex.processors.PublishProcessor
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.instanceOf
@ -37,7 +40,7 @@ class PagingDataSourceFactoryTest {
fun `create returns a dataSource`() {
assertThat(
factory.create(),
instanceOf(SearchDataSource::class.java)
instanceOf(PagingDataSource::class.java)
)
}
@ -45,7 +48,7 @@ class PagingDataSourceFactoryTest {
@Ignore("Rewrite with Mockk constructor mocks")
fun `retryFailedRequest invokes method if not null`() {
val spyFactory = spy(factory)
val dataSource = mock<SearchDataSource<String>>()
val dataSource = mock<PagingDataSource<String>>()
Mockito.doReturn(dataSource).`when`(spyFactory).create()
factory.retryFailedRequest()
verify(dataSource).retryFailedRequest()

View file

@ -2,7 +2,9 @@ package fr.free.nrw.commons.explore
import androidx.paging.PositionalDataSource
import com.nhaarman.mockitokotlin2.*
import fr.free.nrw.commons.explore.depictions.LoadingStates
import fr.free.nrw.commons.explore.depictions.search.LoadingStates
import fr.free.nrw.commons.explore.paging.LoadingState
import fr.free.nrw.commons.explore.paging.PagingDataSource
import io.reactivex.plugins.RxJavaPlugins
import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.Schedulers
@ -12,10 +14,10 @@ import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class SearchDataSourceTest {
class PagingDataSourceTest {
private lateinit var loadingStates: PublishProcessor<LoadingState>
private lateinit var searchDepictionsDataSource: TestSearchDataSource
private lateinit var searchDepictionsDataSource: TestPagingDataSource
@Mock
private lateinit var mockGetItems: MockGetItems
@ -26,7 +28,7 @@ class SearchDataSourceTest {
MockitoAnnotations.initMocks(this)
loadingStates = PublishProcessor.create()
searchDepictionsDataSource =
TestSearchDataSource(
TestPagingDataSource(
loadingStates,
mockGetItems
)
@ -109,8 +111,8 @@ class SearchDataSourceTest {
}
}
class TestSearchDataSource(loadingStates: LoadingStates, val mockGetItems: MockGetItems) :
SearchDataSource<String>(loadingStates) {
class TestPagingDataSource(loadingStates: LoadingStates, val mockGetItems: MockGetItems) :
PagingDataSource<String>(loadingStates) {
override fun getItems(loadSize: Int, startPosition: Int): List<String> =
mockGetItems.getItems(loadSize, startPosition)
}

View file

@ -2,6 +2,7 @@ package fr.free.nrw.commons.explore.depictions
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.explore.depictions.search.PageableDepictionsDataSource
import io.reactivex.Single
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers
@ -12,10 +13,14 @@ class PageableDepictionsDataSourceTest {
@Test
fun `loadFunction loads depictions`() {
val depictsClient: DepictsClient = mock()
whenever(depictsClient.searchForDepictions("test", 0, 1)).thenReturn(Single.just(emptyList()))
whenever(depictsClient.searchForDepictions("test", 0, 1))
.thenReturn(Single.just(emptyList()))
val pageableDepictionsDataSource = PageableDepictionsDataSource(mock(), depictsClient)
pageableDepictionsDataSource.onQueryUpdated("test")
assertThat(pageableDepictionsDataSource.loadFunction.invoke(0, 1), Matchers.`is`(emptyList()))
assertThat(
pageableDepictionsDataSource.loadFunction.invoke(0, 1),
Matchers.`is`(emptyList())
)
}
}

View file

@ -1,53 +0,0 @@
package fr.free.nrw.commons.explore.depictions
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.spy
import com.nhaarman.mockitokotlin2.verify
import io.reactivex.processors.PublishProcessor
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
class SearchDepictionsDataSourceFactoryTest {
@Mock
private lateinit var depictsClient: DepictsClient
@Mock
private lateinit var loadingStates: PublishProcessor<LoadingState>
private lateinit var factory: SearchDepictionsDataSourceFactory
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
factory = SearchDepictionsDataSourceFactory(depictsClient, "test", loadingStates)
}
@Test
fun `create returns a dataSource`() {
assertThat(
factory.create(),
`is`(SearchDepictionsDataSource(depictsClient, loadingStates, "test"))
)
}
@Test
@Ignore("Rewrite with Mockk constructor mocks")
fun `retryFailedRequest invokes method if not null`() {
val spyFactory = spy(factory)
val dataSource = mock<SearchDepictionsDataSource>()
Mockito.doReturn(dataSource).`when`(spyFactory).create()
factory.retryFailedRequest()
verify(dataSource).retryFailedRequest()
}
@Test
fun `retryFailedRequest does not invoke method if null`() {
factory.retryFailedRequest()
}
}

View file

@ -1,106 +0,0 @@
package fr.free.nrw.commons.explore.depictions
import androidx.paging.PositionalDataSource
import com.nhaarman.mockitokotlin2.*
import fr.free.nrw.commons.explore.depictions.LoadingState.*
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import io.reactivex.Single
import io.reactivex.plugins.RxJavaPlugins
import io.reactivex.processors.PublishProcessor
import io.reactivex.schedulers.Schedulers
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class SearchDepictionsDataSourceTest {
@Mock
private lateinit var depictsClient: DepictsClient
private lateinit var loadingStates: PublishProcessor<LoadingState>
private lateinit var searchDepictionsDataSource: SearchDepictionsDataSource
@Before
fun setUp() {
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
MockitoAnnotations.initMocks(this)
loadingStates = PublishProcessor.create()
searchDepictionsDataSource =
SearchDepictionsDataSource(depictsClient, loadingStates, "test")
}
@After
fun tearDown() {
RxJavaPlugins.reset()
}
@Test
fun `loadInitial returns results and emits InitialLoad & Complete`() {
val params = PositionalDataSource.LoadInitialParams(0, 1, 2, false)
val callback = mock<PositionalDataSource.LoadInitialCallback<DepictedItem>>()
whenever(depictsClient.searchForDepictions("test", 1, 0))
.thenReturn(Single.just(emptyList()))
val testSubscriber = loadingStates.test()
searchDepictionsDataSource.loadInitial(params, callback)
verify(callback).onResult(emptyList(), 0)
testSubscriber.assertValues(InitialLoad, Complete)
}
@Test
fun `loadInitial onError does not return results and emits InitialLoad & Error`() {
val params = PositionalDataSource.LoadInitialParams(0, 1, 2, false)
val callback = mock<PositionalDataSource.LoadInitialCallback<DepictedItem>>()
whenever(depictsClient.searchForDepictions("test", 1, 0))
.thenThrow(RuntimeException())
val testSubscriber = loadingStates.test()
searchDepictionsDataSource.loadInitial(params, callback)
verify(callback, never()).onResult(any(), any())
testSubscriber.assertValues(InitialLoad, Error)
}
@Test
fun `loadRange returns results and emits Loading & Complete`() {
val callback: PositionalDataSource.LoadRangeCallback<DepictedItem> = mock()
val params = PositionalDataSource.LoadRangeParams(0, 1)
whenever(depictsClient.searchForDepictions("test", params.loadSize, params.startPosition))
.thenReturn(Single.just(emptyList()))
val testSubscriber = loadingStates.test()
searchDepictionsDataSource.loadRange(params, callback)
verify(callback).onResult(emptyList())
testSubscriber.assertValues(Loading, Complete)
}
@Test
fun `loadRange onError does not return results and emits Loading & Error`() {
val callback: PositionalDataSource.LoadRangeCallback<DepictedItem> = mock()
val params = PositionalDataSource.LoadRangeParams(0, 1)
whenever(depictsClient.searchForDepictions("test", params.loadSize, params.startPosition))
.thenThrow(RuntimeException())
val testSubscriber = loadingStates.test()
searchDepictionsDataSource.loadRange(params, callback)
verify(callback, never()).onResult(any())
testSubscriber.assertValues(Loading, Error)
}
@Test
fun `retryFailedRequest does nothing when null`() {
searchDepictionsDataSource.retryFailedRequest()
verifyNoMoreInteractions(depictsClient)
}
@Test
fun `retryFailedRequest retries last request`() {
val callback: PositionalDataSource.LoadRangeCallback<DepictedItem> = mock()
val params = PositionalDataSource.LoadRangeParams(0, 1)
whenever(depictsClient.searchForDepictions("test", params.loadSize, params.startPosition))
.thenThrow(RuntimeException()).thenReturn(Single.just(emptyList()))
val testSubscriber = loadingStates.test()
searchDepictionsDataSource.loadRange(params, callback)
verify(callback, never()).onResult(any())
searchDepictionsDataSource.retryFailedRequest()
verify(callback).onResult(emptyList())
testSubscriber.assertValues(Loading, Error, Loading, Complete)
}
}

View file

@ -1,80 +0,0 @@
package fr.free.nrw.commons.explore.depictions
import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import com.nhaarman.mockitokotlin2.*
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import io.reactivex.processors.PublishProcessor
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class SearchableDepictionsDataSourceFactoryTest {
@Mock
private lateinit var searchDepictionsDataSourceFactoryFactory: SearchDepictionsDataSourceFactoryFactory
@Mock
private lateinit var liveDataConverter: LiveDataConverter
private lateinit var factory: SearchableDepictionsDataSourceFactory
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
factory = SearchableDepictionsDataSourceFactory(
searchDepictionsDataSourceFactoryFactory,
liveDataConverter
)
}
@Test
fun `onQueryUpdated emits new liveData`() {
val (_, liveData) = expectNewLiveData()
factory.searchResults.test()
.also { factory.onQueryUpdated("test") }
.assertValue(liveData)
}
@Test
fun `onQueryUpdated invokes livedatconverter with no items emitter`() {
val (captor, _) = expectNewLiveData()
factory.onQueryUpdated("test")
factory.noItemsLoadedEvent.test()
.also { captor.firstValue.invoke() }
.assertValue(Unit)
}
/*
* Just for coverage, no way to really assert this
* */
@Test
fun `retryFailedRequest does nothing without a factory`() {
factory.retryFailedRequest()
}
@Test
fun `retryFailedRequest retries with a factory`() {
val (_, _, dataSourceFactory) = expectNewLiveData()
factory.onQueryUpdated("test")
factory.retryFailedRequest()
verify(dataSourceFactory).retryFailedRequest()
}
private fun expectNewLiveData(): Triple<KArgumentCaptor<() -> Unit>, LiveData<PagedList<DepictedItem>>, SearchDepictionsDataSourceFactory> {
val dataSourceFactory: SearchDepictionsDataSourceFactory = mock()
whenever(
searchDepictionsDataSourceFactoryFactory.create(
"test",
factory.loadingStates as PublishProcessor<LoadingState>
)
).thenReturn(dataSourceFactory)
val captor = argumentCaptor<() -> Unit>()
val liveData: LiveData<PagedList<DepictedItem>> = mock()
whenever(liveDataConverter.convert(eq(dataSourceFactory), captor.capture()))
.thenReturn(liveData)
return Triple(captor, liveData, dataSourceFactory)
}
}

View file

@ -0,0 +1,35 @@
package fr.free.nrw.commons.explore.depictions.child
import com.nhaarman.mockitokotlin2.whenever
import depictedItem
import fr.free.nrw.commons.explore.paging.LiveDataConverter
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
import io.reactivex.Observable
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class PageableChildDepictionsDataSourceTest {
@Mock
lateinit var okHttpJsonApiClient: OkHttpJsonApiClient
@Mock
lateinit var liveDataConverter: LiveDataConverter
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
@Test
fun `loadFunction loads from api at position 0`() {
val dataSource =
PageableChildDepictionsDataSource(liveDataConverter, okHttpJsonApiClient)
dataSource.onQueryUpdated("test")
whenever(okHttpJsonApiClient.getChildDepictions("test", 0, 1))
.thenReturn(Observable.just(listOf(depictedItem())))
assertThat(dataSource.loadFunction(1, 0), `is`(listOf(depictedItem())))
}
}

View file

@ -1,4 +1,4 @@
package fr.free.nrw.commons.depictions.Media
package fr.free.nrw.commons.explore.depictions.media
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever

View file

@ -0,0 +1,37 @@
package fr.free.nrw.commons.explore.depictions.parent
import com.nhaarman.mockitokotlin2.whenever
import depictedItem
import fr.free.nrw.commons.explore.paging.LiveDataConverter
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
import io.reactivex.Observable
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class PageableParentDepictionsDataSourceTest {
@Mock
lateinit var okHttpJsonApiClient: OkHttpJsonApiClient
@Mock
lateinit var liveDataConverter: LiveDataConverter
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
@Test
fun `loadFunction loads from api`() {
val dataSource =
PageableParentDepictionsDataSource(liveDataConverter, okHttpJsonApiClient)
dataSource.onQueryUpdated("test")
whenever(okHttpJsonApiClient.getParentDepictions("test", 0, 1))
.thenReturn(Observable.just(listOf(depictedItem())))
assertThat(dataSource.loadFunction(1, 0), `is`(listOf(depictedItem())))
}
}