Skip to content

Commit 5b4ba07

Browse files
committed
Observe display settings
1 parent 21ff69d commit 5b4ba07

9 files changed

Lines changed: 242 additions & 103 deletions

File tree

app/src/test/kotlin/com/android/contacts/data/settings/repository/DisplaySettingsRepositoryImplTest.kt

Lines changed: 84 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.android.contacts.data.settings.repository
22

3+
import app.cash.turbine.test
34
import com.android.contacts.data.settings.model.DisplayOrder
45
import com.android.contacts.data.settings.model.DisplaySettings
56
import com.android.contacts.data.settings.model.PhoneticNameDisplay
@@ -26,80 +27,122 @@ class DisplaySettingsRepositoryImplTest {
2627
)
2728

2829
@Test
29-
fun getDisplaySettings_whenPrimaryValuesAreStored_mapsToGivenNameFirst() = runTest {
30+
fun observeDisplaySettings_whenPrimaryValuesAreStored_mapsToGivenNameFirst() = runTest {
3031
givenStoredValues(
3132
sortOrder = ContactsPreferences.SORT_ORDER_PRIMARY,
3233
displayOrder = ContactsPreferences.DISPLAY_ORDER_PRIMARY,
3334
phoneticNameDisplay = ContactsPreferences.PHONETIC_NAME_DISPLAY_SHOW_ALWAYS,
3435
)
3536

36-
val settings = repository.getDisplaySettings()
37+
repository.observeDisplaySettings().test {
38+
val settings = awaitItem()
3739

38-
assertEquals(SortOrder.GIVEN_NAME_FIRST, settings.sortOrder)
39-
assertEquals(DisplayOrder.GIVEN_NAME_FIRST, settings.displayOrder)
40-
assertEquals(PhoneticNameDisplay.SHOW_ALWAYS, settings.phoneticNameDisplay)
40+
assertEquals(SortOrder.GIVEN_NAME_FIRST, settings.sortOrder)
41+
assertEquals(DisplayOrder.GIVEN_NAME_FIRST, settings.displayOrder)
42+
assertEquals(PhoneticNameDisplay.SHOW_ALWAYS, settings.phoneticNameDisplay)
43+
cancelAndIgnoreRemainingEvents()
44+
}
4145
}
4246

4347
@Test
44-
fun getDisplaySettings_whenAlternativeValuesAreStored_mapsToFamilyNameFirst() = runTest {
48+
fun observeDisplaySettings_whenAlternativeValuesAreStored_mapsToFamilyNameFirst() = runTest {
4549
givenStoredValues(
4650
sortOrder = ContactsPreferences.SORT_ORDER_ALTERNATIVE,
4751
displayOrder = ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE,
4852
phoneticNameDisplay = ContactsPreferences.PHONETIC_NAME_DISPLAY_HIDE_IF_EMPTY,
4953
)
5054

51-
val settings = repository.getDisplaySettings()
55+
repository.observeDisplaySettings().test {
56+
val settings = awaitItem()
5257

53-
assertEquals(SortOrder.FAMILY_NAME_FIRST, settings.sortOrder)
54-
assertEquals(DisplayOrder.FAMILY_NAME_FIRST, settings.displayOrder)
55-
assertEquals(PhoneticNameDisplay.HIDE_IF_EMPTY, settings.phoneticNameDisplay)
58+
assertEquals(SortOrder.FAMILY_NAME_FIRST, settings.sortOrder)
59+
assertEquals(DisplayOrder.FAMILY_NAME_FIRST, settings.displayOrder)
60+
assertEquals(PhoneticNameDisplay.HIDE_IF_EMPTY, settings.phoneticNameDisplay)
61+
cancelAndIgnoreRemainingEvents()
62+
}
5663
}
5764

5865
@Test
59-
fun getDisplaySettings_whenStoredValuesAreUnknown_fallsBackToPrimaryOptions() = runTest {
66+
fun observeDisplaySettings_whenStoredValuesAreUnknown_fallsBackToPrimaryOptions() = runTest {
6067
givenStoredValues(
6168
sortOrder = UNKNOWN_PREFERENCE_VALUE,
6269
displayOrder = UNKNOWN_PREFERENCE_VALUE,
6370
phoneticNameDisplay = UNKNOWN_PREFERENCE_VALUE,
6471
)
6572

66-
val settings = repository.getDisplaySettings()
73+
repository.observeDisplaySettings().test {
74+
val settings = awaitItem()
6775

68-
assertEquals(SortOrder.GIVEN_NAME_FIRST, settings.sortOrder)
69-
assertEquals(DisplayOrder.GIVEN_NAME_FIRST, settings.displayOrder)
70-
assertEquals(PhoneticNameDisplay.SHOW_ALWAYS, settings.phoneticNameDisplay)
76+
assertEquals(SortOrder.GIVEN_NAME_FIRST, settings.sortOrder)
77+
assertEquals(DisplayOrder.GIVEN_NAME_FIRST, settings.displayOrder)
78+
assertEquals(PhoneticNameDisplay.SHOW_ALWAYS, settings.phoneticNameDisplay)
79+
cancelAndIgnoreRemainingEvents()
80+
}
7181
}
7282

7383
@Test
74-
fun getDisplaySettings_whenOptionsAreChangeable_reportsThemAsChangeable() = runTest {
84+
fun observeDisplaySettings_whenOptionsAreChangeable_reportsThemAsChangeable() = runTest {
7585
givenStoredValues()
7686
givenOptionsChangeable(true)
7787

78-
val settings = repository.getDisplaySettings()
79-
80-
assertEquals(
81-
DisplaySettings(
82-
sortOrder = SortOrder.GIVEN_NAME_FIRST,
83-
isSortOrderChangeable = true,
84-
displayOrder = DisplayOrder.GIVEN_NAME_FIRST,
85-
isDisplayOrderChangeable = true,
86-
phoneticNameDisplay = PhoneticNameDisplay.SHOW_ALWAYS,
87-
isPhoneticNameDisplayChangeable = true,
88-
),
89-
settings,
90-
)
88+
repository.observeDisplaySettings().test {
89+
assertEquals(
90+
DisplaySettings(
91+
sortOrder = SortOrder.GIVEN_NAME_FIRST,
92+
isSortOrderChangeable = true,
93+
displayOrder = DisplayOrder.GIVEN_NAME_FIRST,
94+
isDisplayOrderChangeable = true,
95+
phoneticNameDisplay = PhoneticNameDisplay.SHOW_ALWAYS,
96+
isPhoneticNameDisplayChangeable = true,
97+
),
98+
awaitItem(),
99+
)
100+
cancelAndIgnoreRemainingEvents()
101+
}
91102
}
92103

93104
@Test
94-
fun getDisplaySettings_whenOptionsAreLocked_reportsThemAsNotChangeable() = runTest {
105+
fun observeDisplaySettings_whenOptionsAreLocked_reportsThemAsNotChangeable() = runTest {
95106
givenStoredValues()
96107
givenOptionsChangeable(false)
97108

98-
val settings = repository.getDisplaySettings()
109+
repository.observeDisplaySettings().test {
110+
val settings = awaitItem()
99111

100-
assertFalse(settings.isSortOrderChangeable)
101-
assertFalse(settings.isDisplayOrderChangeable)
102-
assertFalse(settings.isPhoneticNameDisplayChangeable)
112+
assertFalse(settings.isSortOrderChangeable)
113+
assertFalse(settings.isDisplayOrderChangeable)
114+
assertFalse(settings.isPhoneticNameDisplayChangeable)
115+
cancelAndIgnoreRemainingEvents()
116+
}
117+
}
118+
119+
@Test
120+
fun observeDisplaySettings_whenASettingIsChanged_emitsTheStoredValueAgain() = runTest {
121+
givenStoredValues()
122+
givenSortOrderWritesAreStored()
123+
124+
repository.observeDisplaySettings().test {
125+
assertEquals(SortOrder.GIVEN_NAME_FIRST, awaitItem().sortOrder)
126+
127+
repository.setSortOrder(SortOrder.FAMILY_NAME_FIRST)
128+
129+
assertEquals(SortOrder.FAMILY_NAME_FIRST, awaitItem().sortOrder)
130+
cancelAndIgnoreRemainingEvents()
131+
}
132+
}
133+
134+
@Test
135+
fun observeDisplaySettings_whenNothingIsWritten_doesNotEmitAgain() = runTest {
136+
givenStoredValues(sortOrder = ContactsPreferences.SORT_ORDER_PRIMARY)
137+
138+
repository.observeDisplaySettings().test {
139+
assertEquals(SortOrder.GIVEN_NAME_FIRST, awaitItem().sortOrder)
140+
141+
repository.setSortOrder(SortOrder.GIVEN_NAME_FIRST)
142+
143+
expectNoEvents()
144+
cancelAndIgnoreRemainingEvents()
145+
}
103146
}
104147

105148
@Test
@@ -205,6 +248,13 @@ class DisplaySettingsRepositoryImplTest {
205248
every { contactsPreferences.phoneticNameDisplayPreference } returns phoneticNameDisplay
206249
}
207250

251+
private fun givenSortOrderWritesAreStored() {
252+
var storedSortOrder = ContactsPreferences.SORT_ORDER_PRIMARY
253+
254+
every { contactsPreferences.sortOrder } answers { storedSortOrder }
255+
every { contactsPreferences.sortOrder = any() } answers { storedSortOrder = firstArg() }
256+
}
257+
208258
private fun givenOptionsChangeable(isChangeable: Boolean) {
209259
every { contactsPreferences.isSortOrderUserChangeable } returns isChangeable
210260
every { contactsPreferences.isDisplayOrderUserChangeable } returns isChangeable

app/src/test/kotlin/com/android/contacts/domain/settings/usecase/GetSettingsDataImplTest.kt

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.android.contacts.domain.settings.usecase
22

3+
import app.cash.turbine.test
34
import com.android.contacts.data.accounts.repository.AccountsRepository
45
import com.android.contacts.data.appinfo.repository.AppInfoRepository
56
import com.android.contacts.data.contactsfilter.model.ContactsFilter
@@ -15,10 +16,14 @@ import com.android.contacts.data.settings.repository.SettingsAvailabilityReposit
1516
import com.android.contacts.domain.settings.model.SettingsData
1617
import io.mockk.coEvery
1718
import io.mockk.coVerify
19+
import io.mockk.every
1820
import io.mockk.mockk
1921
import kotlinx.coroutines.CompletableDeferred
2022
import kotlinx.coroutines.ExperimentalCoroutinesApi
2123
import kotlinx.coroutines.async
24+
import kotlinx.coroutines.flow.MutableSharedFlow
25+
import kotlinx.coroutines.flow.first
26+
import kotlinx.coroutines.flow.flowOf
2227
import kotlinx.coroutines.test.runCurrent
2328
import kotlinx.coroutines.test.runTest
2429
import org.junit.Assert.assertEquals
@@ -48,7 +53,8 @@ class GetSettingsDataImplTest {
4853
@Before
4954
fun setUp() {
5055
coEvery { settingsAvailabilityRepository.getSettingsAvailability() } returns AVAILABILITY
51-
coEvery { displaySettingsRepository.getDisplaySettings() } returns DISPLAY_SETTINGS
56+
every { displaySettingsRepository.observeDisplaySettings() } returns
57+
flowOf(DISPLAY_SETTINGS)
5258
coEvery { accountsRepository.getDefaultAccountLabel() } returns "Device"
5359
coEvery { contactsFilterRepository.getContactsFilter() } returns ContactsFilter.CUSTOM
5460
coEvery { appInfoRepository.getBuildVersion() } returns BUILD_VERSION
@@ -57,30 +63,34 @@ class GetSettingsDataImplTest {
5763

5864
@Test
5965
fun invoke_collectsEverySource() = runTest {
60-
val settingsData = useCase()
61-
62-
assertEquals(
63-
SettingsData(
64-
availability = AVAILABILITY,
65-
displaySettings = DISPLAY_SETTINGS,
66-
defaultAccountLabel = "Device",
67-
contactsFilter = ContactsFilter.CUSTOM,
68-
buildVersion = BUILD_VERSION,
69-
isCallLogPermissionGranted = true,
70-
),
71-
settingsData,
72-
)
66+
useCase().test {
67+
assertEquals(
68+
SettingsData(
69+
availability = AVAILABILITY,
70+
displaySettings = DISPLAY_SETTINGS,
71+
defaultAccountLabel = "Device",
72+
contactsFilter = ContactsFilter.CUSTOM,
73+
buildVersion = BUILD_VERSION,
74+
isCallLogPermissionGranted = true,
75+
),
76+
awaitItem(),
77+
)
78+
cancelAndIgnoreRemainingEvents()
79+
}
7380
}
7481

7582
@Test
7683
fun invoke_whenThereIsNoDefaultAccountOrFilter_keepsThemNull() = runTest {
7784
coEvery { accountsRepository.getDefaultAccountLabel() } returns null
7885
coEvery { contactsFilterRepository.getContactsFilter() } returns null
7986

80-
val settingsData = useCase()
87+
useCase().test {
88+
val settingsData = awaitItem()
8189

82-
assertNull(settingsData.defaultAccountLabel)
83-
assertNull(settingsData.contactsFilter)
90+
assertNull(settingsData.defaultAccountLabel)
91+
assertNull(settingsData.contactsFilter)
92+
cancelAndIgnoreRemainingEvents()
93+
}
8494
}
8595

8696
@Test
@@ -90,17 +100,35 @@ class GetSettingsDataImplTest {
90100
slowAvailability.await()
91101
}
92102

93-
val settingsData = async { useCase() }
103+
val settingsData = async { useCase().first() }
94104
runCurrent()
95105

96-
coVerify(exactly = 1) { displaySettingsRepository.getDisplaySettings() }
97106
coVerify(exactly = 1) { accountsRepository.getDefaultAccountLabel() }
98107
coVerify(exactly = 1) { contactsFilterRepository.getContactsFilter() }
108+
coVerify(exactly = 1) { appInfoRepository.getBuildVersion() }
99109

100110
slowAvailability.complete(AVAILABILITY)
101111
assertEquals(AVAILABILITY, settingsData.await().availability)
102112
}
103113

114+
@Test
115+
fun invoke_whenDisplaySettingsChange_emitsTheDataAgain() = runTest {
116+
val displaySettings = MutableSharedFlow<DisplaySettings>(extraBufferCapacity = 1)
117+
every { displaySettingsRepository.observeDisplaySettings() } returns displaySettings
118+
119+
useCase().test {
120+
displaySettings.emit(DISPLAY_SETTINGS)
121+
122+
assertEquals(DISPLAY_SETTINGS, awaitItem().displaySettings)
123+
124+
val alternative = DISPLAY_SETTINGS.copy(sortOrder = SortOrder.FAMILY_NAME_FIRST)
125+
displaySettings.emit(alternative)
126+
127+
assertEquals(alternative, awaitItem().displaySettings)
128+
cancelAndIgnoreRemainingEvents()
129+
}
130+
}
131+
104132
private companion object {
105133
const val BUILD_VERSION = "1.7.40"
106134

app/src/test/kotlin/com/android/contacts/ui/settings/screen/settingsviewmodel/BaseSettingsViewModelTest.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import com.android.contacts.tests.MainDispatcherRule
1212
import com.android.contacts.ui.settings.screen.SettingsViewModel
1313
import com.android.contacts.ui.settings.screen.mapper.SettingsUiStateMapper
1414
import com.android.contacts.ui.settings.screen.model.SettingsUiState
15-
import io.mockk.coEvery
1615
import io.mockk.every
1716
import io.mockk.mockk
1817
import kotlinx.coroutines.ExperimentalCoroutinesApi
18+
import kotlinx.coroutines.flow.Flow
1919
import kotlinx.coroutines.flow.MutableSharedFlow
2020
import kotlinx.coroutines.flow.MutableStateFlow
21+
import kotlinx.coroutines.flow.flowOf
2122
import org.junit.Before
2223
import org.junit.Rule
2324

@@ -36,6 +37,7 @@ internal abstract class BaseSettingsViewModelTest {
3637

3738
protected val settingsData = mockk<SettingsData>()
3839
protected val reloadedSettingsData = mockk<SettingsData>()
40+
protected var settingsDataSource: Flow<SettingsData> = flowOf(settingsData)
3941
protected val mappedState = SettingsUiState(sortOrder = SortOrder.GIVEN_NAME_FIRST)
4042
protected val reloadedState = SettingsUiState(sortOrder = SortOrder.FAMILY_NAME_FIRST)
4143

@@ -44,7 +46,7 @@ internal abstract class BaseSettingsViewModelTest {
4446

4547
@Before
4648
fun setUpDefaultStubs() {
47-
coEvery { getSettingsData() } returns settingsData
49+
every { getSettingsData() } answers { settingsDataSource }
4850
every { profileRepository.observeProfile() } returns profiles
4951
every { simImportResultRepository.observeSimImportResults() } returns simImportResults
5052
every { settingsUiStateMapper.map(settingsData = settingsData, profile = any()) } returns

app/src/test/kotlin/com/android/contacts/ui/settings/screen/settingsviewmodel/SettingsViewModelActionTest.kt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import com.android.contacts.data.settings.model.SortOrder
88
import com.android.contacts.ui.settings.screen.model.SettingsAction as Action
99
import com.android.contacts.ui.settings.screen.model.SettingsEffect as Effect
1010
import com.android.contacts.ui.settings.screen.model.SettingsItemId
11-
import io.mockk.coEvery
11+
import com.android.contacts.ui.settings.screen.model.SettingsUiState
1212
import io.mockk.coVerify
13+
import io.mockk.every
1314
import kotlinx.coroutines.ExperimentalCoroutinesApi
15+
import kotlinx.coroutines.launch
1416
import kotlinx.coroutines.test.advanceUntilIdle
1517
import kotlinx.coroutines.test.runTest
1618
import org.junit.Assert.assertEquals
@@ -96,6 +98,7 @@ internal class SettingsViewModelActionTest : BaseSettingsViewModelTest() {
9698
fun onAction_whenMyInfoClickedWithProfile_opensIt() =
9799
runTest(context = mainDispatcherRule.testDispatcher) {
98100
profiles.value = ProfileData(hasProfile = true, contactId = 7L)
101+
99102
val viewModel = createViewModel()
100103
advanceUntilIdle()
101104

@@ -111,6 +114,7 @@ internal class SettingsViewModelActionTest : BaseSettingsViewModelTest() {
111114
fun onAction_whenMyInfoClickedWithoutProfile_offersToCreateIt() =
112115
runTest(context = mainDispatcherRule.testDispatcher) {
113116
profiles.value = ProfileData(hasProfile = false, contactId = 7L)
117+
114118
val viewModel = createViewModel()
115119
advanceUntilIdle()
116120

@@ -139,21 +143,15 @@ internal class SettingsViewModelActionTest : BaseSettingsViewModelTest() {
139143
}
140144

141145
@Test
142-
fun onAction_whenSortOrderSelected_storesItAndReloads() =
146+
fun onAction_whenSortOrderSelected_storesIt() =
143147
runTest(context = mainDispatcherRule.testDispatcher) {
144148
val viewModel = createViewModel()
145-
viewModel.uiState.test {
146-
advanceUntilIdle()
147149

148-
coEvery { getSettingsData() } returns reloadedSettingsData
149-
viewModel.onAction(Action.SortOrderSelected(SortOrder.FAMILY_NAME_FIRST))
150-
advanceUntilIdle()
150+
viewModel.onAction(Action.SortOrderSelected(SortOrder.FAMILY_NAME_FIRST))
151+
advanceUntilIdle()
151152

152-
coVerify(exactly = 1) {
153-
displaySettingsRepository.setSortOrder(SortOrder.FAMILY_NAME_FIRST)
154-
}
155-
assertEquals(reloadedState, expectMostRecentItem())
156-
cancelAndIgnoreRemainingEvents()
153+
coVerify(exactly = 1) {
154+
displaySettingsRepository.setSortOrder(SortOrder.FAMILY_NAME_FIRST)
157155
}
158156
}
159157

@@ -198,4 +196,8 @@ internal class SettingsViewModelActionTest : BaseSettingsViewModelTest() {
198196
cancelAndIgnoreRemainingEvents()
199197
}
200198
}
199+
200+
private companion object {
201+
const val BUILD_VERSION = "1.7.40"
202+
}
201203
}

0 commit comments

Comments
 (0)