From 35adf5ec01c4120f912d2138638315ca4cdea166 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sun, 23 Jun 2024 13:45:33 +0200 Subject: [PATCH] Workaround for KSP support on testFixtures --- .../core/data/di/TestDataModule.kt | 2 +- .../repository/FakeRecentSearchRepository.kt | 2 +- .../FakeSearchContentsRepository.kt | 2 +- .../data/repository/FakeTopicsRepository.kt | 2 +- core/testing/build.gradle.kts | 3 + .../core/testing/di/TestingModule.kt | 70 +++++++++++++++++++ .../core/sync/di/TestSyncModule.kt | 2 +- .../sync/status/NeverSyncingSyncManager.kt | 2 +- 8 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/di/TestingModule.kt diff --git a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/di/TestDataModule.kt b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/di/TestDataModule.kt index c2ae30260..ddc965d4f 100644 --- a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/di/TestDataModule.kt +++ b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/di/TestDataModule.kt @@ -40,7 +40,7 @@ import dagger.hilt.testing.TestInstallIn components = [SingletonComponent::class], replaces = [DataModule::class], ) -internal interface TestDataModule { +interface TestDataModule { @Binds fun bindsTopicRepository(it: FakeTopicsRepository): TopicsRepository diff --git a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeRecentSearchRepository.kt b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeRecentSearchRepository.kt index 4c54f06c1..38852483c 100644 --- a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeRecentSearchRepository.kt +++ b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeRecentSearchRepository.kt @@ -24,7 +24,7 @@ import javax.inject.Inject /** * Fake implementation of the [RecentSearchRepository] */ -internal class FakeRecentSearchRepository @Inject constructor() : RecentSearchRepository { +class FakeRecentSearchRepository @Inject constructor() : RecentSearchRepository { override suspend fun insertOrReplaceRecentSearch(searchQuery: String) = Unit override fun getRecentSearchQueries(limit: Int): Flow> = diff --git a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeSearchContentsRepository.kt b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeSearchContentsRepository.kt index 3de72baa6..6d7101d69 100644 --- a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeSearchContentsRepository.kt +++ b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeSearchContentsRepository.kt @@ -24,7 +24,7 @@ import javax.inject.Inject /** * Fake implementation of the [SearchContentsRepository] */ -internal class FakeSearchContentsRepository @Inject constructor() : SearchContentsRepository { +class FakeSearchContentsRepository @Inject constructor() : SearchContentsRepository { override suspend fun populateFtsData() = Unit override fun searchContents(searchQuery: String): Flow = flowOf() diff --git a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeTopicsRepository.kt b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeTopicsRepository.kt index c484c1c0f..b0ee523cb 100644 --- a/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeTopicsRepository.kt +++ b/core/data/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/FakeTopicsRepository.kt @@ -35,7 +35,7 @@ import javax.inject.Inject * This allows us to run the app with fake data, without needing an internet connection or working * backend. */ -internal class FakeTopicsRepository @Inject constructor( +class FakeTopicsRepository @Inject constructor( @Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher, private val datasource: DemoNiaNetworkDataSource, ) : TopicsRepository { diff --git a/core/testing/build.gradle.kts b/core/testing/build.gradle.kts index 02729ceff..338432cdc 100644 --- a/core/testing/build.gradle.kts +++ b/core/testing/build.gradle.kts @@ -39,4 +39,7 @@ dependencies { implementation(libs.kotlinx.datetime) implementation(projects.core.common) implementation(projects.core.designsystem) + implementation(testFixtures(projects.core.data)) + implementation(testFixtures(projects.core.datastore)) + implementation(testFixtures(projects.sync)) } diff --git a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/di/TestingModule.kt b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/di/TestingModule.kt new file mode 100644 index 000000000..528e396a6 --- /dev/null +++ b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/di/TestingModule.kt @@ -0,0 +1,70 @@ +/* + * 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.testing.di + +import androidx.datastore.core.DataStore +import com.google.samples.apps.nowinandroid.core.data.di.DataModule +import com.google.samples.apps.nowinandroid.core.data.di.TestDataModule +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.datastore.di.TestDataStoreModule +import com.google.samples.apps.nowinandroid.core.network.di.ApplicationScope +import com.google.samples.apps.nowinandroid.core.sync.di.TestSyncModule +import com.google.samples.apps.nowinandroid.sync.di.SyncModule +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 + +/** + * KSP is currently not supported on Android testFixtures ([issuetracker](https://issuetracker.google.com/issues/259523353#comment32)). + * + * Including [TestDataStoreModule] in [Module.includes] leads to an unexpected compilation error (maybe due to datastore-proto and KSP ordering, certainly related to the initial issue). + * + * ``` + * > Task :app:hiltJavaCompileDemoDebugAndroidTest FAILED + * nowinandroid\app\build\generated\hilt\component_sources\demoDebugAndroidTest\dagger\hilt\android\internal\testing\root\DaggerNavigationTest_HiltComponents_SingletonC.java:38: error: cannot find symbol + * import com.google.samples.apps.nowinandroid.core.datastore.di.TestDataStoreModule_ProvidesUserPreferencesDataStoreFactory; + * ^ + * symbol: class TestDataStoreModule_ProvidesUserPreferencesDataStoreFactory + * location: package com.google.samples.apps.nowinandroid.core.datastore.di + * ``` + * + * Therefore, a [providesUserPreferencesDataStore] delegate is added in this module. + */ +@Module(includes = [TestDataModule::class, TestSyncModule::class]) +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [DataModule::class, SyncModule::class, DataStoreModule::class], +) +internal object TestingModule { + @Provides + @Singleton + fun providesUserPreferencesDataStore( + @ApplicationScope scope: CoroutineScope, + userPreferencesSerializer: UserPreferencesSerializer, + tmpFolder: TemporaryFolder, + ): DataStore = TestDataStoreModule.providesUserPreferencesDataStore( + scope, + userPreferencesSerializer, + tmpFolder, + ) +} diff --git a/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/sync/di/TestSyncModule.kt b/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/sync/di/TestSyncModule.kt index 397844d5a..c97328f3f 100644 --- a/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/sync/di/TestSyncModule.kt +++ b/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/core/sync/di/TestSyncModule.kt @@ -31,7 +31,7 @@ import dagger.hilt.testing.TestInstallIn components = [SingletonComponent::class], replaces = [SyncModule::class], ) -internal interface TestSyncModule { +interface TestSyncModule { @Binds fun bindsSyncManager(it: NeverSyncingSyncManager): SyncManager diff --git a/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/sync/status/NeverSyncingSyncManager.kt b/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/sync/status/NeverSyncingSyncManager.kt index da44a635d..aca0bdfab 100644 --- a/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/sync/status/NeverSyncingSyncManager.kt +++ b/sync/src/testFixtures/kotlin/com/google/samples/apps/nowinandroid/sync/status/NeverSyncingSyncManager.kt @@ -21,7 +21,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import javax.inject.Inject -internal class NeverSyncingSyncManager @Inject constructor() : SyncManager { +class NeverSyncingSyncManager @Inject constructor() : SyncManager { override val isSyncing: Flow = flowOf(false) override fun requestSync() = Unit }