Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Closes #2368: SearchSuggestionProvider: Allow setting a limit.
Browse files Browse the repository at this point in the history
  • Loading branch information
pocmo committed Mar 20, 2019
1 parent 4ed62a9 commit 72dc75b
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ class AwesomeBarFeature(
searchEngine: SearchEngine,
searchUseCase: SearchUseCases.SearchUseCase,
fetchClient: Client,
limit: Int = 15,
mode: SearchSuggestionProvider.Mode = SearchSuggestionProvider.Mode.SINGLE_SUGGESTION
): AwesomeBarFeature {
awesomeBar.addProviders(SearchSuggestionProvider(searchEngine, searchUseCase, fetchClient, mode))
awesomeBar.addProviders(SearchSuggestionProvider(searchEngine, searchUseCase, fetchClient, limit, mode))
return this
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ import java.util.concurrent.TimeUnit
/**
* A [AwesomeBar.SuggestionProvider] implementation that provides a suggestion containing search engine suggestions (as
* chips) from the passed in [SearchEngine].
*
* @param searchEngine The search engine to request suggestions from.
* @param searchUseCase The use case to invoke for searches.
* @param fetchClient The HTTP client for requesting suggestions from the search engine.
* @param limit The maximum number of suggestions that should be returned.
* @param mode Whether to return a single search suggestion (with chips) or one suggestion per item.
*/
class SearchSuggestionProvider(
private val searchEngine: SearchEngine,
private val searchUseCase: SearchUseCases.SearchUseCase,
private val fetchClient: Client,
private val limit: Int = 15,
private val mode: Mode = Mode.SINGLE_SUGGESTION
) : AwesomeBar.SuggestionProvider {
override val id: String = UUID.randomUUID().toString()
Expand Down Expand Up @@ -78,7 +85,7 @@ class SearchSuggestionProvider(
list.add(0, text)
}

list.forEachIndexed { index, item ->
list.take(limit).forEachIndexed { index, item ->
suggestions.add(AwesomeBar.Suggestion(
provider = this,
// We always use the same ID for the entered text so that this suggestion gets replaced "in place".
Expand Down Expand Up @@ -106,7 +113,7 @@ class SearchSuggestionProvider(
chips.add(AwesomeBar.Suggestion.Chip(text))
}

result?.forEach { title ->
result?.take(limit - chips.size)?. forEach { title ->
chips.add(AwesomeBar.Suggestion.Chip(title))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package mozilla.components.feature.awesomebar.provider

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.search.SearchEngine
Expand Down Expand Up @@ -34,6 +36,9 @@ private const val GOOGLE_MOCK_RESPONSE = "[\"firefox\",[\"firefox\",\"firefox fo

@RunWith(RobolectricTestRunner::class)
class SearchSuggestionProviderTest {
private val context: Context
get() = ApplicationProvider.getApplicationContext()

@Test
fun `Provider returns suggestion with chips based on search engine suggestion`() {
runBlocking {
Expand Down Expand Up @@ -117,7 +122,7 @@ class SearchSuggestionProviderTest {
searchEngine,
useCase,
HttpURLConnectionClient(),
SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS
)

try {
Expand Down Expand Up @@ -150,6 +155,99 @@ class SearchSuggestionProviderTest {
}
}

@Test
fun `Provider returns multiple suggestions with limit`() {
runBlocking {
val server = MockWebServer()
server.enqueue(MockResponse().setBody(GOOGLE_MOCK_RESPONSE))
server.start()

val searchEngine: SearchEngine = mock()
doReturn(server.url("/").toString())
.`when`(searchEngine).buildSuggestionsURL("fire")
doReturn(true).`when`(searchEngine).canProvideSearchSuggestions
doReturn("google").`when`(searchEngine).name

val searchEngineManager: SearchEngineManager = mock()
doReturn(searchEngine).`when`(searchEngineManager).getDefaultSearchEngine(any(), any())

val useCase = spy(SearchUseCases(
RuntimeEnvironment.application,
searchEngineManager,
SessionManager(mock()).apply { add(Session("https://www.mozilla.org")) }
).defaultSearch)
doNothing().`when`(useCase).invoke(anyString(), any<Session>(), any<SearchEngine>())

val provider = SearchSuggestionProvider(
searchEngine,
useCase,
HttpURLConnectionClient(),
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS,
limit = 5
)

try {
val suggestions = provider.onInputChanged("fire")

println(suggestions)

assertEquals(5, suggestions.size)

assertEquals("fire", suggestions[0].title)
assertEquals("firefox", suggestions[1].title)
assertEquals("firefox for mac", suggestions[2].title)
assertEquals("firefox quantum", suggestions[3].title)
assertEquals("firefox update", suggestions[4].title)
} finally {
server.shutdown()
}
}
}

@Test
fun `Provider returns chips with limit`() {
runBlocking {
val server = MockWebServer()
server.enqueue(MockResponse().setBody(GOOGLE_MOCK_RESPONSE))
server.start()

val searchEngine: SearchEngine = mock()
doReturn(server.url("/").toString())
.`when`(searchEngine).buildSuggestionsURL("fire")
doReturn(true).`when`(searchEngine).canProvideSearchSuggestions
doReturn("google").`when`(searchEngine).name

val searchEngineManager: SearchEngineManager = mock()
doReturn(searchEngine).`when`(searchEngineManager).getDefaultSearchEngine(any(), any())

val useCase = spy(SearchUseCases(
RuntimeEnvironment.application,
searchEngineManager,
SessionManager(mock()).apply { add(Session("https://www.mozilla.org")) }
).defaultSearch)
doNothing().`when`(useCase).invoke(anyString(), any<Session>(), any<SearchEngine>())

val provider =
SearchSuggestionProvider(searchEngine, useCase, HttpURLConnectionClient(), limit = 5)

try {
val suggestions = provider.onInputChanged("fire")
assertEquals(1, suggestions.size)

val suggestion = suggestions[0]
assertEquals(5, suggestion.chips.size)

assertEquals("fire", suggestion.chips[0].title)
assertEquals("firefox", suggestion.chips[1].title)
assertEquals("firefox for mac", suggestion.chips[2].title)
assertEquals("firefox quantum", suggestion.chips[3].title)
assertEquals("firefox update", suggestion.chips[4].title)
} finally {
server.shutdown()
}
}
}

@Test
fun `Provider should not clear suggestions`() {
val provider = SearchSuggestionProvider(mock(), mock(), mock())
Expand Down
3 changes: 3 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ permalink: /changelog/
* Saving, restoring and removing `SessionBundle` instances need to happen on a worker thread now (off the main thread).
* The actual session state is now saved on the file system outside of the internally used SQLite database.

* **feature-awesomebar**
* `SearchSuggestionProvider` and `AwesomeBarFeature` now allow setting a search suggestion limit.

* **support-ktx**
* Added `File.truncateDirectory()` to remove all files (and sub directories) in a directory.
* Added `Activity.applyOrientation(manifest: WebAppManifest)` extension method for applying orientation modes #2291.
Expand Down

0 comments on commit 72dc75b

Please sign in to comment.