diff --git a/app/src/main/java/fr/free/nrw/commons/explore/depictions/DepictsClient.kt b/app/src/main/java/fr/free/nrw/commons/explore/depictions/DepictsClient.kt index 14e674744..13b7d1cd3 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/depictions/DepictsClient.kt +++ b/app/src/main/java/fr/free/nrw/commons/explore/depictions/DepictsClient.kt @@ -1,9 +1,10 @@ package fr.free.nrw.commons.explore.depictions +import fr.free.nrw.commons.mwapi.Binding import fr.free.nrw.commons.mwapi.SparqlResponse import fr.free.nrw.commons.upload.depicts.DepictsInterface import fr.free.nrw.commons.upload.structure.depictions.DepictedItem -import io.reactivex.Observable +import fr.free.nrw.commons.wikidata.model.DepictSearchItem import io.reactivex.Single import org.wikipedia.wikidata.Entities import java.util.* @@ -14,9 +15,7 @@ import javax.inject.Singleton * Depicts Client to handle custom calls to Commons Wikibase APIs */ @Singleton -class DepictsClient @Inject constructor( - private val depictsInterface: DepictsInterface -) { +class DepictsClient @Inject constructor(private val depictsInterface: DepictsInterface) { /** * Search for depictions using the search item @@ -25,22 +24,21 @@ class DepictsClient @Inject constructor( fun searchForDepictions(query: String?, limit: Int, offset: Int): Single> { val language = Locale.getDefault().language return depictsInterface.searchForDepicts(query, "$limit", language, language, "$offset") - .map { it.search.joinToString("|") { searchItem -> searchItem.id } } - .flatMap(::getEntities) - .map { it.entities().values.map(::DepictedItem) } + .map { it.search.joinToString("|", transform = DepictSearchItem::id) } + .mapToDepictions() } fun getEntities(ids: String): Single { return depictsInterface.getEntities(ids) } - fun toDepictions(sparqlResponse: Observable): Observable> { + fun toDepictions(sparqlResponse: Single): Single> { return sparqlResponse.map { - it.results.bindings.joinToString("|") { binding -> - binding.id - } - } - .flatMap { getEntities(it).toObservable() } - .map { it.entities().values.map(::DepictedItem) } + it.results.bindings.joinToString("|", transform = Binding::id) + }.mapToDepictions() } + + private fun Single.mapToDepictions() = + flatMap(::getEntities) + .map { it.entities().values.map(::DepictedItem) } } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSource.kt b/app/src/main/java/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSource.kt index 2fb549f28..c189a2e0a 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSource.kt +++ b/app/src/main/java/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSource.kt @@ -11,7 +11,7 @@ class PageableChildDepictionsDataSource @Inject constructor( private val okHttpJsonApiClient: OkHttpJsonApiClient ) : PageableBaseDataSource(liveDataConverter) { override val loadFunction = { limit: Int, startPosition: Int -> - okHttpJsonApiClient.getChildDepictions(query, startPosition, limit).blockingFirst() + okHttpJsonApiClient.getChildDepictions(query, startPosition, limit).blockingGet() } } diff --git a/app/src/main/java/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSource.kt b/app/src/main/java/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSource.kt index e2459bf66..8771adbfa 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSource.kt +++ b/app/src/main/java/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSource.kt @@ -11,7 +11,7 @@ class PageableParentDepictionsDataSource @Inject constructor( private val okHttpJsonApiClient: OkHttpJsonApiClient ) : PageableBaseDataSource(liveDataConverter) { override val loadFunction = { limit: Int, startPosition: Int -> - okHttpJsonApiClient.getParentDepictions(query, startPosition, limit).blockingFirst() + okHttpJsonApiClient.getParentDepictions(query, startPosition, limit).blockingGet() } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java index 1d010e00a..21435116c 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java @@ -209,7 +209,7 @@ public class OkHttpJsonApiClient { * Get the QIDs of all Wikidata items that are subclasses of the given Wikidata item. Example: * bridge -> suspended bridge, aqueduct, etc */ - public Observable> getChildDepictions(String qid, int startPosition, + public Single> getChildDepictions(String qid, int startPosition, int limit) throws IOException { return depictedItemsFrom(sparqlQuery(qid, startPosition, limit,"/queries/subclasses_query.rq")); } @@ -218,14 +218,14 @@ public class OkHttpJsonApiClient { * Get the QIDs of all Wikidata items that are subclasses of the given Wikidata item. Example: * bridge -> suspended bridge, aqueduct, etc */ - public Observable> getParentDepictions(String qid, int startPosition, + public Single> getParentDepictions(String qid, int startPosition, int limit) throws IOException { return depictedItemsFrom(sparqlQuery(qid, startPosition, limit, "/queries/parentclasses_query.rq")); } - private Observable> depictedItemsFrom(Request request) { - return depictsClient.toDepictions(Observable.fromCallable(() -> { + private Single> depictedItemsFrom(Request request) { + return depictsClient.toDepictions(Single.fromCallable(() -> { try (ResponseBody body = okHttpClient.newCall(request).execute().body()) { return gson.fromJson(body.string(), SparqlResponse.class); } diff --git a/app/src/test/kotlin/ModelFunctions.kt b/app/src/test/kotlin/ModelFunctions.kt index 684cab3ac..3e39ead37 100644 --- a/app/src/test/kotlin/ModelFunctions.kt +++ b/app/src/test/kotlin/ModelFunctions.kt @@ -7,6 +7,7 @@ import fr.free.nrw.commons.nearby.Label import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.Sitelinks import fr.free.nrw.commons.upload.structure.depictions.DepictedItem +import fr.free.nrw.commons.wikidata.model.DepictSearchItem import org.wikipedia.wikidata.* import java.util.* @@ -63,6 +64,14 @@ fun media( depictionIds ) +fun depictSearchItem( + id: String = "id", + pageId: String = "pageid", + url: String = "url", + label: String = "label", + description: String = "description" +) = DepictSearchItem(id, pageId, url, label, description) + fun place( name: String = "name", label: Label? = null, diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/DepictsClientTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/DepictsClientTest.kt new file mode 100644 index 000000000..237fb49f4 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/DepictsClientTest.kt @@ -0,0 +1,69 @@ +package fr.free.nrw.commons.explore.depictions + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import depictSearchItem +import fr.free.nrw.commons.mwapi.Binding +import fr.free.nrw.commons.mwapi.Result +import fr.free.nrw.commons.mwapi.SparqlResponse +import fr.free.nrw.commons.upload.depicts.DepictsInterface +import fr.free.nrw.commons.wikidata.model.DepictSearchResponse +import io.reactivex.Single +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.wikipedia.wikidata.Entities + +class DepictsClientTest { + + @Mock + private lateinit var depictsInterface: DepictsInterface + private lateinit var depictsClient: DepictsClient + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + depictsClient = DepictsClient(depictsInterface) + } + + @Test + fun searchForDepictions() { + val depictSearchResponse = mock() + whenever(depictsInterface.searchForDepicts("query", "1", "en", "en", "0")) + .thenReturn(Single.just(depictSearchResponse)) + whenever(depictSearchResponse.search).thenReturn(listOf(depictSearchItem("1"),depictSearchItem("2"))) + val entities = mock() + whenever(depictsInterface.getEntities("1|2")).thenReturn(Single.just(entities)) + whenever(entities.entities()).thenReturn(emptyMap()) + depictsClient.searchForDepictions("query", 1, 0) + .test() + .assertValue(emptyList()) + } + + + @Test + fun getEntities() { + val entities = mock() + whenever(depictsInterface.getEntities("ids")).thenReturn(Single.just(entities)) + depictsClient.getEntities("ids").test().assertValue(entities) + } + + @Test + fun toDepictions() { + val sparqlResponse = mock() + val result = mock() + whenever(sparqlResponse.results).thenReturn(result) + val binding1 = mock() + val binding2 = mock() + whenever(result.bindings).thenReturn(listOf(binding1, binding2)) + whenever(binding1.id).thenReturn("1") + whenever(binding2.id).thenReturn("2") + val entities = mock() + whenever(depictsInterface.getEntities("1|2")).thenReturn(Single.just(entities)) + whenever(entities.entities()).thenReturn(emptyMap()) + depictsClient.toDepictions(Single.just(sparqlResponse)) + .test() + .assertValue(emptyList()) + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSourceTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSourceTest.kt index 9300bb9fa..6230c1620 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSourceTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/child/PageableChildDepictionsDataSourceTest.kt @@ -1,11 +1,10 @@ package fr.free.nrw.commons.explore.depictions.child -import com.nhaarman.mockitokotlin2.verifyZeroInteractions 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 io.reactivex.Single import org.hamcrest.CoreMatchers.`is` import org.hamcrest.MatcherAssert.assertThat import org.junit.Before @@ -30,7 +29,7 @@ class PageableChildDepictionsDataSourceTest { PageableChildDepictionsDataSource(liveDataConverter, okHttpJsonApiClient) dataSource.onQueryUpdated("test") whenever(okHttpJsonApiClient.getChildDepictions("test", 0, 1)) - .thenReturn(Observable.just(listOf(depictedItem()))) + .thenReturn(Single.just(listOf(depictedItem()))) assertThat(dataSource.loadFunction(1, 0), `is`(listOf(depictedItem()))) } } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSourceTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSourceTest.kt index 7e1346854..16972c1dd 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSourceTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/explore/depictions/parent/PageableParentDepictionsDataSourceTest.kt @@ -4,7 +4,7 @@ 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 io.reactivex.Single import org.hamcrest.CoreMatchers.`is` import org.hamcrest.MatcherAssert.assertThat import org.junit.Before @@ -30,7 +30,7 @@ class PageableParentDepictionsDataSourceTest { PageableParentDepictionsDataSource(liveDataConverter, okHttpJsonApiClient) dataSource.onQueryUpdated("test") whenever(okHttpJsonApiClient.getParentDepictions("test", 0, 1)) - .thenReturn(Observable.just(listOf(depictedItem()))) + .thenReturn(Single.just(listOf(depictedItem()))) assertThat(dataSource.loadFunction(1, 0), `is`(listOf(depictedItem()))) } }