Loading app/src/test/java/foundation/e/apps/data/fdroid/FDroidRepositoryTest.kt 0 → 100644 +168 −0 Original line number Diff line number Diff line package foundation.e.apps.data.fdroid import com.google.common.truth.Truth.assertThat import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.enums.Source import foundation.e.apps.data.fdroid.models.BuildInfo import foundation.e.apps.data.fdroid.models.FdroidApiModel import foundation.e.apps.data.fdroid.models.FdroidEntity import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Test import retrofit2.Response import java.io.InterruptedIOException import kotlin.test.assertFailsWith @OptIn(ExperimentalCoroutinesApi::class) class FDroidRepositoryTest { private val fdroidApi = mockk<FdroidApiInterface>() private val fdroidDao = mockk<FdroidDao>(relaxed = true) private val repository = FDroidRepository(fdroidApi, fdroidDao) @Test fun getFdroidInfo_returnsDaoEntityWithoutCallingApi() = runTest { val entity = FdroidEntity("org.example.app", "DAO Author") coEvery { fdroidDao.getFdroidEntityFromPackageName(entity.packageName) } returns entity val result = repository.getFdroidInfo(entity.packageName) assertThat(result).isSameInstanceAs(entity) coVerify(exactly = 1) { fdroidDao.getFdroidEntityFromPackageName(entity.packageName) } coVerify(exactly = 0) { fdroidApi.getFdroidInfoForPackage(any()) } coVerify(exactly = 0) { fdroidDao.saveFdroidEntity(any()) } } @Test fun getFdroidInfo_fetchesFromApiAndPersistsEntity() = runTest { val packageName = "org.example.app" coEvery { fdroidDao.getFdroidEntityFromPackageName(packageName) } returns null coEvery { fdroidApi.getFdroidInfoForPackage(packageName) } returns Response.success(FdroidApiModel("API Author", emptyList())) val result = repository.getFdroidInfo(packageName) assertThat(result?.packageName).isEqualTo(packageName) assertThat(result?.authorName).isEqualTo("API Author") coVerify(exactly = 1) { fdroidApi.getFdroidInfoForPackage(packageName) } coVerify(exactly = 1) { fdroidDao.saveFdroidEntity(match { it.packageName == packageName && it.authorName == "API Author" }) } } @Test fun getAuthorName_returnsDefaultWhenFdroidRequestFails() = runTest { val application = Application( author = FDroidRepository.UNKNOWN, package_name = "org.example.app", source = Source.OPEN_SOURCE, ) coEvery { fdroidDao.getFdroidEntityFromPackageName(application.package_name) } returns null coEvery { fdroidApi.getFdroidInfoForPackage(application.package_name) } throws InterruptedIOException("timeout") val authorName = repository.getAuthorName(application) assertThat(authorName).isEqualTo(FdroidEntity.DEFAULT_FDROID_AUTHOR_NAME) } @Test fun getAuthorName_returnsUnknownForPlayStoreAppsWithoutLookup() = runTest { val application = Application( author = "", package_name = "org.example.play", source = Source.PLAY_STORE, ) val authorName = repository.getAuthorName(application) assertThat(authorName).isEqualTo(FDroidRepository.UNKNOWN) coVerify(exactly = 0) { fdroidDao.getFdroidEntityFromPackageName(any()) } coVerify(exactly = 0) { fdroidApi.getFdroidInfoForPackage(any()) } } @Test fun getAuthorName_usesInMemoryCacheAfterFirstLookup() = runTest { val application = Application( author = FDroidRepository.UNKNOWN, package_name = "org.example.cached", source = Source.OPEN_SOURCE, ) coEvery { fdroidDao.getFdroidEntityFromPackageName(application.package_name) } returns null coEvery { fdroidApi.getFdroidInfoForPackage(application.package_name) } returns Response.success(FdroidApiModel("Cached Author", emptyList())) val firstAuthorName = repository.getAuthorName(application) val secondAuthorName = repository.getAuthorName(application) assertThat(firstAuthorName).isEqualTo("Cached Author") assertThat(secondAuthorName).isEqualTo("Cached Author") coVerify(exactly = 1) { fdroidDao.getFdroidEntityFromPackageName(application.package_name) } coVerify(exactly = 1) { fdroidApi.getFdroidInfoForPackage(application.package_name) } coVerify(exactly = 1) { fdroidDao.saveFdroidEntity(any()) } } @Test fun isFdroidApplication_returnsFalseWhenRequestFails() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } throws InterruptedIOException("timeout") val isFdroidApplication = repository.isFdroidApplication("org.example.app") assertThat(isFdroidApplication).isFalse() } @Test fun isFdroidApplication_returnsTrueForSuccessfulResponse() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } returns Response.success(FdroidApiModel("Author", emptyList())) val isFdroidApplication = repository.isFdroidApplication("org.example.app") assertThat(isFdroidApplication).isTrue() } @Test fun getBuildVersionInfo_returnsNullWhenRequestFails() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } throws InterruptedIOException("timeout") val buildVersionInfo = repository.getBuildVersionInfo("org.example.app") assertThat(buildVersionInfo).isNull() } @Test fun getBuildVersionInfo_returnsBuildsFromApi() = runTest { val builds = listOf( BuildInfo("123", "1.2.3"), BuildInfo("124", "1.2.4"), ) coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } returns Response.success(FdroidApiModel("Author", builds)) val buildVersionInfo = repository.getBuildVersionInfo("org.example.app") assertThat(buildVersionInfo).hasSize(2) assertThat(buildVersionInfo?.map { it.versionCode }).containsExactly("123", "124").inOrder() assertThat(buildVersionInfo?.map { it.versionName }).containsExactly("1.2.3", "1.2.4").inOrder() } @Test fun getBuildVersionInfo_rethrowsCancellationException() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } throws CancellationException("cancelled") val exception = assertFailsWith<CancellationException> { repository.getBuildVersionInfo("org.example.app") } assertThat(exception).hasMessageThat().contains("cancelled") } } Loading
app/src/test/java/foundation/e/apps/data/fdroid/FDroidRepositoryTest.kt 0 → 100644 +168 −0 Original line number Diff line number Diff line package foundation.e.apps.data.fdroid import com.google.common.truth.Truth.assertThat import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.enums.Source import foundation.e.apps.data.fdroid.models.BuildInfo import foundation.e.apps.data.fdroid.models.FdroidApiModel import foundation.e.apps.data.fdroid.models.FdroidEntity import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Test import retrofit2.Response import java.io.InterruptedIOException import kotlin.test.assertFailsWith @OptIn(ExperimentalCoroutinesApi::class) class FDroidRepositoryTest { private val fdroidApi = mockk<FdroidApiInterface>() private val fdroidDao = mockk<FdroidDao>(relaxed = true) private val repository = FDroidRepository(fdroidApi, fdroidDao) @Test fun getFdroidInfo_returnsDaoEntityWithoutCallingApi() = runTest { val entity = FdroidEntity("org.example.app", "DAO Author") coEvery { fdroidDao.getFdroidEntityFromPackageName(entity.packageName) } returns entity val result = repository.getFdroidInfo(entity.packageName) assertThat(result).isSameInstanceAs(entity) coVerify(exactly = 1) { fdroidDao.getFdroidEntityFromPackageName(entity.packageName) } coVerify(exactly = 0) { fdroidApi.getFdroidInfoForPackage(any()) } coVerify(exactly = 0) { fdroidDao.saveFdroidEntity(any()) } } @Test fun getFdroidInfo_fetchesFromApiAndPersistsEntity() = runTest { val packageName = "org.example.app" coEvery { fdroidDao.getFdroidEntityFromPackageName(packageName) } returns null coEvery { fdroidApi.getFdroidInfoForPackage(packageName) } returns Response.success(FdroidApiModel("API Author", emptyList())) val result = repository.getFdroidInfo(packageName) assertThat(result?.packageName).isEqualTo(packageName) assertThat(result?.authorName).isEqualTo("API Author") coVerify(exactly = 1) { fdroidApi.getFdroidInfoForPackage(packageName) } coVerify(exactly = 1) { fdroidDao.saveFdroidEntity(match { it.packageName == packageName && it.authorName == "API Author" }) } } @Test fun getAuthorName_returnsDefaultWhenFdroidRequestFails() = runTest { val application = Application( author = FDroidRepository.UNKNOWN, package_name = "org.example.app", source = Source.OPEN_SOURCE, ) coEvery { fdroidDao.getFdroidEntityFromPackageName(application.package_name) } returns null coEvery { fdroidApi.getFdroidInfoForPackage(application.package_name) } throws InterruptedIOException("timeout") val authorName = repository.getAuthorName(application) assertThat(authorName).isEqualTo(FdroidEntity.DEFAULT_FDROID_AUTHOR_NAME) } @Test fun getAuthorName_returnsUnknownForPlayStoreAppsWithoutLookup() = runTest { val application = Application( author = "", package_name = "org.example.play", source = Source.PLAY_STORE, ) val authorName = repository.getAuthorName(application) assertThat(authorName).isEqualTo(FDroidRepository.UNKNOWN) coVerify(exactly = 0) { fdroidDao.getFdroidEntityFromPackageName(any()) } coVerify(exactly = 0) { fdroidApi.getFdroidInfoForPackage(any()) } } @Test fun getAuthorName_usesInMemoryCacheAfterFirstLookup() = runTest { val application = Application( author = FDroidRepository.UNKNOWN, package_name = "org.example.cached", source = Source.OPEN_SOURCE, ) coEvery { fdroidDao.getFdroidEntityFromPackageName(application.package_name) } returns null coEvery { fdroidApi.getFdroidInfoForPackage(application.package_name) } returns Response.success(FdroidApiModel("Cached Author", emptyList())) val firstAuthorName = repository.getAuthorName(application) val secondAuthorName = repository.getAuthorName(application) assertThat(firstAuthorName).isEqualTo("Cached Author") assertThat(secondAuthorName).isEqualTo("Cached Author") coVerify(exactly = 1) { fdroidDao.getFdroidEntityFromPackageName(application.package_name) } coVerify(exactly = 1) { fdroidApi.getFdroidInfoForPackage(application.package_name) } coVerify(exactly = 1) { fdroidDao.saveFdroidEntity(any()) } } @Test fun isFdroidApplication_returnsFalseWhenRequestFails() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } throws InterruptedIOException("timeout") val isFdroidApplication = repository.isFdroidApplication("org.example.app") assertThat(isFdroidApplication).isFalse() } @Test fun isFdroidApplication_returnsTrueForSuccessfulResponse() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } returns Response.success(FdroidApiModel("Author", emptyList())) val isFdroidApplication = repository.isFdroidApplication("org.example.app") assertThat(isFdroidApplication).isTrue() } @Test fun getBuildVersionInfo_returnsNullWhenRequestFails() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } throws InterruptedIOException("timeout") val buildVersionInfo = repository.getBuildVersionInfo("org.example.app") assertThat(buildVersionInfo).isNull() } @Test fun getBuildVersionInfo_returnsBuildsFromApi() = runTest { val builds = listOf( BuildInfo("123", "1.2.3"), BuildInfo("124", "1.2.4"), ) coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } returns Response.success(FdroidApiModel("Author", builds)) val buildVersionInfo = repository.getBuildVersionInfo("org.example.app") assertThat(buildVersionInfo).hasSize(2) assertThat(buildVersionInfo?.map { it.versionCode }).containsExactly("123", "124").inOrder() assertThat(buildVersionInfo?.map { it.versionName }).containsExactly("1.2.3", "1.2.4").inOrder() } @Test fun getBuildVersionInfo_rethrowsCancellationException() = runTest { coEvery { fdroidApi.getFdroidInfoForPackage("org.example.app") } throws CancellationException("cancelled") val exception = assertFailsWith<CancellationException> { repository.getBuildVersionInfo("org.example.app") } assertThat(exception).hasMessageThat().contains("cancelled") } }