diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4fc2ea36c..1e4361008 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -114,6 +114,7 @@ dependencies { kspTest(libs.hilt.compiler) testImplementation(projects.core.dataTest) + testImplementation(projects.core.datastoreTest) testImplementation(libs.hilt.android.testing) testImplementation(projects.sync.syncTest) testImplementation(libs.kotlin.test) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt index b15024cc7..f421adaeb 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt @@ -35,7 +35,6 @@ import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule -import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import kotlinx.coroutines.flow.first @@ -43,7 +42,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import javax.inject.Inject import com.google.samples.apps.nowinandroid.feature.bookmarks.R as BookmarksR import com.google.samples.apps.nowinandroid.feature.foryou.R as FeatureForyouR @@ -62,24 +60,16 @@ class NavigationTest { @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this) - /** - * Create a temporary folder used to create a Data Store file. This guarantees that - * the file is removed in between each test, preventing a crash. - */ - @BindValue - @get:Rule(order = 1) - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - /** * Grant [android.Manifest.permission.POST_NOTIFICATIONS] permission. */ - @get:Rule(order = 2) + @get:Rule(order = 1) val postNotificationsPermission = GrantPostNotificationsPermissionRule() /** * Use the primary activity to initialize the app normally. */ - @get:Rule(order = 3) + @get:Rule(order = 2) val composeTestRule = createAndroidComposeRule() @Inject diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/InterestsListDetailScreenTest.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/InterestsListDetailScreenTest.kt index a5b243537..1062c7e56 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/InterestsListDetailScreenTest.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/InterestsListDetailScreenTest.kt @@ -31,7 +31,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.ui.interests2pane.InterestsListDetailScreen import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity -import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltTestApplication @@ -40,7 +39,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @@ -60,11 +58,7 @@ class InterestsListDetailScreenTest { @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this) - @BindValue @get:Rule(order = 1) - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - - @get:Rule(order = 2) val composeTestRule = createAndroidComposeRule() @Inject diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt index 1cca5a13a..e84b96b73 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt @@ -38,7 +38,6 @@ import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity -import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltTestApplication @@ -47,7 +46,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @@ -74,18 +72,10 @@ class NiaAppScreenSizesScreenshotTests { @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this) - /** - * Create a temporary folder used to create a Data Store file. This guarantees that - * the file is removed in between each test, preventing a crash. - */ - @BindValue - @get:Rule(order = 1) - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - /** * Use a test activity to set the content on. */ - @get:Rule(order = 2) + @get:Rule(order = 1) val composeTestRule = createAndroidComposeRule() @Inject diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt index b9970effd..2ef0d3e4f 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarInsetsScreenshotTests.kt @@ -69,7 +69,6 @@ import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity -import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltTestApplication @@ -80,7 +79,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @@ -107,18 +105,10 @@ class SnackbarInsetsScreenshotTests { @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this) - /** - * Create a temporary folder used to create a Data Store file. This guarantees that - * the file is removed in between each test, preventing a crash. - */ - @BindValue - @get:Rule(order = 1) - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - /** * Use a test activity to set the content on. */ - @get:Rule(order = 2) + @get:Rule(order = 1) val composeTestRule = createAndroidComposeRule() @Inject diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt index 6f12dd620..fe2e98452 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt @@ -42,7 +42,6 @@ import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.testing.util.DefaultRoborazziOptions import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActivity -import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltTestApplication @@ -53,7 +52,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @@ -80,18 +78,10 @@ class SnackbarScreenshotTests { @get:Rule(order = 0) val hiltRule = HiltAndroidRule(this) - /** - * Create a temporary folder used to create a Data Store file. This guarantees that - * the file is removed in between each test, preventing a crash. - */ - @BindValue - @get:Rule(order = 1) - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - /** * Use a test activity to set the content on. */ - @get:Rule(order = 2) + @get:Rule(order = 1) val composeTestRule = createAndroidComposeRule() @Inject diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt index 413147f0e..01111013f 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt @@ -32,7 +32,8 @@ import com.google.samples.apps.nowinandroid.core.database.model.PopulatedNewsRes import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferencesDataSource -import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore +import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences +import com.google.samples.apps.nowinandroid.core.datastore.test.InMemoryDataStore import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList @@ -43,9 +44,7 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -67,14 +66,9 @@ class OfflineFirstNewsRepositoryTest { private lateinit var synchronizer: Synchronizer - @get:Rule - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - @Before fun setup() { - niaPreferencesDataSource = NiaPreferencesDataSource( - tmpFolder.testUserPreferencesDataStore(testScope.backgroundScope), - ) + niaPreferencesDataSource = NiaPreferencesDataSource(InMemoryDataStore(UserPreferences.getDefaultInstance())) newsResourceDao = TestNewsResourceDao() topicDao = TestTopicDao() network = TestNiaNetworkDataSource() diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt index be41c86f2..d32f424d8 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt @@ -25,7 +25,8 @@ import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferencesDataSource -import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore +import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences +import com.google.samples.apps.nowinandroid.core.datastore.test.InMemoryDataStore import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic import kotlinx.coroutines.flow.first @@ -33,9 +34,7 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import kotlin.test.assertEquals class OfflineFirstTopicsRepositoryTest { @@ -52,16 +51,11 @@ class OfflineFirstTopicsRepositoryTest { private lateinit var synchronizer: Synchronizer - @get:Rule - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - @Before fun setup() { topicDao = TestTopicDao() network = TestNiaNetworkDataSource() - niaPreferences = NiaPreferencesDataSource( - tmpFolder.testUserPreferencesDataStore(testScope.backgroundScope), - ) + niaPreferences = NiaPreferencesDataSource(InMemoryDataStore(UserPreferences.getDefaultInstance())) synchronizer = TestSynchronizer(niaPreferences) subject = OfflineFirstTopicsRepository( diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt index 88b3251e5..8860a6b35 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt @@ -18,7 +18,8 @@ package com.google.samples.apps.nowinandroid.core.data.repository import com.google.samples.apps.nowinandroid.core.analytics.NoOpAnalyticsHelper import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferencesDataSource -import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore +import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences +import com.google.samples.apps.nowinandroid.core.datastore.test.InMemoryDataStore import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand import com.google.samples.apps.nowinandroid.core.model.data.UserData @@ -28,9 +29,7 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -45,14 +44,9 @@ class OfflineFirstUserDataRepositoryTest { private val analyticsHelper = NoOpAnalyticsHelper() - @get:Rule - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - @Before fun setup() { - niaPreferencesDataSource = NiaPreferencesDataSource( - tmpFolder.testUserPreferencesDataStore(testScope.backgroundScope), - ) + niaPreferencesDataSource = NiaPreferencesDataSource(InMemoryDataStore(UserPreferences.getDefaultInstance())) subject = OfflineFirstUserDataRepository( niaPreferencesDataSource = niaPreferencesDataSource, diff --git a/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/InMemoryDataStore.kt b/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/InMemoryDataStore.kt new file mode 100644 index 000000000..f1da66dd0 --- /dev/null +++ b/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/InMemoryDataStore.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.samples.apps.nowinandroid.core.datastore.test + +import androidx.datastore.core.DataStore +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.updateAndGet + +class InMemoryDataStore(initialValue: T) : DataStore { + override val data = MutableStateFlow(initialValue) + override suspend fun updateData( + transform: suspend (it: T) -> T, + ) = data.updateAndGet { transform(it) } +} diff --git a/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/TestDataStoreModule.kt b/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/TestDataStoreModule.kt index 295b2978a..5cc48af12 100644 --- a/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/TestDataStoreModule.kt +++ b/core/datastore-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/datastore/test/TestDataStoreModule.kt @@ -17,17 +17,13 @@ package com.google.samples.apps.nowinandroid.core.datastore.test import androidx.datastore.core.DataStore -import androidx.datastore.core.DataStoreFactory import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences import com.google.samples.apps.nowinandroid.core.datastore.UserPreferencesSerializer import com.google.samples.apps.nowinandroid.core.datastore.di.DataStoreModule -import com.google.samples.apps.nowinandroid.core.network.di.ApplicationScope import dagger.Module import dagger.Provides import dagger.hilt.components.SingletonComponent import dagger.hilt.testing.TestInstallIn -import kotlinx.coroutines.CoroutineScope -import org.junit.rules.TemporaryFolder import javax.inject.Singleton @Module @@ -36,26 +32,9 @@ import javax.inject.Singleton replaces = [DataStoreModule::class], ) internal object TestDataStoreModule { - @Provides @Singleton fun providesUserPreferencesDataStore( - @ApplicationScope scope: CoroutineScope, - userPreferencesSerializer: UserPreferencesSerializer, - tmpFolder: TemporaryFolder, - ): DataStore = - tmpFolder.testUserPreferencesDataStore( - coroutineScope = scope, - userPreferencesSerializer = userPreferencesSerializer, - ) -} - -fun TemporaryFolder.testUserPreferencesDataStore( - coroutineScope: CoroutineScope, - userPreferencesSerializer: UserPreferencesSerializer = UserPreferencesSerializer(), -) = DataStoreFactory.create( - serializer = userPreferencesSerializer, - scope = coroutineScope, -) { - newFile("user_preferences_test.pb") + serializer: UserPreferencesSerializer, + ): DataStore = InMemoryDataStore(serializer.defaultValue) } diff --git a/core/datastore/src/test/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSourceTest.kt b/core/datastore/src/test/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSourceTest.kt index ba1706461..433bbb5ea 100644 --- a/core/datastore/src/test/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSourceTest.kt +++ b/core/datastore/src/test/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSourceTest.kt @@ -16,15 +16,13 @@ package com.google.samples.apps.nowinandroid.core.datastore -import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore +import com.google.samples.apps.nowinandroid.core.datastore.test.InMemoryDataStore import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Rule import org.junit.Test -import org.junit.rules.TemporaryFolder import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -34,14 +32,9 @@ class NiaPreferencesDataSourceTest { private lateinit var subject: NiaPreferencesDataSource - @get:Rule - val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - @Before fun setup() { - subject = NiaPreferencesDataSource( - tmpFolder.testUserPreferencesDataStore(testScope.backgroundScope), - ) + subject = NiaPreferencesDataSource(InMemoryDataStore(UserPreferences.getDefaultInstance())) } @Test