package bou.amine.apps.readerforselfossv2.repository import bou.amine.apps.readerforselfossv2.dao.ITEM import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB import bou.amine.apps.readerforselfossv2.dao.SOURCE import bou.amine.apps.readerforselfossv2.dao.TAG import bou.amine.apps.readerforselfossv2.model.SelfossModel import bou.amine.apps.readerforselfossv2.rest.SelfossApi import bou.amine.apps.readerforselfossv2.service.AppSettingsService import bou.amine.apps.readerforselfossv2.utils.ItemType import bou.amine.apps.readerforselfossv2.utils.toView import io.mockk.* import junit.framework.TestCase.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import org.junit.Assert.assertNotEquals import org.junit.Before import org.junit.Test class RepositoryTest { private val db = mockk(relaxed = true) private val appSettingsService = mockk() private val api = mockk() private val NUMBER_ARTICLES = 100 private val NUMBER_UNREAD = 50 private val NUMBER_STARRED = 20 private lateinit var repository: Repository private fun initializeRepository( isConnectionAvailable: MutableStateFlow = MutableStateFlow( true ) ) { repository = Repository(api, appSettingsService, isConnectionAvailable, db) runBlocking { repository.updateApiVersion() } } @Before fun setup() { clearAllMocks() every { appSettingsService.getApiVersion() } returns 4 every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/" every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns false coEvery { api.version() } returns SelfossModel.StatusAndData( success = true, data = SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0") ) coEvery { api.stats() } returns SelfossModel.StatusAndData( success = true, data = SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED) ) every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems() every { db.tagsQueries.deleteAllTags() } returns Unit every { db.tagsQueries.transaction(any(), any()) } returns Unit every { db.tagsQueries.insertTag(any()) } returns Unit } @Test fun instantiate_repository() { initializeRepository() coVerify(exactly = 1) { api.version() } } @Test fun instantiate_repository_without_api_version() { every { appSettingsService.getApiVersion() } returns -1 initializeRepository(MutableStateFlow(false)) coVerify(exactly = 0) { api.version() } coVerify(exactly = 0) { api.stats() } } @Test fun get_api_4_date_with_api_1_version_stored() { every { appSettingsService.getApiVersion() } returns 1 coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) every { appSettingsService.updateApiVersion(any()) } returns Unit initializeRepository() runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) verify(exactly = 1) { appSettingsService.updateApiVersion(4) } } @Test fun get_api_1_date_with_api_4_version_stored() { every { appSettingsService.getApiVersion() } returns 4 coEvery { api.version() } returns SelfossModel.StatusAndData(success = false, null) val itemParameters = FakeItemParameters() itemParameters.datetime = "2021-04-23 11:45:32" coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData( success = true, data = generateTestApiItem(itemParameters) ) initializeRepository() runBlocking { repository.getNewerItems() } assertSame(1, repository.items.size) } @Test fun get_newer_items() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) initializeRepository() runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) coVerify(exactly = 1) { api.getItems("unread", 0, null, null, null, null, any()) } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun get_all_newer_items() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) initializeRepository() repository.displayedItems = ItemType.ALL runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) coVerify(exactly = 1) { api.getItems("all", 0, null, null, null, null, any()) } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun get_newer_starred_items() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) initializeRepository() repository.displayedItems = ItemType.STARRED runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) coVerify(exactly = 1) { api.getItems("starred", 0, null, null, null, null, any()) } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun get_newer_items_without_connectivity() { every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository(MutableStateFlow(false)) runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) coVerify(exactly = 0) { api.getItems("unread", 0, null, null, null, null, any()) } verify(atLeast = 1) { db.itemsQueries.items().executeAsList() } } @Test fun get_newer_items_without_connectivity_and_tag_filter() { val itemParameter1 = FakeItemParameters() val itemParameter2 = FakeItemParameters() val itemParameter3 = FakeItemParameters() itemParameter2.tags = "Test, Stuff" itemParameter2.id = "2" itemParameter3.tags = "Other, Tag" itemParameter3.id = "3" coEvery { db.itemsQueries.items().executeAsList() } returns generateTestDBItems( itemParameter1 ) + generateTestDBItems(itemParameter2) + generateTestDBItems(itemParameter3) every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository(MutableStateFlow(false)) repository.tagFilter = SelfossModel.Tag("Test", "red", 3) runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) coVerify(exactly = 0) { api.getItems("unread", 0, null, null, null, null, any()) } verify(atLeast = 1) { db.itemsQueries.items().executeAsList() } } @Test fun get_newer_items_without_connectivity_and_source_filter() { val itemParameter1 = FakeItemParameters() val itemParameter2 = FakeItemParameters() val itemParameter3 = FakeItemParameters() itemParameter2.sourcetitle = "Test" itemParameter2.id = "2" itemParameter3.sourcetitle = "Other" itemParameter3.id = "3" coEvery { db.itemsQueries.items().executeAsList() } returns generateTestDBItems( itemParameter1 ) + generateTestDBItems(itemParameter2) + generateTestDBItems(itemParameter3) every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository(MutableStateFlow(false)) repository.sourceFilter = SelfossModel.Source( 1, "Test", listOf("tags"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) runBlocking { repository.getNewerItems() } assertSame(repository.items.size, 1) coVerify(exactly = 0) { api.getItems("unread", 0, null, null, null, null, any()) } verify(atLeast = 1) { db.itemsQueries.items().executeAsList() } } @Test fun get_older_items() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) initializeRepository() repository.items = ArrayList(generateTestApiItem()) runBlocking { repository.getOlderItems() } assertSame(repository.items.size, 2) coVerify(exactly = 1) { api.getItems("unread", 1, null, null, null, null, any()) } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun get_all_older_items() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) initializeRepository() repository.items = ArrayList(generateTestApiItem()) repository.displayedItems = ItemType.ALL runBlocking { repository.getOlderItems() } assertSame(repository.items.size, 2) coVerify(exactly = 1) { api.getItems("all", 1, null, null, null, null, any()) } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun get_older_starred_items() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) initializeRepository() repository.displayedItems = ItemType.STARRED repository.items = ArrayList(generateTestApiItem()) runBlocking { repository.getOlderItems() } assertSame(repository.items.size, 2) coVerify(exactly = 1) { api.getItems("starred", 1, null, null, null, null, any()) } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun reload_badges() { var success: Boolean initializeRepository() runBlocking { success = repository.reloadBadges() } assertSame(true, success) assertSame(NUMBER_ARTICLES, repository.badgeAll) assertSame(NUMBER_UNREAD, repository.badgeUnread) assertSame(NUMBER_STARRED, repository.badgeStarred) coVerify(atLeast = 1) { api.stats() } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun reload_badges_without_response() { coEvery { api.stats() } returns SelfossModel.StatusAndData(success = false, data = null) var success: Boolean initializeRepository() runBlocking { success = repository.reloadBadges() } assertSame(false, success) assertSame(0, repository.badgeAll) assertSame(0, repository.badgeUnread) assertSame(0, repository.badgeStarred) coVerify(atLeast = 1) { api.stats() } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun reload_badges_without_connection() { every { appSettingsService.isItemCachingEnabled() } returns true every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems() var success: Boolean initializeRepository(MutableStateFlow(false)) runBlocking { success = repository.reloadBadges() } assertTrue(success) assertSame(1, repository.badgeAll) assertSame(1, repository.badgeUnread) assertSame(1, repository.badgeStarred) coVerify(exactly = 0) { api.stats() } verify(atLeast = 1) { db.itemsQueries.items().executeAsList() } } @Test fun reload_badges_without_connection_and_items_caching_disabled() { every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns true var success: Boolean initializeRepository(MutableStateFlow(false)) runBlocking { success = repository.reloadBadges() } assertFalse(success) assertSame(0, repository.badgeAll) assertSame(0, repository.badgeUnread) assertSame(0, repository.badgeStarred) coVerify(exactly = 0) { api.stats() } verify(exactly = 0) { db.itemsQueries.items().executeAsList() } } @Test fun get_tags() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns true every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository() var testTags: List? runBlocking { testTags = repository.getTags() } assertSame(tags, testTags) assertNotSame(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 1) { api.tags() } } @Test fun get_tags_with_sources_update_disabled() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository() var testTags: List runBlocking { testTags = repository.getTags() // Tags will be fetched from the database on the second call, thus testTags != tags testTags = repository.getTags() } coVerify(exactly = 1) { api.tags() } assertNotSame(tags, testTags) assertEquals(tagsDB.map { it.toView() }, testTags) verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test fun get_tags_with_items_caching_disabled() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns true every { appSettingsService.isItemCachingEnabled() } returns false initializeRepository() var testTags: List runBlocking { testTags = repository.getTags() } assertSame(tags, testTags) coVerify(exactly = 1) { api.tags() } verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } } @Test fun get_tags_with_sources_update_and_items_caching_disabled() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns false initializeRepository() var testTags: List runBlocking { testTags = repository.getTags() testTags = repository.getTags() } coVerify(exactly = 1) { api.tags() } assertNotSame(tags, testTags) assertEquals(tagsDB.map { it.toView() }, testTags) verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test fun get_tags_without_connection() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns true every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository(MutableStateFlow(false)) var testTags: List runBlocking { testTags = repository.getTags() } assertNotSame(tags, testTags) assertEquals(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 0) { api.tags() } verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test fun get_tags_without_connection_and_items_caching_disabled() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns true initializeRepository(MutableStateFlow(false)) var testTags: List runBlocking { testTags = repository.getTags() } assertSame(emptyList(), testTags) coVerify(exactly = 0) { api.tags() } verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } } @Test fun get_tags_without_connection_and_sources_update_disabled() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository(MutableStateFlow(false)) var testTags: List runBlocking { testTags = repository.getTags() } assertNotSame(tags, testTags) assertEquals(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 0) { api.tags() } verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test fun get_tags_without_connection_and_sources_update_and_items_caching_disabled() { val tags = listOf( SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0) ) val tagsDB = listOf( TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0) ) coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns false initializeRepository(MutableStateFlow(false)) var testTags: List runBlocking { testTags = repository.getTags() } assertEquals(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 0) { api.tags() } verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test fun get_sources() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First DB source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository() var testSources: List? runBlocking { testSources = repository.getSources() } assertSame(sources, testSources) assertNotEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 1) { api.sources() } } @Test fun get_sources_with_sources_update_disabled() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second DB source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns true coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository() var testSources: List? runBlocking { testSources = repository.getSources() // Sources will be fetched from the database on the second call, thus testSources != sources testSources = repository.getSources() } coVerify(exactly = 1) { api.sources() } assertNotSame(sources, testSources) assertEquals(sourcesDB.map { it.toView() }, testSources) verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @Test fun get_sources_with_items_caching_disabled() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) every { appSettingsService.isUpdateSourcesEnabled() } returns true every { appSettingsService.isItemCachingEnabled() } returns false coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository() var testSources: List? runBlocking { testSources = repository.getSources() } assertSame(sources, testSources) coVerify(exactly = 1) { api.sources() } verify(exactly = 0) { db.sourcesQueries } } @Test fun get_sources_with_sources_update_and_items_caching_disabled() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns false coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository() var testSources: List? runBlocking { testSources = repository.getSources() } assertSame(sources, testSources) coVerify(exactly = 1) { api.sources() } verify(atLeast = 1) { db.sourcesQueries } } @Test fun get_sources_without_connection() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First DB source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository(MutableStateFlow(false)) var testSources: List? runBlocking { testSources = repository.getSources() } assertEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 0) { api.sources() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @Test fun get_sources_without_connection_and_items_caching_disabled() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First DB source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns true coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository(MutableStateFlow(false)) var testSources: List? runBlocking { testSources = repository.getSources() } assertEquals(emptyList(), testSources) coVerify(exactly = 0) { api.sources() } verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } } @Test fun get_sources_without_connection_and_sources_update_disabled() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First DB source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) every { appSettingsService.isItemCachingEnabled() } returns true every { appSettingsService.isUpdateSourcesEnabled() } returns false coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository(MutableStateFlow(false)) var testSources: List? runBlocking { testSources = repository.getSources() } assertEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 0) { api.sources() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @Test fun get_sources_without_connection_and_items_caching_and_sources_update_disabled() { val sources = arrayListOf( SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SelfossModel.Source( 2, "Second source", listOf("second"), "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) val sourcesDB = listOf( SOURCE( "1", "First DB source", "Test,second", "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ), SOURCE( "2", "Second source", "second", "spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png" ) ) every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns false coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB initializeRepository(MutableStateFlow(false)) var testSources: List? runBlocking { testSources = repository.getSources() } assertEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 0) { api.sources() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @Test fun create_source() { coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns SelfossModel.SuccessResponse(true) initializeRepository() var response: Boolean runBlocking { response = repository.createSource( "test", "https://test.com/feed", "spouts\\rss\\fulltextrss", "Test, New", "" ) } coVerify(exactly = 1) { api.createSourceForVersion( any(), any(), any(), any(), any(), any() ) } assertSame(true, response) } @Test fun create_source_but_response_fails() { coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns SelfossModel.SuccessResponse(false) initializeRepository() var response: Boolean runBlocking { response = repository.createSource( "test", "https://test.com/feed", "spouts\\rss\\fulltextrss", "Test, New", "" ) } coVerify(exactly = 1) { api.createSourceForVersion( any(), any(), any(), any(), any(), any() ) } assertSame(false, response) } @Test fun create_source_without_connection() { coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns SelfossModel.SuccessResponse(true) initializeRepository(MutableStateFlow(false)) var response: Boolean runBlocking { response = repository.createSource( "test", "https://test.com/feed", "spouts\\rss\\fulltextrss", "Test, New", "" ) } coVerify(exactly = 0) { api.createSourceForVersion( any(), any(), any(), any(), any(), any() ) } assertSame(false, response) } @Test fun delete_source() { coEvery { api.deleteSource(any()) } returns SelfossModel.SuccessResponse(true) initializeRepository() var response: Boolean runBlocking { response = repository.deleteSource(5) } coVerify(exactly = 1) { api.deleteSource(5) } assertSame(true, response) } @Test fun delete_source_but_response_fails() { coEvery { api.deleteSource(any()) } returns SelfossModel.SuccessResponse(false) initializeRepository() var response: Boolean runBlocking { response = repository.deleteSource(5) } coVerify(exactly = 1) { api.deleteSource(5) } assertSame(false, response) } @Test fun delete_source_without_connection() { coEvery { api.deleteSource(any()) } returns SelfossModel.SuccessResponse(false) initializeRepository(MutableStateFlow(false)) var response: Boolean runBlocking { response = repository.deleteSource(5) } coVerify(exactly = 0) { api.deleteSource(5) } assertSame(false, response) } @Test fun update_remote() { coEvery { api.update() } returns SelfossModel.StatusAndData( success = true, data = "finished" ) initializeRepository() var response: Boolean runBlocking { response = repository.updateRemote() } coVerify(exactly = 1) { api.update() } assertTrue(response) } @Test fun update_remote_but_response_fails() { coEvery { api.update() } returns SelfossModel.StatusAndData( success = false, data = "unallowed access" ) initializeRepository() var response: Boolean runBlocking { response = repository.updateRemote() } coVerify(exactly = 1) { api.update() } assertSame(false, response) } @Test fun update_remote_with_unallowed_access() { coEvery { api.update() } returns SelfossModel.StatusAndData( success = true, data = "unallowed access" ) initializeRepository() var response: Boolean runBlocking { response = repository.updateRemote() } coVerify(exactly = 1) { api.update() } assertSame(false, response) } @Test fun update_remote_without_connection() { coEvery { api.update() } returns SelfossModel.StatusAndData( success = true, data = "undocumented..." ) initializeRepository(MutableStateFlow(false)) var response: Boolean runBlocking { response = repository.updateRemote() } coVerify(exactly = 0) { api.update() } assertSame(false, response) } @Test fun login() { coEvery { api.login() } returns SelfossModel.SuccessResponse(success = true) initializeRepository() var response: Boolean runBlocking { response = repository.login() } coVerify(exactly = 1) { api.login() } assertSame(true, response) } @Test fun login_but_response_fails() { coEvery { api.login() } returns SelfossModel.SuccessResponse(success = false) initializeRepository() var response: Boolean runBlocking { response = repository.login() } coVerify(exactly = 1) { api.login() } assertSame(false, response) } @Test fun login_but_without_connection() { coEvery { api.login() } returns SelfossModel.SuccessResponse(success = true) initializeRepository(MutableStateFlow(false)) var response: Boolean runBlocking { response = repository.login() } coVerify(exactly = 0) { api.login() } assertSame(false, response) } @Test fun refresh_login_information() { coEvery { api.refreshLoginInformation() } returns Unit coEvery { appSettingsService.refreshLoginInformation(any(), any(), any()) } returns Unit initializeRepository() repository.refreshLoginInformation("https://test.com/selfoss/", "login", "password") coVerify(exactly = 1) { api.refreshLoginInformation() } coVerify(exactly = 1) { appSettingsService.refreshLoginInformation( "https://test.com/selfoss/", "login", "password" ) } } @Test fun cache_items() { val itemParameter1 = FakeItemParameters() val itemParameter2 = FakeItemParameters() val itemParameter3 = FakeItemParameters() itemParameter2.id = "2" itemParameter3.id = "3" coEvery { api.getItems( any(), any(), any(), any(), any(), any(), any() ) } returnsMany listOf( SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter1)), SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter2)), SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameter1)), ) initializeRepository() repository.tagFilter = SelfossModel.Tag("Tag", "read", 0) repository.sourceFilter = SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ) repository.searchFilter = "search" runBlocking { repository.tryToCacheItemsAndGetNewOnes() } coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } } @Test fun cache_items_but_response_fails() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = false, data = generateTestApiItem()) initializeRepository() repository.tagFilter = SelfossModel.Tag("Tag", "read", 0) repository.sourceFilter = SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ) repository.searchFilter = "search" runBlocking { repository.tryToCacheItemsAndGetNewOnes() } coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } } @Test fun cache_items_without_connection() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns SelfossModel.StatusAndData(success = false, data = generateTestApiItem()) initializeRepository(MutableStateFlow(false)) repository.tagFilter = SelfossModel.Tag("Tag", "read", 0) repository.sourceFilter = SelfossModel.Source( 1, "First source", listOf("Test", "second"), "spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png" ) repository.searchFilter = "search" runBlocking { repository.tryToCacheItemsAndGetNewOnes() } coVerify(exactly = 0) { api.getItems(any(), 0, null, null, null, null, 200) } } }