Merge remote-tracking branch 'fork/main' into patch/assets-as-json-files

pull/417/head
Simon Marquis 3 years ago
commit b5d342468e

@ -34,16 +34,16 @@ jobs:
uses: gradle/gradle-build-action@v2 uses: gradle/gradle-build-action@v2
- name: Check spotless - name: Check spotless
run: ./gradlew spotlessCheck --init-script gradle/init.gradle.kts --no-configuration-cache --stacktrace run: ./gradlew spotlessCheck --init-script gradle/init.gradle.kts --no-configuration-cache
- name: Check lint - name: Check lint
run: ./gradlew lintDemoDebug --stacktrace run: ./gradlew lintDemoDebug
- name: Build all build type and flavor permutations - name: Build all build type and flavor permutations
run: ./gradlew assemble --stacktrace run: ./gradlew assemble
- name: Run local tests - name: Run local tests
run: ./gradlew testDemoDebug testProdDebug --stacktrace run: ./gradlew testDemoDebug testProdDebug
- name: Upload build outputs (APKs) - name: Upload build outputs (APKs)
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@ -90,7 +90,7 @@ jobs:
disable-animations: true disable-animations: true
disk-size: 6000M disk-size: 6000M
heap-size: 600M heap-size: 600M
script: ./gradlew connectedProdDebugAndroidTest -x :benchmark:connectedProdBenchmarkAndroidTest --stacktrace script: ./gradlew connectedProdDebugAndroidTest -x :benchmark:connectedProdBenchmarkAndroidTest
- name: Upload test reports - name: Upload test reports
if: always() if: always()

@ -18,15 +18,31 @@
# End users may safely ignore this file. It has no relevance to other systems. # End users may safely ignore this file. It has no relevance to other systems.
--- ---
status: PUBLISHED status: PUBLISHED
technologies: [Android] technologies: [Android, JetpackCompose, Coroutines]
categories: categories:
- AndroidTesting - AndroidTesting
- AndroidArchitecture - AndroidArchitecture
- AndroidArchitectureUILayer - AndroidArchitectureUILayer
- AndroidArchitectureDomainLayer - AndroidArchitectureDomainLayer
- AndroidArchitectureDataLayer - AndroidArchitectureDataLayer
- AndroidArchitectureStateProduction
- AndroidArchitectureStateHolder
- JetpackComposeTesting
- JetpackComposeA11y
- JetpackComposeArchitectureAndState
- JetpackComposeDesignSystems
- JetpackComposeNavigation
- JetpackComposeAnimation
solutions:
- Mobile
- Flow
- JetpackHilt
- JetpackDataStore
- JetpackRoom
- JetpackNavigation
- JetpackWorkManager
- JetpackLifecycle
languages: [Kotlin] languages: [Kotlin]
solutions: [Mobile]
github: android/nowinandroid github: android/nowinandroid
level: ADVANCED level: ADVANCED
license: apache2 license: apache2

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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
http://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.
-->
<component name="ProjectRunConfigurationManager">
<!--
Baseline Profiles improve code execution speed by around 30% from the first launch by avoiding interpretation and just-in-time (JIT) compilation steps for included code paths.
More information at http://d.android.com/baseline-profiles.
-->
<configuration default="false" name="Generate Demo Baseline Profile" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<!-- TODO Once we use Gradle wrapper 7.6, we can use rerun instead of rerun-tasks that will skip cache only for one task -->
<option name="scriptParameters" value="--rerun-tasks -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value=":benchmark:pixel6Api31DemoBenchmarkAndroidTest" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

