From 948e22efc82dde418957db2befb9b43c1dcba512 Mon Sep 17 00:00:00 2001 From: Tobias_Groza <304016-Tobias_Groza@noreply.gitlab.com> Date: Thu, 17 Apr 2025 14:27:22 +0200 Subject: [PATCH] Fix and add tests for hasAuthorMoreThanOneApp(), getAppListItemsForAuthor() --- .../org/fdroid/database/AppListItemsTest.kt | 102 ++++++++++++++++++ .../main/java/org/fdroid/database/AppDao.kt | 5 +- .../kotlin/org/fdroid/test/TestAppUtils.kt | 9 +- 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/libs/database/src/dbTest/java/org/fdroid/database/AppListItemsTest.kt b/libs/database/src/dbTest/java/org/fdroid/database/AppListItemsTest.kt index 2ced2bfd1..460a1f462 100644 --- a/libs/database/src/dbTest/java/org/fdroid/database/AppListItemsTest.kt +++ b/libs/database/src/dbTest/java/org/fdroid/database/AppListItemsTest.kt @@ -11,11 +11,13 @@ import org.fdroid.database.AppListSortOrder.LAST_UPDATED import org.fdroid.database.AppListSortOrder.NAME import org.fdroid.database.TestUtils.getOrFail import org.fdroid.index.v2.MetadataV2 +import org.fdroid.test.TestAppUtils.getRandomMetadataV2 import org.fdroid.test.TestRepoUtils.getRandomRepo import org.fdroid.test.TestUtils.getRandomString import org.fdroid.test.TestVersionUtils.getRandomPackageVersionV2 import org.junit.Test import org.junit.runner.RunWith +import kotlin.collections.map import kotlin.random.Random import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -614,6 +616,106 @@ internal class AppListItemsTest : AppTest() { assertNotNull(appDao.getInstalledAppListItems(pm).getOrFail()[0].installedVersionName) } + // region author tests + @Test + fun testAuthor_NoApp() { + // should never happen, but test this just in case + every { pm.getInstalledPackages(0) } returns emptyList() + val author = getRandomString() + + assertFalse(appDao.hasAuthorMoreThanOneApp(author).getOrFail()) + assertTrue(appDao.getAppListItemsForAuthor(pm, author, null, NAME).getOrFail().isEmpty()) + assertTrue(appDao.getAppListItemsForAuthor(pm, author, null, LAST_UPDATED) + .getOrFail().isEmpty()) + } + + @Test + fun testAuthor_OneApp() { + every { pm.getInstalledPackages(0) } returns emptyList() + val author = getRandomString() + val packageName = getRandomString() + val repoId = repoDao.insertOrReplace(getRandomRepo()) + appDao.insert(repoId, packageName, getRandomMetadataV2(author), locales) + + assertFalse(appDao.hasAuthorMoreThanOneApp(author).getOrFail()) + val appsForAuthor = appDao.getAppListItemsForAuthor(pm, author, null, NAME).getOrFail() + assertEquals(1, appsForAuthor.size) + assertEquals(1, appDao.getAppListItemsForAuthor(pm, author, null, LAST_UPDATED) + .getOrFail().size) + assertEquals(packageName, appsForAuthor[0].packageName) + } + + @Test + fun testAuthor_TwoApps() { + every { pm.getInstalledPackages(0) } returns emptyList() + val author = getRandomString() + val repoId = repoDao.insertOrReplace(getRandomRepo()) + val packageName1 = getRandomString() + val packageName2 = getRandomString() + val metadata2 = getRandomMetadataV2(author) + val metadata1 = getRandomMetadataV2(author, metadata2.lastUpdated + 1) + appDao.insert(repoId, packageName1, metadata1, locales) + appDao.insert(repoId, packageName2, metadata2, locales) + + assertTrue(appDao.hasAuthorMoreThanOneApp(author).getOrFail()) + val appsForAuthor = appDao.getAppListItemsForAuthor(pm, author, null, LAST_UPDATED) + .getOrFail() + assertEquals(2, appsForAuthor.size) + assertEquals(packageName1, appsForAuthor[0].packageName) + assertEquals(packageName2, appsForAuthor[1].packageName) + } + + @Test + fun testAuthor_MultipleApps() { + every { pm.getInstalledPackages(0) } returns emptyList() + val author = getRandomString() + val repoId = repoDao.insertOrReplace(getRandomRepo()) + for (i in 1..50) { + appDao.insert(repoId, getRandomString(), getRandomMetadataV2(author), locales) + } + + assertTrue(appDao.hasAuthorMoreThanOneApp(author).getOrFail()) + assertEquals(50, appDao.getAppListItemsForAuthor(pm, author, null, NAME).getOrFail().size) + } + + @Test + fun testHasAuthorMoreThanOneApp_OneAppDifferentRepos() { + every { pm.getInstalledPackages(0) } returns emptyList() + val author = getRandomString() + val repoId1 = repoDao.insertOrReplace(getRandomRepo()) + val repoId2 = repoDao.insertOrReplace(getRandomRepo()) + val packageName = getRandomString() + appDao.insert(repoId1, packageName, getRandomMetadataV2(author), locales) + val app4 = getRandomMetadataV2(author) + appDao.insert(repoId2, packageName, app4, locales) + appPrefsDao.update( + AppPrefs( + packageName = packageName, + preferredRepoId = repoId2, + ) + ) + assertFalse(appDao.hasAuthorMoreThanOneApp(author).getOrFail()) + val appsForAuthor = appDao.getAppListItemsForAuthor(pm, author, null, NAME).getOrFail() + assertEquals(1, appsForAuthor.size) + assertEquals(packageName, appsForAuthor[0].packageName) + assertEquals(repoId2, appsForAuthor[0].repoId) + } + + @Test + fun testHasAuthorMoreThanOneApp_TwoAppsDifferentRepos() { + every { pm.getInstalledPackages(0) } returns emptyList() + val author = getRandomString() + val repoId1 = repoDao.insertOrReplace(getRandomRepo()) + val repoId2 = repoDao.insertOrReplace(getRandomRepo()) + appDao.insert(repoId1, getRandomString(), getRandomMetadataV2(author), locales) + appDao.insert(repoId2, getRandomString(), getRandomMetadataV2(author), locales) + + assertTrue(appDao.hasAuthorMoreThanOneApp(author).getOrFail()) + val appsForAuthor = appDao.getAppListItemsForAuthor(pm, author, null, NAME).getOrFail() + assertEquals(2, appsForAuthor.size) + } + // endregion + /** * Runs the given block on all getAppListItems* methods. * Uses category "A" as all apps should be in that. diff --git a/libs/database/src/main/java/org/fdroid/database/AppDao.kt b/libs/database/src/main/java/org/fdroid/database/AppDao.kt index 78f46adc4..2e62839e7 100644 --- a/libs/database/src/main/java/org/fdroid/database/AppDao.kt +++ b/libs/database/src/main/java/org/fdroid/database/AppDao.kt @@ -647,7 +647,10 @@ internal interface AppDaoInt : AppDao { FROM ( SELECT 1 FROM AppMetadata - WHERE authorName = :author + JOIN ${RepositoryPreferences.TABLE} AS pref USING (repoId) + JOIN PreferredRepo USING (packageName) + WHERE authorName = :author AND repoId = preferredRepoId + GROUP BY packageName LIMIT 2)""") override fun hasAuthorMoreThanOneApp(author: String): LiveData diff --git a/libs/sharedTest/src/main/kotlin/org/fdroid/test/TestAppUtils.kt b/libs/sharedTest/src/main/kotlin/org/fdroid/test/TestAppUtils.kt index 4d7ee9830..5f5020668 100644 --- a/libs/sharedTest/src/main/kotlin/org/fdroid/test/TestAppUtils.kt +++ b/libs/sharedTest/src/main/kotlin/org/fdroid/test/TestAppUtils.kt @@ -15,9 +15,12 @@ import kotlin.test.assertEquals object TestAppUtils { - fun getRandomMetadataV2(): MetadataV2 = MetadataV2( + fun getRandomMetadataV2( + authorName: String? = null, + lastUpdated: Long? = null + ): MetadataV2 = MetadataV2( added = Random.nextLong(), - lastUpdated = Random.nextLong(), + lastUpdated = lastUpdated ?: Random.nextLong(), name = getRandomLocalizedTextV2().orNull(), summary = getRandomLocalizedTextV2().orNull(), description = getRandomLocalizedTextV2().orNull(), @@ -29,7 +32,7 @@ object TestAppUtils { translation = getRandomString().orNull(), preferredSigner = getRandomString().orNull(), video = getRandomLocalizedTextV2().orNull(), - authorName = getRandomString().orNull(), + authorName = authorName ?: getRandomString().orNull(), authorEmail = getRandomString().orNull(), authorWebSite = getRandomString().orNull(), authorPhone = getRandomString().orNull(),