From f19fe74513e89d523aeaef3a4f36d036822382af Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 2 Mar 2024 20:30:36 +0900 Subject: [PATCH 01/19] Apply withContext(defaultDispatchers) for main-safe. Change-Id: Ic3474b86f1af0aaf80c13769223409d7ba070871 --- .../CompositeUserNewsResourceRepository.kt | 9 +++- .../DefaultSearchContentsRepository.kt | 16 ++++--- .../core/domain/GetFollowableTopicsUseCase.kt | 25 +++++++---- .../core/domain/GetSearchContentsUseCase.kt | 42 ++++++++++++------- 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt index 64e02e7d9..44fbb1658 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt @@ -18,12 +18,16 @@ package com.google.samples.apps.nowinandroid.core.data.repository import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.mapToUserNewsResources +import com.google.samples.apps.nowinandroid.core.network.Dispatcher +import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.Default +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext import javax.inject.Inject /** @@ -33,6 +37,7 @@ import javax.inject.Inject class CompositeUserNewsResourceRepository @Inject constructor( val newsRepository: NewsRepository, val userDataRepository: UserDataRepository, + @Dispatcher(Default) private val defaultDispatcher: CoroutineDispatcher, ) : UserNewsResourceRepository { /** @@ -43,7 +48,9 @@ class CompositeUserNewsResourceRepository @Inject constructor( ): Flow> = newsRepository.getNewsResources(query) .combine(userDataRepository.userData) { newsResources, userData -> - newsResources.mapToUserNewsResources(userData) + withContext(defaultDispatcher) { + newsResources.mapToUserNewsResources(userData) + } } /** diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt index 3bacb8a14..38c0ebe86 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt @@ -25,6 +25,7 @@ import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel import com.google.samples.apps.nowinandroid.core.database.model.asFtsEntity import com.google.samples.apps.nowinandroid.core.model.data.SearchResult import com.google.samples.apps.nowinandroid.core.network.Dispatcher +import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.Default import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow @@ -42,6 +43,7 @@ internal class DefaultSearchContentsRepository @Inject constructor( private val topicDao: TopicDao, private val topicFtsDao: TopicFtsDao, @Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher, + @Dispatcher(Default) private val defaultDispatcher: CoroutineDispatcher, ) : SearchContentsRepository { override suspend fun populateFtsData() { @@ -75,10 +77,12 @@ internal class DefaultSearchContentsRepository @Inject constructor( .distinctUntilChanged() .flatMapLatest(topicDao::getTopicEntities) return combine(newsResourcesFlow, topicsFlow) { newsResources, topics -> - SearchResult( - topics = topics.map { it.asExternalModel() }, - newsResources = newsResources.map { it.asExternalModel() }, - ) + withContext(defaultDispatcher) { + SearchResult( + topics = topics.map { it.asExternalModel() }, + newsResources = newsResources.map { it.asExternalModel() }, + ) + } } } @@ -87,6 +91,8 @@ internal class DefaultSearchContentsRepository @Inject constructor( newsResourceFtsDao.getCount(), topicFtsDao.getCount(), ) { newsResourceCount, topicsCount -> - newsResourceCount + topicsCount + withContext(defaultDispatcher) { + newsResourceCount + topicsCount + } } } diff --git a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt index 0167a3192..f80a722ed 100644 --- a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt +++ b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt @@ -21,8 +21,12 @@ import com.google.samples.apps.nowinandroid.core.data.repository.UserDataReposit import com.google.samples.apps.nowinandroid.core.domain.TopicSortField.NAME import com.google.samples.apps.nowinandroid.core.domain.TopicSortField.NONE import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic +import com.google.samples.apps.nowinandroid.core.network.Dispatcher +import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.Default +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.withContext import javax.inject.Inject /** @@ -31,6 +35,7 @@ import javax.inject.Inject class GetFollowableTopicsUseCase @Inject constructor( private val topicsRepository: TopicsRepository, private val userDataRepository: UserDataRepository, + @Dispatcher(Default) private val defaultDispatcher: CoroutineDispatcher, ) { /** * Returns a list of topics with their associated followed state. @@ -41,16 +46,18 @@ class GetFollowableTopicsUseCase @Inject constructor( userDataRepository.userData, topicsRepository.getTopics(), ) { userData, topics -> - val followedTopics = topics - .map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id in userData.followedTopics, - ) + withContext(defaultDispatcher) { + val followedTopics = topics + .map { topic -> + FollowableTopic( + topic = topic, + isFollowed = topic.id in userData.followedTopics, + ) + } + when (sortBy) { + NAME -> followedTopics.sortedBy { it.topic.name } + else -> followedTopics } - when (sortBy) { - NAME -> followedTopics.sortedBy { it.topic.name } - else -> followedTopics } } } diff --git a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt index d1065e87c..edb12641d 100644 --- a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt +++ b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt @@ -23,8 +23,12 @@ import com.google.samples.apps.nowinandroid.core.model.data.SearchResult import com.google.samples.apps.nowinandroid.core.model.data.UserData import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.UserSearchResult +import com.google.samples.apps.nowinandroid.core.network.Dispatcher +import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.Default +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.withContext import javax.inject.Inject /** @@ -33,29 +37,35 @@ import javax.inject.Inject class GetSearchContentsUseCase @Inject constructor( private val searchContentsRepository: SearchContentsRepository, private val userDataRepository: UserDataRepository, + @Dispatcher(Default) private val defaultDispatcher: CoroutineDispatcher, ) { operator fun invoke( searchQuery: String, ): Flow = searchContentsRepository.searchContents(searchQuery) - .mapToUserSearchResult(userDataRepository.userData) + .mapToUserSearchResult(userDataRepository.userData, defaultDispatcher) } -private fun Flow.mapToUserSearchResult(userDataStream: Flow): Flow = +private fun Flow.mapToUserSearchResult( + userDataStream: Flow, + defaultDispatcher: CoroutineDispatcher, +): Flow = combine(userDataStream) { searchResult, userData -> - UserSearchResult( - topics = searchResult.topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id in userData.followedTopics, - ) - }, - newsResources = searchResult.newsResources.map { news -> - UserNewsResource( - newsResource = news, - userData = userData, - ) - }, - ) + withContext(defaultDispatcher) { + UserSearchResult( + topics = searchResult.topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = topic.id in userData.followedTopics, + ) + }, + newsResources = searchResult.newsResources.map { news -> + UserNewsResource( + newsResource = news, + userData = userData, + ) + }, + ) + } } From 3075835df89c54a69cca603ca1938d996994c8f3 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 2 Mar 2024 20:36:08 +0900 Subject: [PATCH 02/19] Pass argument defaultDispatcher. Change-Id: Ibadc91344a9ac57fed8449e5174a41e25ec7271e --- .../apps/nowinandroid/feature/topic/TopicViewModelTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt b/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt index a9c9d96dc..97641d0fc 100644 --- a/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt +++ b/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt @@ -26,6 +26,7 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRe import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.feature.topic.navigation.TOPIC_ID_ARG +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first @@ -54,6 +55,7 @@ class TopicViewModelTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default, ) private lateinit var viewModel: TopicViewModel From dbf3e262cd00826ee50c45e3a46f406672583574 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 2 Mar 2024 21:25:01 +0900 Subject: [PATCH 03/19] Pass argument defaultDispatcher. Change-Id: I3bd11f32b42cb224f4de1b58616c52e0fd982833 --- .../com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt index d92390918..a5daca883 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt @@ -34,6 +34,7 @@ import com.google.samples.apps.nowinandroid.uitesthiltmanifest.HiltComponentActi import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest +import kotlinx.coroutines.Dispatchers import org.junit.Before import org.junit.Rule import org.junit.Test @@ -76,6 +77,7 @@ class NavigationUiTest { val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = TestNewsRepository(), userDataRepository = TestUserDataRepository(), + defaultDispatcher = Dispatchers.Default, ) @Inject From cba92eac322b967f169603a3b19b9a63837f9ac9 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sat, 2 Mar 2024 21:30:59 +0900 Subject: [PATCH 04/19] Pass argument defaultDispatcher. Change-Id: I0e050bcecff5d43050103a9a19d0d6b6b31d4ba2 --- .../com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt index 1560a74eb..87eaf3058 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt @@ -34,6 +34,7 @@ import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNe import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -60,7 +61,7 @@ class NiaAppStateTest { private val networkMonitor = TestNetworkMonitor() private val userNewsResourceRepository = - CompositeUserNewsResourceRepository(TestNewsRepository(), TestUserDataRepository()) + CompositeUserNewsResourceRepository(TestNewsRepository(), TestUserDataRepository(), Dispatchers.Default) // Subject under test. private lateinit var state: NiaAppState From 30cfcf0de384222cde1426553d1c1725533f55a7 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Sun, 3 Mar 2024 13:39:49 +0900 Subject: [PATCH 05/19] Pass argument defaultDispatcher. Change-Id: I142352cd418b147e538e8982b4b4dc17fb6b0d53 --- .../apps/nowinandroid/feature/search/SearchViewModelTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt index da0d5654e..e88562453 100644 --- a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt +++ b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt @@ -32,6 +32,7 @@ import com.google.samples.apps.nowinandroid.feature.search.RecentSearchQueriesUi import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.EmptyQuery import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.Loading import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.SearchNotReady +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -56,6 +57,7 @@ class SearchViewModelTest { private val getSearchContentsUseCase = GetSearchContentsUseCase( searchContentsRepository = searchContentsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default ) private val recentSearchRepository = TestRecentSearchRepository() private val getRecentQueryUseCase = GetRecentSearchQueriesUseCase(recentSearchRepository) From 22130b62cb58ba705409d6fe74fa032cb1b5bf8a Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Mon, 4 Mar 2024 21:05:34 +0900 Subject: [PATCH 06/19] Change withContext to flowOn. Change-Id: Iec1e30326807f79753ec68ee10f2ef5f4ad40535 --- .../repository/CompositeUserNewsResourceRepository.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt index 44fbb1658..9346af6a9 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt @@ -26,8 +26,8 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.withContext import javax.inject.Inject /** @@ -48,10 +48,10 @@ class CompositeUserNewsResourceRepository @Inject constructor( ): Flow> = newsRepository.getNewsResources(query) .combine(userDataRepository.userData) { newsResources, userData -> - withContext(defaultDispatcher) { newsResources.mapToUserNewsResources(userData) - } - } + }.flowOn( + defaultDispatcher + ) /** * Returns available news resources (joined with user data) for the followed topics. From 4916b9f58c14a0350d559465f98f2a7a3b3a688d Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Mon, 4 Mar 2024 21:11:52 +0900 Subject: [PATCH 07/19] Change withContext to flowOn. Change-Id: I679f11aa0bcae1d2de54b0373a284f83d0f0c81b --- .../DefaultSearchContentsRepository.kt | 19 +++++------ .../core/domain/GetFollowableTopicsUseCase.kt | 24 ++++++------- .../core/domain/GetSearchContentsUseCase.kt | 34 +++++++++---------- 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt index 38c0ebe86..8893665fc 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt @@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.withContext import javax.inject.Inject @@ -77,13 +78,11 @@ internal class DefaultSearchContentsRepository @Inject constructor( .distinctUntilChanged() .flatMapLatest(topicDao::getTopicEntities) return combine(newsResourcesFlow, topicsFlow) { newsResources, topics -> - withContext(defaultDispatcher) { - SearchResult( - topics = topics.map { it.asExternalModel() }, - newsResources = newsResources.map { it.asExternalModel() }, - ) - } - } + SearchResult( + topics = topics.map { it.asExternalModel() }, + newsResources = newsResources.map { it.asExternalModel() }, + ) + }.flowOn(defaultDispatcher) } override fun getSearchContentsCount(): Flow = @@ -91,8 +90,6 @@ internal class DefaultSearchContentsRepository @Inject constructor( newsResourceFtsDao.getCount(), topicFtsDao.getCount(), ) { newsResourceCount, topicsCount -> - withContext(defaultDispatcher) { - newsResourceCount + topicsCount - } - } + newsResourceCount + topicsCount + }.flowOn(defaultDispatcher) } diff --git a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt index f80a722ed..680b317c6 100644 --- a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt +++ b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt @@ -26,7 +26,7 @@ import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.Default import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.flowOn import javax.inject.Inject /** @@ -46,20 +46,18 @@ class GetFollowableTopicsUseCase @Inject constructor( userDataRepository.userData, topicsRepository.getTopics(), ) { userData, topics -> - withContext(defaultDispatcher) { - val followedTopics = topics - .map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id in userData.followedTopics, - ) - } - when (sortBy) { - NAME -> followedTopics.sortedBy { it.topic.name } - else -> followedTopics + val followedTopics = topics + .map { topic -> + FollowableTopic( + topic = topic, + isFollowed = topic.id in userData.followedTopics, + ) } + when (sortBy) { + NAME -> followedTopics.sortedBy { it.topic.name } + else -> followedTopics } - } + }.flowOn(defaultDispatcher) } enum class TopicSortField { diff --git a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt index edb12641d..2e8db5f0e 100644 --- a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt +++ b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt @@ -28,7 +28,7 @@ import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.Default import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.flowOn import javax.inject.Inject /** @@ -52,20 +52,18 @@ private fun Flow.mapToUserSearchResult( defaultDispatcher: CoroutineDispatcher, ): Flow = combine(userDataStream) { searchResult, userData -> - withContext(defaultDispatcher) { - UserSearchResult( - topics = searchResult.topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id in userData.followedTopics, - ) - }, - newsResources = searchResult.newsResources.map { news -> - UserNewsResource( - newsResource = news, - userData = userData, - ) - }, - ) - } - } + UserSearchResult( + topics = searchResult.topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = topic.id in userData.followedTopics, + ) + }, + newsResources = searchResult.newsResources.map { news -> + UserNewsResource( + newsResource = news, + userData = userData, + ) + }, + ) + }.flowOn(defaultDispatcher) From ff1744b34f25c8ecce7494016e8ad6dd5264a65c Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Tue, 5 Mar 2024 08:55:24 +0900 Subject: [PATCH 08/19] Fix spotless - Style. Change-Id: Iefae14197b1347c7fb00c2d1f754d51cf5419b80 --- .../google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt | 6 +++++- .../data/repository/CompositeUserNewsResourceRepository.kt | 6 ++---- .../apps/nowinandroid/feature/search/SearchViewModelTest.kt | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt index 68f496d51..739cecf46 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt @@ -65,7 +65,11 @@ class NiaAppStateTest { private val timeZoneMonitor = TestTimeZoneMonitor() private val userNewsResourceRepository = - CompositeUserNewsResourceRepository(TestNewsRepository(), TestUserDataRepository(), Dispatchers.Default) + CompositeUserNewsResourceRepository( + TestNewsRepository(), + TestUserDataRepository(), + Dispatchers.Default, + ) // Subject under test. private lateinit var state: NiaAppState diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt index 9346af6a9..5fcd0d698 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt @@ -48,10 +48,8 @@ class CompositeUserNewsResourceRepository @Inject constructor( ): Flow> = newsRepository.getNewsResources(query) .combine(userDataRepository.userData) { newsResources, userData -> - newsResources.mapToUserNewsResources(userData) - }.flowOn( - defaultDispatcher - ) + newsResources.mapToUserNewsResources(userData) + }.flowOn(defaultDispatcher) /** * Returns available news resources (joined with user data) for the followed topics. diff --git a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt index e88562453..e9768c825 100644 --- a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt +++ b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt @@ -57,7 +57,7 @@ class SearchViewModelTest { private val getSearchContentsUseCase = GetSearchContentsUseCase( searchContentsRepository = searchContentsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default + defaultDispatcher = Dispatchers.Default, ) private val recentSearchRepository = TestRecentSearchRepository() private val getRecentQueryUseCase = GetRecentSearchQueriesUseCase(recentSearchRepository) From 3fc2365e649dba91fe30d94b992d9ba82b0ad4df Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Wed, 6 Mar 2024 20:12:39 +0900 Subject: [PATCH 09/19] Pass argument defaultDispatcher. Change-Id: Ie68dda7a4082d994e2d8d82c1737587f95ab15a0 --- .../core/data/CompositeUserNewsResourceRepositoryTest.kt | 2 ++ .../nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt | 2 ++ .../nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt | 2 ++ .../apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt | 3 +++ .../apps/nowinandroid/interests/InterestsViewModelTest.kt | 2 ++ 5 files changed, 11 insertions(+) diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt index 05811f4be..cb921f155 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt @@ -24,6 +24,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.mapToUserNewsResourc import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.repository.emptyUserData +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant @@ -38,6 +39,7 @@ class CompositeUserNewsResourceRepositoryTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default, ) @Test diff --git a/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt b/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt index 42a31f858..34bbfb756 100644 --- a/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt +++ b/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt @@ -22,6 +22,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -39,6 +40,7 @@ class GetFollowableTopicsUseCaseTest { val useCase = GetFollowableTopicsUseCase( topicsRepository, userDataRepository, + defaultDispatcher = Dispatchers.Default, ) @Test diff --git a/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt b/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt index 6469a684b..f10205629 100644 --- a/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt +++ b/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt @@ -23,6 +23,7 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserData import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -46,6 +47,7 @@ class BookmarksViewModelTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default, ) private lateinit var viewModel: BookmarksViewModel diff --git a/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt index b75573975..3c8a9785c 100644 --- a/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt +++ b/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt @@ -35,6 +35,7 @@ import com.google.samples.apps.nowinandroid.core.testing.util.TestAnalyticsHelpe import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncManager import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.feature.foryou.navigation.LINKED_NEWS_RESOURCE_ID +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -64,11 +65,13 @@ class ForYouViewModelTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default, ) private val getFollowableTopicsUseCase = GetFollowableTopicsUseCase( topicsRepository = topicsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default, ) private val savedStateHandle = SavedStateHandle() private lateinit var viewModel: ForYouViewModel diff --git a/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt b/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt index c46cb7780..dab3035a8 100644 --- a/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt +++ b/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt @@ -24,6 +24,7 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserData import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState import com.google.samples.apps.nowinandroid.feature.interests.InterestsViewModel +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -47,6 +48,7 @@ class InterestsViewModelTest { private val getFollowableTopicsUseCase = GetFollowableTopicsUseCase( topicsRepository = topicsRepository, userDataRepository = userDataRepository, + defaultDispatcher = Dispatchers.Default, ) private lateinit var viewModel: InterestsViewModel From 7d98d199079f655f54bd17ad1a0cd22c53c2fc52 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Wed, 6 Mar 2024 20:13:14 +0900 Subject: [PATCH 10/19] Set private visibility. Change-Id: I185e86f9481bfdb9dea014acb403f00a41edd434 --- .../com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt index ef72ec3a1..eefa55695 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt @@ -77,7 +77,7 @@ class NavigationUiTest { @get:Rule(order = 3) val composeTestRule = createAndroidComposeRule() - val userNewsResourceRepository = CompositeUserNewsResourceRepository( + private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = TestNewsRepository(), userDataRepository = TestUserDataRepository(), defaultDispatcher = Dispatchers.Default, From 79b7df7b8efe3f514abc7f029d1c2ec0b696bc1e Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 12:52:22 +0900 Subject: [PATCH 11/19] Remove private visibility. Change-Id: Iee06da9ddded4ed5ba19bbfd5652b4a7a38f4cb9 --- .../apps/nowinandroid/core/testing/util/MainDispatcherRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt index 666c4edd4..e0e2a2b0a 100644 --- a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt +++ b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt @@ -30,7 +30,7 @@ import org.junit.runner.Description * for the duration of the test. */ class MainDispatcherRule( - private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), + val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), ) : TestWatcher() { override fun starting(description: Description) = Dispatchers.setMain(testDispatcher) From 09a5cd86954cff38a84f0fd36ea4f777a36edef5 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 12:53:46 +0900 Subject: [PATCH 12/19] Add code documentation. Change-Id: Idb9fe56112f3764a1d20ae7499b8e9be37674188 --- .../apps/nowinandroid/core/testing/util/MainDispatcherRule.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt index e0e2a2b0a..5d68f6e2a 100644 --- a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt +++ b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/MainDispatcherRule.kt @@ -30,6 +30,10 @@ import org.junit.runner.Description * for the duration of the test. */ class MainDispatcherRule( + /** + * Expose testDispatcher to share the scheduler to the test. + * See more in [Documentation](https://developer.android.com/kotlin/coroutines/test#injecting-test-dispatchers) + */ val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(), ) : TestWatcher() { override fun starting(description: Description) = Dispatchers.setMain(testDispatcher) From d4b1c3edc092cb3eb1d3c719df744743974c05e8 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 15:05:22 +0900 Subject: [PATCH 13/19] Add MainDispatcherRule() Change-Id: I4db56855bb25aa8036b3a2ed5b9c5fd40d8468e1 --- .../core/data/CompositeUserNewsResourceRepositoryTest.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt index cb921f155..863b24bea 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt @@ -24,15 +24,19 @@ import com.google.samples.apps.nowinandroid.core.model.data.mapToUserNewsResourc import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.repository.emptyUserData -import kotlinx.coroutines.Dispatchers +import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant +import org.junit.Rule import org.junit.Test import kotlin.test.assertEquals class CompositeUserNewsResourceRepositoryTest { + @get:Rule + val dispatcherRule = MainDispatcherRule() + private val newsRepository = TestNewsRepository() private val userDataRepository = TestUserDataRepository() From a564345c7852060b286d3e0a11aac5eb7a3d2bcc Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 15:17:16 +0900 Subject: [PATCH 14/19] Show parameter name. Change-Id: I0da5c272dcda1355b573fa51746256309fde5d8a --- .../core/domain/GetFollowableTopicsUseCaseTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt b/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt index 34bbfb756..ddc79e4b1 100644 --- a/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt +++ b/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt @@ -38,8 +38,8 @@ class GetFollowableTopicsUseCaseTest { private val userDataRepository = TestUserDataRepository() val useCase = GetFollowableTopicsUseCase( - topicsRepository, - userDataRepository, + topicsRepository = topicsRepository, + userDataRepository = userDataRepository, defaultDispatcher = Dispatchers.Default, ) From 1cead627ff1aa1b2a1087728f4ecd982292c937f Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 15:17:42 +0900 Subject: [PATCH 15/19] Show parameters name. Change-Id: Idff0551cc91d27df7a582f822df62f7b96b907ed --- .../google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt index 739cecf46..e55a2fa7a 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt @@ -66,9 +66,9 @@ class NiaAppStateTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( - TestNewsRepository(), - TestUserDataRepository(), - Dispatchers.Default, + newsRepository = TestNewsRepository(), + userDataRepository = TestUserDataRepository(), + defaultDispatcher = Dispatchers.Default, ) // Subject under test. From e4854fdae92a7a9599a48c07e43ebe222a692cc4 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 15:21:30 +0900 Subject: [PATCH 16/19] Pass dispatcherRule.testDispatcher to run test same scheduler. Change-Id: I343a85dfb6d9a101cd6934eceda803c0456184cf --- .../core/data/CompositeUserNewsResourceRepositoryTest.kt | 2 +- .../core/domain/GetFollowableTopicsUseCaseTest.kt | 3 +-- .../nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt | 3 +-- .../apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt | 5 ++--- .../apps/nowinandroid/interests/InterestsViewModelTest.kt | 3 +-- .../apps/nowinandroid/feature/search/SearchViewModelTest.kt | 3 +-- .../apps/nowinandroid/feature/topic/TopicViewModelTest.kt | 3 +-- 7 files changed, 8 insertions(+), 14 deletions(-) diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt index 863b24bea..b1920db4f 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt +++ b/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt @@ -43,7 +43,7 @@ class CompositeUserNewsResourceRepositoryTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = dispatcherRule.testDispatcher, ) @Test diff --git a/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt b/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt index ddc79e4b1..8da3a300a 100644 --- a/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt +++ b/core/domain/src/test/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCaseTest.kt @@ -22,7 +22,6 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -40,7 +39,7 @@ class GetFollowableTopicsUseCaseTest { val useCase = GetFollowableTopicsUseCase( topicsRepository = topicsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = mainDispatcherRule.testDispatcher, ) @Test diff --git a/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt b/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt index f10205629..807d3aaa8 100644 --- a/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt +++ b/feature/bookmarks/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt @@ -23,7 +23,6 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserData import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -47,7 +46,7 @@ class BookmarksViewModelTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = dispatcherRule.testDispatcher, ) private lateinit var viewModel: BookmarksViewModel diff --git a/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt index 3c8a9785c..d5b3704e9 100644 --- a/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt +++ b/feature/foryou/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt @@ -35,7 +35,6 @@ import com.google.samples.apps.nowinandroid.core.testing.util.TestAnalyticsHelpe import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncManager import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.feature.foryou.navigation.LINKED_NEWS_RESOURCE_ID -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -65,13 +64,13 @@ class ForYouViewModelTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = mainDispatcherRule.testDispatcher, ) private val getFollowableTopicsUseCase = GetFollowableTopicsUseCase( topicsRepository = topicsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = mainDispatcherRule.testDispatcher, ) private val savedStateHandle = SavedStateHandle() private lateinit var viewModel: ForYouViewModel diff --git a/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt b/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt index dab3035a8..0dcbecf35 100644 --- a/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt +++ b/feature/interests/src/test/kotlin/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt @@ -24,7 +24,6 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserData import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState import com.google.samples.apps.nowinandroid.feature.interests.InterestsViewModel -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -48,7 +47,7 @@ class InterestsViewModelTest { private val getFollowableTopicsUseCase = GetFollowableTopicsUseCase( topicsRepository = topicsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = mainDispatcherRule.testDispatcher, ) private lateinit var viewModel: InterestsViewModel diff --git a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt index e9768c825..6558a251b 100644 --- a/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt +++ b/feature/search/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/search/SearchViewModelTest.kt @@ -32,7 +32,6 @@ import com.google.samples.apps.nowinandroid.feature.search.RecentSearchQueriesUi import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.EmptyQuery import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.Loading import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.SearchNotReady -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher @@ -57,7 +56,7 @@ class SearchViewModelTest { private val getSearchContentsUseCase = GetSearchContentsUseCase( searchContentsRepository = searchContentsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = dispatcherRule.testDispatcher, ) private val recentSearchRepository = TestRecentSearchRepository() private val getRecentQueryUseCase = GetRecentSearchQueriesUseCase(recentSearchRepository) diff --git a/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt b/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt index 97641d0fc..967e5d5a2 100644 --- a/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt +++ b/feature/topic/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt @@ -26,7 +26,6 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRe import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.feature.topic.navigation.TOPIC_ID_ARG -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first @@ -55,7 +54,7 @@ class TopicViewModelTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( newsRepository = newsRepository, userDataRepository = userDataRepository, - defaultDispatcher = Dispatchers.Default, + defaultDispatcher = dispatcherRule.testDispatcher, ) private lateinit var viewModel: TopicViewModel From 4cb837ad070f10ee20d0df2f7967656777485b2d Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Fri, 8 Mar 2024 15:36:47 +0900 Subject: [PATCH 17/19] Fix spotless. Change-Id: Icf972886746a53662bae4e70f04f2499c8295236 --- .../google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt index e55a2fa7a..2f30b172c 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt @@ -66,9 +66,9 @@ class NiaAppStateTest { private val userNewsResourceRepository = CompositeUserNewsResourceRepository( - newsRepository = TestNewsRepository(), - userDataRepository = TestUserDataRepository(), - defaultDispatcher = Dispatchers.Default, + newsRepository = TestNewsRepository(), + userDataRepository = TestUserDataRepository(), + defaultDispatcher = Dispatchers.Default, ) // Subject under test. From 5f124ead18622351197ca72d7ebb27ff5eca1cfe Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Thu, 9 May 2024 19:08:07 +0900 Subject: [PATCH 18/19] Add trace. Change-Id: Iac1e30f357149fc4c6076d688088f6a54fce73da --- .../DefaultSearchContentsRepository.kt | 15 ++++++--- .../core/domain/GetFollowableTopicsUseCase.kt | 21 +++++++------ .../core/domain/GetSearchContentsUseCase.kt | 31 ++++++++++--------- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt index 8893665fc..c355e07c4 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.data.repository +import androidx.tracing.trace import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceDao import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceFtsDao import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao @@ -78,10 +79,12 @@ internal class DefaultSearchContentsRepository @Inject constructor( .distinctUntilChanged() .flatMapLatest(topicDao::getTopicEntities) return combine(newsResourcesFlow, topicsFlow) { newsResources, topics -> - SearchResult( - topics = topics.map { it.asExternalModel() }, - newsResources = newsResources.map { it.asExternalModel() }, - ) + trace("DefaultSearchContentsRepository.searchContents") { + SearchResult( + topics = topics.map { it.asExternalModel() }, + newsResources = newsResources.map { it.asExternalModel() }, + ) + } }.flowOn(defaultDispatcher) } @@ -90,6 +93,8 @@ internal class DefaultSearchContentsRepository @Inject constructor( newsResourceFtsDao.getCount(), topicFtsDao.getCount(), ) { newsResourceCount, topicsCount -> - newsResourceCount + topicsCount + trace("DefaultSearchContentsRepository.getSearchContentsCount") { + newsResourceCount + topicsCount + } }.flowOn(defaultDispatcher) } diff --git a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt index 680b317c6..82057234f 100644 --- a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt +++ b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetFollowableTopicsUseCase.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.domain +import androidx.tracing.trace import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.domain.TopicSortField.NAME @@ -46,16 +47,18 @@ class GetFollowableTopicsUseCase @Inject constructor( userDataRepository.userData, topicsRepository.getTopics(), ) { userData, topics -> - val followedTopics = topics - .map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id in userData.followedTopics, - ) + trace("GetFollowableTopicsUseCase.invoke") { + val followedTopics = topics + .map { topic -> + FollowableTopic( + topic = topic, + isFollowed = topic.id in userData.followedTopics, + ) + } + when (sortBy) { + NAME -> followedTopics.sortedBy { it.topic.name } + else -> followedTopics } - when (sortBy) { - NAME -> followedTopics.sortedBy { it.topic.name } - else -> followedTopics } }.flowOn(defaultDispatcher) } diff --git a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt index 2e8db5f0e..6634562ab 100644 --- a/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt +++ b/core/domain/src/main/kotlin/com/google/samples/apps/nowinandroid/core/domain/GetSearchContentsUseCase.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.domain +import androidx.tracing.trace import com.google.samples.apps.nowinandroid.core.data.repository.SearchContentsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic @@ -52,18 +53,20 @@ private fun Flow.mapToUserSearchResult( defaultDispatcher: CoroutineDispatcher, ): Flow = combine(userDataStream) { searchResult, userData -> - UserSearchResult( - topics = searchResult.topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id in userData.followedTopics, - ) - }, - newsResources = searchResult.newsResources.map { news -> - UserNewsResource( - newsResource = news, - userData = userData, - ) - }, - ) + trace("Flow.mapToUserSearchResult") { + UserSearchResult( + topics = searchResult.topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = topic.id in userData.followedTopics, + ) + }, + newsResources = searchResult.newsResources.map { news -> + UserNewsResource( + newsResource = news, + userData = userData, + ) + }, + ) + } }.flowOn(defaultDispatcher) From 3545a80d2e09ee592a799d8cb65f9973f650ee66 Mon Sep 17 00:00:00 2001 From: Jaehwa Noh Date: Mon, 9 Dec 2024 21:29:49 +0900 Subject: [PATCH 19/19] Apply spotless. Change-Id: I983c7b196c88280dfdb0427900ea548799330c84 --- .../com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationUiTest.kt deleted file mode 100644 index e69de29bb..000000000