Change-Id: I97772a8b65e1e94a95187ebb7c514104af2d3a08pull/406/head
parent
10447f2dfa
commit
6654403498
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.samples.apps.nowinandroid.core.datastore
|
||||||
|
|
||||||
|
import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
|
||||||
|
class NiaPreferencesDataSourceTest {
|
||||||
|
private lateinit var subject: NiaPreferencesDataSource
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
subject = NiaPreferencesDataSource(
|
||||||
|
tmpFolder.testUserPreferencesDataStore()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasDismissedOnboardingIsFalseByDefault() = runTest {
|
||||||
|
assertEquals(false, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboardingIsTrueWhenSet() = runTest {
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
assertEquals(true, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboarding_unfollowsLastAuthor_hasDismissedOnboardingIsFalse() = runTest {
|
||||||
|
|
||||||
|
// Given: user completes onboarding by selecting a single author.
|
||||||
|
subject.toggleFollowedAuthorId("1", true)
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
|
||||||
|
// When: they unfollow that author.
|
||||||
|
subject.toggleFollowedAuthorId("1", false)
|
||||||
|
|
||||||
|
// Then: onboarding should be shown again
|
||||||
|
assertEquals(false, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboarding_unfollowsLastTopic_hasDismissedOnboardingIsFalse() = runTest {
|
||||||
|
|
||||||
|
// Given: user completes onboarding by selecting a single topic.
|
||||||
|
subject.toggleFollowedTopicId("1", true)
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
|
||||||
|
// When: they unfollow that topic.
|
||||||
|
subject.toggleFollowedTopicId("1", false)
|
||||||
|
|
||||||
|
// Then: onboarding should be shown again
|
||||||
|
assertEquals(false, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboarding_unfollowsAllAuthors_hasDismissedOnboardingIsFalse() = runTest {
|
||||||
|
|
||||||
|
// Given: user completes onboarding by selecting several authors.
|
||||||
|
subject.setFollowedAuthorIds(setOf("1", "2"))
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
|
||||||
|
// When: they unfollow those authors.
|
||||||
|
subject.setFollowedAuthorIds(emptySet())
|
||||||
|
|
||||||
|
// Then: onboarding should be shown again
|
||||||
|
assertEquals(false, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboarding_unfollowsAllTopics_hasDismissedOnboardingIsFalse() = runTest {
|
||||||
|
|
||||||
|
// Given: user completes onboarding by selecting several topics.
|
||||||
|
subject.setFollowedTopicIds(setOf("1", "2"))
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
|
||||||
|
// When: they unfollow those topics.
|
||||||
|
subject.setFollowedTopicIds(emptySet())
|
||||||
|
|
||||||
|
// Then: onboarding should be shown again
|
||||||
|
assertEquals(false, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboarding_unfollowsAllTopicsButNotAuthors_hasDismissedOnboardingIsTrue() =
|
||||||
|
runTest {
|
||||||
|
// Given: user completes onboarding by selecting several topics and authors.
|
||||||
|
subject.setFollowedTopicIds(setOf("1", "2"))
|
||||||
|
subject.setFollowedAuthorIds(setOf("3", "4"))
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
|
||||||
|
// When: they unfollow just the topics.
|
||||||
|
subject.setFollowedTopicIds(emptySet())
|
||||||
|
|
||||||
|
// Then: onboarding should still be dismissed
|
||||||
|
assertEquals(true, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userHasDismissedOnboarding_unfollowsAllAuthorsButNotTopics_hasDismissedOnboardingIsTrue() =
|
||||||
|
runTest {
|
||||||
|
// Given: user completes onboarding by selecting several topics and authors.
|
||||||
|
subject.setFollowedTopicIds(setOf("1", "2"))
|
||||||
|
subject.setFollowedAuthorIds(setOf("3", "4"))
|
||||||
|
subject.setHasDismissedOnboarding(true)
|
||||||
|
|
||||||
|
// When: they unfollow just the authors.
|
||||||
|
subject.setFollowedAuthorIds(emptySet())
|
||||||
|
|
||||||
|
// Then: onboarding should still be dismissed
|
||||||
|
assertEquals(true, subject.userDataStream.first().hasDismissedOnboarding)
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.samples.apps.nowinandroid.core.domain
|
|
||||||
|
|
||||||
import com.google.samples.apps.nowinandroid.core.data.repository.AuthorsRepository
|
|
||||||
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
|
|
||||||
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A use case which obtains a sorted list of authors with their followed state obtained from user
|
|
||||||
* data.
|
|
||||||
*/
|
|
||||||
class GetPersistentSortedFollowableAuthorsStreamUseCase @Inject constructor(
|
|
||||||
authorsRepository: AuthorsRepository,
|
|
||||||
private val userDataRepository: UserDataRepository
|
|
||||||
) {
|
|
||||||
private val getSortedFollowableAuthorsStream =
|
|
||||||
GetSortedFollowableAuthorsStreamUseCase(authorsRepository)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of authors with their associated followed state sorted alphabetically by name.
|
|
||||||
*/
|
|
||||||
operator fun invoke(): Flow<List<FollowableAuthor>> {
|
|
||||||
return userDataRepository.userDataStream.map { userdata ->
|
|
||||||
userdata.followedAuthors
|
|
||||||
}.flatMapLatest {
|
|
||||||
getSortedFollowableAuthorsStream(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.samples.apps.nowinandroid.core.domain
|
|
||||||
|
|
||||||
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
|
|
||||||
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.TestUserDataRepository
|
|
||||||
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
|
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class GetPersistentSortedFollowableAuthorsStreamUseCaseTest {
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val mainDispatcherRule = MainDispatcherRule()
|
|
||||||
|
|
||||||
private val authorsRepository = TestAuthorsRepository()
|
|
||||||
private val userDataRepository = TestUserDataRepository()
|
|
||||||
|
|
||||||
val useCase = GetPersistentSortedFollowableAuthorsStreamUseCase(
|
|
||||||
authorsRepository = authorsRepository,
|
|
||||||
userDataRepository = userDataRepository
|
|
||||||
)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun whenFollowedAuthorsSupplied_sortedFollowableAuthorsAreReturned() = runTest {
|
|
||||||
|
|
||||||
// Obtain the stream of authors.
|
|
||||||
val followableAuthorsStream = useCase()
|
|
||||||
|
|
||||||
// Supply some authors and their followed state in user data.
|
|
||||||
authorsRepository.sendAuthors(sampleAuthors)
|
|
||||||
userDataRepository.setFollowedAuthorIds(setOf(sampleAuthor1.id, sampleAuthor3.id))
|
|
||||||
|
|
||||||
// Check that the authors have been sorted, and that the followed state is correct.
|
|
||||||
assertEquals(
|
|
||||||
listOf(
|
|
||||||
FollowableAuthor(sampleAuthor2, false),
|
|
||||||
FollowableAuthor(sampleAuthor1, true),
|
|
||||||
FollowableAuthor(sampleAuthor3, true)
|
|
||||||
),
|
|
||||||
followableAuthorsStream.first()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sampleAuthor1 =
|
|
||||||
Author(
|
|
||||||
id = "Author1",
|
|
||||||
name = "Mandy",
|
|
||||||
imageUrl = "",
|
|
||||||
twitter = "",
|
|
||||||
mediumPage = "",
|
|
||||||
bio = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
private val sampleAuthor2 =
|
|
||||||
Author(
|
|
||||||
id = "Author2",
|
|
||||||
name = "Andy",
|
|
||||||
imageUrl = "",
|
|
||||||
twitter = "",
|
|
||||||
mediumPage = "",
|
|
||||||
bio = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
private val sampleAuthor3 =
|
|
||||||
Author(
|
|
||||||
id = "Author3",
|
|
||||||
name = "Sandy",
|
|
||||||
imageUrl = "",
|
|
||||||
twitter = "",
|
|
||||||
mediumPage = "",
|
|
||||||
bio = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
private val sampleAuthors = listOf(sampleAuthor1, sampleAuthor2, sampleAuthor3)
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.samples.apps.nowinandroid.feature.foryou
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sealed hierarchy for the user's current followed interests state.
|
|
||||||
*/
|
|
||||||
sealed interface FollowedInterestsUiState {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current state is unknown (hasn't loaded yet)
|
|
||||||
*/
|
|
||||||
object Unknown : FollowedInterestsUiState
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user hasn't followed any interests yet.
|
|
||||||
*/
|
|
||||||
object None : FollowedInterestsUiState
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user has followed the given (non-empty) set of [topicIds] or [authorIds].
|
|
||||||
*/
|
|
||||||
data class FollowedInterests(
|
|
||||||
val topicIds: Set<String>,
|
|
||||||
val authorIds: Set<String>
|
|
||||||
) : FollowedInterestsUiState
|
|
||||||
}
|
|
Loading…
Reference in new issue