diff --git a/.run/Generate Demo Baseline Profile.run.xml b/.run/Generate Demo Baseline Profile.run.xml
deleted file mode 100644
index a4b0de892..000000000
--- a/.run/Generate Demo Baseline Profile.run.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- true
- false
-
-
-
diff --git a/.run/spotlessApply.run.xml b/.run/spotlessApply.run.xml
deleted file mode 100644
index 5c4dac833..000000000
--- a/.run/spotlessApply.run.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- true
- false
-
-
-
\ No newline at end of file
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..4b5e7a5f8 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
@@ -17,13 +17,11 @@
package com.google.samples.apps.nowinandroid.core.data
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
-import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQuery
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.model.data.mapToUserNewsResources
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.flow.first
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
@@ -42,23 +40,16 @@ class CompositeUserNewsResourceRepositoryTest {
@Test
fun whenNoFilters_allNewsResourcesAreReturned() = runTest {
- // Obtain the user news resources flow.
+ // Obtain the user news resources flow without any filters applied.
val userNewsResources = userNewsResourceRepository.observeAll()
- // Send some news resources and user data into the data repositories.
+ // Send test data into the repositories.
newsRepository.sendNewsResources(sampleNewsResources)
+ userDataRepository.setFollowedTopicIds(emptySet())
- // Construct the test user data with bookmarks and followed topics.
- val userData = emptyUserData.copy(
- bookmarkedNewsResources = setOf(sampleNewsResources[0].id, sampleNewsResources[2].id),
- followedTopics = setOf(sampleTopic1.id),
- )
-
- userDataRepository.setUserData(userData)
-
- // Check that the correct news resources are returned with their bookmarked state.
+ // Check that the correct list of news resources is returned.
assertEquals(
- sampleNewsResources.mapToUserNewsResources(userData),
+ sampleNewsResources.mapToUserNewsResources(userDataRepository.userData.first()),
userNewsResources.first(),
)
}
@@ -66,46 +57,35 @@ class CompositeUserNewsResourceRepositoryTest {
@Test
fun whenFilteredByTopicId_matchingNewsResourcesAreReturned() = runTest {
// Obtain a stream of user news resources for the given topic id.
- val userNewsResources =
- userNewsResourceRepository.observeAll(
- NewsResourceQuery(
- filterTopicIds = setOf(
- sampleTopic1.id,
- ),
- ),
- )
+ val userNewsResources = userNewsResourceRepository.observeAllForFollowedTopics()
// Send test data into the repositories.
newsRepository.sendNewsResources(sampleNewsResources)
- userDataRepository.setUserData(emptyUserData)
+ userDataRepository.setTopicIdFollowed(sampleTopic1.id, true)
// Check that only news resources with the given topic id are returned.
assertEquals(
sampleNewsResources
.filter { sampleTopic1 in it.topics }
- .mapToUserNewsResources(emptyUserData),
+ .mapToUserNewsResources(userDataRepository.userData.first()),
userNewsResources.first(),
)
}
@Test
fun whenFilteredByFollowedTopics_matchingNewsResourcesAreReturned() = runTest {
- // Obtain a stream of user news resources for the given topic id.
- val userNewsResources =
- userNewsResourceRepository.observeAllForFollowedTopics()
+ // Obtain a stream of user news resources filtered by followed topics
+ val userNewsResources = userNewsResourceRepository.observeAllForFollowedTopics()
// Send test data into the repositories.
- val userData = emptyUserData.copy(
- followedTopics = setOf(sampleTopic1.id),
- )
newsRepository.sendNewsResources(sampleNewsResources)
- userDataRepository.setUserData(userData)
+ userDataRepository.setFollowedTopicIds(setOf(sampleTopic1.id))
- // Check that only news resources with the given topic id are returned.
+ // Check that only news resources with the followed topics are returned.
assertEquals(
sampleNewsResources
.filter { sampleTopic1 in it.topics }
- .mapToUserNewsResources(userData),
+ .mapToUserNewsResources(userDataRepository.userData.first()),
userNewsResources.first(),
)
}
@@ -119,16 +99,14 @@ class CompositeUserNewsResourceRepositoryTest {
newsRepository.sendNewsResources(sampleNewsResources)
// Construct the test user data with bookmarks and followed topics.
- val userData = emptyUserData.copy(
- bookmarkedNewsResources = setOf(sampleNewsResources[0].id, sampleNewsResources[2].id),
- followedTopics = setOf(sampleTopic1.id),
- )
-
- userDataRepository.setUserData(userData)
+ userDataRepository.setNewsResourceBookmarked(sampleNewsResources[0].id, true)
+ userDataRepository.setNewsResourceBookmarked(sampleNewsResources[2].id, true)
+ userDataRepository.setFollowedTopicIds(setOf(sampleTopic1.id))
// Check that the correct news resources are returned with their bookmarked state.
assertEquals(
- listOf(sampleNewsResources[0], sampleNewsResources[2]).mapToUserNewsResources(userData),
+ listOf(sampleNewsResources[0], sampleNewsResources[2])
+ .mapToUserNewsResources(userDataRepository.userData.first()),
userNewsResources.first(),
)
}
diff --git a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt
index be76112dc..0b2013db3 100644
--- a/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt
+++ b/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/repository/TestUserDataRepository.kt
@@ -75,16 +75,13 @@ class TestUserDataRepository : UserDataRepository {
override suspend fun setNewsResourceViewed(newsResourceId: String, viewed: Boolean) {
currentUserData.let { current ->
- _userData.tryEmit(
- current.copy(
- viewedNewsResources =
- if (viewed) {
- current.viewedNewsResources + newsResourceId
- } else {
- current.viewedNewsResources - newsResourceId
- },
- ),
- )
+ val viewedNews = if (viewed) {
+ current.viewedNewsResources + newsResourceId
+ } else {
+ current.viewedNewsResources - newsResourceId
+ }
+
+ _userData.tryEmit(current.copy(viewedNewsResources = viewedNews))
}
}
@@ -111,11 +108,4 @@ class TestUserDataRepository : UserDataRepository {
_userData.tryEmit(current.copy(shouldHideOnboarding = shouldHideOnboarding))
}
}
-
- /**
- * A test-only API to allow setting of user data directly.
- */
- fun setUserData(userData: UserData) {
- _userData.tryEmit(userData)
- }
}
diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt b/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt
index 8e94a491a..a0776a41d 100644
--- a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt
+++ b/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/navigation/ForYouNavigation.kt
@@ -16,6 +16,7 @@
package com.google.samples.apps.nowinandroid.feature.foryou.navigation
+import androidx.annotation.VisibleForTesting
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
@@ -25,6 +26,7 @@ import androidx.navigation.navArgument
import androidx.navigation.navDeepLink
import com.google.samples.apps.nowinandroid.feature.foryou.ForYouRoute
+@VisibleForTesting
const val LINKED_NEWS_RESOURCE_ID = "linkedNewsResourceId"
const val FOR_YOU_ROUTE = "for_you_route/{$LINKED_NEWS_RESOURCE_ID}"
private const val DEEP_LINK_URI_PATTERN =
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 2fbdf0a79..e41bc0c26 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
@@ -29,7 +29,6 @@ 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.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.TestAnalyticsHelper
import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncManager
@@ -277,8 +276,7 @@ class ForYouViewModelTest {
topicsRepository.sendTopics(sampleTopics)
val followedTopicIds = setOf("0", "1")
- val userData = emptyUserData.copy(followedTopics = followedTopicIds)
- userDataRepository.setUserData(userData)
+ userDataRepository.setFollowedTopicIds(followedTopicIds)
viewModel.dismissOnboarding()
assertEquals(
@@ -295,7 +293,7 @@ class ForYouViewModelTest {
)
assertEquals(
NewsFeedUiState.Success(
- feed = sampleNewsResources.mapToUserNewsResources(userData),
+ feed = sampleNewsResources.mapToUserNewsResources(userDataRepository.userData.first()),
),
viewModel.feedState.value,
)
@@ -341,13 +339,11 @@ class ForYouViewModelTest {
viewModel.onboardingUiState.value,
)
- val userData = emptyUserData.copy(followedTopics = setOf(followedTopicId))
-
assertEquals(
NewsFeedUiState.Success(
feed = listOf(
- UserNewsResource(sampleNewsResources[1], userData),
- UserNewsResource(sampleNewsResources[2], userData),
+ UserNewsResource(newsResource = sampleNewsResources[1], userData = userDataRepository.userData.first()),
+ UserNewsResource(newsResource = sampleNewsResources[2], userData = userDataRepository.userData.first()),
),
),
viewModel.feedState.value,
@@ -427,14 +423,9 @@ class ForYouViewModelTest {
launch(UnconfinedTestDispatcher()) { viewModel.onboardingUiState.collect() }
val collectJob2 = launch(UnconfinedTestDispatcher()) { viewModel.feedState.collect() }
- val followedTopicIds = setOf("1")
- val userData = emptyUserData.copy(
- followedTopics = followedTopicIds,
- shouldHideOnboarding = true,
- )
-
topicsRepository.sendTopics(sampleTopics)
- userDataRepository.setUserData(userData)
+ userDataRepository.setFollowedTopicIds(setOf("1"))
+ userDataRepository.setShouldHideOnboarding(true)
newsRepository.sendNewsResources(sampleNewsResources)
val bookmarkedNewsResourceId = "2"
@@ -443,10 +434,6 @@ class ForYouViewModelTest {
isChecked = true,
)
- val userDataExpected = userData.copy(
- bookmarkedNewsResources = setOf(bookmarkedNewsResourceId),
- )
-
assertEquals(
OnboardingUiState.NotShown,
viewModel.onboardingUiState.value,
@@ -454,8 +441,8 @@ class ForYouViewModelTest {
assertEquals(
NewsFeedUiState.Success(
feed = listOf(
- UserNewsResource(newsResource = sampleNewsResources[1], userDataExpected),
- UserNewsResource(newsResource = sampleNewsResources[2], userDataExpected),
+ UserNewsResource(newsResource = sampleNewsResources[1], userData = userDataRepository.userData.first()),
+ UserNewsResource(newsResource = sampleNewsResources[2], userData = userDataRepository.userData.first()),
),
),
viewModel.feedState.value,
@@ -471,13 +458,13 @@ class ForYouViewModelTest {
launch(UnconfinedTestDispatcher()) { viewModel.deepLinkedNewsResource.collect() }
newsRepository.sendNewsResources(sampleNewsResources)
- userDataRepository.setUserData(emptyUserData)
+ userDataRepository.setFollowedTopicIds(emptySet())
savedStateHandle[LINKED_NEWS_RESOURCE_ID] = sampleNewsResources.first().id
assertEquals(
expected = UserNewsResource(
newsResource = sampleNewsResources.first(),
- userData = emptyUserData,
+ userData = userDataRepository.userData.first(),
),
actual = viewModel.deepLinkedNewsResource.value,
)
@@ -524,6 +511,17 @@ class ForYouViewModelTest {
actual = userDataRepository.userData.first().bookmarkedNewsResources,
)
}
+
+ @Test
+ fun whenSetNewsResourceViewedIsCalled_viewedStateIsUpdated() = runTest {
+ val newsResourceId = "123"
+ viewModel.setNewsResourceViewed(newsResourceId, true)
+
+ assertEquals(
+ expected = setOf(newsResourceId),
+ actual = userDataRepository.userData.first().viewedNewsResources,
+ )
+ }
}
private val sampleTopics = listOf(
diff --git a/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/navigation/InterestsNavigation.kt b/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/navigation/InterestsNavigation.kt
index 8a0f2d130..c23b4dbc6 100644
--- a/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/navigation/InterestsNavigation.kt
+++ b/feature/interests/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/interests/navigation/InterestsNavigation.kt
@@ -16,6 +16,7 @@
package com.google.samples.apps.nowinandroid.feature.interests.navigation
+import androidx.annotation.VisibleForTesting
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
@@ -24,6 +25,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute
+@VisibleForTesting
const val TOPIC_ID_ARG = "topicId"
const val INTERESTS_ROUTE_BASE = "interests_route"
const val INTERESTS_ROUTE = "$INTERESTS_ROUTE_BASE?$TOPIC_ID_ARG={$TOPIC_ID_ARG}"
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 c832401de..417fb07ee 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
@@ -25,7 +25,6 @@ import com.google.samples.apps.nowinandroid.core.testing.data.topicsTestData
import com.google.samples.apps.nowinandroid.core.testing.repository.TestRecentSearchRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestSearchContentsRepository
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.feature.search.RecentSearchQueriesUiState.Success
import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.EmptyQuery
@@ -41,6 +40,7 @@ import org.junit.Rule
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
+import kotlin.test.assertTrue
/**
* To learn more about how this test handles Flows created with stateIn, see
@@ -73,7 +73,6 @@ class SearchViewModelTest {
userDataRepository = userDataRepository,
analyticsHelper = NoOpAnalyticsHelper(),
)
- userDataRepository.setUserData(emptyUserData)
}
@Test
@@ -103,6 +102,7 @@ class SearchViewModelTest {
viewModel.onSearchQueryChanged("XXX")
searchContentsRepository.addNewsResources(newsResourcesTestData)
searchContentsRepository.addTopics(topicsTestData)
+ userDataRepository.setFollowedTopicIds(emptySet())
val result = viewModel.searchResultUiState.value
assertIs(result)
@@ -122,6 +122,20 @@ class SearchViewModelTest {
collectJob.cancel()
}
+ @Test
+ fun recentSearches_verifyQueryHistoryClear() = runTest {
+ val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.recentSearchQueriesUiState.collect() }
+
+ viewModel.onSearchTriggered("kotlin")
+ viewModel.clearRecentSearches()
+
+ val result = viewModel.recentSearchQueriesUiState.value
+ assertIs(result)
+ assertTrue(result.recentQueries.isEmpty())
+
+ collectJob.cancel()
+ }
+
@Test
fun searchNotReady_withNoFtsTableEntity() = runTest {
val collectJob =
diff --git a/feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt b/feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt
index 9062abee6..bcc9b8dfe 100644
--- a/feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt
+++ b/feature/settings/src/test/kotlin/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModelTest.kt
@@ -55,8 +55,9 @@ class SettingsViewModelTest {
val collectJob =
launch(UnconfinedTestDispatcher()) { viewModel.settingsUiState.collect() }
- userDataRepository.setThemeBrand(ANDROID)
- userDataRepository.setDarkThemeConfig(DARK)
+ viewModel.updateThemeBrand(ANDROID)
+ viewModel.updateDarkThemeConfig(DARK)
+ viewModel.updateDynamicColorPreference(false)
assertEquals(
Success(