Skip to content

Commit 660de61

Browse files
authored
Prioritize domain matches when searching passwords (#7164)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1203822806345703/task/1209279523573208?focus=true ### Description When searching passwords, surface items with domains matching the search query as suggested items ### Steps to test this PR _Pre-rquisites_ - [ ] Apply [patch](https://app.asana.com/app/asana/-/get_asset?asset_id=1212005991463752) - [ ] Go to Settings > Autofill dev settings > Add a few sample logins (patch will create some usernames for example.com and logins for other sites using an example.com address) _Feature 1_ - [ ] Enable `autofill.prioritizeDomainMatchesOnSearch` (enabled by default for internal) - [ ] Go to Settings > Passwords & Autofill > Passwords - [ ] Check there are no suggested items - [ ] Click search icon and type "exam" - [ ] Check login items for "cris@example.com" and "cristina@example.com" appear as suggested _Feature 2_ - [ ] Enable `autofill.prioritizeDomainMatchesOnSearch` (enabled by default for internal) - [ ] Navigate to example.com - [ ] Access "Passwords" from the overflow menu, not settings - [ ] Check login items for "cris@example.com" and "cristina@example.com" appear as suggested - [ ] Click search icon and type "exam" - [ ] Check login items for "cris@example.com" and "cristina@example.com" appear as suggested - [ ] Delete query and type "cristina" - [ ] Check only login item for "cristina@example.com" appears as suggested _Feature 3_ - [ ] Disable `autofill.prioritizeDomainMatchesOnSearch` - [ ] Go to Settings > Passwords & Autofill > Passwords - [ ] Check there are no suggested items - [ ] Click search icon and type "exam" - [ ] Check there are no suggested items _Feature 4_ - [ ] Disable `autofill.prioritizeDomainMatchesOnSearch` - [ ] Navigate to example.com - [ ] Access "Passwords" from the overflow menu, not settings - [ ] Check login items for "cris@example.com" and "cristina@example.com" appear as suggested - [ ] Click search icon and type "exam" - [ ] Check login items for "cris@example.com" and "cristina@example.com" appear as suggested - [ ] Delete query and type "cristina" - [ ] Check only login item for "cristina@example.com" appears as suggested ### UI changes | Before | After | | ------ | ----- | !(Upload before screenshot)|(Upload after screenshot)|
1 parent 81ccf1e commit 660de61

File tree

8 files changed

+139
-35
lines changed

8 files changed

+139
-35
lines changed

autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillFeature.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,7 @@ interface AutofillFeature {
176176

177177
@Toggle.DefaultValue(defaultValue = DefaultFeatureValue.TRUE)
178178
fun canDetectSystemAutofillEngagement(): Toggle
179+
180+
@Toggle.DefaultValue(defaultValue = DefaultFeatureValue.TRUE)
181+
fun prioritizeDomainMatchesOnSearch(): Toggle
179182
}

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/service/AutofillSimpleCredentialsListFragment.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,12 @@ class AutofillSimpleCredentialsListFragment : DuckDuckGoFragment(R.layout.fragme
231231
logcat(INFO) { "DDGAutofillService showSuggestionsFor: $showSuggestionsFor" }
232232
val directSuggestions = suggestionMatcher.getDirectSuggestions(showSuggestionsFor, credentials)
233233
val shareableCredentials = suggestionMatcher.getShareableSuggestions(showSuggestionsFor)
234-
val directSuggestionsListItems = suggestionListBuilder.build(directSuggestions, shareableCredentials, allowBreakageReporting = false)
234+
val directSuggestionsListItems = suggestionListBuilder.build(
235+
unsortedQuerySuggestions = listOf(),
236+
unsortedDirectSuggestions = directSuggestions,
237+
unsortedSharableSuggestions = shareableCredentials,
238+
allowBreakageReporting = false,
239+
)
235240
val groupedCredentials = credentialGrouper.group(credentials)
236241

237242
withContext(dispatchers.main()) {

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/ui/credential/management/AutofillPasswordsManagementViewModel.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,10 @@ class AutofillPasswordsManagementViewModel @Inject constructor(
428428
fun onViewCreated() {
429429
if (combineJob != null) return
430430
combineJob = viewModelScope.launch(dispatchers.io()) {
431-
_viewState.value = _viewState.value.copy(autofillEnabled = autofillStore.autofillEnabled)
431+
_viewState.value = _viewState.value.copy(
432+
autofillEnabled = autofillStore.autofillEnabled,
433+
prioritizeDomainMatchesOnSearch = autofillFeature.prioritizeDomainMatchesOnSearch().isEnabled(),
434+
)
432435

433436
val allCredentials = autofillStore.getAllCredentials().distinctUntilChanged()
434437
val combined = allCredentials.combine(searchQueryFilter) { credentials, filter ->
@@ -820,6 +823,7 @@ class AutofillPasswordsManagementViewModel @Inject constructor(
820823
val reportBreakageState: ReportBreakageState = ReportBreakageState(),
821824
val canShowPromo: Boolean = false,
822825
val canImportFromGooglePasswords: Boolean = false,
826+
val prioritizeDomainMatchesOnSearch: Boolean = false,
823827
)
824828

825829
data class ReportBreakageState(

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/ui/credential/management/suggestion/SuggestionListBuilder.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,21 @@ class SuggestionListBuilder @Inject constructor(
3232
) {
3333

3434
fun build(
35+
unsortedQuerySuggestions: List<LoginCredentials>,
3536
unsortedDirectSuggestions: List<LoginCredentials>,
3637
unsortedSharableSuggestions: List<LoginCredentials>,
3738
allowBreakageReporting: Boolean,
3839
): List<ListItem> {
3940
val list = mutableListOf<ListItem>()
4041

41-
if (unsortedDirectSuggestions.isNotEmpty() || unsortedSharableSuggestions.isNotEmpty()) {
42+
if (unsortedQuerySuggestions.isNotEmpty() || unsortedDirectSuggestions.isNotEmpty() || unsortedSharableSuggestions.isNotEmpty()) {
4243
list.add(GroupHeading(context.getString(string.credentialManagementSuggestionsLabel)))
4344

45+
val sortedQuerySuggestions = sorter.sort(unsortedQuerySuggestions)
4446
val sortedDirectSuggestions = sorter.sort(unsortedDirectSuggestions)
4547
val sortedSharableSuggestions = sorter.sort(unsortedSharableSuggestions)
4648

47-
val allSuggestions = sortedDirectSuggestions + sortedSharableSuggestions
49+
val allSuggestions = (sortedQuerySuggestions + sortedDirectSuggestions + sortedSharableSuggestions).distinct()
4850
list.addAll(allSuggestions.map { SuggestedCredential(it) })
4951

5052
if (allowBreakageReporting) {

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/ui/credential/management/suggestion/SuggestionMatcher.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ class SuggestionMatcher @Inject constructor(
4545
}
4646
}
4747

48+
fun getQuerySuggestions(
49+
query: String?,
50+
credentials: List<LoginCredentials>,
51+
): List<LoginCredentials> {
52+
if (query.isNullOrBlank()) return emptyList()
53+
return credentials.filter { it.domain?.contains(query, ignoreCase = true) == true }
54+
}
55+
4856
/**
4957
* Returns a list of credentials that are not a direct match for the current URL, but are considered shareable.
5058
*/

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/ui/credential/management/viewing/AutofillManagementListMode.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
322322
canShowImportGooglePasswordsButton = state.canImportFromGooglePasswords,
323323
showAutofillToggle = state.showAutofillEnabledToggle,
324324
promotionView = promotionView,
325+
query = state.credentialSearchQuery,
326+
prioritizeDomainMatchesOnSearch = state.prioritizeDomainMatchesOnSearch,
325327
)
326328
parentActivity()?.invalidateOptionsMenu()
327329
}
@@ -413,6 +415,8 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
413415
canShowImportGooglePasswordsButton: Boolean,
414416
showAutofillToggle: Boolean,
415417
promotionView: View?,
418+
query: String,
419+
prioritizeDomainMatchesOnSearch: Boolean,
416420
) {
417421
if (credentials == null) {
418422
logcat(VERBOSE) { "Credentials is null, meaning we haven't retrieved them yet. Don't know if empty or not yet" }
@@ -423,12 +427,16 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
423427
autofillEnabled = viewModel.viewState.value.autofillEnabled,
424428
promotionView = promotionView,
425429
showGoogleImportPasswordsButton = canShowImportGooglePasswordsButton,
430+
query = query,
431+
prioritizeDomainMatchesOnSearch = prioritizeDomainMatchesOnSearch,
426432
)
427433
} else if (credentials.isEmpty() && credentialSearchQuery.isEmpty()) {
428434
showEmptyCredentialsPlaceholders(
429435
canShowImportGooglePasswordsButton = canShowImportGooglePasswordsButton,
430436
showAutofillToggle = showAutofillToggle,
431437
promotionView = promotionView,
438+
query = query,
439+
prioritizeDomainMatchesOnSearch = prioritizeDomainMatchesOnSearch,
432440
)
433441
} else if (credentials.isEmpty()) {
434442
showNoResultsPlaceholders(credentialSearchQuery)
@@ -440,6 +448,8 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
440448
autofillEnabled = viewModel.viewState.value.autofillEnabled,
441449
promotionView = promotionView,
442450
showGoogleImportPasswordsButton = canShowImportGooglePasswordsButton,
451+
query = query,
452+
prioritizeDomainMatchesOnSearch = prioritizeDomainMatchesOnSearch,
443453
)
444454
}
445455
}
@@ -452,6 +462,8 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
452462
canShowImportGooglePasswordsButton: Boolean,
453463
showAutofillToggle: Boolean,
454464
promotionView: View?,
465+
query: String,
466+
prioritizeDomainMatchesOnSearch: Boolean,
455467
) {
456468
renderCredentialList(
457469
credentials = emptyList(),
@@ -460,6 +472,8 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
460472
autofillEnabled = viewModel.viewState.value.autofillEnabled,
461473
promotionView = promotionView,
462474
showGoogleImportPasswordsButton = canShowImportGooglePasswordsButton,
475+
query = query,
476+
prioritizeDomainMatchesOnSearch = prioritizeDomainMatchesOnSearch,
463477
)
464478

465479
if (canShowImportGooglePasswordsButton) {
@@ -474,16 +488,24 @@ class AutofillManagementListMode : DuckDuckGoFragment(R.layout.fragment_autofill
474488
autofillEnabled: Boolean,
475489
promotionView: View?,
476490
showGoogleImportPasswordsButton: Boolean,
491+
query: String,
492+
prioritizeDomainMatchesOnSearch: Boolean,
477493
) {
478494
withContext(dispatchers.io()) {
479495
val currentUrl = getCurrentSiteUrl()
480-
481496
val credentialLoadingState = if (credentials == null) {
482497
Loading
483498
} else {
499+
val querySuggestions =
500+
if (prioritizeDomainMatchesOnSearch) { suggestionMatcher.getQuerySuggestions(query, credentials) } else emptyList()
484501
val directSuggestions = suggestionMatcher.getDirectSuggestions(currentUrl, credentials)
485502
val shareableCredentials = suggestionMatcher.getShareableSuggestions(currentUrl)
486-
val directSuggestionsListItems = suggestionListBuilder.build(directSuggestions, shareableCredentials, allowBreakageReporting)
503+
val directSuggestionsListItems = suggestionListBuilder.build(
504+
querySuggestions,
505+
directSuggestions,
506+
shareableCredentials,
507+
allowBreakageReporting,
508+
)
487509
val groupedCredentials = grouper.group(credentials)
488510

489511
val hasSuggestions = directSuggestions.isNotEmpty() || shareableCredentials.isNotEmpty()

autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/ui/credential/management/suggestion/SuggestionListBuilderTest.kt

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import androidx.test.platform.app.InstrumentationRegistry
2121
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
2222
import com.duckduckgo.autofill.impl.encoding.TestUrlUnicodeNormalizer
2323
import com.duckduckgo.autofill.impl.ui.credential.management.sorting.CredentialListSorterByTitleAndDomain
24+
import com.duckduckgo.autofill.impl.ui.credential.management.suggestion.SuggestionListBuilderTest.Type.DIRECT
25+
import com.duckduckgo.autofill.impl.ui.credential.management.suggestion.SuggestionListBuilderTest.Type.QUERY
26+
import com.duckduckgo.autofill.impl.ui.credential.management.suggestion.SuggestionListBuilderTest.Type.SHAREABLE
2427
import com.duckduckgo.autofill.impl.ui.credential.management.viewing.list.ListItem
2528
import com.duckduckgo.autofill.impl.ui.credential.management.viewing.list.ListItem.CredentialListItem.SuggestedCredential
2629
import com.duckduckgo.autofill.impl.urlmatcher.AutofillDomainNameUrlMatcher
@@ -39,95 +42,144 @@ class SuggestionListBuilderTest {
3942

4043
@Test
4144
fun whenNoSuggestionThenEmptyListReturned() {
42-
assertTrue(testee.build(emptyList(), emptyList(), allowBreakageReporting = false).isEmpty())
45+
assertTrue(testee.build(emptyList(), emptyList(), emptyList(), allowBreakageReporting = false).isEmpty())
4346
}
4447

4548
@Test
4649
fun whenOneDirectSuggestionThenDividerAddedLast() {
47-
val suggestions = buildSuggestions(1)
48-
val list = testee.build(suggestions, emptyList(), allowBreakageReporting = false)
50+
val suggestions = buildSuggestions(1, type = DIRECT)
51+
val list = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false)
52+
assertTrue(list.last() is ListItem.Divider)
53+
}
54+
55+
@Test
56+
fun whenOneQuerySuggestionThenDividerAddedLast() {
57+
val suggestions = buildSuggestions(1, type = QUERY)
58+
val list = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false)
4959
assertTrue(list.last() is ListItem.Divider)
5060
}
5161

5262
@Test
5363
fun whenTwoDirectSuggestionsThenDividerAddedLast() {
54-
val suggestions = buildSuggestions(2)
55-
val list = testee.build(suggestions, emptyList(), allowBreakageReporting = false)
64+
val suggestions = buildSuggestions(2, type = DIRECT)
65+
val list = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false)
5666
assertTrue(list.last() is ListItem.Divider)
5767
}
5868

5969
@Test
6070
fun whenOneDirectSuggestionThenCorrectNumberOfListItemsReturned() {
61-
val suggestions = buildSuggestions(1)
62-
val list = testee.build(suggestions, emptyList(), allowBreakageReporting = false)
71+
val suggestions = buildSuggestions(1, type = DIRECT)
72+
val list = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false)
6373
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + suggestions.size, list.size)
6474
}
6575

6676
@Test
6777
fun whenTwoDirectSuggestionsThenCorrectNumberOfListItemsReturned() {
68-
val suggestions = buildSuggestions(2)
69-
val list = testee.build(suggestions, emptyList(), allowBreakageReporting = false)
78+
val suggestions = buildSuggestions(2, type = DIRECT)
79+
val list = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false)
7080
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + suggestions.size, list.size)
7181
}
7282

7383
@Test
7484
fun whenTenDirectSuggestionsThenThirteenListItemsReturned() {
75-
val suggestions = buildSuggestions(10)
76-
val list = testee.build(suggestions, emptyList(), allowBreakageReporting = false)
85+
val suggestions = buildSuggestions(10, type = DIRECT)
86+
val list = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false)
7787
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + suggestions.size, list.size)
7888
}
7989

8090
@Test
8191
fun whenDirectSuggestionAddedThenGroupNameIsCorrect() {
82-
val suggestions = buildSuggestions(1)
83-
val heading = testee.build(suggestions, emptyList(), allowBreakageReporting = false).first()
92+
val suggestions = buildSuggestions(1, type = DIRECT)
93+
val heading = testee.build(emptyList(), suggestions, emptyList(), allowBreakageReporting = false).first()
8494
assertTrue(heading is ListItem.GroupHeading)
8595
}
8696

8797
@Test
8898
fun whenNoDirectSuggestionsButOneShareableThenCorrectNumberOfListItemsReturned() {
89-
val suggestions = buildSuggestions(1)
90-
val list = testee.build(emptyList(), suggestions, allowBreakageReporting = false)
99+
val suggestions = buildSuggestions(1, type = DIRECT)
100+
val list = testee.build(emptyList(), emptyList(), suggestions, allowBreakageReporting = false)
91101
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + suggestions.size, list.size)
92102
}
93103

94104
@Test
95105
fun whenNoDirectSuggestionsButMultipleShareableThenCorrectNumberOfListItemsReturned() {
96-
val suggestions = buildSuggestions(10)
97-
val list = testee.build(emptyList(), suggestions, allowBreakageReporting = false)
106+
val suggestions = buildSuggestions(10, type = DIRECT)
107+
val list = testee.build(emptyList(), emptyList(), suggestions, allowBreakageReporting = false)
98108
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + suggestions.size, list.size)
99109
}
100110

101111
@Test
102112
fun whenOneDirectAndOneShareableThenDirectSuggestionsAppearFirst() {
103-
val directSuggestions = buildSuggestions(1)
104-
val sharableSuggestions = buildSuggestions(1, startingIndex = directSuggestions.size)
105-
val list = testee.build(directSuggestions, sharableSuggestions, allowBreakageReporting = false)
113+
val directSuggestions = buildSuggestions(1, type = DIRECT)
114+
val sharableSuggestions = buildSuggestions(1, startingIndex = directSuggestions.size, type = SHAREABLE)
115+
val list = testee.build(emptyList(), directSuggestions, sharableSuggestions, allowBreakageReporting = false)
106116
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + directSuggestions.size + sharableSuggestions.size, list.size)
107117
assertTrue(list[0] is ListItem.GroupHeading)
108-
assertEquals(0L, (list[1] as SuggestedCredential).credentials.id)
109-
assertEquals(1L, (list[2] as SuggestedCredential).credentials.id)
118+
assertEquals(DIRECT.name, (list[1] as SuggestedCredential).credentials.username)
119+
assertEquals(SHAREABLE.name, (list[2] as SuggestedCredential).credentials.username)
120+
}
121+
122+
@Test
123+
fun whenOneQueryAndOneDirectAndOneShareableThenQuerySuggestionsAppearFirst() {
124+
val querySuggestions = buildSuggestions(1, type = QUERY)
125+
val directSuggestions = buildSuggestions(1, startingIndex = querySuggestions.size, type = DIRECT)
126+
val sharableSuggestions = buildSuggestions(1, startingIndex = querySuggestions.size + directSuggestions.size, type = SHAREABLE)
127+
val list = testee.build(querySuggestions, directSuggestions, sharableSuggestions, allowBreakageReporting = false)
128+
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + querySuggestions.size + directSuggestions.size + sharableSuggestions.size, list.size)
129+
assertTrue(list[0] is ListItem.GroupHeading)
130+
assertEquals(QUERY.name, (list[1] as SuggestedCredential).credentials.username)
131+
assertEquals(DIRECT.name, (list[2] as SuggestedCredential).credentials.username)
132+
assertEquals(SHAREABLE.name, (list[3] as SuggestedCredential).credentials.username)
133+
}
134+
135+
@Test
136+
fun whenOneQueryAndOneDirectWithDuplicatesThenRemoveDuplicates() {
137+
val credential = aCredential(username = "test")
138+
val querySuggestions = listOf(credential)
139+
val directSuggestions = listOf(credential)
140+
val sharableSuggestions = emptyList<LoginCredentials>()
141+
val list = testee.build(querySuggestions, directSuggestions, sharableSuggestions, allowBreakageReporting = false)
142+
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + 1, list.size)
110143
}
111144

