If depicted Wikidata item has no associated Commons category property, then suggest categories from its P18 (#6130)

* Fix NPE with UploadMediaDetails.captionText

* Store P18 instead of processed image url in DepictedItem

* Add routes for fetching category info from titles

* Consider depict's P18 when suggesting categories

* Add tests

* Corrected DepictedItem constructor arguments

* Add test for DepictedItem::primaryImage
This commit is contained in:
Tanmay Gupta 2025-01-16 14:34:04 +05:30 committed by GitHub
parent 1f33926ed5
commit 1e64acdf1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 212 additions and 28 deletions

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons.category
import categoryItem
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import depictedItem
@ -90,14 +92,18 @@ class CategoriesModelTest {
val depictedItem =
depictedItem(
commonsCategories =
listOf(
CategoryItem(
"depictionCategory",
"",
"",
false,
),
listOf(
CategoryItem(
"depictionCategory",
"",
"",
false,
),
),
)
val depictedItemWithoutCategories =
depictedItem(
imageUrl = "testUrl"
)
whenever(gpsCategoryModel.categoriesFromLocation)
@ -159,6 +165,23 @@ class CategoriesModelTest {
),
),
)
whenever(
categoryClient.getCategoriesOfImage(
"testUrl",
25,
),
).thenReturn(
Single.just(
listOf(
CategoryItem(
"categoriesOfP18",
"",
"",
false,
),
),
),
)
val imageTitleList = listOf("Test")
CategoriesModel(categoryClient, categoryDao, gpsCategoryModel)
.searchAll("", imageTitleList, listOf(depictedItem))
@ -171,8 +194,21 @@ class CategoriesModelTest {
categoryItem("recentCategories"),
),
)
CategoriesModel(categoryClient, categoryDao, gpsCategoryModel)
.searchAll("", imageTitleList, listOf(depictedItemWithoutCategories))
.test()
.assertValue(
listOf(
categoryItem("categoriesOfP18"),
categoryItem("gpsCategory"),
categoryItem("titleSearch"),
categoryItem("recentCategories"),
),
)
imageTitleList.forEach {
verify(categoryClient).searchCategories(it, CategoriesModel.SEARCH_CATS_LIMIT)
verify(categoryClient, times(2)).searchCategories(it, CategoriesModel.SEARCH_CATS_LIMIT)
verify(categoryClient).getCategoriesByName(any(), any(), any(), any())
verify(categoryClient).getCategoriesOfImage(any(), any())
}
}

View file

@ -132,6 +132,45 @@ class CategoryClientTest {
)
}
@Test
fun getCategoriesByTitlesFound() {
val mockResponse = withMockResponse("Category:Test")
whenever(
categoryInterface.getCategoriesByTitles(
anyString(),
anyInt(),
),
).thenReturn(Single.just(mockResponse))
categoryClient
.getCategoriesOfImage("tes", 10)
.test()
.assertValues(
listOf(
CategoryItem(
"Test",
"",
"",
false,
),
),
)
categoryClient
.getCategoriesOfImage(
"tes",
10,
).test()
.assertValues(
listOf(
CategoryItem(
"Test",
"",
"",
false,
),
),
)
}
@Test
fun getCategoriesByNameNull() {
val mockResponse = withNullPages()
@ -160,6 +199,29 @@ class CategoryClientTest {
.assertValues(emptyList())
}
@Test
fun getCategoriesByTitlesNull() {
val mockResponse = withNullPages()
whenever(
categoryInterface.getCategoriesByTitles(
anyString(),
anyInt(),
),
).thenReturn(Single.just(mockResponse))
categoryClient
.getCategoriesOfImage(
"tes",
10,
).test()
.assertValues(emptyList())
categoryClient
.getCategoriesOfImage(
"tes",
10,
).test()
.assertValues(emptyList())
}
@Test
fun getParentCategoryListFound() {
val mockResponse = withMockResponse("Category:Test")

View file

@ -181,4 +181,20 @@ class DepictedItemTest {
fun `hashCode returns different values for objects with different name`() {
Assert.assertNotEquals(depictedItem(name = "a").hashCode(), depictedItem(name = "b").hashCode())
}
@Test
fun `primaryImage is derived correctly from imageUrl`() {
Assert.assertEquals(
DepictedItem(
entity(
statements = mapOf(
WikidataProperties.IMAGE.propertyName to listOf(
statement(snak(dataValue = valueString("prefix: example_image name"))),
),
),
),
).primaryImage,
"_example_image_name",
)
}
}