diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaClient.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaClient.kt index 02b28ff36..0db413466 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaClient.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaClient.kt @@ -107,21 +107,6 @@ class MediaClient @Inject constructor( ) } - private fun mediaFromPageAndEntity(pages: List): Single> { - return if (pages.isEmpty()) - Single.just(emptyList()) - else - getEntities(pages.map { "$PAGE_ID_PREFIX${it.pageId()}" }) - .map { - pages.zip(it.entities().values) - .mapNotNull { (page, entity) -> - page.imageInfo()?.let { - mediaConverter.convert(page, entity, it) - } - } - } - } - /** * Fetches Media object from the imageInfo API * @@ -141,7 +126,6 @@ class MediaClient @Inject constructor( fun getPictureOfTheDay(): Single { val date = CommonsDateUtil.getIso8601DateFormatShort().format(Date()) return responseMapper(mediaInterface.getMediaWithGenerator("Template:Potd/$date")).map { it.first() } - } fun getPageHtml(title: String?): Single { @@ -156,7 +140,6 @@ class MediaClient @Inject constructor( mediaDetailInterface.getEntity(entityIds.joinToString("|")) } - fun doesPageContainMedia(title: String?): Single { return pageMediaInterface.getMediaList(title) .map { it.items.isNotEmpty() } @@ -175,4 +158,19 @@ class MediaClient @Inject constructor( it.query()?.pages() ?: emptyList() }.flatMap(::mediaFromPageAndEntity) } + + private fun mediaFromPageAndEntity(pages: List): Single> { + return if (pages.isEmpty()) + Single.just(emptyList()) + else + getEntities(pages.map { "$PAGE_ID_PREFIX${it.pageId()}" }) + .map { + pages.zip(it.entities().values) + .mapNotNull { (page, entity) -> + page.imageInfo()?.let { + mediaConverter.convert(page, entity, it) + } + } + } + } } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/media/MediaClientTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/media/MediaClientTest.kt index 8c39e6e9d..46d401a3e 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/media/MediaClientTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/media/MediaClientTest.kt @@ -4,266 +4,231 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever import fr.free.nrw.commons.Media import fr.free.nrw.commons.explore.media.MediaConverter -import fr.free.nrw.commons.media.model.PageMediaListItem import fr.free.nrw.commons.media.model.PageMediaListResponse -import fr.free.nrw.commons.utils.CommonsDateUtil import io.reactivex.Single -import junit.framework.Assert.* +import media import org.junit.Before import org.junit.Test -import org.mockito.* -import org.mockito.Mockito.* -import org.wikipedia.dataclient.mwapi.ImageDetails +import org.mockito.ArgumentMatchers +import org.mockito.Mock +import org.mockito.MockitoAnnotations import org.wikipedia.dataclient.mwapi.MwQueryPage import org.wikipedia.dataclient.mwapi.MwQueryResponse import org.wikipedia.dataclient.mwapi.MwQueryResult import org.wikipedia.gallery.ImageInfo import org.wikipedia.wikidata.Entities -import java.util.* class MediaClientTest { @Mock - internal var mediaInterface: MediaInterface? = null - @Mock - internal var mediaConverter: MediaConverter? = null - @Mock - internal var mediaDetailInterface: MediaDetailInterface? = null + internal lateinit var mediaInterface: MediaInterface @Mock - internal var pageMediaInterface: PageMediaInterface? = null + internal lateinit var mediaConverter: MediaConverter + @Mock + internal lateinit var mediaDetailInterface: MediaDetailInterface - @InjectMocks - var mediaClient: MediaClient? = null + @Mock + internal lateinit var pageMediaInterface: PageMediaInterface + + val continuationMap = mapOf("continuation" to "continuation") + + private lateinit var mediaClient: MediaClient @Before @Throws(Exception::class) fun setUp() { MockitoAnnotations.initMocks(this) + mediaClient = + MediaClient(mediaInterface, pageMediaInterface, mediaDetailInterface, mediaConverter) } @Test - fun checkPageExistsUsingTitle() { - val mwQueryPage = mock(MwQueryPage::class.java) - `when`(mwQueryPage.pageId()).thenReturn(10) - val mwQueryResult = mock(MwQueryResult::class.java) - `when`(mwQueryResult.firstPage()).thenReturn(mwQueryPage) - `when`(mwQueryResult.pages()).thenReturn(listOf(mwQueryPage)) - val mockResponse = mock(MwQueryResponse::class.java) - `when`(mockResponse.query()).thenReturn(mwQueryResult) - - `when`(mediaInterface!!.checkPageExistsUsingTitle(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - val checkPageExistsUsingTitle = - mediaClient!!.checkPageExistsUsingTitle("File:Test.jpg").blockingGet() - assertTrue(checkPageExistsUsingTitle) + fun `getMediaById maps response of interface`() { + val (mwQueryResponse, media) = expectSuccessfulMapping() + whenever(mediaInterface.getMediaById("id")).thenReturn(Single.just(mwQueryResponse)) + mediaClient.getMediaById("id").test().assertValue(media) } @Test - fun checkPageNotExistsUsingTitle() { - val mwQueryPage = mock(MwQueryPage::class.java) - `when`(mwQueryPage.pageId()).thenReturn(0) - val mwQueryResult = mock(MwQueryResult::class.java) - `when`(mwQueryResult.firstPage()).thenReturn(mwQueryPage) - `when`(mwQueryResult.pages()).thenReturn(listOf()) - val mockResponse = mock(MwQueryResponse::class.java) - `when`(mockResponse.query()).thenReturn(mwQueryResult) - - `when`(mediaInterface!!.checkPageExistsUsingTitle(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - val checkPageExistsUsingTitle = - mediaClient!!.checkPageExistsUsingTitle("File:Test.jpg").blockingGet() - assertFalse(checkPageExistsUsingTitle) + fun `checkPageExistsUsingTitle returns true for greater than 0 id`() { + val mwQueryResponse = expectResponseWithPageId(1) + whenever(mediaInterface.checkPageExistsUsingTitle("")) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.checkPageExistsUsingTitle("").test().assertValue(true) } @Test - fun checkFileExistsUsingSha() { - val mwQueryPage = mock(MwQueryPage::class.java) - val mwQueryResult = mock(MwQueryResult::class.java) - `when`(mwQueryResult.allImages()).thenReturn(listOf(mock(ImageDetails::class.java))) - `when`(mwQueryResult.firstPage()).thenReturn(mwQueryPage) - `when`(mwQueryResult.pages()).thenReturn(listOf(mwQueryPage)) - val mockResponse = mock(MwQueryResponse::class.java) - `when`(mockResponse.query()).thenReturn(mwQueryResult) - - `when`(mediaInterface!!.checkFileExistsUsingSha(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - val checkFileExistsUsingSha = mediaClient!!.checkFileExistsUsingSha("abcde").blockingGet() - assertTrue(checkFileExistsUsingSha) + fun `checkPageExistsUsingTitle returns false for 0 id`() { + val mwQueryResponse = expectResponseWithPageId(0) + whenever(mediaInterface.checkPageExistsUsingTitle("")) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.checkPageExistsUsingTitle("").test().assertValue(false) } @Test - fun checkFileNotExistsUsingSha() { - val mwQueryPage = mock(MwQueryPage::class.java) - val mwQueryResult = mock(MwQueryResult::class.java) - `when`(mwQueryResult.allImages()).thenReturn(listOf()) - `when`(mwQueryResult.firstPage()).thenReturn(mwQueryPage) - `when`(mwQueryResult.pages()).thenReturn(listOf(mwQueryPage)) - val mockResponse = mock(MwQueryResponse::class.java) - `when`(mockResponse.query()).thenReturn(mwQueryResult) - - `when`(mediaInterface!!.checkFileExistsUsingSha(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - val checkFileExistsUsingSha = mediaClient!!.checkFileExistsUsingSha("abcde").blockingGet() - assertFalse(checkFileExistsUsingSha) + fun `checkFileExistsUsingSha returns false with no Images`() { + val mwQueryResponse = mockQuery { + whenever(allImages()).thenReturn(listOf()) + } + whenever(mediaInterface.checkFileExistsUsingSha("")) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.checkFileExistsUsingSha("").test().assertValue(false) } @Test - fun getMedia() { - val (mockResponse, media: Media) = expectGetEntitiesAndMediaConversion() - - `when`(mediaInterface!!.getMedia(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - mediaClient!!.getMedia("abcde").test().assertValue(media) + fun `checkFileExistsUsingSha returns true with Images`() { + val mwQueryResponse = mockQuery { + whenever(allImages()).thenReturn(listOf(mock())) + } + whenever(mediaInterface.checkFileExistsUsingSha("")) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.checkFileExistsUsingSha("").test().assertValue(true) } @Test - fun getMediaNull() { - val imageInfo = ImageInfo() + fun `getMediaListFromCategory is continuable and returns mapped response`() { + val (mwQueryResponse, media) = expectSuccessfulMapping(continuationMap) + whenever(mediaInterface.getMediaListFromCategory("", 10, emptyMap())) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.getMediaListFromCategory("").test().assertValues(listOf(media)) - val mwQueryPage = mock(MwQueryPage::class.java) - `when`(mwQueryPage.title()).thenReturn("Test") - `when`(mwQueryPage.imageInfo()).thenReturn(imageInfo) + whenever(mediaInterface.getMediaListFromCategory("", 10, continuationMap)) + .thenReturn(Single.error(Exception())) + mediaClient.getMediaListFromCategory("").test().assertError { true } - val mwQueryResult = mock(MwQueryResult::class.java) - `when`(mwQueryResult.firstPage()).thenReturn(null) - val mockResponse = mock(MwQueryResponse::class.java) - `when`(mockResponse.query()).thenReturn(mwQueryResult) - - `when`(mediaInterface!!.getMedia(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - mediaClient!!.getMedia("abcde").test().assertErrorMessage("List is empty.") + mediaClient.resetCategoryContinuation("") + val (resetMwQueryResponse, resetMedia)=expectSuccessfulMapping() + whenever(mediaInterface.getMediaListFromCategory("", 10, emptyMap())) + .thenReturn(Single.just(resetMwQueryResponse)) + mediaClient.getMediaListFromCategory("").test().assertValues(listOf(resetMedia)) } @Test - fun getPictureOfTheDay() { - val template = "Template:Potd/" + CommonsDateUtil.getIso8601DateFormatShort().format(Date()) - - val (mockResponse, media: Media) = expectGetEntitiesAndMediaConversion() - `when`(mediaInterface!!.getMediaWithGenerator(template)) - .thenReturn(Single.just(mockResponse)) - mediaClient!!.getPictureOfTheDay().test().assertValue(media) + fun `getMediaListForUser is continuable and returns mapped response`() { + val (mwQueryResponse, media) = expectSuccessfulMapping(null) + whenever(mediaInterface.getMediaListForUser("", 10, emptyMap())) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.getMediaListForUser("").test().assertValues(listOf(media)) + mediaClient.getMediaListForUser("").test().assertValue(emptyList()) } - private fun expectGetEntitiesAndMediaConversion(): Pair { - val mockResponse = mock(MwQueryResponse::class.java) - val queryResult: MwQueryResult = mock() - whenever(mockResponse.query()).thenReturn(queryResult) - val queryPage: MwQueryPage = mock() - whenever(queryResult.pages()).thenReturn(listOf(queryPage)) - whenever(queryPage.pageId()).thenReturn(0) - val entities: Entities = mock() - whenever(mediaDetailInterface!!.getEntity("M0")).thenReturn(Single.just(entities)) - val entity: Entities.Entity = mock() - whenever(entities.entities()).thenReturn(mapOf("id" to entity)) - val media: Media = mock() + @Test + fun `getMediaListFromSearch returns mapped response`() { + val (mwQueryResponse, media) = expectSuccessfulMapping() + whenever(mediaInterface.getMediaListFromSearch("", 0, 1)) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.getMediaListFromSearch("", 0, 1) + .test() + .assertValues(listOf(media)) + } + + @Test + fun `fetchImagesForDepictedItem returns mapped response`() { + val (mwQueryResponse, media) = expectSuccessfulMapping() + whenever(mediaInterface.fetchImagesForDepictedItem("haswbstatement:P180=", "0", "1")) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.fetchImagesForDepictedItem("", 0, 1) + .test() + .assertValues(listOf(media)) + } + + @Test + fun `getMedia returns mapped response`() { + val (mwQueryResponse, media) = expectSuccessfulMapping() + whenever(mediaInterface.getMedia("")).thenReturn(Single.just(mwQueryResponse)) + mediaClient.getMedia("").test().assertValues(media) + } + + @Test + fun `getPictureOfTheDay returns mapped response`() { + val (mwQueryResponse, media) = expectSuccessfulMapping() + whenever(mediaInterface.getMediaWithGenerator(ArgumentMatchers.startsWith("Template:Potd/"))) + .thenReturn(Single.just(mwQueryResponse)) + mediaClient.getPictureOfTheDay().test().assertValues(media) + } + + @Test + fun `getPageHtml with null parse result returns empty`() { + val mwParseResponse = mock() + whenever(mediaInterface.getPageHtml("")).thenReturn(Single.just(mwParseResponse)) + whenever(mwParseResponse.parse()).thenReturn(null) + mediaClient.getPageHtml("").test().assertValues("") + } + + @Test + fun `getPageHtml with parse result returns text`() { + val mwParseResponse = mock() + whenever(mediaInterface.getPageHtml("")).thenReturn(Single.just(mwParseResponse)) + val mwParseResult = mock() + whenever(mwParseResponse.parse()).thenReturn(mwParseResult) + whenever(mwParseResult.text()).thenReturn("text") + mediaClient.getPageHtml("").test().assertValues("text") + } + + @Test + fun `getEntities throws exception for empty ids`() { + mediaClient.getEntities(emptyList()).test().assertErrorMessage("empty list passed for ids") + } + + @Test + fun `getEntities invokes interface with non empty ids`() { + val entities = mock() + whenever(mediaDetailInterface.getEntity("1|2")).thenReturn(Single.just(entities)) + mediaClient.getEntities(listOf("1","2")).test().assertValue(entities) + } + + @Test + fun `doesPageContainMedia returns false for empty items`() { + val pageMediaListResponse = mock() + whenever(pageMediaInterface.getMediaList("")) + .thenReturn(Single.just(pageMediaListResponse)) + whenever(pageMediaListResponse.items).thenReturn(emptyList()) + mediaClient.doesPageContainMedia("").test().assertValue(false) + } + + @Test + fun `doesPageContainMedia returns true for non empty items`() { + val pageMediaListResponse = mock() + whenever(pageMediaInterface.getMediaList("")) + .thenReturn(Single.just(pageMediaListResponse)) + whenever(pageMediaListResponse.items).thenReturn(listOf(mock())) + mediaClient.doesPageContainMedia("").test().assertValue(true) + } + + private fun mockQuery(queryReceiver: MwQueryResult.() -> Unit): MwQueryResponse { + val mwQueryResponse = mock() + val mwQueryResult = mock() + whenever(mwQueryResponse.query()).thenReturn(mwQueryResult) + mwQueryResult.queryReceiver() + return mwQueryResponse + } + + private fun expectResponseWithPageId(expectedId: Int): MwQueryResponse { + return mockQuery { + val mwQueryPage = mock() + whenever(firstPage()).thenReturn(mwQueryPage) + whenever(mwQueryPage.pageId()).thenReturn(expectedId) + } + } + + private fun expectSuccessfulMapping(continuationMap: Map? = emptyMap()): Pair { + val media = media() + val mwQueryPage = mock() + val mwQueryResponse = mockQuery { + whenever(pages()).thenReturn(listOf(mwQueryPage, mwQueryPage)) + whenever(mwQueryPage.pageId()).thenReturn(1, 2) + } + whenever(mwQueryResponse.continuation()).thenReturn(continuationMap) + val entities = mock() + whenever(mediaDetailInterface.getEntity("M1|M2")).thenReturn(Single.just(entities)) + val entity = mock() + whenever(entities.entities()).thenReturn(mapOf("a" to entity, "b" to entity)) val imageInfo = mock() - whenever(queryPage.imageInfo()).thenReturn(imageInfo) - whenever(mediaConverter!!.convert(queryPage, entity, imageInfo)).thenReturn(media) - return Pair(mockResponse, media) - } - - @Captor - private val continuationCaptor: ArgumentCaptor>? = null - - @Test - fun getMediaListFromCategoryTwice() { - val mockContinuation = mapOf(Pair("gcmcontinue", "test")) - - val (mockResponse, media: Media) = expectGetEntitiesAndMediaConversion() - `when`(mockResponse.continuation()).thenReturn(mockContinuation) - - `when`( - mediaInterface!!.getMediaListFromCategory( - ArgumentMatchers.anyString(), ArgumentMatchers.anyInt(), - continuationCaptor!!.capture() - ) - ) - .thenReturn(Single.just(mockResponse)) - - val media1 = mediaClient!!.getMediaListFromCategory("abcde").blockingGet().get(0) - val media2 = mediaClient!!.getMediaListFromCategory("abcde").blockingGet().get(0) - - assertEquals(continuationCaptor.allValues[0], emptyMap()) - assertEquals(continuationCaptor.allValues[1], mockContinuation) - - assertEquals(media1, media) - assertEquals(media2, media) - } - - @Test - fun getMediaListForUser() { - val mockContinuation = mapOf("gcmcontinue" to "test") - - val (mockResponse, media: Media) = expectGetEntitiesAndMediaConversion() - whenever(mockResponse.continuation()).thenReturn(mockContinuation) - - whenever( - mediaInterface!!.getMediaListForUser( - ArgumentMatchers.anyString(), ArgumentMatchers.anyInt(), - continuationCaptor!!.capture() - ) - ) - .thenReturn(Single.just(mockResponse)) - val media1 = mediaClient!!.getMediaListForUser("Test").blockingGet().get(0) - val media2 = mediaClient!!.getMediaListForUser("Test").blockingGet().get(0) - - verify(mediaInterface, times(2))?.getMediaListForUser( - ArgumentMatchers.anyString(), - ArgumentMatchers.anyInt(), ArgumentMatchers.anyMap() - ) - } - - @Test - fun getPageHtmlTest() { - val mwParseResult = mock(MwParseResult::class.java) - - `when`(mwParseResult.text()).thenReturn("Test") - - val mockResponse = MwParseResponse() - mockResponse.setParse(mwParseResult) - - `when`(mediaInterface!!.getPageHtml(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - assertEquals("Test", mediaClient!!.getPageHtml("abcde").blockingGet()) - } - - @Test - fun doesPageContainMedia() { - val mock = mock(PageMediaListResponse::class.java) - whenever(mock.items).thenReturn(listOf(mock(PageMediaListItem::class.java))) - `when`(pageMediaInterface!!.getMediaList(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mock)) - - mediaClient!!.doesPageContainMedia("Test").test().assertValue(true) - } - - @Test - fun doesPageContainMediaWithNoMedia() { - val mock = mock(PageMediaListResponse::class.java) - whenever(mock.items).thenReturn(listOf()) - `when`(pageMediaInterface!!.getMediaList(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mock)) - - mediaClient!!.doesPageContainMedia("Test").test().assertValue(false) - } - - @Test - fun getPageHtmlTestNull() { - val mockResponse = MwParseResponse() - mockResponse.setParse(null) - - `when`(mediaInterface!!.getPageHtml(ArgumentMatchers.anyString())) - .thenReturn(Single.just(mockResponse)) - - assertEquals("", mediaClient!!.getPageHtml("abcde").blockingGet()) + whenever(mwQueryPage.imageInfo()).thenReturn(imageInfo, null) + whenever(mediaConverter.convert(mwQueryPage, entity, imageInfo)).thenReturn(media) + return Pair(mwQueryResponse, media) } }