#3810 Convert DepictedImagesFragment to use Pagination (#3815)

* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchDepictionsRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadCategoryDepictionsRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - update BaseAdapter to be easier to use

* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchImagesRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchCategoriesRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace NotificationRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadDepictsRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace PlaceRenderer

* #3756 Convert SearchDepictionsFragment to use Pagination - convert SearchDepictionsFragment

* #3756 Convert SearchDepictionsFragment to use Pagination - fix presenter unit tests now that view is not nullable - fix Category prefix imports

* #3756 Convert SearchDepictionsFragment to use Pagination - test DataSource related classes

* #3756 Convert SearchDepictionsFragment to use Pagination - reset rx scheduler - ignore failing test

* #3760 Convert SearchCategoriesFragment to use Pagination - extract functionality of pagination to base classes - add category pagination

* #3772 Convert SearchImagesFragment to use Pagination  - convert SearchImagesFragment - tidy up showing the empty view - make search fragments show snackbar with appropriate text

* #3772 Convert SearchImagesFragment to use Pagination  - allow viewpager to load more data

* #3760 remove test that got re-added by merge

* #3760 remove duplicate dependency

* #3772 fix compilation

* #3780 Create media using a combination of Entities & MwQueryResult - construct media with an entity - move fields from media down to contribution - move dynamic fields outside of media - remove unused constructors - remove all unnecessary fetching of captions/descriptions - bump database version

* #3808 Construct media objects that depict an item id correctly - use generator to construct media for DepictedImages

* #3810 Convert DepictedImagesFragment to use Pagination - extract common media paging methods - convert to DepictedImages to use pagination

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

* #3810 Convert DepictedImagesFragment to use Pagination - map to empty result with no pages

* #3810 Convert DepictedImagesFragment to use Pagination - align test with returned values

* #3780 Create media using a combination of Entities & MwQueryResult - update wikicode to align with expected behaviour

* #3780 Create media using a combination of Entities & MwQueryResult - replace old site of thumbnail title with most relevant caption
This commit is contained in:
Seán Mac Gillicuddy 2020-06-25 09:02:51 +01:00 committed by GitHub
parent 4b22583b60
commit 34ab6f581b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 306 additions and 987 deletions

View file

@ -1,63 +0,0 @@
package fr.free.nrw.commons.depictions
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.depictions.Media.DepictedImagesFragment
import fr.free.nrw.commons.depictions.Media.DepictedImagesPresenter
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.media.MediaClient
import io.reactivex.Single
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 DepictedImagesPresenterTest {
@Mock
internal lateinit var view: DepictedImagesFragment
lateinit var depictedImagesPresenter: DepictedImagesPresenter
@Mock
lateinit var jsonKvStore: JsonKvStore
@Mock
lateinit var mediaClient: MediaClient
lateinit var testScheduler: TestScheduler
val mediaList: ArrayList<Media> = ArrayList()
@Mock
lateinit var mediaItem: Media
var testSingle: Single<List<Media>>? = null
@Before
@Throws(Exception::class)
fun setUp() {
MockitoAnnotations.initMocks(this)
testScheduler = TestScheduler()
mediaList.add(mediaItem)
testSingle = Single.just(mediaList)
depictedImagesPresenter = DepictedImagesPresenter(jsonKvStore,
mediaClient, testScheduler, testScheduler)
depictedImagesPresenter.onAttachView(view)
}
@Test
fun initList() {
Mockito.`when`(
mediaClient.fetchImagesForDepictedItem(ArgumentMatchers.anyString(),
ArgumentMatchers.anyInt())
).thenReturn(testSingle)
depictedImagesPresenter.initList("rabbit")
depictedImagesPresenter.handleSuccess(mediaList)
verify(view)?.handleSuccess(mediaList)
}
}

View file

@ -0,0 +1,21 @@
package fr.free.nrw.commons.depictions.Media
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.media.MediaClient
import io.reactivex.Single
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.junit.Test
class PageableDepictedMediaDataSourceTest{
@Test
fun `loadFunction loads Media`() {
val mediaClient = mock<MediaClient>()
whenever(mediaClient.fetchImagesForDepictedItem("test",0,1))
.thenReturn(Single.just(emptyList()))
val pageableDepictedMediaDataSource = PageableDepictedMediaDataSource(mock(), mediaClient)
pageableDepictedMediaDataSource.onQueryUpdated("test")
assertThat(pageableDepictedMediaDataSource.loadFunction(0,1), `is`(emptyList()))
}
}

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
}
}

View file

@ -139,7 +139,7 @@ class MediaClientTest {
`when`(mediaInterface!!.getMedia(ArgumentMatchers.anyString()))
.thenReturn(Single.just(mockResponse))
mediaClient!!.getMedia("abcde").test().assertErrorMessage("empty list passed for ids")
mediaClient!!.getMedia("abcde").test().assertErrorMessage("List is empty.")
}
@Test