112145
@Test
113146
fun whenMultipleDirectAndSomeShareableThenDirectSuggestionsAppearFirst() {
114-
val directSuggestions = buildSuggestions(10, isShareable = false)
115-
val sharableSuggestions = buildSuggestions(1, isShareable = true, startingIndex = directSuggestions.size)
116-
val list = testee.build(directSuggestions, sharableSuggestions, allowBreakageReporting = false)
147+
val directSuggestions = buildSuggestions(10, type = DIRECT)
148+
val sharableSuggestions = buildSuggestions(1, type = SHAREABLE, startingIndex = directSuggestions.size)
149+
val list = testee.build(emptyList(), directSuggestions, sharableSuggestions, allowBreakageReporting = false)
117150
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + directSuggestions.size + sharableSuggestions.size, list.size)
118151
assertTrue(list[0] is ListItem.GroupHeading)
119-
assertEquals("direct", (list[1] as SuggestedCredential).credentials.username)
120-
assertEquals("shareable", (list[11] as SuggestedCredential).credentials.username)
152+
assertEquals(DIRECT.name, (list[1] as SuggestedCredential).credentials.username)
153+
assertEquals(SHAREABLE.name, (list[11] as SuggestedCredential).credentials.username)
154+
}
155+
156+
@Test
157+
fun whenMultipleQueryAndMultipleDirectAndSomeShareableThenQuerySuggestionsAppearFirst() {
158+
val querySuggestions = buildSuggestions(10, type = QUERY)
159+
val directSuggestions = buildSuggestions(10, type = DIRECT, startingIndex = querySuggestions.size)
160+
val sharableSuggestions = buildSuggestions(1, type = SHAREABLE, startingIndex = querySuggestions.size + directSuggestions.size)
161+
val list = testee.build(querySuggestions, directSuggestions, sharableSuggestions, allowBreakageReporting = false)
162+
assertEquals(NUM_SUGGESTION_HEADERS + NUM_DIVIDERS + querySuggestions.size + directSuggestions.size + sharableSuggestions.size, list.size)
163+
assertTrue(list[0] is ListItem.GroupHeading)
164+
assertEquals(QUERY.name, (list[1] as SuggestedCredential).credentials.username)
165+
assertEquals(DIRECT.name, (list[11] as SuggestedCredential).credentials.username)
166+
assertEquals(SHAREABLE.name, (list[21] as SuggestedCredential).credentials.username)
121167
}
122168

123-
private fun buildSuggestions(listSize: Int, startingIndex: Int = 0, isShareable: Boolean = false): List<LoginCredentials> {
169+
private fun buildSuggestions(listSize: Int, startingIndex: Int = 0, type: Type): List<LoginCredentials> {
124170
val list = mutableListOf<LoginCredentials>()
125171
for (i in 0 until listSize) {
126-
list.add(aCredential(id = startingIndex + i.toLong(), username = if (isShareable) "shareable" else "direct"))
172+
list.add(aCredential(id = startingIndex + i.toLong(), username = type.name))
127173
}
128174
return list
129175
}
130176

177+
private enum class Type {
178+
QUERY,
179+
DIRECT,
180+
SHAREABLE,
181+
}
182+
131183
private fun aCredential(id: Long = 0, username: String): LoginCredentials {
132184
return LoginCredentials(id = id, domain = null, password = null, username = username)
133185
}

0 commit comments

Comments
 (0)