From 99f2c04bf6e57c19accb3dd4e876fbf6d8f74c9e Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 9 Sep 2022 13:41:04 +0200 Subject: [PATCH 01/35] Initial testing setup --- shared/build.gradle.kts | 2 + .../repository/RepositoryImpl.kt | 3 +- .../repository/RepositoryTest.kt | 68 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 725d301..e2f6b91 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -56,6 +56,8 @@ kotlin { dependencies { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) + implementation("io.mockk:mockk:1.12.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0") } } val androidMain by getting { diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index c970507..e5dbc14 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -11,6 +11,7 @@ import io.github.aakira.napier.Napier import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) { @@ -38,7 +39,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap init { // TODO: Dispatchers.IO not available in KMM, an alternative solution should be found - CoroutineScope(Dispatchers.Main).launch { + runBlocking { updateApiVersion() dateUtils = DateUtils(appSettingsService) reloadBadges() diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt new file mode 100644 index 0000000..178a695 --- /dev/null +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -0,0 +1,68 @@ +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.model.SelfossModel +import bou.amine.apps.readerforselfossv2.rest.SelfossApi +import bou.amine.apps.readerforselfossv2.service.AppSettingsService +import com.github.ln_12.library.ConnectivityStatus +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.flow.MutableStateFlow +import kotlin.test.BeforeTest +import kotlin.test.Test + +class RepositoryTest() { + private val connectivityStatus = mockk() + private val db = mockk() + private val appSettingsService = mockk() + private val api = mockk() + + @BeforeTest + fun setup() { + every { appSettingsService.getApiVersion() } returns 4 + every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/" + + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true) + + coEvery { api.version() } returns SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0") + coEvery { api.stats() } returns SelfossModel.Stats(100, 50, 20) + + every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems() + } + + @Test + fun `Instantiate repository`() { + val repository = Repository(api, appSettingsService, connectivityStatus, db) + } + + @Test + fun `Instantiate repository without api version`() { + every { appSettingsService.getApiVersion() } returns -1 + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + } + + @Test + fun `Instantiate repository with negative stats`() { + coEvery { api.stats() } returns SelfossModel.Stats(-100, -50, -20) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + } +} + +fun generateTestDBItems() = listOf(ITEM( + id = "20", + datetime = "2022-09-09T03:32:01-04:00", + title = "Etica della ricerca sotto i riflettori.", + content = "

Luigi Campanella, già Presidente SCI

\n

L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.

\n

L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.

\n

Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.

\n

Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.

\n

Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.

\n

La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.

\n

L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.

\n\"\"\"\"

Magdalena Zernicka-Goetz

\n\"\"

Gianluca Amadei

\n

Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.

\n

L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.

", + unread = true, + starred = true, + thumbnail = null, + icon = "ba79e238383ce83c23a169929c8906ef.png", + link = "https://ilblogdellasci.wordpress.com/2022/09/09/etica-della-ricerca-sotto-i-riflettori/", + sourcetitle = "La Chimica e la Società", + tags = "Chimica, Testing" +)) \ No newline at end of file -- 2.34.1 From 5853a199378033e2d625e36e004bd1b9c5bd623a Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sat, 10 Sep 2022 09:08:26 +0200 Subject: [PATCH 02/35] Normal items fetch test --- .../repository/RepositoryTest.kt | 73 +++++++++++++++---- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 178a695..3a2a475 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -10,8 +10,10 @@ import io.mockk.coEvery import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.runBlocking import kotlin.test.BeforeTest import kotlin.test.Test +import kotlin.test.assertSame class RepositoryTest() { private val connectivityStatus = mockk() @@ -51,18 +53,63 @@ class RepositoryTest() { val repository = Repository(api, appSettingsService, connectivityStatus, db) } + + @Test + fun `Get newer items`() { + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + runBlocking { + repository.getNewerItems() + } + + assertSame(repository.items.size, 1) + } } -fun generateTestDBItems() = listOf(ITEM( - id = "20", - datetime = "2022-09-09T03:32:01-04:00", - title = "Etica della ricerca sotto i riflettori.", - content = "

Luigi Campanella, già Presidente SCI

\n

L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.

\n

L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.

\n

Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.

\n

Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.

\n

Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.

\n

La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.

\n

L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.

\n\"\"\"\"

Magdalena Zernicka-Goetz

\n\"\"

Gianluca Amadei

\n

Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.

\n

L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.

", - unread = true, - starred = true, - thumbnail = null, - icon = "ba79e238383ce83c23a169929c8906ef.png", - link = "https://ilblogdellasci.wordpress.com/2022/09/09/etica-della-ricerca-sotto-i-riflettori/", - sourcetitle = "La Chimica e la Società", - tags = "Chimica, Testing" -)) \ No newline at end of file +fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { + return listOf(ITEM( + id = item.id, + datetime = item.datetime, + title = item.title, + content = item.content, + unread = item.unread, + starred = item.starred, + thumbnail = item.thumbnail, + icon = item.icon, + link = item.link, + sourcetitle = item.sourcetitle, + tags = item.tags +))} + +fun generateTestApiItem(item : FakeItemParameters = FakeItemParameters()) : List { + return listOf( + SelfossModel.Item( + id = item.id.toInt(), + datetime = item.datetime, + title = item.title, + content = item.content, + unread = item.unread, + starred = item.starred, + thumbnail = item.thumbnail, + icon = item.icon, + link = item.link, + sourcetitle = item.sourcetitle, + tags = item.tags.split(',') + ) + ) +} + +class FakeItemParameters() { + val id = "20" + val datetime = "2022-09-09T03:32:01-04:00" + val title = "Etica della ricerca sotto i riflettori." + val content = "

Luigi Campanella, già Presidente SCI

\n

L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.

\n

L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.

\n

Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.

\n

Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.

\n

Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.

\n

La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.

\n

L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.

\n\"\"\"\"

Magdalena Zernicka-Goetz

\n\"\"

Gianluca Amadei

\n

Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.

\n

L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.

" + val unread = true + val starred = true + val thumbnail = null + val icon = "ba79e238383ce83c23a169929c8906ef.png" + val link = "https://ilblogdellasci.wordpress.com/2022/09/09/etica-della-ricerca-sotto-i-riflettori/" + val sourcetitle = "La Chimica e la Società" + val tags = "Chimica, Testing" +} \ No newline at end of file -- 2.34.1 From 60c24fc75af53619b2b8d60794dd8a3934e11b75 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sat, 10 Sep 2022 09:37:14 +0200 Subject: [PATCH 03/35] Check that the api is being used rather than the db --- .../apps/readerforselfossv2/repository/RepositoryTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 3a2a475..5981752 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -6,9 +6,7 @@ import bou.amine.apps.readerforselfossv2.model.SelfossModel import bou.amine.apps.readerforselfossv2.rest.SelfossApi import bou.amine.apps.readerforselfossv2.service.AppSettingsService import com.github.ln_12.library.ConnectivityStatus -import io.mockk.coEvery -import io.mockk.every -import io.mockk.mockk +import io.mockk.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlin.test.BeforeTest @@ -64,6 +62,8 @@ class RepositoryTest() { } assertSame(repository.items.size, 1) + coVerify(exactly = 1) { api.getItems("unread", 0, null, null, null, null, any()) } + verify(exactly = 0) { db.itemsQueries.items().executeAsList()} } } -- 2.34.1 From a4636cc0c874e906f74f2ce415c69ac63015f458 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Thu, 15 Sep 2022 14:07:50 +0200 Subject: [PATCH 04/35] Add item fetching tests --- .../repository/RepositoryTest.kt | 128 +++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 5981752..c90a570 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -5,12 +5,14 @@ import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB 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 com.github.ln_12.library.ConnectivityStatus import io.mockk.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlin.test.BeforeTest import kotlin.test.Test +import kotlin.test.assertNotSame import kotlin.test.assertSame class RepositoryTest() { @@ -23,6 +25,7 @@ class RepositoryTest() { fun setup() { every { appSettingsService.getApiVersion() } returns 4 every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/" + every { appSettingsService.isItemCachingEnabled() } returns false every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true) @@ -52,6 +55,37 @@ class RepositoryTest() { val repository = Repository(api, appSettingsService, connectivityStatus, db) } + @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 generateTestApiItem() + every { appSettingsService.updateApiVersion(any()) } returns Unit + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 null + val itemParameters = FakeItemParameters() + itemParameters.datetime = "2021-04-23 11:45:32" + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem(itemParameters) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + runBlocking { + repository.getNewerItems() + } + + assertSame(1, repository.items.size) + } + @Test fun `Get newer items`() { coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() @@ -65,6 +99,98 @@ class RepositoryTest() { 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 generateTestApiItem() + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 generateTestApiItem() + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isItemCachingEnabled() } returns true + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 generateTestApiItem() + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 generateTestApiItem() + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 generateTestApiItem() + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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()} + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { @@ -102,7 +228,7 @@ fun generateTestApiItem(item : FakeItemParameters = FakeItemParameters()) : List class FakeItemParameters() { val id = "20" - val datetime = "2022-09-09T03:32:01-04:00" + var datetime = "2022-09-09T03:32:01-04:00" val title = "Etica della ricerca sotto i riflettori." val content = "

Luigi Campanella, già Presidente SCI

\n

L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.

\n

L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.

\n

Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.

\n

Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.

\n

Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.

\n

La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.

\n

L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.

\n\"\"\"\"

Magdalena Zernicka-Goetz

\n\"\"

Gianluca Amadei

\n

Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.

\n

L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.

" val unread = true -- 2.34.1 From cda3ba6cb4092154222be6d3ac39da9d2d6c76de Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 16 Sep 2022 12:04:05 +0200 Subject: [PATCH 05/35] Test badge fetching --- .../repository/RepositoryTest.kt | 98 ++++++++++++++++++- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index c90a570..a78a858 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -12,7 +12,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlin.test.BeforeTest import kotlin.test.Test -import kotlin.test.assertNotSame import kotlin.test.assertSame class RepositoryTest() { @@ -21,8 +20,13 @@ class RepositoryTest() { private val appSettingsService = mockk() private val api = mockk() + private val NUMBER_ARTICLES = 100 + private val NUMBER_UNREAD = 50 + private val NUMBER_STARRED = 20 + @BeforeTest fun setup() { + clearAllMocks() every { appSettingsService.getApiVersion() } returns 4 every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/" every { appSettingsService.isItemCachingEnabled() } returns false @@ -30,7 +34,7 @@ class RepositoryTest() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true) coEvery { api.version() } returns SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0") - coEvery { api.stats() } returns SelfossModel.Stats(100, 50, 20) + coEvery { api.stats() } returns SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED) every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems() } @@ -191,6 +195,92 @@ class RepositoryTest() { 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 = false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 null + + var success = false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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 with items caching`() { + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isItemCachingEnabled() } returns true + + val itemParameter = FakeItemParameters() + itemParameter.starred = true + itemParameter.unread = false + + var success = false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + repository.items = ArrayList(generateTestApiItem(itemParameter)) + runBlocking { + success = repository.reloadBadges() + } + + assertSame(true, success) + assertSame(1, repository.badgeAll) + assertSame(0, repository.badgeUnread) + assertSame(1, repository.badgeStarred) + coVerify(exactly = 0) { api.stats() } + verify(atLeast = 1) { db.itemsQueries.items().executeAsList()} + } + + @Test + fun `Reload badges without items caching`() { + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isItemCachingEnabled() } returns false + + val itemParameter = FakeItemParameters() + itemParameter.starred = true + itemParameter.unread = false + + var success = false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + repository.items = ArrayList(generateTestApiItem(itemParameter)) + runBlocking { + success = repository.reloadBadges() + } + + assertSame(false, 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()} + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { @@ -231,8 +321,8 @@ class FakeItemParameters() { var datetime = "2022-09-09T03:32:01-04:00" val title = "Etica della ricerca sotto i riflettori." val content = "

Luigi Campanella, già Presidente SCI

\n

L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.

\n

L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.

\n

Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.

\n

Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.

\n

Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.

\n

La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.

\n

L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.

\n\"\"\"\"

Magdalena Zernicka-Goetz

\n\"\"

Gianluca Amadei

\n

Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.

\n

L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.

" - val unread = true - val starred = true + var unread = true + var starred = true val thumbnail = null val icon = "ba79e238383ce83c23a169929c8906ef.png" val link = "https://ilblogdellasci.wordpress.com/2022/09/09/etica-della-ricerca-sotto-i-riflettori/" -- 2.34.1 From c0381144d1baca385fc186c8ba8ddf41c47591d4 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sat, 17 Sep 2022 21:29:37 +0200 Subject: [PATCH 06/35] Add CI test step --- .drone.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.drone.yml b/.drone.yml index b401477..2e44be0 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,6 +15,11 @@ steps: SONAR_LOGIN: from_secret: sonarScannerLogin + - name: test + image: mingc/android-build-box:latest + commands: + - ./gradlew test -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false + - name: build image: mingc/android-build-box:latest commands: -- 2.34.1 From 758708e18d44b1bf7a0adc1db61148ed16bf28d0 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sat, 17 Sep 2022 22:04:24 +0200 Subject: [PATCH 07/35] Tags tests --- .../repository/RepositoryImpl.kt | 6 +- .../repository/RepositoryTest.kt | 116 ++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index e5dbc14..0dc55d9 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -380,11 +380,13 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun deleteDBAction(action: ACTION) = db.actionsQueries.deleteAction(action.id) + // TODO: This function should be private fun getDBTags(): List = db.tagsQueries.tags().executeAsList() + // TODO: This function should be private fun getDBSources(): List = db.sourcesQueries.sources().executeAsList() - fun resetDBTagsWithData(tagEntities: List) { + private fun resetDBTagsWithData(tagEntities: List) { db.tagsQueries.deleteAllTags() db.tagsQueries.transaction { @@ -394,7 +396,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } - fun resetDBSourcesWithData(sources: List) { + private fun resetDBSourcesWithData(sources: List) { db.sourcesQueries.deleteAllSources() db.sourcesQueries.transaction { diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index a78a858..8e0e5c3 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -2,16 +2,19 @@ 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.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.toEntity import com.github.ln_12.library.ConnectivityStatus import io.mockk.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlin.test.BeforeTest import kotlin.test.Test +import kotlin.test.assertNotSame import kotlin.test.assertSame class RepositoryTest() { @@ -30,6 +33,7 @@ class RepositoryTest() { every { appSettingsService.getApiVersion() } returns 4 every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/" every { appSettingsService.isItemCachingEnabled() } returns false + every { appSettingsService.isUpdateSourcesEnabled() } returns true every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true) @@ -37,6 +41,9 @@ class RepositoryTest() { coEvery { api.stats() } returns 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 @@ -281,6 +288,115 @@ class RepositoryTest() { 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)) + + coEvery { api.tags() } returns tags + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List? = null + runBlocking { + testTags = repository.getTags() + } + + assertSame(tags, testTags) + verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + } + + @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 tags + coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB + every { appSettingsService.isUpdateSourcesEnabled() } returns false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List? = null + runBlocking { + testTags = repository.getTags() + } + + assertNotSame(tags, testTags) + assertSame(tagsDB.first().name, testTags?.first()?.tag) + coVerify(exactly = 0) { api.tags() } + verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } + } + + @Test + fun `Get tags with sources update and db 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 tags + coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB + every { appSettingsService.isUpdateSourcesEnabled() } returns false + every { appSettingsService.isItemCachingEnabled() } returns false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List? = null + runBlocking { + testTags = repository.getTags() + } + + assertSame(null, testTags) + coVerify(exactly = 0) { api.tags() } + verify(exactly = 0) { 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 tags + coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List? = null + runBlocking { + testTags = repository.getTags() + } + + assertNotSame(tags, testTags) + assertSame(tagsDB.first().name, testTags?.first()?.tag) + 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 tags + coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isItemCachingEnabled() } returns false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List? = null + runBlocking { + testTags = repository.getTags() + } + + assertSame(null, testTags) + coVerify(exactly = 0) { api.tags() } + verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From ef994460c1cb5d22ff37d2cba300351c2444c69a Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sun, 18 Sep 2022 18:14:14 +0200 Subject: [PATCH 08/35] get sources tests --- .../repository/RepositoryImpl.kt | 1 + .../repository/RepositoryTest.kt | 110 +++++++++++++++++- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 0dc55d9..f1add44 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -148,6 +148,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } + // TODO: Add tests suspend fun getSpouts(): Map? { return if (isNetworkAvailable()) { api.spouts() diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 8e0e5c3..eff73b9 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -2,20 +2,19 @@ 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.toEntity +import bou.amine.apps.readerforselfossv2.utils.toView import com.github.ln_12.library.ConnectivityStatus import io.mockk.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertNotSame -import kotlin.test.assertSame +import kotlin.test.* class RepositoryTest() { private val connectivityStatus = mockk() @@ -397,6 +396,109 @@ class RepositoryTest() { coVerify(exactly = 0) { api.tags() } verify(exactly = 0) { 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")) + + coEvery { api.sources() } returns sources + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertSame(sources, testSources) + coVerify(exactly = 1) { api.sources() } + verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } + } + + @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 source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"), + SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")) + + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + coEvery { api.sources() } returns sources + every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertContentEquals(sources, 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 source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"), + SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")) + + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isItemCachingEnabled() } returns false + coEvery { api.sources() } returns sources + every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertSame(null, testSources) + coVerify(exactly = 0) { api.sources() } + verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } + } + + @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 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 + coEvery { api.sources() } returns sources + every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertContentEquals(sources, testSources) + coVerify(exactly = 0) { api.sources() } + verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } + } + + @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 sources + every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertSame(null, testSources) + coVerify(exactly = 0) { api.sources() } + verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From 366b2e10f15554da7320a4630bf7552637fe86bb Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sun, 25 Sep 2022 22:02:25 +0200 Subject: [PATCH 09/35] Adjust tests to changes in the data models --- .../repository/RepositoryTest.kt | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index eff73b9..73f6cb0 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -8,8 +8,6 @@ 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.toEntity -import bou.amine.apps.readerforselfossv2.utils.toView import com.github.ln_12.library.ConnectivityStatus import io.mockk.* import kotlinx.coroutines.flow.MutableStateFlow @@ -36,8 +34,8 @@ class RepositoryTest() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true) - coEvery { api.version() } returns SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0") - coEvery { api.stats() } returns SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED) + 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 @@ -60,7 +58,7 @@ class RepositoryTest() { @Test fun `Instantiate repository with negative stats`() { - coEvery { api.stats() } returns SelfossModel.Stats(-100, -50, -20) + coEvery { api.stats() } returns SelfossModel.StatusAndData(success = true, data = SelfossModel.Stats(-100, -50, -20)) val repository = Repository(api, appSettingsService, connectivityStatus, db) } @@ -68,7 +66,8 @@ class RepositoryTest() { @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 generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) every { appSettingsService.updateApiVersion(any()) } returns Unit val repository = Repository(api, appSettingsService, connectivityStatus, db) @@ -83,10 +82,11 @@ class RepositoryTest() { @Test fun `Get api 1 date with api 4 version stored`() { every { appSettingsService.getApiVersion() } returns 4 - coEvery { api.version() } returns null + 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 generateTestApiItem(itemParameters) + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem(itemParameters)) val repository = Repository(api, appSettingsService, connectivityStatus, db) runBlocking { @@ -98,7 +98,8 @@ class RepositoryTest() { @Test fun `Get newer items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) val repository = Repository(api, appSettingsService, connectivityStatus, db) runBlocking { @@ -112,7 +113,8 @@ class RepositoryTest() { @Test fun `Get all newer items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) val repository = Repository(api, appSettingsService, connectivityStatus, db) repository.displayedItems = ItemType.ALL @@ -127,7 +129,8 @@ class RepositoryTest() { @Test fun `Get newer starred items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) val repository = Repository(api, appSettingsService, connectivityStatus, db) repository.displayedItems = ItemType.STARRED @@ -157,7 +160,8 @@ class RepositoryTest() { @Test fun `Get older items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) val repository = Repository(api, appSettingsService, connectivityStatus, db) repository.items = ArrayList(generateTestApiItem()) @@ -172,7 +176,8 @@ class RepositoryTest() { @Test fun `Get all older items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) val repository = Repository(api, appSettingsService, connectivityStatus, db) repository.items = ArrayList(generateTestApiItem()) @@ -188,7 +193,8 @@ class RepositoryTest() { @Test fun `Get older starred items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns generateTestApiItem() + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) val repository = Repository(api, appSettingsService, connectivityStatus, db) repository.displayedItems = ItemType.STARRED @@ -221,7 +227,7 @@ class RepositoryTest() { @Test fun `Reload badges without response`() { - coEvery { api.stats() } returns null + coEvery { api.stats() } returns SelfossModel.StatusAndData(success = false, data = null) var success = false @@ -293,7 +299,7 @@ class RepositoryTest() { val tags = listOf(SelfossModel.Tag("test", "red", 6), SelfossModel.Tag("second", "yellow", 0)) - coEvery { api.tags() } returns tags + coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List? = null @@ -312,7 +318,7 @@ class RepositoryTest() { val tagsDB = listOf(TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0)) - coEvery { api.tags() } returns tags + coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { appSettingsService.isUpdateSourcesEnabled() } returns false @@ -335,7 +341,7 @@ class RepositoryTest() { val tagsDB = listOf(TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0)) - coEvery { api.tags() } returns tags + 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 @@ -358,7 +364,7 @@ class RepositoryTest() { val tagsDB = listOf(TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0)) - coEvery { api.tags() } returns tags + coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) @@ -381,7 +387,7 @@ class RepositoryTest() { val tagsDB = listOf(TAG("test_DB", "red", 6), TAG("second_DB", "yellow", 0)) - coEvery { api.tags() } returns tags + coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isItemCachingEnabled() } returns false @@ -402,7 +408,7 @@ class RepositoryTest() { 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")) - coEvery { api.sources() } returns sources + coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) val repository = Repository(api, appSettingsService, connectivityStatus, db) var testSources: List? = null runBlocking { @@ -422,7 +428,7 @@ class RepositoryTest() { SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")) every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) - coEvery { api.sources() } returns sources + coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB val repository = Repository(api, appSettingsService, connectivityStatus, db) var testSources: List? = null @@ -444,7 +450,7 @@ class RepositoryTest() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isItemCachingEnabled() } returns false - coEvery { api.sources() } returns sources + coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB val repository = Repository(api, appSettingsService, connectivityStatus, db) var testSources: List? = null @@ -465,7 +471,7 @@ class RepositoryTest() { SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")) every { appSettingsService.isUpdateSourcesEnabled() } returns false - coEvery { api.sources() } returns sources + coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB val repository = Repository(api, appSettingsService, connectivityStatus, db) var testSources: List? = null @@ -487,7 +493,7 @@ class RepositoryTest() { every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns false - coEvery { api.sources() } returns sources + coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB val repository = Repository(api, appSettingsService, connectivityStatus, db) var testSources: List? = null -- 2.34.1 From 63c550ead38c689ccefb4f5c87a48cf3cd810351 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 22:21:48 +0200 Subject: [PATCH 10/35] Test create source --- .../repository/RepositoryImpl.kt | 6 ++- .../repository/RepositoryTest.kt | 46 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 65fbfbe..22d9a7f 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -181,6 +181,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } + // TODO: Add tests suspend fun markAsRead(item: SelfossModel.Item): Boolean { val success = markAsReadById(item.id) @@ -199,7 +200,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } - + // TODO: Add tests suspend fun unmarkAsRead(item: SelfossModel.Item): Boolean { val success = unmarkAsReadById(item.id) @@ -218,6 +219,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } + // TODO: Add tests suspend fun starr(item: SelfossModel.Item): Boolean { val success = starrById(item.id) @@ -236,6 +238,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } + // TODO: Add tests suspend fun unstarr(item: SelfossModel.Item): Boolean { val success = unstarrById(item.id) @@ -254,6 +257,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } + // TODO: Add tests suspend fun markAllAsRead(items: ArrayList): Boolean { var success = false diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 73f6cb0..34891bf 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -505,6 +505,52 @@ class RepositoryTest() { coVerify(exactly = 0) { api.sources() } verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } } + + @Test + fun `create source`() { + coEvery { api.createSourceForVersion(any(), any(), any(), any(), any(), any()) } returns + SelfossModel.SuccessResponse(true) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From 71c0a4d3401af0a4186e3e84002103c5f149f614 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 22:26:01 +0200 Subject: [PATCH 11/35] Test delete source --- .../repository/RepositoryTest.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 34891bf..137acfd 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -551,6 +551,49 @@ class RepositoryTest() { 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) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + runBlocking { + response = repository.deleteSource(5) + } + + coVerify(exactly = 0) { api.deleteSource(5) } + assertSame(false, response) + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From bf6f1a917ee95dd4c1fb8a0c76c1e6945105955c Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 22:42:24 +0200 Subject: [PATCH 12/35] Test update remote --- .../repository/RepositoryTest.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 137acfd..4672515 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -594,6 +594,49 @@ class RepositoryTest() { coVerify(exactly = 0) { api.deleteSource(5) } assertSame(false, response) } + + @Test + fun `update remote`() { + coEvery { api.update()} returns SelfossModel.StatusAndData(success = true, data = "finished") + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + runBlocking { + response = repository.updateRemote() + } + + coVerify(exactly = 1) { api.update() } + assertSame(true, response) + } + + @Test + fun `update remote but response fails`() { + coEvery { api.update()} returns SelfossModel.StatusAndData(success = false, data = "undocumented...") + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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...") + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + runBlocking { + response = repository.updateRemote() + } + + coVerify(exactly = 0) { api.update() } + assertSame(false, response) + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From f46f98cef04b5fbdcf0cdb19bb18f4169c4395bf Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 22:46:37 +0200 Subject: [PATCH 13/35] Test login --- .../repository/RepositoryTest.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 4672515..ea76e26 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -637,6 +637,49 @@ class RepositoryTest() { coVerify(exactly = 0) { api.update() } assertSame(false, response) } + + @Test + fun login() { + coEvery { api.login() } returns SelfossModel.SuccessResponse(success = true) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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) + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + runBlocking { + response = repository.login() + } + + coVerify(exactly = 0) { api.login() } + assertSame(false, response) + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From 3f0a3903ae0b2ab34dab0a08595e02e7d8d162a5 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 22:50:55 +0200 Subject: [PATCH 14/35] Test refresh login information --- .../readerforselfossv2/repository/RepositoryTest.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index ea76e26..dc762a2 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -680,6 +680,18 @@ class RepositoryTest() { 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 + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + repository.refreshLoginInformation("https://test.com/selfoss/", "login", "password") + + coVerify(exactly = 1) { api.refreshLoginInformation() } + coVerify(exactly = 1) {appSettingsService.refreshLoginInformation("https://test.com/selfoss/", "login", "password")} + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From a382fc89eaf1e38af7a78c0a631b04743e919abd Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 23:11:26 +0200 Subject: [PATCH 15/35] Test item caching --- .../android/fragments/ArticleFragment.kt | 1 + .../repository/RepositoryImpl.kt | 5 +- .../repository/RepositoryTest.kt | 76 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt index 7e24dea..6cf09b0 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt @@ -269,6 +269,7 @@ class ArticleFragment : Fragment(), DIAware { private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) { if (repository.isNetworkAvailable()) { binding.progressBar.visibility = View.VISIBLE + // TODO: The api should be accessed through the repository val parser = MercuryApi() parser.parseUrl(url).enqueue( diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 22d9a7f..9acb07e 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -378,6 +378,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap api.refreshLoginInformation() } + // TODO: This should be private suspend fun updateApiVersion() { val apiMajorVersion = appSettingsService.getApiVersion() @@ -389,6 +390,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } + // TODO: This should be private (since all api calls are made through the repository + // no other entity needs to know about the connectivity status) fun isNetworkAvailable() = isConnectionAvailable.value && !offlineOverride private fun getDBActions(): List = @@ -440,7 +443,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString()) - suspend fun tryToCacheItemsAndGetNewOnes(): List? { + suspend fun tryToCacheItemsAndGetNewOnes(): List { try { val newItems = getMaxItemsForBackground(ItemType.UNREAD) val allItems = getMaxItemsForBackground(ItemType.ALL) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index dc762a2..cc498a2 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -692,6 +692,82 @@ class RepositoryTest() { coVerify(exactly = 1) { api.refreshLoginInformation() } coVerify(exactly = 1) {appSettingsService.refreshLoginInformation("https://test.com/selfoss/", "login", "password")} } + + @Test + fun `cache items`() { + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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" + var items = emptyList() + runBlocking { + items = repository.tryToCacheItemsAndGetNewOnes() + } + + coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } + assertSame(3, items.size) + } + + @Test + fun `cache items but response fails`() { + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = false, data = generateTestApiItem()) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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" + var items = emptyList() + runBlocking { + items = repository.tryToCacheItemsAndGetNewOnes() + } + + coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } + assertSame(0, items.size) + } + + @Test + fun `cache items without connection`() { + coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns + SelfossModel.StatusAndData(success = false, data = generateTestApiItem()) + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + 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" + var items = emptyList() + runBlocking { + items = repository.tryToCacheItemsAndGetNewOnes() + } + + coVerify(exactly = 0) { api.getItems(any(), 0, null, null, null, null, 200) } + assertSame(emptyList(), items) + } } fun generateTestDBItems(item : FakeItemParameters = FakeItemParameters()) : List { -- 2.34.1 From e2afff0b8e0917bc59e1153a2d3bf07c9fcd3cb9 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Mon, 26 Sep 2022 23:19:31 +0200 Subject: [PATCH 16/35] Add comment --- .../amine/apps/readerforselfossv2/repository/RepositoryImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 9acb07e..cc2d700 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -456,6 +456,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap return emptyList() } + // TODO: Add tests suspend fun handleDBActions() { val actions: List = getDBActions() -- 2.34.1 From 41c951b6593087a939f19215dd45f011f6209b9a Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 27 Sep 2022 23:16:30 +0200 Subject: [PATCH 17/35] Add test cases for repository instantiation cases --- .../repository/RepositoryTest.kt | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index cc498a2..b18f653 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -45,7 +45,14 @@ class RepositoryTest() { @Test fun `Instantiate repository`() { - val repository = Repository(api, appSettingsService, connectivityStatus, db) + val success = try { + Repository(api, appSettingsService, connectivityStatus, db) + true + } catch (e: Exception) { + false + } + + assertEquals(true, success) } @Test @@ -53,14 +60,28 @@ class RepositoryTest() { every { appSettingsService.getApiVersion() } returns -1 every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) - val repository = Repository(api, appSettingsService, connectivityStatus, db) + val success = try { + Repository(api, appSettingsService, connectivityStatus, db) + true + } catch (e: Exception) { + false + } + + assertEquals(true, success) } @Test fun `Instantiate repository with negative stats`() { coEvery { api.stats() } returns SelfossModel.StatusAndData(success = true, data = SelfossModel.Stats(-100, -50, -20)) - val repository = Repository(api, appSettingsService, connectivityStatus, db) + val success = try { + Repository(api, appSettingsService, connectivityStatus, db) + true + } catch (e: Exception) { + false + } + + assertEquals(true, success) } @Test -- 2.34.1 From 7517626ab79594f46deb7f171f738d15fe56610e Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 27 Sep 2022 23:25:47 +0200 Subject: [PATCH 18/35] Include database return definition within test function --- .../amine/apps/readerforselfossv2/repository/RepositoryTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index b18f653..3114cfc 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -269,6 +269,7 @@ class RepositoryTest() { fun `Reload badges with items caching`() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isItemCachingEnabled() } returns true + every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems() val itemParameter = FakeItemParameters() itemParameter.starred = true -- 2.34.1 From cb4f2f02ef07b0b7b96783f5b8ebf5c919ff838b Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 27 Sep 2022 23:26:44 +0200 Subject: [PATCH 19/35] Fix repository.tags() returning null --- .../apps/readerforselfossv2/repository/RepositoryImpl.kt | 4 ++-- .../apps/readerforselfossv2/repository/RepositoryTest.kt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index cc2d700..541425c 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -143,13 +143,13 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap return success } - suspend fun getTags(): List? { + suspend fun getTags(): List { return if (isNetworkAvailable()) { val apiTags = api.tags() if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { resetDBTagsWithData(apiTags.data) } - apiTags.data + apiTags.data ?: emptyList() } else { getDBTags().map { it.toView() } } diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 3114cfc..f4ce3e1 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -285,7 +285,7 @@ class RepositoryTest() { assertSame(true, success) assertSame(1, repository.badgeAll) - assertSame(0, repository.badgeUnread) + assertSame(1, repository.badgeUnread) assertSame(1, repository.badgeStarred) coVerify(exactly = 0) { api.stats() } verify(atLeast = 1) { db.itemsQueries.items().executeAsList()} @@ -391,13 +391,13 @@ class RepositoryTest() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) val repository = Repository(api, appSettingsService, connectivityStatus, db) - var testTags: List? = null + var testTags: List = emptyList() runBlocking { testTags = repository.getTags() } assertNotSame(tags, testTags) - assertSame(tagsDB.first().name, testTags?.first()?.tag) + assertSame(tagsDB.first().name, testTags.first().tag) coVerify(exactly = 0) { api.tags() } verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } -- 2.34.1 From c8759cc0358df4cee29f0157dfd4b218319911a7 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 27 Sep 2022 23:37:30 +0200 Subject: [PATCH 20/35] Fix tags tests --- .../repository/RepositoryTest.kt | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index f4ce3e1..4418e5d 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -8,6 +8,7 @@ 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 com.github.ln_12.library.ConnectivityStatus import io.mockk.* import kotlinx.coroutines.flow.MutableStateFlow @@ -345,19 +346,20 @@ class RepositoryTest() { every { appSettingsService.isUpdateSourcesEnabled() } returns false val repository = Repository(api, appSettingsService, connectivityStatus, db) - var testTags: List? = null + var testTags: List = emptyList() runBlocking { testTags = repository.getTags() + testTags = repository.getTags() } assertNotSame(tags, testTags) - assertSame(tagsDB.first().name, testTags?.first()?.tag) - coVerify(exactly = 0) { api.tags() } + assertContentEquals(tagsDB.map { it.toView() }, testTags) + coVerify(exactly = 1) { api.tags() } verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test - fun `Get tags with sources update and db disabled`() { + 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), @@ -369,12 +371,12 @@ class RepositoryTest() { every { appSettingsService.isItemCachingEnabled() } returns false val repository = Repository(api, appSettingsService, connectivityStatus, db) - var testTags: List? = null + var testTags: List = emptyList() runBlocking { testTags = repository.getTags() } - assertSame(null, testTags) + assertSame(emptyList(), testTags) coVerify(exactly = 0) { api.tags() } verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } } @@ -415,14 +417,38 @@ class RepositoryTest() { every { appSettingsService.isItemCachingEnabled() } returns false val repository = Repository(api, appSettingsService, connectivityStatus, db) - var testTags: List? = null + var testTags: List = emptyList() runBlocking { testTags = repository.getTags() } - assertSame(null, testTags) + assertContentEquals(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 0) { api.tags() } - verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + verify(atLeast = 1) { 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 { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isUpdateSourcesEnabled() } returns false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List = emptyList() + runBlocking { + testTags = repository.getTags() + } + + assertNotSame(tags, testTags) + assertContentEquals(tagsDB.map { it.toView() }, testTags) + coVerify(exactly = 0) { api.tags() } + verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test -- 2.34.1 From 4781e30da2ed39b106e494380b9f6ac3cfdd57dd Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 27 Sep 2022 23:44:42 +0200 Subject: [PATCH 21/35] Remove unnecessary safe calls --- .../repository/RepositoryImpl.kt | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 541425c..28fd2d6 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -156,10 +156,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } // TODO: Add tests - suspend fun getSpouts(): Map? { + suspend fun getSpouts(): Map { return if (isNetworkAvailable()) { val spouts = api.spouts() - return if (spouts.success && spouts.data != null) { + if (spouts.success && spouts.data != null) { spouts.data } else { emptyMap() // TODO: do something here @@ -193,7 +193,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun markAsReadById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.markAsRead(id.toString())?.isSuccess + api.markAsRead(id.toString()).isSuccess } else { insertDBAction(id.toString(), read = true) true @@ -212,7 +212,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun unmarkAsReadById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.unmarkAsRead(id.toString())?.isSuccess + api.unmarkAsRead(id.toString()).isSuccess } else { insertDBAction(id.toString(), unread = true) true @@ -231,7 +231,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun starrById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.starr(id.toString())?.isSuccess + api.starr(id.toString()).isSuccess } else { insertDBAction(id.toString(), starred = true) true @@ -250,7 +250,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private suspend fun unstarrById(id: Int): Boolean { return if (isNetworkAvailable()) { - api.unstarr(id.toString())?.isSuccess + api.unstarr(id.toString()).isSuccess } else { insertDBAction(id.toString(), starred = true) true @@ -261,7 +261,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun markAllAsRead(items: ArrayList): Boolean { var success = false - if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess) { + if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() }).isSuccess) { success = true for (item in items) { markAsReadLocally(item) @@ -330,7 +330,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap tags, filter, appSettingsService.getApiVersion() - )?.isSuccess == true + ).isSuccess == true } return response @@ -340,9 +340,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap var success = false if (isNetworkAvailable()) { val response = api.deleteSource(id) - if (response != null) { - success = response.isSuccess - } + success = response.isSuccess } return success @@ -350,7 +348,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun updateRemote(): Boolean { return if (isNetworkAvailable()) { - api.update()?.equals("finished") + api.update().equals("finished") } else { false } @@ -361,7 +359,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap if (isNetworkAvailable()) { try { val response = api.login() - result = response?.isSuccess == true + result = response.isSuccess == true if (result) { updateApiVersion() } -- 2.34.1 From 6cb4b35c9371aee51d4e11a92a55e1dbbe9c0d87 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Wed, 28 Sep 2022 09:14:47 +0200 Subject: [PATCH 22/35] Introduce useful assertions in repository instantiation tests --- .../repository/RepositoryTest.kt | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 4418e5d..d2c9044 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -46,14 +46,10 @@ class RepositoryTest() { @Test fun `Instantiate repository`() { - val success = try { - Repository(api, appSettingsService, connectivityStatus, db) - true - } catch (e: Exception) { - false - } + Repository(api, appSettingsService, connectivityStatus, db) - assertEquals(true, success) + coVerify(exactly = 1) { api.version() } + coVerify(exactly = 1) { api.stats() } } @Test @@ -61,28 +57,23 @@ class RepositoryTest() { every { appSettingsService.getApiVersion() } returns -1 every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) - val success = try { - Repository(api, appSettingsService, connectivityStatus, db) - true - } catch (e: Exception) { - false - } + Repository(api, appSettingsService, connectivityStatus, db) - assertEquals(true, success) + coVerify(exactly = 0) { api.version() } + coVerify(exactly = 0) { api.stats() } } @Test fun `Instantiate repository with negative stats`() { coEvery { api.stats() } returns SelfossModel.StatusAndData(success = true, data = SelfossModel.Stats(-100, -50, -20)) - val success = try { - Repository(api, appSettingsService, connectivityStatus, db) - true - } catch (e: Exception) { - false - } + val repository = Repository(api, appSettingsService, connectivityStatus, db) - assertEquals(true, success) + assertEquals(0, repository.badgeAll) + assertEquals(0, repository.badgeStarred) + assertEquals(0, repository.badgeUnread) + coVerify(exactly = 1) { api.version() } + coVerify(exactly = 1) { api.stats() } } @Test -- 2.34.1 From 2968aee3094a83b0a34e05da6d4eb146f54ada4d Mon Sep 17 00:00:00 2001 From: davidoskky Date: Wed, 28 Sep 2022 09:43:28 +0200 Subject: [PATCH 23/35] Fix badges tests --- .../repository/RepositoryImpl.kt | 5 +++-- .../repository/RepositoryTest.kt | 21 ++++++------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index bb2519e..f235771 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -132,12 +132,13 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap badgeStarred = response.data.starred success = true } - } else { + } else if (appSettingsService.isItemCachingEnabled()) { // TODO: do this differently, because it's not efficient val dbItems = getDBItems() badgeUnread = dbItems.filter { item -> item.unread }.size badgeStarred = dbItems.filter { item -> item.starred }.size - badgeAll = items.size + badgeAll = dbItems.size + success = true } return success } diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index d2c9044..094def3 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -31,7 +31,7 @@ class RepositoryTest() { every { appSettingsService.getApiVersion() } returns 4 every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/" every { appSettingsService.isItemCachingEnabled() } returns false - every { appSettingsService.isUpdateSourcesEnabled() } returns true + every { appSettingsService.isUpdateSourcesEnabled() } returns false every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true) @@ -258,24 +258,19 @@ class RepositoryTest() { } @Test - fun `Reload badges with items caching`() { + fun `Reload badges without connection`() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isItemCachingEnabled() } returns true every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems() - val itemParameter = FakeItemParameters() - itemParameter.starred = true - itemParameter.unread = false - var success = false val repository = Repository(api, appSettingsService, connectivityStatus, db) - repository.items = ArrayList(generateTestApiItem(itemParameter)) runBlocking { success = repository.reloadBadges() } - assertSame(true, success) + assertTrue(success) assertSame(1, repository.badgeAll) assertSame(1, repository.badgeUnread) assertSame(1, repository.badgeStarred) @@ -284,23 +279,19 @@ class RepositoryTest() { } @Test - fun `Reload badges without items caching`() { + fun `Reload badges without connection and items caching disabled`() { every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isItemCachingEnabled() } returns false - - val itemParameter = FakeItemParameters() - itemParameter.starred = true - itemParameter.unread = false + every { appSettingsService.isUpdateSourcesEnabled() } returns true var success = false val repository = Repository(api, appSettingsService, connectivityStatus, db) - repository.items = ArrayList(generateTestApiItem(itemParameter)) runBlocking { success = repository.reloadBadges() } - assertSame(false, success) + assertFalse(success) assertSame(0, repository.badgeAll) assertSame(0, repository.badgeUnread) assertSame(0, repository.badgeStarred) -- 2.34.1 From 219cae5d7491ddb395d1afaa7462d4595b9ce5de Mon Sep 17 00:00:00 2001 From: davidoskky Date: Wed, 28 Sep 2022 18:22:06 +0200 Subject: [PATCH 24/35] Fix tags tests --- .../repository/RepositoryImpl.kt | 6 ++-- .../repository/RepositoryTest.kt | 35 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index f235771..5009e38 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -146,12 +146,14 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun getTags(): List { return if (isNetworkAvailable()) { val apiTags = api.tags() - if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { + if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled())) { resetDBTagsWithData(apiTags.data) } apiTags.data ?: emptyList() - } else { + } else if (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled()) { getDBTags().map { it.toView() } + } else { + emptyList() } } diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 094def3..84425af 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -303,8 +303,11 @@ class RepositoryTest() { 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 val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List? = null @@ -313,7 +316,8 @@ class RepositoryTest() { } assertSame(tags, testTags) - verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + assertNotSame(tagsDB.map { it.toView() }, testTags) + coVerify(exactly = 1) { api.tags() } } @Test @@ -331,6 +335,7 @@ class RepositoryTest() { var testTags: List = emptyList() runBlocking { testTags = repository.getTags() + // Tags will be fetched from the database on the second call, thus testTags != tags testTags = repository.getTags() } @@ -358,8 +363,8 @@ class RepositoryTest() { testTags = repository.getTags() } - assertSame(emptyList(), testTags) - coVerify(exactly = 0) { api.tags() } + assertSame(tags, testTags) + coVerify(exactly = 1) { api.tags() } verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } } @@ -433,6 +438,30 @@ class RepositoryTest() { 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 { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isUpdateSourcesEnabled() } returns false + every { appSettingsService.isItemCachingEnabled() } returns false + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List = emptyList() + runBlocking { + testTags = repository.getTags() + } + + assertSame(emptyList(), testTags) + coVerify(exactly = 0) { api.tags() } + verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + } + @Test fun `get sources`() { val sources = arrayListOf(SelfossModel.Source(1, "First source", listOf("Test", "second"),"spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"), -- 2.34.1 From d311c2cdebae84981ec2433aab716bd1d274a579 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Wed, 28 Sep 2022 18:45:21 +0200 Subject: [PATCH 25/35] Fix sources tests --- .../repository/RepositoryImpl.kt | 10 +- .../repository/RepositoryTest.kt | 151 ++++++++++++------ 2 files changed, 108 insertions(+), 53 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 5009e38..fdba511 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -171,15 +171,17 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } - suspend fun getSources(): ArrayList? { + suspend fun getSources(): ArrayList { return if (isNetworkAvailable()) { val apiSources = api.sources() - if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) { + if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled())) { resetDBSourcesWithData(apiSources.data) } - apiSources.data - } else { + apiSources.data ?: ArrayList() + } else if (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled()) { ArrayList(getDBSources().map { it.toView() }) + } else { + ArrayList() } } diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 84425af..46fbc06 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -17,7 +17,7 @@ import kotlin.test.* class RepositoryTest() { private val connectivityStatus = mockk() - private val db = mockk() + private val db = mockk(relaxed = true) private val appSettingsService = mockk() private val api = mockk() @@ -466,8 +466,11 @@ class RepositoryTest() { 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 val repository = Repository(api, appSettingsService, connectivityStatus, db) var testSources: List? = null runBlocking { @@ -475,57 +478,14 @@ class RepositoryTest() { } assertSame(sources, testSources) + assertNotEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 1) { api.sources() } - verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } - } - - @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 source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"), - SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")) - - every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) - coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) - every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB - val repository = Repository(api, appSettingsService, connectivityStatus, db) - var testSources: List? = null - runBlocking { - testSources = repository.getSources() - } - - assertContentEquals(sources, 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 source", "Test,second","spouts\\rss\\fulltextrss", "", "d8c92cdb1ef119ea85c4b9205c879ca7.png"), - SOURCE("2", "Second source", "second","spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.png")) - - every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) - every { appSettingsService.isItemCachingEnabled() } returns false - coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) - every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB - val repository = Repository(api, appSettingsService, connectivityStatus, db) - var testSources: List? = null - runBlocking { - testSources = repository.getSources() - } - - assertSame(null, testSources) - coVerify(exactly = 0) { api.sources() } - verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } } @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 source", listOf("second"),"spouts\\rss\\fulltextrss", "", "b3aa8a664d08eb15d6ff1db2fa83e0d9.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")) @@ -536,10 +496,13 @@ class RepositoryTest() { var testSources: List? = null runBlocking { testSources = repository.getSources() + // Sources will be fetched from the database on the second call, thus testSources != sources + testSources = repository.getSources() } - assertContentEquals(sources, testSources) - coVerify(exactly = 0) { api.sources() } + assertNotSame(sources, testSources) + assertContentEquals(sourcesDB.map { it.toView() }, testSources) + coVerify(exactly = 1) { api.sources() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @@ -560,7 +523,97 @@ class RepositoryTest() { testSources = repository.getSources() } - assertSame(null, testSources) + assertSame(sources, testSources) + coVerify(exactly = 1) { api.sources() } + verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } + } + + @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")) + + every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + coEvery { api.sources() } returns SelfossModel.StatusAndData(success = true, data = sources) + every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertContentEquals(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 { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + 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 + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertContentEquals(sourcesDB.map { it.toView() }, testSources) + coVerify(exactly = 0) { api.sources() } + verify(atLeast = 1) { 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 { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + 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 + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertContentEquals(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 { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + 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 + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + runBlocking { + testSources = repository.getSources() + } + + assertContentEquals(ArrayList(), testSources) coVerify(exactly = 0) { api.sources() } verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } } -- 2.34.1 From 7211fdb1a3a272410b10b01079d4b27488bb17f9 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Thu, 29 Sep 2022 18:58:00 +0200 Subject: [PATCH 26/35] Fix update remote tests --- .../repository/RepositoryImpl.kt | 2 +- .../repository/RepositoryTest.kt | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index fdba511..26f4ebb 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -352,7 +352,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap suspend fun updateRemote(): Boolean { return if (isNetworkAvailable()) { - api.update().equals("finished") + api.update().data.equals("finished") } else { false } diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 46fbc06..3a9a27e 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -718,12 +718,26 @@ class RepositoryTest() { } coVerify(exactly = 1) { api.update() } - assertSame(true, response) + assertTrue(response) } @Test fun `update remote but response fails`() { - coEvery { api.update()} returns SelfossModel.StatusAndData(success = false, data = "undocumented...") + coEvery { api.update()} returns SelfossModel.StatusAndData(success = false, data = "unallowed access") + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var response = false + 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") val repository = Repository(api, appSettingsService, connectivityStatus, db) var response = false -- 2.34.1 From 0e96d313ec69eadbf20f1c460ff5dc96bf230ccc Mon Sep 17 00:00:00 2001 From: davidoskky Date: Thu, 29 Sep 2022 19:09:09 +0200 Subject: [PATCH 27/35] Add tags parameters explicitly --- .../apps/readerforselfossv2/repository/RepositoryTest.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 3a9a27e..567dbd6 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -308,6 +308,8 @@ class RepositoryTest() { 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 val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List? = null @@ -330,6 +332,7 @@ class RepositoryTest() { 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 val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List = emptyList() @@ -378,6 +381,8 @@ class RepositoryTest() { coEvery { api.tags() } returns SelfossModel.StatusAndData(success = true, data = tags) coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) + every { appSettingsService.isUpdateSourcesEnabled() } returns true + every { appSettingsService.isItemCachingEnabled() } returns true val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List = emptyList() @@ -386,7 +391,7 @@ class RepositoryTest() { } assertNotSame(tags, testTags) - assertSame(tagsDB.first().name, testTags.first().tag) + assertContentEquals(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 0) { api.tags() } verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @@ -402,6 +407,7 @@ class RepositoryTest() { coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isItemCachingEnabled() } returns false + every { appSettingsService.isUpdateSourcesEnabled() } returns true val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List = emptyList() @@ -425,6 +431,7 @@ class RepositoryTest() { coEvery { db.tagsQueries.tags().executeAsList() } returns tagsDB every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false) every { appSettingsService.isUpdateSourcesEnabled() } returns false + every { appSettingsService.isItemCachingEnabled() } returns true val repository = Repository(api, appSettingsService, connectivityStatus, db) var testTags: List = emptyList() -- 2.34.1 From 920d4ac1ef99bf0f53fd7253f4a52100b32b86c1 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Thu, 29 Sep 2022 19:34:25 +0200 Subject: [PATCH 28/35] Correctly implement disabling sources update --- .../repository/RepositoryImpl.kt | 23 ++++-- .../repository/RepositoryTest.kt | 74 +++++++++++++++---- 2 files changed, 78 insertions(+), 19 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 26f4ebb..3afd977 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -37,6 +37,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap var badgeStarred = 0 set(value) {field = if (value < 0) { 0 } else { value } } + private var fetchedSources = false + private var fetchedTags = false + init { // TODO: Dispatchers.IO not available in KMM, an alternative solution should be found runBlocking { @@ -144,13 +147,17 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } suspend fun getTags(): List { - return if (isNetworkAvailable()) { + val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() + return if (isNetworkAvailable() && !fetchedTags) { val apiTags = api.tags() - if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled())) { + if (apiTags.success && apiTags.data != null && isDatabaseEnabled) { resetDBTagsWithData(apiTags.data) + if (!appSettingsService.isUpdateSourcesEnabled()) { + fetchedTags = true + } } apiTags.data ?: emptyList() - } else if (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled()) { + } else if (isDatabaseEnabled) { getDBTags().map { it.toView() } } else { emptyList() @@ -172,13 +179,17 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } suspend fun getSources(): ArrayList { - return if (isNetworkAvailable()) { + val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() + return if (isNetworkAvailable() && !fetchedSources) { val apiSources = api.sources() - if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled())) { + if (apiSources.success && apiSources.data != null && isDatabaseEnabled) { resetDBSourcesWithData(apiSources.data) + if (!appSettingsService.isUpdateSourcesEnabled()) { + fetchedSources = true + } } apiSources.data ?: ArrayList() - } else if (appSettingsService.isItemCachingEnabled() || appSettingsService.isUpdateSourcesEnabled()) { + } else if (isDatabaseEnabled) { ArrayList(getDBSources().map { it.toView() }) } else { ArrayList() diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 567dbd6..7ca5948 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -342,12 +342,35 @@ class RepositoryTest() { testTags = repository.getTags() } + coVerify(exactly = 1) { api.tags() } assertNotSame(tags, testTags) assertContentEquals(tagsDB.map { it.toView() }, testTags) - coVerify(exactly = 1) { api.tags() } 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 + + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testTags: List = emptyList() + 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), @@ -364,11 +387,13 @@ class RepositoryTest() { var testTags: List = emptyList() runBlocking { testTags = repository.getTags() + testTags = repository.getTags() } - assertSame(tags, testTags) coVerify(exactly = 1) { api.tags() } - verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + assertNotSame(tags, testTags) + assertContentEquals(tagsDB.map { it.toView() }, testTags) + verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test @@ -415,9 +440,9 @@ class RepositoryTest() { testTags = repository.getTags() } - assertContentEquals(tagsDB.map { it.toView() }, testTags) + assertSame(emptyList(), testTags) coVerify(exactly = 0) { api.tags() } - verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } + verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } } @Test @@ -464,9 +489,9 @@ class RepositoryTest() { testTags = repository.getTags() } - assertSame(emptyList(), testTags) + assertContentEquals(tagsDB.map { it.toView() }, testTags) coVerify(exactly = 0) { api.tags() } - verify(exactly = 0) { db.tagsQueries.tags().executeAsList() } + verify(atLeast = 1) { db.tagsQueries.tags().executeAsList() } } @Test @@ -497,6 +522,7 @@ class RepositoryTest() { 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 val repository = Repository(api, appSettingsService, connectivityStatus, db) @@ -507,12 +533,34 @@ class RepositoryTest() { testSources = repository.getSources() } + coVerify(exactly = 1) { api.sources() } assertNotSame(sources, testSources) assertContentEquals(sourcesDB.map { it.toView() }, testSources) - coVerify(exactly = 1) { api.sources() } 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 + val repository = Repository(api, appSettingsService, connectivityStatus, db) + var testSources: List? = null + 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"), @@ -532,7 +580,7 @@ class RepositoryTest() { assertSame(sources, testSources) coVerify(exactly = 1) { api.sources() } - verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } + verify(atLeast = 1) { db.sourcesQueries } } @Test @@ -574,9 +622,9 @@ class RepositoryTest() { testSources = repository.getSources() } - assertContentEquals(sourcesDB.map { it.toView() }, testSources) + assertContentEquals(ArrayList(), testSources) coVerify(exactly = 0) { api.sources() } - verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } + verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } } @Test @@ -620,9 +668,9 @@ class RepositoryTest() { testSources = repository.getSources() } - assertContentEquals(ArrayList(), testSources) + assertContentEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 0) { api.sources() } - verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } + verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @Test -- 2.34.1 From a9c7ec3dc15ddd78fe6ff5ac68b953050411fca7 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 01:19:28 +0200 Subject: [PATCH 29/35] Cache items in background without filtering --- .../repository/RepositoryImpl.kt | 8 ++++---- .../repository/RepositoryTest.kt | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 3afd977..c484a26 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -109,9 +109,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap val items = api.getItems( itemType.type, 0, - tagFilter?.tag, - sourceFilter?.id?.toLong(), - searchFilter, + null, + null, + null, null, 200 ) @@ -455,7 +455,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun updateDBItem(item: SelfossModel.Item) = db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString()) - + // TODO: This function should check for duplicate items suspend fun tryToCacheItemsAndGetNewOnes(): List { try { val newItems = getMaxItemsForBackground(ItemType.UNREAD) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 7ca5948..f6f80ae 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -874,10 +874,19 @@ class RepositoryTest() { coVerify(exactly = 1) {appSettingsService.refreshLoginInformation("https://test.com/selfoss/", "login", "password")} } + // TODO: This function should check if duplicate items are added to the database @Test fun `cache items`() { - coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns - SelfossModel.StatusAndData(success = true, data = generateTestApiItem()) + 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)), + ) val repository = Repository(api, appSettingsService, connectivityStatus, db) repository.tagFilter = SelfossModel.Tag("Tag", "read", 0) @@ -896,7 +905,6 @@ class RepositoryTest() { } coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } - assertSame(3, items.size) } @Test @@ -985,7 +993,7 @@ fun generateTestApiItem(item : FakeItemParameters = FakeItemParameters()) : List } class FakeItemParameters() { - val id = "20" + var id = "20" var datetime = "2022-09-09T03:32:01-04:00" val title = "Etica della ricerca sotto i riflettori." val content = "

Luigi Campanella, già Presidente SCI

\n

L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.

\n

L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.

\n

Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.

\n

Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.

\n

Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.

\n

La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.

\n

L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.

\n\"\"\"\"

Magdalena Zernicka-Goetz

\n\"\"

Gianluca Amadei

\n

Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.

\n

L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.

" -- 2.34.1 From 6f60ef434680c741b9c23445b4dbd3c33508d638 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 09:11:55 +0200 Subject: [PATCH 30/35] Remove unnecessary return value --- .../readerforselfossv2/repository/RepositoryImpl.kt | 7 +++---- .../readerforselfossv2/repository/RepositoryTest.kt | 11 +++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index c484a26..c96d40b 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -456,17 +456,16 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString()) // TODO: This function should check for duplicate items - suspend fun tryToCacheItemsAndGetNewOnes(): List { + suspend fun tryToCacheItemsAndGetNewOnes() { try { val newItems = getMaxItemsForBackground(ItemType.UNREAD) val allItems = getMaxItemsForBackground(ItemType.ALL) val starredItems = getMaxItemsForBackground(ItemType.STARRED) - insertDBItems(newItems + allItems + starredItems) - return newItems + val fullItemsList = newItems + allItems + starredItems + insertDBItems(fullItemsList) } catch (e: Throwable) { // We do nothing } - return emptyList() } // TODO: Add tests diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index f6f80ae..2e06685 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -899,9 +899,8 @@ class RepositoryTest() { "d8c92cdb1ef119ea85c4b9205c879ca7.png" ) repository.searchFilter = "search" - var items = emptyList() runBlocking { - items = repository.tryToCacheItemsAndGetNewOnes() + repository.tryToCacheItemsAndGetNewOnes() } coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } @@ -923,13 +922,11 @@ class RepositoryTest() { "d8c92cdb1ef119ea85c4b9205c879ca7.png" ) repository.searchFilter = "search" - var items = emptyList() runBlocking { - items = repository.tryToCacheItemsAndGetNewOnes() + repository.tryToCacheItemsAndGetNewOnes() } coVerify(exactly = 3) { api.getItems(any(), 0, null, null, null, null, 200) } - assertSame(0, items.size) } @Test @@ -949,13 +946,11 @@ class RepositoryTest() { "d8c92cdb1ef119ea85c4b9205c879ca7.png" ) repository.searchFilter = "search" - var items = emptyList() runBlocking { - items = repository.tryToCacheItemsAndGetNewOnes() + repository.tryToCacheItemsAndGetNewOnes() } coVerify(exactly = 0) { api.getItems(any(), 0, null, null, null, null, 200) } - assertSame(emptyList(), items) } } -- 2.34.1 From f9ba13dc32524cf3c970d565d7594e45465c974d Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 11:23:43 +0200 Subject: [PATCH 31/35] Always cache images in background --- .../readerforselfossv2/android/background/background.kt | 6 ++++-- .../apps/readerforselfossv2/repository/RepositoryImpl.kt | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/background/background.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/background/background.kt index 74a0739..a565507 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/background/background.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/background/background.kt @@ -52,11 +52,13 @@ override fun doWork(): Result { repository.handleDBActions() + val apiItems = repository.tryToCacheItemsAndGetNewOnes() if (appSettingsService.isNotifyNewItemsEnabled()) { launch { - handleNewItemsNotification(repository.tryToCacheItemsAndGetNewOnes(), notificationManager) + handleNewItemsNotification(apiItems, notificationManager) } } + apiItems.map { it.preloadImages(context) } } } return Result.success() @@ -66,6 +68,7 @@ override fun doWork(): Result { newItems: List?, notificationManager: NotificationManager ) { + // TODO: Check if this coroutine is actually required CoroutineScope(Dispatchers.IO).launch { val apiItems = newItems.orEmpty() @@ -102,7 +105,6 @@ override fun doWork(): Result { notificationManager.notify(2, newItemsNotification.build()) } } - apiItems.map { it.preloadImages(context) } Timer("", false).schedule(4000) { notificationManager.cancel(1) } diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index c96d40b..eb6e794 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -456,16 +456,19 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString()) // TODO: This function should check for duplicate items - suspend fun tryToCacheItemsAndGetNewOnes() { + suspend fun tryToCacheItemsAndGetNewOnes(): List { try { + val previousNewItems = getDBItems().count { it.unread } val newItems = getMaxItemsForBackground(ItemType.UNREAD) val allItems = getMaxItemsForBackground(ItemType.ALL) val starredItems = getMaxItemsForBackground(ItemType.STARRED) val fullItemsList = newItems + allItems + starredItems insertDBItems(fullItemsList) + return fullItemsList } catch (e: Throwable) { // We do nothing } + return emptyList() } // TODO: Add tests -- 2.34.1 From 27bb056397f60dba7e78ef5c4647cb7be2e68482 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 11:49:31 +0200 Subject: [PATCH 32/35] Cleanup --- .../readerforselfossv2/android/fragments/ArticleFragment.kt | 1 - .../amine/apps/readerforselfossv2/repository/RepositoryImpl.kt | 3 --- 2 files changed, 4 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt index 6e0b18b..4e9ada7 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/ArticleFragment.kt @@ -249,7 +249,6 @@ class ArticleFragment : Fragment(), DIAware { private fun getContentFromMercury() { if (repository.isNetworkAvailable()) { binding.progressBar.visibility = View.VISIBLE - // TODO: The api should be accessed through the repository val parser = MercuryApi() parser.parseUrl(url).enqueue( diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index eb6e794..7b1cea2 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -403,8 +403,6 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap } } - // TODO: This should be private (since all api calls are made through the repository - // no other entity needs to know about the connectivity status) fun isNetworkAvailable() = isConnectionAvailable.value && !offlineOverride private fun getDBActions(): List = @@ -458,7 +456,6 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap // TODO: This function should check for duplicate items suspend fun tryToCacheItemsAndGetNewOnes(): List { try { - val previousNewItems = getDBItems().count { it.unread } val newItems = getMaxItemsForBackground(ItemType.UNREAD) val allItems = getMaxItemsForBackground(ItemType.ALL) val starredItems = getMaxItemsForBackground(ItemType.STARRED) -- 2.34.1 From 8dc3d319cd34902581842bfdb43d11d08cefd20f Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 11:59:08 +0200 Subject: [PATCH 33/35] Cleanup --- .../bou/amine/apps/readerforselfossv2/android/HomeActivity.kt | 1 + .../apps/readerforselfossv2/repository/RepositoryImpl.kt | 4 +--- .../apps/readerforselfossv2/repository/RepositoryTest.kt | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt index 87828ad..29c7835 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/HomeActivity.kt @@ -355,6 +355,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar val drawerData = DrawerData(repository.getDBTags().map { it.toView() }, repository.getDBSources().map { it.toView() }) runOnUiThread { + // TODO: All this logic should be handled by the repository, simplify and remove direct DB access // Only refresh if there is no data in the DB, or if the `UpdateSources` setting is enabled if (drawerData.sources?.isEmpty() == true || appSettingsService.isUpdateSourcesEnabled()) { drawerApiCalls(drawerData) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 7b1cea2..61222f6 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -391,8 +391,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap api.refreshLoginInformation() } - // TODO: This should be private - suspend fun updateApiVersion() { + private suspend fun updateApiVersion() { val apiMajorVersion = appSettingsService.getApiVersion() if (isNetworkAvailable()) { @@ -453,7 +452,6 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap private fun updateDBItem(item: SelfossModel.Item) = db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString()) - // TODO: This function should check for duplicate items suspend fun tryToCacheItemsAndGetNewOnes(): List { try { val newItems = getMaxItemsForBackground(ItemType.UNREAD) diff --git a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt index 2e06685..1d99897 100644 --- a/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt +++ b/shared/src/commonTest/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryTest.kt @@ -874,7 +874,6 @@ class RepositoryTest() { coVerify(exactly = 1) {appSettingsService.refreshLoginInformation("https://test.com/selfoss/", "login", "password")} } - // TODO: This function should check if duplicate items are added to the database @Test fun `cache items`() { val itemParameter1 = FakeItemParameters() -- 2.34.1 From 79fd115f5ebb32e38c3f9d3179f3503b3c604ca4 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 13:16:42 +0200 Subject: [PATCH 34/35] Only return new cached items --- .../apps/readerforselfossv2/repository/RepositoryImpl.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 61222f6..8a1fa86 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -457,9 +457,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap val newItems = getMaxItemsForBackground(ItemType.UNREAD) val allItems = getMaxItemsForBackground(ItemType.ALL) val starredItems = getMaxItemsForBackground(ItemType.STARRED) - val fullItemsList = newItems + allItems + starredItems - insertDBItems(fullItemsList) - return fullItemsList + insertDBItems(newItems + allItems + starredItems) + return newItems } catch (e: Throwable) { // We do nothing } -- 2.34.1 From 22da30eaa819cbdd05c555cde02a13e1a4b057c4 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 30 Sep 2022 13:17:40 +0200 Subject: [PATCH 35/35] Remove unnecessary call to api --- .../bou/amine/apps/readerforselfossv2/android/LoginActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt index bd17f42..00e1e7e 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/LoginActivity.kt @@ -163,7 +163,6 @@ class LoginActivity : AppCompatActivity(), DIAware { CoroutineScope(Dispatchers.IO).launch { val result = repository.login() if (result) { - repository.updateApiVersion() goToMain() } else { CoroutineScope(Dispatchers.Main).launch { -- 2.34.1