From 24df51349d6341af62e2ebe63e28073cd24f6ab3 Mon Sep 17 00:00:00 2001 From: Don Turner Date: Thu, 5 Jan 2023 12:58:13 +0000 Subject: [PATCH] Move mapping logic into secondary constructor Change-Id: I032326f502d27f2d3bd9fb8273ae44df878d172c --- .../domain/GetUserNewsResourcesUseCase.kt | 2 +- .../core/domain/model/UserNewsResource.kt | 43 +++---- .../domain/GetUserNewsResourcesUseCaseTest.kt | 8 +- .../core/domain/UserNewsResourceTest.kt | 2 +- .../repository/TestUserDataRepository.kt | 2 +- .../feature/foryou/ForYouViewModelTest.kt | 114 +++++------------- 6 files changed, 56 insertions(+), 115 deletions(-) diff --git a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt index 39bd38e1e..d77f8e9df 100644 --- a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt +++ b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt @@ -56,6 +56,6 @@ private fun Flow>.mapToUserNewsResources( filterNot { it.isEmpty() } .combine(userDataStream) { newsResources, userData -> newsResources.map { newsResource -> - UserNewsResource.from(newsResource, userData) + UserNewsResource(newsResource, userData) } } diff --git a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt index 280f6b78a..872f93f16 100644 --- a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt +++ b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt @@ -30,9 +30,10 @@ import kotlinx.datetime.toInstant /* ktlint-disable max-line-length */ /** - * A [NewsResource] with the additional user information. + * A [NewsResource] with additional user information such as whether the user is following the + * news resource's topics and whether they have saved (bookmarked) this news resource. */ -data class UserNewsResource( +data class UserNewsResource internal constructor( val id: String, val title: String, val content: String, @@ -43,26 +44,26 @@ data class UserNewsResource( val followableTopics: List, val isSaved: Boolean ) { - companion object { - fun from(newsResource: NewsResource, userData: UserData): UserNewsResource { - return UserNewsResource( - id = newsResource.id, - title = newsResource.title, - content = newsResource.content, - url = newsResource.url, - headerImageUrl = newsResource.headerImageUrl, - publishDate = newsResource.publishDate, - type = newsResource.type, - followableTopics = newsResource.topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = userData.followedTopics.contains(topic.id) - ) - }, - isSaved = userData.bookmarkedNewsResources.contains(newsResource.id) + constructor(newsResource: NewsResource, userData: UserData) : this( + id = newsResource.id, + title = newsResource.title, + content = newsResource.content, + url = newsResource.url, + headerImageUrl = newsResource.headerImageUrl, + publishDate = newsResource.publishDate, + type = newsResource.type, + followableTopics = newsResource.topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = userData.followedTopics.contains(topic.id) ) - } - } + }, + isSaved = userData.bookmarkedNewsResources.contains(newsResource.id) + ) +} + +fun List.mapToUserNewsResources(userData: UserData): List { + return map { UserNewsResource(it, userData) } } val previewUserNewsResources = listOf( diff --git a/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt b/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt index 80d6013c9..61eab3ba8 100644 --- a/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt +++ b/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt @@ -66,9 +66,9 @@ class GetUserNewsResourcesUseCaseTest { // Check that the correct news resources are returned with their bookmarked state. assertEquals( listOf( - UserNewsResource.from(sampleNewsResources[0], userData), - UserNewsResource.from(sampleNewsResources[1], userData), - UserNewsResource.from(sampleNewsResources[2], userData), + UserNewsResource(sampleNewsResources[0], userData), + UserNewsResource(sampleNewsResources[1], userData), + UserNewsResource(sampleNewsResources[2], userData), ), userNewsResources.first() ) @@ -96,7 +96,7 @@ class GetUserNewsResourcesUseCaseTest { sampleNewsResources .filter { it.topics.contains(sampleTopic1) } .map { - UserNewsResource.from(it, userData) + UserNewsResource(it, userData) }, userNewsResources.first() ) diff --git a/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/UserNewsResourceTest.kt b/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/UserNewsResourceTest.kt index 6268b28f8..d1ea7b569 100644 --- a/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/UserNewsResourceTest.kt +++ b/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/UserNewsResourceTest.kt @@ -75,7 +75,7 @@ class UserNewsResourceTest { shouldHideOnboarding = true ) - val userNewsResource = UserNewsResource.from(newsResource1, userData) + val userNewsResource = UserNewsResource(newsResource1, userData) // Check that the simple field mappings have been done correctly. assertEquals(newsResource1.id, userNewsResource.id) diff --git a/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt b/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt index 04d5b3b10..8dba1bfc7 100644 --- a/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt +++ b/core/testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.filterNotNull -private val emptyUserData = UserData( +val emptyUserData = UserData( bookmarkedNewsResources = emptySet(), followedTopics = emptySet(), themeBrand = ThemeBrand.DEFAULT, diff --git a/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt index 7069c5ff5..4427b44fe 100644 --- a/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt +++ b/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt @@ -20,12 +20,14 @@ import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCa import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource +import com.google.samples.apps.nowinandroid.core.domain.model.mapToUserNewsResources import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository 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.repository.emptyUserData import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncStatusMonitor @@ -265,7 +267,8 @@ class ForYouViewModelTest { topicsRepository.sendTopics(sampleTopics) val followedTopicIds = setOf("0", "1") - userDataRepository.setFollowedTopicIds(followedTopicIds) + val userData = emptyUserData.copy(followedTopics = followedTopicIds) + userDataRepository.setUserData(userData) viewModel.dismissOnboarding() assertEquals( @@ -282,25 +285,7 @@ class ForYouViewModelTest { ) assertEquals( NewsFeedUiState.Success( - feed = - sampleNewsResources.map { - UserNewsResource( - id = it.id, - title = it.title, - content = it.content, - url = it.url, - headerImageUrl = it.headerImageUrl, - publishDate = it.publishDate, - type = it.type, - followableTopics = it.topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = followedTopicIds.contains(topic.id) - ) - }, - isSaved = false - ) - } + feed = sampleNewsResources.mapToUserNewsResources(userData) ), viewModel.feedState.value ) @@ -345,41 +330,14 @@ class ForYouViewModelTest { ), viewModel.onboardingUiState.value ) + + val userData = emptyUserData.copy(followedTopics = setOf(followedTopicId)) + assertEquals( NewsFeedUiState.Success( feed = listOf( - UserNewsResource( - id = sampleNewsResources[1].id, - title = sampleNewsResources[1].title, - content = sampleNewsResources[1].content, - url = sampleNewsResources[1].url, - headerImageUrl = sampleNewsResources[1].headerImageUrl, - publishDate = sampleNewsResources[1].publishDate, - type = sampleNewsResources[1].type, - followableTopics = sampleNewsResources[1].topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id == followedTopicId - ) - }, - isSaved = false - ), - UserNewsResource( - id = sampleNewsResources[2].id, - title = sampleNewsResources[2].title, - content = sampleNewsResources[2].content, - url = sampleNewsResources[2].url, - headerImageUrl = sampleNewsResources[2].headerImageUrl, - publishDate = sampleNewsResources[2].publishDate, - type = sampleNewsResources[2].type, - followableTopics = sampleNewsResources[2].topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = topic.id == followedTopicId - ) - }, - isSaved = false - ) + UserNewsResource(sampleNewsResources[1], userData), + UserNewsResource(sampleNewsResources[2], userData), ) ), viewModel.feedState.value @@ -460,12 +418,24 @@ class ForYouViewModelTest { val collectJob2 = launch(UnconfinedTestDispatcher()) { viewModel.feedState.collect() } val followedTopicIds = setOf("1") + val userData = emptyUserData.copy( + followedTopics = followedTopicIds, + shouldHideOnboarding = true + ) topicsRepository.sendTopics(sampleTopics) - userDataRepository.setFollowedTopicIds(followedTopicIds) - userDataRepository.setShouldHideOnboarding(true) + userDataRepository.setUserData(userData) newsRepository.sendNewsResources(sampleNewsResources) - viewModel.updateNewsResourceSaved("2", true) + + val bookmarkedNewsResourceId = "2" + viewModel.updateNewsResourceSaved( + newsResourceId = bookmarkedNewsResourceId, + isChecked = true + ) + + val userDataExpected = userData.copy( + bookmarkedNewsResources = setOf(bookmarkedNewsResourceId) + ) assertEquals( OnboardingUiState.NotShown, @@ -474,38 +444,8 @@ class ForYouViewModelTest { assertEquals( NewsFeedUiState.Success( feed = listOf( - UserNewsResource( - id = sampleNewsResources[1].id, - title = sampleNewsResources[1].title, - content = sampleNewsResources[1].content, - url = sampleNewsResources[1].url, - headerImageUrl = sampleNewsResources[1].headerImageUrl, - publishDate = sampleNewsResources[1].publishDate, - type = sampleNewsResources[1].type, - followableTopics = sampleNewsResources[1].topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = followedTopicIds.contains(topic.id) - ) - }, - isSaved = true - ), - UserNewsResource( - id = sampleNewsResources[2].id, - title = sampleNewsResources[2].title, - content = sampleNewsResources[2].content, - url = sampleNewsResources[2].url, - headerImageUrl = sampleNewsResources[2].headerImageUrl, - publishDate = sampleNewsResources[2].publishDate, - type = sampleNewsResources[2].type, - followableTopics = sampleNewsResources[2].topics.map { topic -> - FollowableTopic( - topic = topic, - isFollowed = followedTopicIds.contains(topic.id) - ) - }, - isSaved = false - ), + UserNewsResource(newsResource = sampleNewsResources[1], userDataExpected), + UserNewsResource(newsResource = sampleNewsResources[2], userDataExpected) ) ), viewModel.feedState.value