Fixes 4539 : When Wikidata has no description showing instance_of's label as a description (#4799)

* Showing instance_of's name as a description

* Indentation fixed

* DepictsClient Test added
This commit is contained in:
Ayan Sarkar 2022-02-16 10:49:27 +05:30 committed by GitHub
parent c2bc5b4f23
commit 27e3f20ba2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 8 deletions

View file

@ -1,12 +1,17 @@
package fr.free.nrw.commons.explore.depictions
import android.annotation.SuppressLint
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 fr.free.nrw.commons.upload.structure.depictions.get
import fr.free.nrw.commons.wikidata.WikidataProperties
import fr.free.nrw.commons.wikidata.model.DepictSearchItem
import io.reactivex.Single
import org.wikipedia.wikidata.DataValue
import org.wikipedia.wikidata.Entities
import org.wikipedia.wikidata.Statement_partial
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@ -38,7 +43,50 @@ class DepictsClient @Inject constructor(private val depictsInterface: DepictsInt
}.mapToDepictions()
}
/**
* Fetches Entities from ids ex. "Q1233|Q546" and converts them into DepictedItem
*/
@SuppressLint("CheckResult")
private fun Single<String>.mapToDepictions() =
flatMap(::getEntities)
.map { it.entities().values.map(::DepictedItem) }
.map { entities ->
entities.entities().values.map { entity ->
if (entity.descriptions().byLanguageOrFirstOrEmpty() == "") {
val entities: Entities = getEntities(entity[WikidataProperties.INSTANCE_OF]
.toIds()[0]).blockingGet()
val nameAsDescription = entities.entities().values.first().labels()
.byLanguageOrFirstOrEmpty()
DepictedItem(
entity,
entity.labels().byLanguageOrFirstOrEmpty(),
nameAsDescription
)
} else {
DepictedItem(
entity,
entity.labels().byLanguageOrFirstOrEmpty(),
entity.descriptions().byLanguageOrFirstOrEmpty()
)
}
}
}
/**
* Tries to get Entities.Label by default language from the map.
* If that returns null, Tries to retrieve first element from the map.
* If that still returns null, function returns "".
*/
private fun Map<String, Entities.Label>.byLanguageOrFirstOrEmpty() =
let {
it[Locale.getDefault().language] ?: it.values.firstOrNull() }?.value() ?: ""
/**
* returns list of id ex. "Q2323" from Statement_partial
*/
private fun List<Statement_partial>?.toIds(): List<String> {
return this?.map { it.mainSnak.dataValue }
?.filterIsInstance<DataValue.EntityId>()
?.map { it.value.id }
?: emptyList()
}
}

View file

@ -46,7 +46,7 @@ data class DepictedItem constructor(
place.longDescription
)
private constructor(entity: Entities.Entity, name: String, description: String) : this(
constructor(entity: Entities.Entity, name: String, description: String) : this(
name,
description,
entity[IMAGE].primaryImageValue?.let {

View file

@ -7,14 +7,14 @@ 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.upload.structure.depictions.DepictedItem
import fr.free.nrw.commons.wikidata.model.DepictSearchResponse
import io.reactivex.Single
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.wikipedia.wikidata.Entities
import org.wikipedia.wikidata.*
class DepictsClientTest {
@ -29,7 +29,6 @@ class DepictsClientTest {
}
@Test
@Ignore()
fun searchForDepictions() {
val depictSearchResponse = mock<DepictSearchResponse>()
whenever(depictsInterface.searchForDepicts("query", "1", "en", "en", "0"))
@ -52,7 +51,7 @@ class DepictsClientTest {
}
@Test
fun toDepictions() {
fun `Test toDepictions when description is empty`() {
val sparqlResponse = mock<SparqlResponse>()
val result = mock<Result>()
whenever(sparqlResponse.results).thenReturn(result)
@ -62,10 +61,51 @@ class DepictsClientTest {
whenever(binding1.id).thenReturn("1")
whenever(binding2.id).thenReturn("2")
val entities = mock<Entities>()
val entity = mock<Entities.Entity>()
val statementPartial = mock<Statement_partial>()
whenever(depictsInterface.getEntities("1|2")).thenReturn(Single.just(entities))
whenever(entities.entities()).thenReturn(emptyMap())
whenever(entities.entities()).thenReturn(mapOf("en" to entity))
whenever(entity.statements).thenReturn(mapOf("P31" to listOf(statementPartial)))
whenever(statementPartial.mainSnak).thenReturn(
Snak_partial("test", "P31",
DataValue.EntityId(
WikiBaseEntityValue("wikibase-entityid", "Q10", 10L)
)
)
)
whenever(depictsInterface.getEntities("Q10")).thenReturn(Single.just(entities))
whenever(entity.id()).thenReturn("Q10")
depictsClient.toDepictions(Single.just(sparqlResponse))
.test()
.assertValue(emptyList())
.assertValue(listOf(
DepictedItem("", "", null,
listOf("Q10"), emptyList(), false, "Q10")
))
}
@Test
fun `Test toDepictions when description is not empty`() {
val sparqlResponse = mock<SparqlResponse>()
val result = mock<Result>()
whenever(sparqlResponse.results).thenReturn(result)
val binding1 = mock<Binding>()
val binding2 = mock<Binding>()
whenever(result.bindings).thenReturn(listOf(binding1, binding2))
whenever(binding1.id).thenReturn("1")
whenever(binding2.id).thenReturn("2")
val entities = mock<Entities>()
val entity = mock<Entities.Entity>()
whenever(depictsInterface.getEntities("1|2")).thenReturn(Single.just(entities))
whenever(entities.entities()).thenReturn(mapOf("en" to entity))
whenever(entity.descriptions()).thenReturn(mapOf("en" to
Entities.Label("en", "Test description")
))
whenever(entity.id()).thenReturn("Q10")
depictsClient.toDepictions(Single.just(sparqlResponse))
.test()
.assertValue(listOf(
DepictedItem("", "", null, listOf("Q10"),
emptyList(), false, "Q10")
))
}
}

View file

@ -78,6 +78,11 @@ public class Entities extends MwResponse implements PostProcessingTypeAdapter.Po
@Nullable private String language;
@Nullable private String value;
public Label(@Nullable final String language, @Nullable final String value) {
this.language = language;
this.value = value;
}
@NonNull public String language() {
return StringUtils.defaultString(language);
}