From ca936b239508dbfced59df73e1aef9acc1564e4f Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 11:30:38 -0500 Subject: [PATCH 01/13] Update Turbine Signed-off-by: matt-ramotar --- gradle/libs.versions.toml | 3 ++- store/build.gradle.kts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d21feac6..1d929358 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,6 +23,7 @@ ktlint = "0.39.0" kover = "0.9.0-RC" store = "5.1.0-SNAPSHOT" truth = "1.1.3" +turbine = "1.2.0" binary-compatibility-validator = "0.15.0-Beta.2" [libraries] @@ -56,7 +57,7 @@ kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-cor junit = { group = "junit", name = "junit", version.ref = "junit" } google-truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } touchlab-kermit = { group = "co.touchlab", name = "kermit", version.ref = "kermit" } -turbine = "app.cash.turbine:turbine:1.0.0" +turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" } binary-compatibility-validator = {module = "org.jetbrains.kotlinx:binary-compatibility-validator", version.ref = "binary-compatibility-validator"} [plugins] diff --git a/store/build.gradle.kts b/store/build.gradle.kts index 790ca937..3b928ce8 100644 --- a/store/build.gradle.kts +++ b/store/build.gradle.kts @@ -26,6 +26,7 @@ kotlin { dependencies { implementation(libs.junit) implementation(libs.kotlinx.coroutines.test) + implementation(libs.turbine) } } } From d5973bbc79973b72137ad6f44c8decebad414a91 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 11:30:43 -0500 Subject: [PATCH 02/13] Update FetcherResponseTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/FetcherResponseTests.kt | 201 +++++++++++------- 1 file changed, 122 insertions(+), 79 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt index 4f009f84..72f1ad90 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt @@ -1,5 +1,6 @@ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.flowOf @@ -7,7 +8,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -34,31 +34,36 @@ class FetcherResponseTests { } @Test - fun givenAFetcherThatEmitsErrorAndDataWhenSteamingThenItCanEmitValueAfterAnError() { + fun givenAFetcherThatEmitsErrorAndDataWhenSteamingThenItCanEmitValueAfterAnError() = testScope.runTest { val exception = RuntimeException("first error") - testScope.runTest { - val store = - StoreBuilder.from( - fetcher = - Fetcher.ofResultFlow { key: Int -> - flowOf( - FetcherResult.Error.Exception(exception), - FetcherResult.Data("$key"), - ) - }, - ).buildWithTestScope() + val store = + StoreBuilder.from( + fetcher = + Fetcher.ofResultFlow { key: Int -> + flowOf( + FetcherResult.Error.Exception(exception), + FetcherResult.Data("$key"), + ) + }, + ).buildWithTestScope() + + store.stream(StoreReadRequest.fresh(1)).test { + assertEquals( + expected = StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), + actual = awaitItem() + ) - assertEmitsExactly( - store.stream( - StoreReadRequest.fresh(1), - ), - listOf( - StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), - StoreReadResponse.Error.Exception(exception, StoreReadResponseOrigin.Fetcher()), - StoreReadResponse.Data("1", StoreReadResponseOrigin.Fetcher()), - ), + assertEquals( + expected = StoreReadResponse.Error.Exception(exception, StoreReadResponseOrigin.Fetcher()), + actual = awaitItem() + ) + + assertEquals( + expected = StoreReadResponse.Data("1", StoreReadResponseOrigin.Fetcher()), + actual = awaitItem() ) } + } @Test @@ -69,27 +74,32 @@ class FetcherResponseTests { StoreBuilder .from(fetcher).buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( - StoreReadResponse.Loading( + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( + expected = StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - StoreReadResponse.Data( + actual = awaitItem() + ) + + assertEquals( + expected = StoreReadResponse.Data( value = 9, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( - StoreReadResponse.Data( + actual = awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( + expected = StoreReadResponse.Data( value = 9, origin = StoreReadResponseOrigin.Cache, ), - ), - ) + actual = awaitItem() + ) + } } @Test @@ -110,30 +120,39 @@ class FetcherResponseTests { StoreBuilder.from(fetcher) .buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( - StoreReadResponse.Loading( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( + expected = StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - StoreReadResponse.Error.Message( + actual = awaitItem() + ) + + assertEquals( + expected = StoreReadResponse.Error.Message( message = "zero", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( - StoreReadResponse.Loading( + actual = awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( + expected = StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - StoreReadResponse.Data( + actual = awaitItem() + ) + + assertEquals( + expected = StoreReadResponse.Data( value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + actual = awaitItem() + ) + } } @Test @@ -156,30 +175,39 @@ class FetcherResponseTests { .from(fetcher) .buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Exception( error = e, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( + awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -200,58 +228,73 @@ class FetcherResponseTests { .from(fetcher = fetcher) .buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Exception( error = e, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( + awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test fun givenAFetcherThatEmitsCustomErrorWhenStreamingThenCustomErrorShouldBeEmitted() = testScope.runTest { data class TestCustomError(val errorMessage: String) + val customError = TestCustomError("Test custom error") val store = StoreBuilder.from( fetcher = - Fetcher.ofResultFlow { _: Int -> - flowOf( - FetcherResult.Error.Custom(customError), - ) - }, + Fetcher.ofResultFlow { _: Int -> + flowOf( + FetcherResult.Error.Custom(customError), + ) + }, ).buildWithTestScope() - assertEmitsExactly( - store.stream(StoreReadRequest.fresh(1)), - listOf( + store.stream(StoreReadRequest.fresh(1)).test { + assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Custom( error = customError, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } private fun StoreBuilder.buildWithTestScope() = scope(testScope).build() From 8ed439918dad29b80eb6f50045c5d5eefa7e1108 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 11:33:35 -0500 Subject: [PATCH 03/13] Update FetcherResponseTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/FetcherResponseTests.kt | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt index 72f1ad90..d2ff4f37 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt @@ -49,18 +49,18 @@ class FetcherResponseTests { store.stream(StoreReadRequest.fresh(1)).test { assertEquals( - expected = StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), - actual = awaitItem() + StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), + awaitItem() ) assertEquals( - expected = StoreReadResponse.Error.Exception(exception, StoreReadResponseOrigin.Fetcher()), - actual = awaitItem() + StoreReadResponse.Error.Exception(exception, StoreReadResponseOrigin.Fetcher()), + awaitItem() ) assertEquals( - expected = StoreReadResponse.Data("1", StoreReadResponseOrigin.Fetcher()), - actual = awaitItem() + StoreReadResponse.Data("1", StoreReadResponseOrigin.Fetcher()), + awaitItem() ) } @@ -76,28 +76,28 @@ class FetcherResponseTests { pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { assertEquals( - expected = StoreReadResponse.Loading( + StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - actual = awaitItem() + awaitItem() ) assertEquals( - expected = StoreReadResponse.Data( + StoreReadResponse.Data( value = 9, origin = StoreReadResponseOrigin.Fetcher(), ), - actual = awaitItem() + awaitItem() ) } pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { assertEquals( - expected = StoreReadResponse.Data( + StoreReadResponse.Data( value = 9, origin = StoreReadResponseOrigin.Cache, ), - actual = awaitItem() + awaitItem() ) } } @@ -122,35 +122,35 @@ class FetcherResponseTests { pipeline.stream(StoreReadRequest.fresh(3)).test { assertEquals( - expected = StoreReadResponse.Loading( + StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - actual = awaitItem() + awaitItem() ) assertEquals( - expected = StoreReadResponse.Error.Message( + StoreReadResponse.Error.Message( message = "zero", origin = StoreReadResponseOrigin.Fetcher(), ), - actual = awaitItem() + awaitItem() ) } pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { assertEquals( - expected = StoreReadResponse.Loading( + StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - actual = awaitItem() + awaitItem() ) assertEquals( - expected = StoreReadResponse.Data( + StoreReadResponse.Data( value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - actual = awaitItem() + awaitItem() ) } } From 2b9123943ceabd47064628c40a87061b02e91d7b Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 12:49:02 -0500 Subject: [PATCH 04/13] Update FlowStoreTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/FlowStoreTests.kt | 478 ++++++++++++------ 1 file changed, 333 insertions(+), 145 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt index af2a2f2d..c8cc67e8 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt @@ -15,6 +15,7 @@ */ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.async @@ -39,7 +40,6 @@ import org.mobilenativefoundation.store.store5.util.FakeFlowingFetcher import org.mobilenativefoundation.store.store5.util.InMemoryPersister import org.mobilenativefoundation.store.store5.util.asFlowable import org.mobilenativefoundation.store.store5.util.asSourceOfTruth -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test import kotlin.test.assertContains import kotlin.test.assertEquals @@ -124,62 +124,79 @@ class FlowStoreTests { sourceOfTruth = persister.asSourceOfTruth(), ).buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Cache, ), - // note that we still get the data from persister as well as we don't listen to - // the persister for the cached items unless there is an active stream, which - // means cache can go out of sync w/ the persister + awaitItem() + ) + + // note that we still get the data from persister as well as we don't listen to + // the persister for the cached items unless there is an active stream, which + // means cache can go out of sync w/ the persister + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - ), - ) + awaitItem() + ) + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Cache, ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.SourceOfTruth, ), - ), - ) + awaitItem() + ) + } } @Test @@ -198,39 +215,55 @@ class FlowStoreTests { sourceOfTruth = persister.asSourceOfTruth(), ).buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Cache, ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -245,35 +278,48 @@ class FlowStoreTests { StoreBuilder.from(fetcher = fetcher) .buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Cache, ), + awaitItem() + ) + + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -288,31 +334,40 @@ class FlowStoreTests { StoreBuilder.from(fetcher = fetcher) .buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.skipMemory(3, refresh = false)), - listOf( + + pipeline.stream(StoreReadRequest.skipMemory(3, refresh = false)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.skipMemory(3, refresh = false)), - listOf( + pipeline.stream(StoreReadRequest.skipMemory(3, refresh = false)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -333,42 +388,64 @@ class FlowStoreTests { .disableCache() .buildWithTestScope() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -392,22 +469,31 @@ class FlowStoreTests { delay(10) persister.flowWriter(3, "local-1") } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -417,14 +503,14 @@ class FlowStoreTests { val pipeline = StoreBuilder.from( fetcher = - Fetcher.ofFlow { - flow { - delay(10) - emit("three-1") - delay(10) - emit("three-2") - } - }, + Fetcher.ofFlow { + flow { + delay(10) + emit("three-1") + delay(10) + emit("three-2") + } + }, sourceOfTruth = persister.asSourceOfTruth(), ) .disableCache() @@ -436,30 +522,47 @@ class FlowStoreTests { delay(10) // go in between two server requests persister.flowWriter(3, "local-2") } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "local-2", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -481,38 +584,56 @@ class FlowStoreTests { delay(10) persister.flowWriter(3, "local-1") } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(key = 3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.cached(key = 3, refresh = true)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Exception( error = exception, origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - ), - ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(key = 3, refresh = true)), - listOf( - Data( - value = "local-1", - origin = StoreReadResponseOrigin.SourceOfTruth, - ), + awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.cached(key = 3, refresh = true)).test { + assertEquals( + Data( + value = "local-1", + origin = StoreReadResponseOrigin.SourceOfTruth, + ), + awaitItem() + ) + + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Exception( error = exception, origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -530,25 +651,37 @@ class FlowStoreTests { val firstFetch = pipeline.fresh(3) // prime the cache assertEquals("local-1", firstFetch) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.Cache, ), + awaitItem() + ) + + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - ), - ) + awaitItem() + ) + } } @Test @@ -566,25 +699,38 @@ class FlowStoreTests { val firstFetch = pipeline.fresh(3) // prime the cache assertEquals("local-1", firstFetch) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.Cache, ), + awaitItem() + ) + + assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -594,34 +740,42 @@ class FlowStoreTests { val pipeline = StoreBuilder.from( fetcher = - Fetcher.ofFlow { - if (createCount++ == 0) { - flowOf("remote-1") - } else { - flowOf() - } - }, + Fetcher.ofFlow { + if (createCount++ == 0) { + flowOf("remote-1") + } else { + flowOf() + } + }, ) .buildWithTestScope() val firstFetch = pipeline.fresh(3) // prime the cache assertEquals("remote-1", firstFetch) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( Data( value = "remote-1", origin = StoreReadResponseOrigin.Cache, ), - ), - ) + awaitItem() + ) + } } @Test @@ -631,34 +785,42 @@ class FlowStoreTests { val pipeline = StoreBuilder.from( fetcher = - Fetcher.ofFlow { - if (createCount++ == 0) { - flowOf("remote-1") - } else { - flowOf() - } - }, + Fetcher.ofFlow { + if (createCount++ == 0) { + flowOf("remote-1") + } else { + flowOf() + } + }, ) .buildWithTestScope() val firstFetch = pipeline.fresh(3) // prime the cache assertEquals("remote-1", firstFetch) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data( value = "remote-1", origin = StoreReadResponseOrigin.Cache, ), + awaitItem() + ) + + assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -821,23 +983,40 @@ class FlowStoreTests { fetcher1Collected, ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data(origin = StoreReadResponseOrigin.Cache, value = "three-1"), + awaitItem() + ) + assertEquals( Loading(origin = StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + + assertEquals( Data(origin = StoreReadResponseOrigin.Fetcher(), value = "three-2"), - ), - ) + awaitItem() + ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + } + + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data(origin = StoreReadResponseOrigin.Cache, value = "three-2"), + awaitItem() + ) + + assertEquals( Loading(origin = StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + assertEquals( Data(origin = StoreReadResponseOrigin.Fetcher(), value = "three-3"), - ), - ) + awaitItem() + ) + } + testScope.advanceUntilIdle() assertEquals( listOf( @@ -880,14 +1059,23 @@ class FlowStoreTests { fetcher1Collected, ) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( Data(origin = StoreReadResponseOrigin.Cache, value = "three-1"), + awaitItem() + ) + + assertEquals( Loading(origin = StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + + assertEquals( Data(origin = StoreReadResponseOrigin.Fetcher(), value = "three-2"), - ), - ) + awaitItem() + ) + } + testScope.runCurrent() assertEquals( listOf( From 25ee58e85e54049eb2c99c2953389ede98c0c178 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 12:52:08 -0500 Subject: [PATCH 05/13] Update MapIndexedTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/MapIndexedTests.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt index a1650e13..ccedcc96 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt @@ -1,20 +1,22 @@ package org.mobilenativefoundation.store.store5 -import kotlinx.coroutines.ExperimentalCoroutinesApi +import app.cash.turbine.test import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.mobilenativefoundation.store.store5.impl.operators.mapIndexed -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test +import kotlin.test.assertEquals -@OptIn(ExperimentalCoroutinesApi::class) class MapIndexedTests { private val scope = TestScope() @Test - fun mapIndexed() = - scope.runTest { - assertEmitsExactly(flowOf(5, 6).mapIndexed { index, value -> index to value }, listOf(0 to 5, 1 to 6)) + fun mapIndexed() = scope.runTest { + flowOf(5, 6).mapIndexed { index, value -> index to value }.test { + assertEquals(0 to 5, awaitItem()) + assertEquals(1 to 6, awaitItem()) + awaitComplete() } + } } From 7ad5a64a81734c8ea88e7b3e4a61232f62bdc7b4 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 13:53:46 -0500 Subject: [PATCH 06/13] Update HotFlowStoreTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/HotFlowStoreTests.kt | 82 +++++++++++-------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt index fdc905e7..04e12117 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt @@ -1,12 +1,13 @@ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test import kotlin.test.assertEquals @@ -29,42 +30,55 @@ class HotFlowStoreTests { .scope(testScope) .build() - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( - StoreReadResponse.Loading( - origin = StoreReadResponseOrigin.Fetcher(), - ), - StoreReadResponse.Data( - value = "three-1", - origin = StoreReadResponseOrigin.Fetcher(), - ), - ), - ) - assertEmitsExactly( + val job = launch { + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( + StoreReadResponse.Loading( + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem() + ) + + assertEquals( + StoreReadResponse.Data( + value = "three-1", + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem() + ) + } + pipeline.stream( StoreReadRequest.cached(3, refresh = false), - ), - listOf( - StoreReadResponse.Data( - value = "three-1", - origin = StoreReadResponseOrigin.Cache, - ), - ), - ) + ).test { + assertEquals( + StoreReadResponse.Data( + value = "three-1", + origin = StoreReadResponseOrigin.Cache, + ), + awaitItem() + ) + } + + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( + StoreReadResponse.Loading( + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem() + ) + + assertEquals( + StoreReadResponse.Data( + value = "three-2", + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem() + ) + } + } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( - StoreReadResponse.Loading( - origin = StoreReadResponseOrigin.Fetcher(), - ), - StoreReadResponse.Data( - value = "three-2", - origin = StoreReadResponseOrigin.Fetcher(), - ), - ), - ) + job.cancel() } } From 7593bec30b79b040e7b227b1c38ff31e822ca2e8 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 13:57:46 -0500 Subject: [PATCH 07/13] Update UpdaterTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/UpdaterTests.kt | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt index 72ae4270..a50e4bcd 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt @@ -1,5 +1,6 @@ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flow @@ -9,7 +10,6 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.mobilenativefoundation.store.core5.ExperimentalStoreApi import org.mobilenativefoundation.store.store5.impl.extensions.inHours -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import org.mobilenativefoundation.store.store5.util.fake.Notes import org.mobilenativefoundation.store.store5.util.fake.NotesApi import org.mobilenativefoundation.store.store5.util.fake.NotesBookkeeping @@ -63,12 +63,12 @@ class UpdaterTests { MutableStoreBuilder.from( fetcher = Fetcher.of { key -> api.get(key, ttl = ttl) }, sourceOfTruth = - SourceOfTruth.of( - nonFlowReader = { key -> notes.get(key) }, - writer = { key, sot: InputNote -> notes.put(key, sot) }, - delete = { key -> notes.clear(key) }, - deleteAll = { notes.clear() }, - ), + SourceOfTruth.of( + nonFlowReader = { key -> notes.get(key) }, + writer = { key, sot: InputNote -> notes.put(key, sot) }, + delete = { key -> notes.clear(key) }, + deleteAll = { notes.clear() }, + ), converter = converter, ) .validator(validator) @@ -82,18 +82,20 @@ class UpdaterTests { val stream = store.stream(readRequest) // Read is success - val expected = - listOf( + stream.test { + assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( OutputNote(NoteData.Single(Notes.One), ttl = ttl), StoreReadResponseOrigin.Fetcher(), ), + awaitItem() ) - assertEmitsExactly( - stream, - expected, - ) + } val newNote = Notes.One.copy(title = "New Title-1") val writeRequest = @@ -174,12 +176,12 @@ class UpdaterTests { MutableStoreBuilder.from( fetcher = Fetcher.of { key -> api.get(key, ttl = ttl) }, sourceOfTruth = - SourceOfTruth.of( - nonFlowReader = { key -> notes.get(key) }, - writer = { key, sot: InputNote -> notes.put(key, sot) }, - delete = { key -> notes.clear(key) }, - deleteAll = { notes.clear() }, - ), + SourceOfTruth.of( + nonFlowReader = { key -> notes.get(key) }, + writer = { key, sot: InputNote -> notes.put(key, sot) }, + delete = { key -> notes.clear(key) }, + deleteAll = { notes.clear() }, + ), converter = converter, ) .validator(validator) @@ -193,18 +195,20 @@ class UpdaterTests { val stream = store.stream(readRequest) // Fetch is success and validator is not used - val expected = - listOf( + stream.test { + assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( OutputNote(NoteData.Single(Notes.One), ttl = ttl), StoreReadResponseOrigin.Fetcher(), ), + awaitItem() ) - assertEmitsExactly( - stream, - expected, - ) + } val cachedReadRequest = StoreReadRequest.cached(NotesKey.Single(Notes.One.id), refresh = false) @@ -215,16 +219,19 @@ class UpdaterTests { // So we do not emit value in cache or SOT // Instead we get latest from network even though refresh = false - assertEmitsExactly( - cachedStream, - listOf( + cachedStream.test { + assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher(name = null)), + awaitItem() + ) + assertEquals( StoreReadResponse.Data( OutputNote(NoteData.Single(Notes.One), ttl = ttl), StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } @Test @@ -244,17 +251,17 @@ class UpdaterTests { val store = MutableStoreBuilder.from( fetcher = - Fetcher.ofFlow { key -> - val network = api.get(key) - flow { emit(network) } - }, + Fetcher.ofFlow { key -> + val network = api.get(key) + flow { emit(network) } + }, sourceOfTruth = - SourceOfTruth.of( - nonFlowReader = { key -> notes.get(key) }, - writer = { key, sot -> notes.put(key, sot) }, - delete = { key -> notes.clear(key) }, - deleteAll = { notes.clear() }, - ), + SourceOfTruth.of( + nonFlowReader = { key -> notes.get(key) }, + writer = { key, sot -> notes.put(key, sot) }, + delete = { key -> notes.clear(key) }, + deleteAll = { notes.clear() }, + ), converter, ) .validator(validator) From 7c051a508359b59b3eb7ee9a838dff26f1ca1f08 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 14:15:24 -0500 Subject: [PATCH 08/13] Update SourceOfTruthErrorsTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/SourceOfTruthErrorsTests.kt | 171 ++++++++++++------ 1 file changed, 111 insertions(+), 60 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt index 200b0ae2..1253340f 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt @@ -1,5 +1,6 @@ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.cancelAndJoin @@ -15,8 +16,8 @@ import org.mobilenativefoundation.store.store5.SourceOfTruth.WriteException import org.mobilenativefoundation.store.store5.util.FakeFetcher import org.mobilenativefoundation.store.store5.util.InMemoryPersister import org.mobilenativefoundation.store.store5.util.asSourceOfTruth -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test +import kotlin.test.assertEquals @OptIn(ExperimentalCoroutinesApi::class) @FlowPreview @@ -44,21 +45,26 @@ class SourceOfTruthErrorsTests { throw TestException("i fail") } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + + assertEquals( StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Exception( error = - WriteException( - key = 3, - value = "a", - cause = TestException("i fail"), - ), + WriteException( + key = 3, + value = "a", + cause = TestException("i fail"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - ), - ) + awaitItem() + ) + } } @Test @@ -83,33 +89,41 @@ class SourceOfTruthErrorsTests { throw TestException(value ?: "null") } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = false)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( StoreReadResponse.Error.Exception( error = - ReadException( - key = 3, - cause = TestException("null"), - ), + ReadException( + key = 3, + cause = TestException("null"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - // after disk fails, we should still invoke fetcher + awaitItem() + ) + + // after disk fails, we should still invoke fetcher + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - // and after fetcher writes the value, it will trigger another read which will also - // fail + awaitItem() + ) + + // and after fetcher writes the value, it will trigger another read which will also + // fail + assertEquals( StoreReadResponse.Error.Exception( error = - ReadException( - key = 3, - cause = TestException("a"), - ), + ReadException( + key = 3, + cause = TestException("a"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - ), - ) + awaitItem() + ) + } } @Test @@ -135,46 +149,65 @@ class SourceOfTruthErrorsTests { } value } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + assertEquals( StoreReadResponse.Error.Exception( error = - WriteException( - key = 3, - value = "a", - cause = TestException("a"), - ), + WriteException( + key = 3, + value = "a", + cause = TestException("a"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = "b", origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Error.Exception( error = - WriteException( - key = 3, - value = "c", - cause = TestException("c"), - ), + WriteException( + key = 3, + value = "c", + cause = TestException("c"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - // disk flow will restart after a failed write (because we stopped it before the - // write attempt starts, so we will get the disk value again). + awaitItem() + ) + + // disk flow will restart after a failed write (because we stopped it before the + // write attempt starts, so we will get the disk value again). + assertEquals( StoreReadResponse.Data( value = "b", origin = StoreReadResponseOrigin.SourceOfTruth, ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = "d", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } // @Test @@ -279,24 +312,34 @@ class SourceOfTruthErrorsTests { // miss both failures but arrive before d is fetched delay(70) - assertEmitsExactly( - pipeline.stream(StoreReadRequest.skipMemory(3, refresh = true)), - listOf( + + pipeline.stream(StoreReadRequest.skipMemory(3, refresh = true)).test { + assertEquals( StoreReadResponse.Data( value = "b", origin = StoreReadResponseOrigin.SourceOfTruth, ), - // don't receive the write exception because technically it started before we - // started reading + awaitItem() + ) + + // don't receive the write exception because technically it started before we + // started reading + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = "d", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } + collector.cancelAndJoin() } @@ -366,26 +409,34 @@ class SourceOfTruthErrorsTests { } value } - assertEmitsExactly( - pipeline.stream(StoreReadRequest.cached(3, refresh = true)), - listOf( + pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { + assertEquals( StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 3, - cause = TestException("first read"), - ), + ReadException( + key = 3, + cause = TestException("first read"), + ), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = "a", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } } } From ba252b908695cc36b34eb09de8f1ece81ed49492 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 14:18:00 -0500 Subject: [PATCH 09/13] Update ValueFetcherTests to use Turbine Signed-off-by: matt-ramotar --- .../store/store5/ValueFetcherTests.kt | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/ValueFetcherTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/ValueFetcherTests.kt index 3e138597..26af2fb1 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/ValueFetcherTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/ValueFetcherTests.kt @@ -1,13 +1,14 @@ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test +import kotlin.test.assertEquals @ExperimentalCoroutinesApi @FlowPreview @@ -18,7 +19,11 @@ class ValueFetcherTests { fun givenValueFetcherWhenInvokeThenResultIsWrapped() = testScope.runTest { val fetcher = Fetcher.ofFlow { flowOf(it * it) } - assertEmitsExactly(fetcher(3), listOf(FetcherResult.Data(value = 9))) + + fetcher(3).test { + assertEquals(FetcherResult.Data(value = 9), awaitItem()) + awaitComplete() + } } @Test @@ -31,10 +36,10 @@ class ValueFetcherTests { throw e } } - assertEmitsExactly( - fetcher(3), - listOf(FetcherResult.Error.Exception(e)), - ) + fetcher(3).test { + assertEquals(FetcherResult.Error.Exception(e), awaitItem()) + awaitComplete() + } } @Test @@ -42,10 +47,10 @@ class ValueFetcherTests { testScope.runTest { val fetcher = Fetcher.of { it * it } - assertEmitsExactly( - fetcher(3), - listOf(FetcherResult.Data(value = 9)), - ) + fetcher(3).test { + assertEquals(FetcherResult.Data(value = 9), awaitItem()) + awaitComplete() + } } @Test @@ -56,6 +61,9 @@ class ValueFetcherTests { Fetcher.of { throw e } - assertEmitsExactly(fetcher(3), listOf(FetcherResult.Error.Exception(e))) + fetcher(3).test { + assertEquals(FetcherResult.Error.Exception(e), awaitItem()) + awaitComplete() + } } } From 10f3449415ec6dc7d6115c2078254aca636d74da Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 14:19:06 -0500 Subject: [PATCH 10/13] Update SourceOfTruthWithBarrierTests to use Turbine Signed-off-by: matt-ramotar --- .../store5/SourceOfTruthWithBarrierTests.kt | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt index 1cbab521..9d138d48 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt @@ -15,6 +15,7 @@ */ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -32,7 +33,6 @@ import org.mobilenativefoundation.store.store5.SourceOfTruth.WriteException import org.mobilenativefoundation.store.store5.impl.PersistentSourceOfTruth import org.mobilenativefoundation.store.store5.impl.SourceOfTruthWithBarrier import org.mobilenativefoundation.store.store5.util.InMemoryPersister -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull @@ -147,19 +147,20 @@ class SourceOfTruthWithBarrierTests { persister.postReadCallback = { key, value -> throw exception } - assertEmitsExactly( - source.reader(1, CompletableDeferred(Unit)), - listOf( + + source.reader(1, CompletableDeferred(Unit)).test { + assertEquals( StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 1, - cause = exception, - ), + ReadException( + key = 1, + cause = exception, + ), ), - ), - ) + awaitItem() + ) + } } @Test @@ -187,10 +188,10 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 1, - cause = exception, - ), + ReadException( + key = 1, + cause = exception, + ), ), collected.first(), ) @@ -204,10 +205,10 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 1, - cause = exception, - ), + ReadException( + key = 1, + cause = exception, + ), ), StoreReadResponse.Data( // this is fetcher since we are using the write API @@ -253,11 +254,11 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - WriteException( - key = 1, - value = failValue, - cause = exception, - ), + WriteException( + key = 1, + value = failValue, + cause = exception, + ), ), StoreReadResponse.Data( origin = StoreReadResponseOrigin.SourceOfTruth, From 0f46ae42b555eda3bfc52dfc61eaff754ea8b37c Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 14:20:40 -0500 Subject: [PATCH 11/13] Update StreamWithoutSourceOfTruthTests to use Turbine Signed-off-by: matt-ramotar --- .../store5/StreamWithoutSourceOfTruthTests.kt | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt index 8610aa23..47f3541f 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt @@ -1,5 +1,6 @@ package org.mobilenativefoundation.store.store5 +import app.cash.turbine.test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.async @@ -9,7 +10,6 @@ import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.mobilenativefoundation.store.store5.util.FakeFetcher -import org.mobilenativefoundation.store.store5.util.assertEmitsExactly import kotlin.test.Test import kotlin.test.assertEquals @@ -37,18 +37,22 @@ class StreamWithoutSourceOfTruthTests { ).take(3).toList() } delay(1_000) // make sure the async block starts first - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } assertEquals( listOf( @@ -88,18 +92,22 @@ class StreamWithoutSourceOfTruthTests { ).take(3).toList() } delay(1_000) // make sure the async block starts first - assertEmitsExactly( - pipeline.stream(StoreReadRequest.fresh(3)), - listOf( + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), + awaitItem() + ) + + assertEquals( StoreReadResponse.Data( value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - ), - ) + awaitItem() + ) + } assertEquals( listOf( From ef568c5cdfb049b29e443deb6b25b90def1ff666 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 14:21:01 -0500 Subject: [PATCH 12/13] Delete AssertEmitsExactly.kt Signed-off-by: matt-ramotar --- .../store/store5/util/AssertEmitsExactly.kt | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/util/AssertEmitsExactly.kt diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/util/AssertEmitsExactly.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/util/AssertEmitsExactly.kt deleted file mode 100644 index c6572c9d..00000000 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/util/AssertEmitsExactly.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.mobilenativefoundation.store.store5.util - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.take -import kotlinx.coroutines.flow.toList -import kotlin.test.assertEquals - -suspend inline fun assertEmitsExactly( - actual: Flow, - expected: List, -) { - val flow = actual.take(expected.size).toList() - assertEquals(expected, flow) -} From f76e371d6c6fba7f981ba2959ff6cad1c1af37e0 Mon Sep 17 00:00:00 2001 From: matt-ramotar Date: Sun, 17 Nov 2024 14:28:25 -0500 Subject: [PATCH 13/13] Run gradlew ktlintFormat Signed-off-by: matt-ramotar --- .../store/store5/FetcherResponseTests.kt | 105 +++++---- .../store/store5/FlowStoreTests.kt | 200 +++++++++--------- .../store/store5/HotFlowStoreTests.kt | 85 ++++---- .../store/store5/MapIndexedTests.kt | 13 +- .../store/store5/SourceOfTruthErrorsTests.kt | 89 ++++---- .../store5/SourceOfTruthWithBarrierTests.kt | 36 ++-- .../store5/StreamWithoutSourceOfTruthTests.kt | 8 +- .../store/store5/UpdaterTests.kt | 56 ++--- 8 files changed, 293 insertions(+), 299 deletions(-) diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt index d2ff4f37..bc1ad503 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FetcherResponseTests.kt @@ -34,37 +34,37 @@ class FetcherResponseTests { } @Test - fun givenAFetcherThatEmitsErrorAndDataWhenSteamingThenItCanEmitValueAfterAnError() = testScope.runTest { - val exception = RuntimeException("first error") - val store = - StoreBuilder.from( - fetcher = - Fetcher.ofResultFlow { key: Int -> - flowOf( - FetcherResult.Error.Exception(exception), - FetcherResult.Data("$key"), - ) - }, - ).buildWithTestScope() - - store.stream(StoreReadRequest.fresh(1)).test { - assertEquals( - StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), - awaitItem() - ) - - assertEquals( - StoreReadResponse.Error.Exception(exception, StoreReadResponseOrigin.Fetcher()), - awaitItem() - ) - - assertEquals( - StoreReadResponse.Data("1", StoreReadResponseOrigin.Fetcher()), - awaitItem() - ) - } + fun givenAFetcherThatEmitsErrorAndDataWhenSteamingThenItCanEmitValueAfterAnError() = + testScope.runTest { + val exception = RuntimeException("first error") + val store = + StoreBuilder.from( + fetcher = + Fetcher.ofResultFlow { key: Int -> + flowOf( + FetcherResult.Error.Exception(exception), + FetcherResult.Data("$key"), + ) + }, + ).buildWithTestScope() - } + store.stream(StoreReadRequest.fresh(1)).test { + assertEquals( + StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), + awaitItem(), + ) + + assertEquals( + StoreReadResponse.Error.Exception(exception, StoreReadResponseOrigin.Fetcher()), + awaitItem(), + ) + + assertEquals( + StoreReadResponse.Data("1", StoreReadResponseOrigin.Fetcher()), + awaitItem(), + ) + } + } @Test fun givenTransformerWhenRawValueThenUnwrappedValueReturnedAndValueIsCached() = @@ -79,7 +79,7 @@ class FetcherResponseTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -87,7 +87,7 @@ class FetcherResponseTests { value = 9, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -97,7 +97,7 @@ class FetcherResponseTests { value = 9, origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) } } @@ -125,7 +125,7 @@ class FetcherResponseTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -133,7 +133,7 @@ class FetcherResponseTests { message = "zero", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -142,7 +142,7 @@ class FetcherResponseTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -150,7 +150,7 @@ class FetcherResponseTests { value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -180,7 +180,7 @@ class FetcherResponseTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -188,7 +188,7 @@ class FetcherResponseTests { error = e, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -197,7 +197,7 @@ class FetcherResponseTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -205,7 +205,7 @@ class FetcherResponseTests { value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -228,13 +228,12 @@ class FetcherResponseTests { .from(fetcher = fetcher) .buildWithTestScope() - pipeline.stream(StoreReadRequest.fresh(3)).test { assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -242,7 +241,7 @@ class FetcherResponseTests { error = e, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -251,7 +250,7 @@ class FetcherResponseTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -259,7 +258,7 @@ class FetcherResponseTests { value = 1, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -274,17 +273,17 @@ class FetcherResponseTests { val store = StoreBuilder.from( fetcher = - Fetcher.ofResultFlow { _: Int -> - flowOf( - FetcherResult.Error.Custom(customError), - ) - }, + Fetcher.ofResultFlow { _: Int -> + flowOf( + FetcherResult.Error.Custom(customError), + ) + }, ).buildWithTestScope() store.stream(StoreReadRequest.fresh(1)).test { assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( @@ -292,7 +291,7 @@ class FetcherResponseTests { error = customError, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt index c8cc67e8..f377ef45 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/FlowStoreTests.kt @@ -129,7 +129,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -137,7 +137,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -147,7 +147,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) // note that we still get the data from persister as well as we don't listen to @@ -159,7 +159,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) } @@ -168,7 +168,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -176,7 +176,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -186,7 +186,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -194,7 +194,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) } } @@ -220,7 +220,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -228,7 +228,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -238,7 +238,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -246,14 +246,14 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -261,7 +261,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -283,7 +283,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -291,25 +291,24 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } - pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { assertEquals( Data( value = "three-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -317,7 +316,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -334,13 +333,12 @@ class FlowStoreTests { StoreBuilder.from(fetcher = fetcher) .buildWithTestScope() - pipeline.stream(StoreReadRequest.skipMemory(3, refresh = false)).test { assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -348,7 +346,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -357,7 +355,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -365,7 +363,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -388,13 +386,12 @@ class FlowStoreTests { .disableCache() .buildWithTestScope() - pipeline.stream(StoreReadRequest.fresh(3)).test { assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -402,7 +399,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -410,7 +407,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -420,14 +417,14 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -435,7 +432,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -443,7 +440,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -475,7 +472,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -483,7 +480,7 @@ class FlowStoreTests { value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -491,7 +488,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -503,14 +500,14 @@ class FlowStoreTests { val pipeline = StoreBuilder.from( fetcher = - Fetcher.ofFlow { - flow { - delay(10) - emit("three-1") - delay(10) - emit("three-2") - } - }, + Fetcher.ofFlow { + flow { + delay(10) + emit("three-1") + delay(10) + emit("three-2") + } + }, sourceOfTruth = persister.asSourceOfTruth(), ) .disableCache() @@ -528,7 +525,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -536,7 +533,7 @@ class FlowStoreTests { value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -544,7 +541,7 @@ class FlowStoreTests { value = "three-1", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -552,7 +549,7 @@ class FlowStoreTests { value = "local-2", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -560,7 +557,7 @@ class FlowStoreTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -590,7 +587,7 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -598,7 +595,7 @@ class FlowStoreTests { error = exception, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -606,24 +603,24 @@ class FlowStoreTests { value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) } pipeline.stream(StoreReadRequest.cached(key = 3, refresh = true)).test { - assertEquals( - Data( - value = "local-1", - origin = StoreReadResponseOrigin.SourceOfTruth, - ), - awaitItem() - ) + assertEquals( + Data( + value = "local-1", + origin = StoreReadResponseOrigin.SourceOfTruth, + ), + awaitItem(), + ) assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -631,7 +628,7 @@ class FlowStoreTests { error = exception, origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -656,14 +653,14 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -671,7 +668,7 @@ class FlowStoreTests { value = "local-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -679,7 +676,7 @@ class FlowStoreTests { value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) } } @@ -699,14 +696,13 @@ class FlowStoreTests { val firstFetch = pipeline.fresh(3) // prime the cache assertEquals("local-1", firstFetch) - pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { assertEquals( Data( value = "local-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -714,21 +710,21 @@ class FlowStoreTests { value = "local-1", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -740,13 +736,13 @@ class FlowStoreTests { val pipeline = StoreBuilder.from( fetcher = - Fetcher.ofFlow { - if (createCount++ == 0) { - flowOf("remote-1") - } else { - flowOf() - } - }, + Fetcher.ofFlow { + if (createCount++ == 0) { + flowOf("remote-1") + } else { + flowOf() + } + }, ) .buildWithTestScope() @@ -758,14 +754,14 @@ class FlowStoreTests { Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -773,7 +769,7 @@ class FlowStoreTests { value = "remote-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) } } @@ -785,13 +781,13 @@ class FlowStoreTests { val pipeline = StoreBuilder.from( fetcher = - Fetcher.ofFlow { - if (createCount++ == 0) { - flowOf("remote-1") - } else { - flowOf() - } - }, + Fetcher.ofFlow { + if (createCount++ == 0) { + flowOf("remote-1") + } else { + flowOf() + } + }, ) .buildWithTestScope() @@ -804,21 +800,21 @@ class FlowStoreTests { value = "remote-1", origin = StoreReadResponseOrigin.Cache, ), - awaitItem() + awaitItem(), ) assertEquals( Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.NoNewData( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -953,7 +949,7 @@ class FlowStoreTests { } @Test - fun givenCacheAndNoSourceOfTruthWhen3CachedStreamsWithRefreshAnd1stHasSlowCollectionThen1stStreamsGets3FetchUpdatesAndOtherStreamsGetCacheResultAndFetchResult() = + fun testSlowFirstCollectorGetsAllFetchUpdatesOthersGetCacheAndLatestFetchResult() = testScope.runTest { val fetcher = FakeFetcher( @@ -983,37 +979,35 @@ class FlowStoreTests { fetcher1Collected, ) - pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { assertEquals( Data(origin = StoreReadResponseOrigin.Cache, value = "three-1"), - awaitItem() + awaitItem(), ) assertEquals( Loading(origin = StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( Data(origin = StoreReadResponseOrigin.Fetcher(), value = "three-2"), - awaitItem() + awaitItem(), ) - } pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { assertEquals( Data(origin = StoreReadResponseOrigin.Cache, value = "three-2"), - awaitItem() + awaitItem(), ) assertEquals( Loading(origin = StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( Data(origin = StoreReadResponseOrigin.Fetcher(), value = "three-3"), - awaitItem() + awaitItem(), ) } @@ -1032,7 +1026,7 @@ class FlowStoreTests { } @Test - fun givenCacheAndNoSourceOfTruthWhen2CachedStreamsWithRefreshThenFirstStreamsGets2FetchUpdatesAnd2ndStreamGetsCacheResultAndFetchResult() = + fun testFirstStreamGetsTwoFetchUpdatesSecondGetsCacheAndFetchResult() = testScope.runTest { val fetcher = FakeFetcher( @@ -1062,17 +1056,17 @@ class FlowStoreTests { pipeline.stream(StoreReadRequest.cached(3, refresh = true)).test { assertEquals( Data(origin = StoreReadResponseOrigin.Cache, value = "three-1"), - awaitItem() + awaitItem(), ) assertEquals( Loading(origin = StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( Data(origin = StoreReadResponseOrigin.Fetcher(), value = "three-2"), - awaitItem() + awaitItem(), ) } diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt index 04e12117..7d3c2e64 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/HotFlowStoreTests.kt @@ -30,53 +30,54 @@ class HotFlowStoreTests { .scope(testScope) .build() - val job = launch { - pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { - assertEquals( - StoreReadResponse.Loading( - origin = StoreReadResponseOrigin.Fetcher(), - ), - awaitItem() - ) + val job = + launch { + pipeline.stream(StoreReadRequest.cached(3, refresh = false)).test { + assertEquals( + StoreReadResponse.Loading( + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem(), + ) - assertEquals( - StoreReadResponse.Data( - value = "three-1", - origin = StoreReadResponseOrigin.Fetcher(), - ), - awaitItem() - ) - } + assertEquals( + StoreReadResponse.Data( + value = "three-1", + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem(), + ) + } - pipeline.stream( - StoreReadRequest.cached(3, refresh = false), - ).test { - assertEquals( - StoreReadResponse.Data( - value = "three-1", - origin = StoreReadResponseOrigin.Cache, - ), - awaitItem() - ) - } + pipeline.stream( + StoreReadRequest.cached(3, refresh = false), + ).test { + assertEquals( + StoreReadResponse.Data( + value = "three-1", + origin = StoreReadResponseOrigin.Cache, + ), + awaitItem(), + ) + } - pipeline.stream(StoreReadRequest.fresh(3)).test { - assertEquals( - StoreReadResponse.Loading( - origin = StoreReadResponseOrigin.Fetcher(), - ), - awaitItem() - ) + pipeline.stream(StoreReadRequest.fresh(3)).test { + assertEquals( + StoreReadResponse.Loading( + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem(), + ) - assertEquals( - StoreReadResponse.Data( - value = "three-2", - origin = StoreReadResponseOrigin.Fetcher(), - ), - awaitItem() - ) + assertEquals( + StoreReadResponse.Data( + value = "three-2", + origin = StoreReadResponseOrigin.Fetcher(), + ), + awaitItem(), + ) + } } - } job.cancel() } diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt index ccedcc96..da4527c7 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/MapIndexedTests.kt @@ -12,11 +12,12 @@ class MapIndexedTests { private val scope = TestScope() @Test - fun mapIndexed() = scope.runTest { - flowOf(5, 6).mapIndexed { index, value -> index to value }.test { - assertEquals(0 to 5, awaitItem()) - assertEquals(1 to 6, awaitItem()) - awaitComplete() + fun mapIndexed() = + scope.runTest { + flowOf(5, 6).mapIndexed { index, value -> index to value }.test { + assertEquals(0 to 5, awaitItem()) + assertEquals(1 to 6, awaitItem()) + awaitComplete() + } } - } } diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt index 1253340f..79808aaf 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthErrorsTests.kt @@ -46,23 +46,22 @@ class SourceOfTruthErrorsTests { } pipeline.stream(StoreReadRequest.fresh(3)).test { - assertEquals( StoreReadResponse.Loading(StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.Error.Exception( error = - WriteException( - key = 3, - value = "a", - cause = TestException("i fail"), - ), + WriteException( + key = 3, + value = "a", + cause = TestException("i fail"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) } } @@ -93,13 +92,13 @@ class SourceOfTruthErrorsTests { assertEquals( StoreReadResponse.Error.Exception( error = - ReadException( - key = 3, - cause = TestException("null"), - ), + ReadException( + key = 3, + cause = TestException("null"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) // after disk fails, we should still invoke fetcher @@ -107,7 +106,7 @@ class SourceOfTruthErrorsTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) // and after fetcher writes the value, it will trigger another read which will also @@ -115,13 +114,13 @@ class SourceOfTruthErrorsTests { assertEquals( StoreReadResponse.Error.Exception( error = - ReadException( - key = 3, - cause = TestException("a"), - ), + ReadException( + key = 3, + cause = TestException("a"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) } } @@ -154,19 +153,19 @@ class SourceOfTruthErrorsTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.Error.Exception( error = - WriteException( - key = 3, - value = "a", - cause = TestException("a"), - ), + WriteException( + key = 3, + value = "a", + cause = TestException("a"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -174,20 +173,20 @@ class SourceOfTruthErrorsTests { value = "b", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.Error.Exception( error = - WriteException( - key = 3, - value = "c", - cause = TestException("c"), - ), + WriteException( + key = 3, + value = "c", + cause = TestException("c"), + ), origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) // disk flow will restart after a failed write (because we stopped it before the @@ -197,7 +196,7 @@ class SourceOfTruthErrorsTests { value = "b", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) assertEquals( @@ -205,7 +204,7 @@ class SourceOfTruthErrorsTests { value = "d", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -319,7 +318,7 @@ class SourceOfTruthErrorsTests { value = "b", origin = StoreReadResponseOrigin.SourceOfTruth, ), - awaitItem() + awaitItem(), ) // don't receive the write exception because technically it started before we @@ -328,7 +327,7 @@ class SourceOfTruthErrorsTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -336,7 +335,7 @@ class SourceOfTruthErrorsTests { value = "d", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -414,19 +413,19 @@ class SourceOfTruthErrorsTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 3, - cause = TestException("first read"), - ), + ReadException( + key = 3, + cause = TestException("first read"), + ), ), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -434,7 +433,7 @@ class SourceOfTruthErrorsTests { value = "a", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt index 9d138d48..656f9b91 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruthWithBarrierTests.kt @@ -153,12 +153,12 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 1, - cause = exception, - ), + ReadException( + key = 1, + cause = exception, + ), ), - awaitItem() + awaitItem(), ) } } @@ -188,10 +188,10 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 1, - cause = exception, - ), + ReadException( + key = 1, + cause = exception, + ), ), collected.first(), ) @@ -205,10 +205,10 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - ReadException( - key = 1, - cause = exception, - ), + ReadException( + key = 1, + cause = exception, + ), ), StoreReadResponse.Data( // this is fetcher since we are using the write API @@ -254,11 +254,11 @@ class SourceOfTruthWithBarrierTests { StoreReadResponse.Error.Exception( origin = StoreReadResponseOrigin.SourceOfTruth, error = - WriteException( - key = 1, - value = failValue, - cause = exception, - ), + WriteException( + key = 1, + value = failValue, + cause = exception, + ), ), StoreReadResponse.Data( origin = StoreReadResponseOrigin.SourceOfTruth, diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt index 47f3541f..a9a81c1b 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/StreamWithoutSourceOfTruthTests.kt @@ -42,7 +42,7 @@ class StreamWithoutSourceOfTruthTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -50,7 +50,7 @@ class StreamWithoutSourceOfTruthTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -97,7 +97,7 @@ class StreamWithoutSourceOfTruthTests { StoreReadResponse.Loading( origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) assertEquals( @@ -105,7 +105,7 @@ class StreamWithoutSourceOfTruthTests { value = "three-2", origin = StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } diff --git a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt index a50e4bcd..d7898fee 100644 --- a/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt +++ b/store/src/commonTest/kotlin/org/mobilenativefoundation/store/store5/UpdaterTests.kt @@ -63,12 +63,12 @@ class UpdaterTests { MutableStoreBuilder.from( fetcher = Fetcher.of { key -> api.get(key, ttl = ttl) }, sourceOfTruth = - SourceOfTruth.of( - nonFlowReader = { key -> notes.get(key) }, - writer = { key, sot: InputNote -> notes.put(key, sot) }, - delete = { key -> notes.clear(key) }, - deleteAll = { notes.clear() }, - ), + SourceOfTruth.of( + nonFlowReader = { key -> notes.get(key) }, + writer = { key, sot: InputNote -> notes.put(key, sot) }, + delete = { key -> notes.clear(key) }, + deleteAll = { notes.clear() }, + ), converter = converter, ) .validator(validator) @@ -85,7 +85,7 @@ class UpdaterTests { stream.test { assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( @@ -93,7 +93,7 @@ class UpdaterTests { OutputNote(NoteData.Single(Notes.One), ttl = ttl), StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -176,12 +176,12 @@ class UpdaterTests { MutableStoreBuilder.from( fetcher = Fetcher.of { key -> api.get(key, ttl = ttl) }, sourceOfTruth = - SourceOfTruth.of( - nonFlowReader = { key -> notes.get(key) }, - writer = { key, sot: InputNote -> notes.put(key, sot) }, - delete = { key -> notes.clear(key) }, - deleteAll = { notes.clear() }, - ), + SourceOfTruth.of( + nonFlowReader = { key -> notes.get(key) }, + writer = { key, sot: InputNote -> notes.put(key, sot) }, + delete = { key -> notes.clear(key) }, + deleteAll = { notes.clear() }, + ), converter = converter, ) .validator(validator) @@ -198,7 +198,7 @@ class UpdaterTests { stream.test { assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher()), - awaitItem() + awaitItem(), ) assertEquals( @@ -206,7 +206,7 @@ class UpdaterTests { OutputNote(NoteData.Single(Notes.One), ttl = ttl), StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } @@ -222,14 +222,14 @@ class UpdaterTests { cachedStream.test { assertEquals( StoreReadResponse.Loading(origin = StoreReadResponseOrigin.Fetcher(name = null)), - awaitItem() + awaitItem(), ) assertEquals( StoreReadResponse.Data( OutputNote(NoteData.Single(Notes.One), ttl = ttl), StoreReadResponseOrigin.Fetcher(), ), - awaitItem() + awaitItem(), ) } } @@ -251,17 +251,17 @@ class UpdaterTests { val store = MutableStoreBuilder.from( fetcher = - Fetcher.ofFlow { key -> - val network = api.get(key) - flow { emit(network) } - }, + Fetcher.ofFlow { key -> + val network = api.get(key) + flow { emit(network) } + }, sourceOfTruth = - SourceOfTruth.of( - nonFlowReader = { key -> notes.get(key) }, - writer = { key, sot -> notes.put(key, sot) }, - delete = { key -> notes.clear(key) }, - deleteAll = { notes.clear() }, - ), + SourceOfTruth.of( + nonFlowReader = { key -> notes.get(key) }, + writer = { key, sot -> notes.put(key, sot) }, + delete = { key -> notes.clear(key) }, + deleteAll = { notes.clear() }, + ), converter, ) .validator(validator)