@ -91,13 +91,13 @@ dependencies {
implementation(project(":core:model")) implementation(project(":core:model"))
implementation(project(":sync:work")) implementation(project(":sync:work"))
implementation(project(":sync:sync-test"))
androidTestImplementation(project(":core:testing")) androidTestImplementation(project(":core:testing"))
androidTestImplementation(project(":core:datastore-test")) androidTestImplementation(project(":core:datastore-test"))
androidTestImplementation(project(":core:data-test")) androidTestImplementation(project(":core:data-test"))
androidTestImplementation(project(":core:network")) androidTestImplementation(project(":core:network"))
androidTestImplementation(libs.androidx.navigation.testing) androidTestImplementation(libs.androidx.navigation.testing)
androidTestImplementation(kotlin("test"))
debugImplementation(libs.androidx.compose.ui.testManifest) debugImplementation(libs.androidx.compose.ui.testManifest)
implementation(libs.accompanist.systemuicontroller) implementation(libs.accompanist.systemuicontroller)

@ -31,13 +31,13 @@ import androidx.navigation.compose.composable
import androidx.navigation.createGraph import androidx.navigation.createGraph
import androidx.navigation.testing.TestNavHostController import androidx.navigation.testing.TestNavHostController
import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -32,8 +32,7 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true">
android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

@ -15,12 +15,6 @@
limitations under the License. limitations under the License.
--> -->
<resources> <resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<!-- Status bar --> <!-- Status bar -->
<color name="black30">#4D000000</color> <color name="black30">#4D000000</color>
</resources> </resources>

@ -21,7 +21,7 @@ plugins {
} }
android { android {
namespace = "com.google.samples.apps.nowinandroid.benchmark" namespace = "com.google.samples.apps.nowinandroid.benchmarks"
defaultConfig { defaultConfig {
minSdk = 23 minSdk = 23
@ -55,9 +55,9 @@ android {
testOptions { testOptions {
managedDevices { managedDevices {
devices { devices {
create<ManagedVirtualDevice>("pixel5Api30") { create<ManagedVirtualDevice>("pixel6Api31") {
device = "Pixel 5" device = "Pixel 6"
apiLevel = 30 apiLevel = 31
systemImageSource = "aosp" systemImageSource = "aosp"
} }
} }

@ -16,10 +16,16 @@
package com.google.samples.apps.nowinandroid package com.google.samples.apps.nowinandroid
import com.google.samples.apps.nowinandroid.benchmark.BuildConfig import com.google.samples.apps.nowinandroid.benchmarks.BuildConfig
/** /**
* Convenience parameter to use proper package name with regards to build type and build flavor. * Convenience parameter to use proper package name with regards to build type and build flavor.
*/ */
const val PACKAGE_NAME = val PACKAGE_NAME = StringBuilder("com.google.samples.apps.nowinandroid").apply {
"com.google.samples.apps.nowinandroid.${BuildConfig.FLAVOR}.${BuildConfig.BUILD_TYPE}" if (BuildConfig.FLAVOR != "prod") {
append(".${BuildConfig.FLAVOR}")
}
if (BuildConfig.BUILD_TYPE != "release") {
append(".${BuildConfig.BUILD_TYPE}")
}
}.toString()

@ -21,6 +21,7 @@ import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.kotlin
class AndroidFeatureConventionPlugin : Plugin<Project> { class AndroidFeatureConventionPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
@ -46,7 +47,9 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
add("implementation", project(":core:common")) add("implementation", project(":core:common"))
add("implementation", project(":core:domain")) add("implementation", project(":core:domain"))
add("testImplementation", kotlin("test"))
add("testImplementation", project(":core:testing")) add("testImplementation", project(":core:testing"))
add("androidTestImplementation", kotlin("test"))
add("androidTestImplementation", project(":core:testing")) add("androidTestImplementation", project(":core:testing"))
add("implementation", libs.findLibrary("coil.kt").get()) add("implementation", libs.findLibrary("coil.kt").get())

@ -26,6 +26,7 @@ import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.kotlin
class AndroidLibraryConventionPlugin : Plugin<Project> { class AndroidLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) { override fun apply(target: Project) {
@ -51,6 +52,10 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
force("org.objenesis:objenesis:2.6") force("org.objenesis:objenesis:2.6")
} }
} }
dependencies {
add("androidTestImplementation", kotlin("test"))
add("testImplementation", kotlin("test"))
}
} }
} }
} }

@ -17,9 +17,9 @@
package com.google.samples.apps.nowinandroid.core.result package com.google.samples.apps.nowinandroid.core.result
import app.cash.turbine.test import app.cash.turbine.test
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
class ResultKtTest { class ResultKtTest {

@ -21,8 +21,8 @@ import com.google.samples.apps.nowinandroid.core.network.model.NetworkAuthor
import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource
import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResourceExpanded import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResourceExpanded
import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic
import kotlin.test.assertEquals
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
class NetworkEntityKtTest { class NetworkEntityKtTest {

@ -29,9 +29,9 @@ import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferen
import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.network.model.NetworkAuthor import com.google.samples.apps.nowinandroid.core.network.model.NetworkAuthor
import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -68,7 +68,7 @@ class OfflineFirstAuthorsRepositoryTest {
@Test @Test
fun offlineFirstAuthorsRepository_Authors_stream_is_backed_by_Authors_dao() = fun offlineFirstAuthorsRepository_Authors_stream_is_backed_by_Authors_dao() =
runTest { runTest {
Assert.assertEquals( assertEquals(
authorDao.getAuthorEntitiesStream() authorDao.getAuthorEntitiesStream()
.first() .first()
.map(AuthorEntity::asExternalModel), .map(AuthorEntity::asExternalModel),
@ -88,13 +88,13 @@ class OfflineFirstAuthorsRepositoryTest {
val dbAuthors = authorDao.getAuthorEntitiesStream() val dbAuthors = authorDao.getAuthorEntitiesStream()
.first() .first()
Assert.assertEquals( assertEquals(
networkAuthors.map(AuthorEntity::id), networkAuthors.map(AuthorEntity::id),
dbAuthors.map(AuthorEntity::id) dbAuthors.map(AuthorEntity::id)
) )
// After sync version should be updated // After sync version should be updated
Assert.assertEquals( assertEquals(
network.latestChangeListVersion(CollectionType.Authors), network.latestChangeListVersion(CollectionType.Authors),
synchronizer.getChangeListVersions().authorVersion synchronizer.getChangeListVersions().authorVersion
) )
@ -125,13 +125,13 @@ class OfflineFirstAuthorsRepositoryTest {
val db = authorDao.getAuthorEntitiesStream() val db = authorDao.getAuthorEntitiesStream()
.first() .first()
Assert.assertEquals( assertEquals(
network.map(AuthorEntity::id), network.map(AuthorEntity::id),
db.map(AuthorEntity::id) db.map(AuthorEntity::id)
) )
// After sync version should be updated // After sync version should be updated
Assert.assertEquals( assertEquals(
changeList.last().changeListVersion, changeList.last().changeListVersion,
synchronizer.getChangeListVersions().authorVersion synchronizer.getChangeListVersions().authorVersion
) )
@ -166,13 +166,13 @@ class OfflineFirstAuthorsRepositoryTest {
.map(AuthorEntity::asExternalModel) .map(AuthorEntity::asExternalModel)
// Assert that items marked deleted on the network have been deleted locally // Assert that items marked deleted on the network have been deleted locally
Assert.assertEquals( assertEquals(
networkAuthors.map(Author::id) - deletedItems, networkAuthors.map(Author::id) - deletedItems,
dbAuthors.map(Author::id) dbAuthors.map(Author::id)
) )
// After sync version should be updated // After sync version should be updated
Assert.assertEquals( assertEquals(
network.latestChangeListVersion(CollectionType.Authors), network.latestChangeListVersion(CollectionType.Authors),
synchronizer.getChangeListVersions().authorVersion synchronizer.getChangeListVersions().authorVersion
) )

@ -39,9 +39,9 @@ import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferen
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList
import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -112,7 +112,7 @@ class OfflineFirstNewsRepositoryTest {
) )
assertEquals( assertEquals(
emptyList<NewsResource>(), emptyList(),
subject.getNewsResourcesStream( subject.getNewsResourcesStream(
filterTopicIds = nonPresentInterestsIds, filterTopicIds = nonPresentInterestsIds,
) )
@ -136,7 +136,7 @@ class OfflineFirstNewsRepositoryTest {
) )
assertEquals( assertEquals(
emptyList<NewsResource>(), emptyList(),
subject.getNewsResourcesStream( subject.getNewsResourcesStream(
filterAuthorIds = nonPresentInterestsIds filterAuthorIds = nonPresentInterestsIds
) )

@ -28,9 +28,9 @@ import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferencesDataSou
import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore
import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -69,7 +69,7 @@ class OfflineFirstTopicsRepositoryTest {
@Test @Test
fun offlineFirstTopicsRepository_topics_stream_is_backed_by_topics_dao() = fun offlineFirstTopicsRepository_topics_stream_is_backed_by_topics_dao() =
runTest { runTest {
Assert.assertEquals( assertEquals(
topicDao.getTopicEntitiesStream() topicDao.getTopicEntitiesStream()
.first() .first()
.map(TopicEntity::asExternalModel), .map(TopicEntity::asExternalModel),
@ -89,13 +89,13 @@ class OfflineFirstTopicsRepositoryTest {
val dbTopics = topicDao.getTopicEntitiesStream() val dbTopics = topicDao.getTopicEntitiesStream()
.first() .first()
Assert.assertEquals( assertEquals(
networkTopics.map(TopicEntity::id), networkTopics.map(TopicEntity::id),
dbTopics.map(TopicEntity::id) dbTopics.map(TopicEntity::id)
) )
// After sync version should be updated // After sync version should be updated
Assert.assertEquals( assertEquals(
network.latestChangeListVersion(CollectionType.Topics), network.latestChangeListVersion(CollectionType.Topics),
synchronizer.getChangeListVersions().topicVersion synchronizer.getChangeListVersions().topicVersion
) )
@ -119,13 +119,13 @@ class OfflineFirstTopicsRepositoryTest {
val dbTopics = topicDao.getTopicEntitiesStream() val dbTopics = topicDao.getTopicEntitiesStream()
.first() .first()
Assert.assertEquals( assertEquals(
networkTopics.map(TopicEntity::id), networkTopics.map(TopicEntity::id),
dbTopics.map(TopicEntity::id) dbTopics.map(TopicEntity::id)
) )
// After sync version should be updated // After sync version should be updated
Assert.assertEquals( assertEquals(
network.latestChangeListVersion(CollectionType.Topics), network.latestChangeListVersion(CollectionType.Topics),
synchronizer.getChangeListVersions().topicVersion synchronizer.getChangeListVersions().topicVersion
) )
@ -160,13 +160,13 @@ class OfflineFirstTopicsRepositoryTest {
.map(TopicEntity::asExternalModel) .map(TopicEntity::asExternalModel)
// Assert that items marked deleted on the network have been deleted locally // Assert that items marked deleted on the network have been deleted locally
Assert.assertEquals( assertEquals(
networkTopics.map(Topic::id) - deletedItems, networkTopics.map(Topic::id) - deletedItems,
dbTopics.map(Topic::id) dbTopics.map(Topic::id)
) )
// After sync version should be updated // After sync version should be updated
Assert.assertEquals( assertEquals(
network.latestChangeListVersion(CollectionType.Topics), network.latestChangeListVersion(CollectionType.Topics),
synchronizer.getChangeListVersions().topicVersion synchronizer.getChangeListVersions().topicVersion
) )

@ -21,10 +21,12 @@ import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferen
import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand
import com.google.samples.apps.nowinandroid.core.model.data.UserData import com.google.samples.apps.nowinandroid.core.model.data.UserData
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -194,9 +196,9 @@ class OfflineFirstUserDataRepositoryTest {
runTest { runTest {
subject.setFollowedTopicIds(setOf("1")) subject.setFollowedTopicIds(setOf("1"))
subject.setShouldHideOnboarding(true) subject.setShouldHideOnboarding(true)
assertEquals(true, subject.userDataStream.first().shouldHideOnboarding) assertTrue(subject.userDataStream.first().shouldHideOnboarding)
subject.setFollowedTopicIds(emptySet()) subject.setFollowedTopicIds(emptySet())
assertEquals(false, subject.userDataStream.first().shouldHideOnboarding) assertFalse(subject.userDataStream.first().shouldHideOnboarding)
} }
} }

@ -20,8 +20,8 @@ import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource 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.NewsResourceType.Video
import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import kotlin.test.assertEquals
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
class PopulatedNewsResourceKtTest { class PopulatedNewsResourceKtTest {

@ -17,7 +17,7 @@
package com.google.samples.apps.nowinandroid.core.database.util package com.google.samples.apps.nowinandroid.core.database.util
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType
import org.junit.Assert.assertEquals import kotlin.test.assertEquals
import org.junit.Test import org.junit.Test
class NewsResourceTypeConverterTest { class NewsResourceTypeConverterTest {

@ -27,10 +27,10 @@ import com.google.samples.apps.nowinandroid.core.database.model.NewsResourceTopi
import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity
import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

@ -16,9 +16,9 @@
package com.google.samples.apps.nowinandroid.core.datastore package com.google.samples.apps.nowinandroid.core.datastore
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
/** /**

@ -16,8 +16,9 @@
package com.google.samples.apps.nowinandroid.core.datastore package com.google.samples.apps.nowinandroid.core.datastore
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Test import org.junit.Test
class ListToMapMigrationTest { class ListToMapMigrationTest {
@ -29,7 +30,7 @@ class ListToMapMigrationTest {
deprecatedFollowedTopicIds.addAll(listOf("1", "2", "3")) deprecatedFollowedTopicIds.addAll(listOf("1", "2", "3"))
} }
// Assert that there are no topic ids in the map yet // Assert that there are no topic ids in the map yet
Assert.assertEquals( assertEquals(
emptyMap<String, Boolean>(), emptyMap<String, Boolean>(),
preMigrationUserPreferences.followedTopicIdsMap preMigrationUserPreferences.followedTopicIdsMap
) )
@ -39,13 +40,13 @@ class ListToMapMigrationTest {
ListToMapMigration.migrate(preMigrationUserPreferences) ListToMapMigration.migrate(preMigrationUserPreferences)
// Assert the deprecated topic ids have been migrated to the topic ids map // Assert the deprecated topic ids have been migrated to the topic ids map
Assert.assertEquals( assertEquals(
mapOf("1" to true, "2" to true, "3" to true), mapOf("1" to true, "2" to true, "3" to true),
postMigrationUserPreferences.followedTopicIdsMap postMigrationUserPreferences.followedTopicIdsMap
) )
// Assert that the migration has been marked complete // Assert that the migration has been marked complete
Assert.assertTrue(postMigrationUserPreferences.hasDoneListToMapMigration) assertTrue(postMigrationUserPreferences.hasDoneListToMapMigration)
} }
@Test @Test
@ -55,7 +56,7 @@ class ListToMapMigrationTest {
deprecatedFollowedAuthorIds.addAll(listOf("4", "5", "6")) deprecatedFollowedAuthorIds.addAll(listOf("4", "5", "6"))
} }
// Assert that there are no author ids in the map yet // Assert that there are no author ids in the map yet
Assert.assertEquals( assertEquals(
emptyMap<String, Boolean>(), emptyMap<String, Boolean>(),
preMigrationUserPreferences.followedAuthorIdsMap preMigrationUserPreferences.followedAuthorIdsMap
) )
@ -65,13 +66,13 @@ class ListToMapMigrationTest {
ListToMapMigration.migrate(preMigrationUserPreferences) ListToMapMigration.migrate(preMigrationUserPreferences)
// Assert the deprecated author ids have been migrated to the author ids map // Assert the deprecated author ids have been migrated to the author ids map
Assert.assertEquals( assertEquals(
mapOf("4" to true, "5" to true, "6" to true), mapOf("4" to true, "5" to true, "6" to true),
postMigrationUserPreferences.followedAuthorIdsMap postMigrationUserPreferences.followedAuthorIdsMap
) )
// Assert that the migration has been marked complete // Assert that the migration has been marked complete
Assert.assertTrue(postMigrationUserPreferences.hasDoneListToMapMigration) assertTrue(postMigrationUserPreferences.hasDoneListToMapMigration)
} }
@Test @Test
@ -81,7 +82,7 @@ class ListToMapMigrationTest {
deprecatedBookmarkedNewsResourceIds.addAll(listOf("7", "8", "9")) deprecatedBookmarkedNewsResourceIds.addAll(listOf("7", "8", "9"))
} }
// Assert that there are no bookmarks in the map yet // Assert that there are no bookmarks in the map yet
Assert.assertEquals( assertEquals(
emptyMap<String, Boolean>(), emptyMap<String, Boolean>(),
preMigrationUserPreferences.bookmarkedNewsResourceIdsMap preMigrationUserPreferences.bookmarkedNewsResourceIdsMap
) )
@ -91,12 +92,12 @@ class ListToMapMigrationTest {
ListToMapMigration.migrate(preMigrationUserPreferences) ListToMapMigration.migrate(preMigrationUserPreferences)
// Assert the deprecated bookmarks have been migrated to the bookmarks map // Assert the deprecated bookmarks have been migrated to the bookmarks map
Assert.assertEquals( assertEquals(
mapOf("7" to true, "8" to true, "9" to true), mapOf("7" to true, "8" to true, "9" to true),
postMigrationUserPreferences.bookmarkedNewsResourceIdsMap postMigrationUserPreferences.bookmarkedNewsResourceIdsMap
) )
// Assert that the migration has been marked complete // Assert that the migration has been marked complete
Assert.assertTrue(postMigrationUserPreferences.hasDoneListToMapMigration) assertTrue(postMigrationUserPreferences.hasDoneListToMapMigration)
} }
} }

@ -17,9 +17,10 @@
package com.google.samples.apps.nowinandroid.core.datastore package com.google.samples.apps.nowinandroid.core.datastore
import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -40,13 +41,13 @@ class NiaPreferencesDataSourceTest {
@Test @Test
fun shouldHideOnboardingIsFalseByDefault() = runTest { fun shouldHideOnboardingIsFalseByDefault() = runTest {
assertEquals(false, subject.userDataStream.first().shouldHideOnboarding) assertFalse(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
fun userShouldHideOnboardingIsTrueWhenSet() = runTest { fun userShouldHideOnboardingIsTrueWhenSet() = runTest {
subject.setShouldHideOnboarding(true) subject.setShouldHideOnboarding(true)
assertEquals(true, subject.userDataStream.first().shouldHideOnboarding) assertTrue(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
@ -60,7 +61,7 @@ class NiaPreferencesDataSourceTest {
subject.toggleFollowedAuthorId("1", false) subject.toggleFollowedAuthorId("1", false)
// Then: onboarding should be shown again // Then: onboarding should be shown again
assertEquals(false, subject.userDataStream.first().shouldHideOnboarding) assertFalse(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
@ -74,7 +75,7 @@ class NiaPreferencesDataSourceTest {
subject.toggleFollowedTopicId("1", false) subject.toggleFollowedTopicId("1", false)
// Then: onboarding should be shown again // Then: onboarding should be shown again
assertEquals(false, subject.userDataStream.first().shouldHideOnboarding) assertFalse(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
@ -88,7 +89,7 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedAuthorIds(emptySet()) subject.setFollowedAuthorIds(emptySet())
// Then: onboarding should be shown again // Then: onboarding should be shown again
assertEquals(false, subject.userDataStream.first().shouldHideOnboarding) assertFalse(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
@ -102,7 +103,7 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedTopicIds(emptySet()) subject.setFollowedTopicIds(emptySet())
// Then: onboarding should be shown again // Then: onboarding should be shown again
assertEquals(false, subject.userDataStream.first().shouldHideOnboarding) assertFalse(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
@ -117,7 +118,7 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedTopicIds(emptySet()) subject.setFollowedTopicIds(emptySet())
// Then: onboarding should still be dismissed // Then: onboarding should still be dismissed
assertEquals(true, subject.userDataStream.first().shouldHideOnboarding) assertTrue(subject.userDataStream.first().shouldHideOnboarding)
} }
@Test @Test
@ -132,6 +133,6 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedAuthorIds(emptySet()) subject.setFollowedAuthorIds(emptySet())
// Then: onboarding should still be dismissed // Then: onboarding should still be dismissed
assertEquals(true, subject.userDataStream.first().shouldHideOnboarding) assertTrue(subject.userDataStream.first().shouldHideOnboarding)
} }
} }

@ -19,8 +19,8 @@ package com.google.samples.apps.nowinandroid.core.datastore
import androidx.datastore.core.CorruptionException import androidx.datastore.core.CorruptionException
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import kotlin.test.assertEquals
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
class UserPreferencesSerializerTest { class UserPreferencesSerializerTest {

@ -36,7 +36,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.theme.LightDefault
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalBackgroundTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalBackgroundTheme
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import org.junit.Assert.assertEquals import kotlin.test.assertEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -22,9 +22,9 @@ 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.TestTopicsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository 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.core.testing.util.MainDispatcherRule
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -24,10 +24,10 @@ 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.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository 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.core.testing.util.MainDispatcherRule
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -21,9 +21,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository 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.core.testing.util.MainDispatcherRule
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -20,13 +20,13 @@ import JvmUnitTestFakeAssetManager
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Codelab import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Codelab
import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource
import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic
import kotlin.test.assertEquals
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant import kotlinx.datetime.toInstant
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

@ -17,8 +17,8 @@
package com.google.samples.apps.nowinandroid.core.network.model.util package com.google.samples.apps.nowinandroid.core.network.model.util
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType
import kotlin.test.assertEquals
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
class NewsResourceTypeSerializerTest { class NewsResourceTypeSerializerTest {

@ -156,12 +156,12 @@ fun NewsResourceAuthors(
authors: List<Author> authors: List<Author>
) { ) {
if (authors.isNotEmpty()) { if (authors.isNotEmpty()) {
// Only display first author for now // display all authors
val author = authors[0] val authorNameFormatted =
authors.joinToString(separator = ", ") { author -> author.name }
.uppercase(Locale.getDefault())
val authorNameFormatted = author.name.uppercase(Locale.getDefault()) val authorImageUrl = authors[0].imageUrl
val authorImageUrl = author.imageUrl
val authorImageModifier = Modifier val authorImageModifier = Modifier
.clip(CircleShape) .clip(CircleShape)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 558 KiB

@ -28,6 +28,9 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepo
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository 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.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.author.navigation.authorIdArg import com.google.samples.apps.nowinandroid.feature.author.navigation.authorIdArg
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertTrue
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@ -35,8 +38,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -83,15 +84,14 @@ class AuthorViewModelTest {
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id))
val item = viewModel.authorUiState.value val item = viewModel.authorUiState.value
assertTrue(item is AuthorUiState.Success) assertIs<AuthorUiState.Success>(item)
val successAuthorUiState = item as AuthorUiState.Success
val authorFromRepository = authorsRepository.getAuthorStream( val authorFromRepository = authorsRepository.getAuthorStream(
id = testInputAuthors[0].author.id id = testInputAuthors[0].author.id
).first() ).first()
successAuthorUiState.followableAuthor.author item.followableAuthor.author
assertEquals(authorFromRepository, successAuthorUiState.followableAuthor.author) assertEquals(authorFromRepository, item.followableAuthor.author)
collectJob.cancel() collectJob.cancel()
} }
@ -132,8 +132,8 @@ class AuthorViewModelTest {
val authorState = viewModel.authorUiState.value val authorState = viewModel.authorUiState.value
val newsUiState = viewModel.newsUiState.value val newsUiState = viewModel.newsUiState.value
assertTrue(authorState is AuthorUiState.Success) assertIs<AuthorUiState.Success>(authorState)
assertTrue(newsUiState is NewsUiState.Loading) assertIs<NewsUiState.Loading>(newsUiState)
collectJob.cancel() collectJob.cancel()
} }
@ -155,8 +155,8 @@ class AuthorViewModelTest {
val authorState = viewModel.authorUiState.value val authorState = viewModel.authorUiState.value
val newsUiState = viewModel.newsUiState.value val newsUiState = viewModel.newsUiState.value
assertTrue(authorState is AuthorUiState.Success) assertIs<AuthorUiState.Success>(authorState)
assertTrue(newsUiState is NewsUiState.Success) assertIs<NewsUiState.Success>(newsUiState)
collectJob.cancel() collectJob.cancel()
} }

@ -34,8 +34,8 @@ import androidx.compose.ui.test.performScrollToNode
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import org.junit.Assert.assertEquals import kotlin.test.assertEquals
import org.junit.Assert.assertTrue import kotlin.test.assertTrue
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -23,12 +23,12 @@ 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.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -69,8 +69,8 @@ class BookmarksViewModelTest {
newsRepository.sendNewsResources(previewNewsResources) newsRepository.sendNewsResources(previewNewsResources)
userDataRepository.updateNewsResourceBookmark(previewNewsResources[0].id, true) userDataRepository.updateNewsResourceBookmark(previewNewsResources[0].id, true)
val item = viewModel.feedUiState.value val item = viewModel.feedUiState.value
assertTrue(item is Success) assertIs<Success>(item)
assertEquals((item as Success).feed.size, 1) assertEquals(item.feed.size, 1)
collectJob.cancel() collectJob.cancel()
} }
@ -86,8 +86,8 @@ class BookmarksViewModelTest {
viewModel.removeFromSavedResources(previewNewsResources[0].id) viewModel.removeFromSavedResources(previewNewsResources[0].id)
// Verify list of saved resources is now empty // Verify list of saved resources is now empty
val item = viewModel.feedUiState.value val item = viewModel.feedUiState.value
assertTrue(item is Success) assertIs<Success>(item)
assertEquals((item as Success).feed.size, 0) assertEquals(item.feed.size, 0)
collectJob.cancel() collectJob.cancel()
} }

@ -16,7 +16,6 @@
package com.google.samples.apps.nowinandroid.feature.foryou package com.google.samples.apps.nowinandroid.feature.foryou
import androidx.compose.runtime.snapshotFlow
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
@ -33,6 +32,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
@ -67,7 +67,7 @@ class ForYouViewModel @Inject constructor(
userData.followedAuthors.isEmpty() && userData.followedAuthors.isEmpty() &&
userData.followedTopics.isEmpty() userData.followedTopics.isEmpty()
) { ) {
snapshotFlow { NewsFeedUiState.Success(emptyList()) } flowOf(NewsFeedUiState.Success(emptyList()))
} else { } else {
getSaveableNewsResourcesStream( getSaveableNewsResourcesStream(
filterTopicIds = userData.followedTopics, filterTopicIds = userData.followedTopics,

@ -34,13 +34,13 @@ 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.TestNetworkMonitor
import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncStatusMonitor import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncStatusMonitor
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -28,11 +28,11 @@ 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.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState
import com.google.samples.apps.nowinandroid.feature.interests.InterestsViewModel import com.google.samples.apps.nowinandroid.feature.interests.InterestsViewModel
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -22,7 +22,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.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success
import junit.framework.Assert.assertEquals import kotlin.test.assertEquals
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher

@ -28,6 +28,8 @@ 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.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicIdArg import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicIdArg
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@ -35,8 +37,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -77,14 +77,13 @@ class TopicViewModelTest {
topicsRepository.sendTopics(testInputTopics.map(FollowableTopic::topic)) topicsRepository.sendTopics(testInputTopics.map(FollowableTopic::topic))
userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id))
val item = viewModel.topicUiState.value val item = viewModel.topicUiState.value
assertTrue(item is TopicUiState.Success) assertIs<TopicUiState.Success>(item)
val successTopicState = item as TopicUiState.Success
val topicFromRepository = topicsRepository.getTopic( val topicFromRepository = topicsRepository.getTopic(
testInputTopics[0].topic.id testInputTopics[0].topic.id
).first() ).first()
assertEquals(topicFromRepository, successTopicState.followableTopic.topic) assertEquals(topicFromRepository, item.followableTopic.topic)
collectJob.cancel() collectJob.cancel()
} }
@ -119,8 +118,8 @@ class TopicViewModelTest {
val topicUiState = viewModel.topicUiState.value val topicUiState = viewModel.topicUiState.value
val newsUiState = viewModel.newUiState.value val newsUiState = viewModel.newUiState.value
assertTrue(topicUiState is TopicUiState.Success) assertIs<TopicUiState.Success>(topicUiState)
assertTrue(newsUiState is NewsUiState.Loading) assertIs<NewsUiState.Loading>(newsUiState)
collectJob.cancel() collectJob.cancel()
} }
@ -141,8 +140,8 @@ class TopicViewModelTest {
val topicUiState = viewModel.topicUiState.value val topicUiState = viewModel.topicUiState.value
val newsUiState = viewModel.newUiState.value val newsUiState = viewModel.newUiState.value
assertTrue(topicUiState is TopicUiState.Success) assertIs<TopicUiState.Success>(topicUiState)
assertTrue(newsUiState is NewsUiState.Success) assertIs<NewsUiState.Success>(newsUiState)
collectJob.cancel() collectJob.cancel()
} }

@ -4,7 +4,7 @@ androidDesugarJdkLibs = "1.2.0"
androidGradlePlugin = "7.3.1" androidGradlePlugin = "7.3.1"
androidxActivity = "1.6.1" androidxActivity = "1.6.1"
androidxAppCompat = "1.5.1" androidxAppCompat = "1.5.1"
androidxComposeBom = "2022.10.00" androidxComposeBom = "2022.11.00"
androidxComposeCompiler = "1.3.2" androidxComposeCompiler = "1.3.2"
androidxComposeRuntimeTracing = "1.0.0-alpha01" androidxComposeRuntimeTracing = "1.0.0-alpha01"
androidxCore = "1.9.0" androidxCore = "1.9.0"
@ -13,7 +13,7 @@ androidxDataStore = "1.0.0"
androidxEspresso = "3.5.0" androidxEspresso = "3.5.0"
androidxHiltNavigationCompose = "1.0.0" androidxHiltNavigationCompose = "1.0.0"
androidxLifecycle = "2.6.0-alpha03" androidxLifecycle = "2.6.0-alpha03"
androidxMacroBenchmark = "1.1.0" androidxMacroBenchmark = "1.1.1"
androidxNavigation = "2.5.3" androidxNavigation = "2.5.3"
androidxMetrics = "1.0.0-alpha03" androidxMetrics = "1.0.0-alpha03"
androidxProfileinstaller = "1.2.0" androidxProfileinstaller = "1.2.0"
@ -27,7 +27,7 @@ androidxTracing = "1.1.0"
androidxUiAutomator = "2.2.0" androidxUiAutomator = "2.2.0"
androidxWork = "2.7.1" androidxWork = "2.7.1"
coil = "2.2.2" coil = "2.2.2"
hilt = "2.44" hilt = "2.44.2"
hiltExt = "1.0.0" hiltExt = "1.0.0"
jacoco = "0.8.7" jacoco = "0.8.7"
junit4 = "4.13.2" junit4 = "4.13.2"
@ -35,14 +35,14 @@ kotlin = "1.7.20"
kotlinxCoroutines = "1.6.4" kotlinxCoroutines = "1.6.4"
kotlinxDatetime = "0.4.0" kotlinxDatetime = "0.4.0"
kotlinxSerializationJson = "1.4.1" kotlinxSerializationJson = "1.4.1"
ksp = "1.7.20-1.0.8" ksp = "1.7.21-1.0.8"
lint = "30.3.1" lint = "30.3.1"
okhttp = "4.10.0" okhttp = "4.10.0"
protobuf = "3.21.9" protobuf = "3.21.9"
protobufPlugin = "0.8.19" protobufPlugin = "0.8.19"
retrofit = "2.9.0" retrofit = "2.9.0"
retrofitKotlinxSerializationJson = "0.8.0" retrofitKotlinxSerializationJson = "0.8.0"
room = "2.5.0-beta01" room = "2.5.0-beta02"
secrets = "2.0.1" secrets = "2.0.1"
turbine = "0.12.1" turbine = "0.12.1"

@ -33,7 +33,7 @@ dependencyResolutionManagement {
rootProject.name = "nowinandroid" rootProject.name = "nowinandroid"
include(":app") include(":app")
include(":app-nia-catalog") include(":app-nia-catalog")
include(":benchmark") include(":benchmarks")
include(":core:common") include(":core:common")
include(":core:data") include(":core:data")
include(":core:data-test") include(":core:data-test")

@ -1,3 +1,3 @@
# :sync module # :sync module
![Dependency graph](../docs/images/graphs/dep_graph_lint.png) ![Dependency graph](../docs/images/graphs/dep_graph_sync.png)

@ -25,7 +25,7 @@ import androidx.work.testing.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper import androidx.work.testing.WorkManagerTestInitHelper
import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Assert.assertEquals import kotlin.test.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

Loading…
Cancel
Save