Commit 1acebe1b authored by Denys M's avatar Denys M Committed by Sebastian Kaspari
Browse files

For #2346. Enable kotlin warningsAsErrors for `browser-domains` module.

- Refactor `ShippedDomainsProvider` and `CustomDomainsProvider`. Using
composition instead of inheritance.
- Add tests for `BaseDomainAutocompleteProvider`.
parent 825430af
......@@ -11,7 +11,5 @@ object KotlinCompiler {
// KotlinCompile task dependencies available to buildSrc so we settle for defining this list here instead.
// Maybe this is easier in Gradle 5+.
@JvmStatic
val projectsWithWarningsAsErrorsDisabled = setOf(
"browser-domains"
)
val projectsWithWarningsAsErrorsDisabled = setOf()
}
......@@ -27,6 +27,8 @@ dependencies {
implementation Dependencies.kotlin_stdlib
implementation Dependencies.kotlin_coroutines
testImplementation project(':support-test')
testImplementation Dependencies.testing_junit
testImplementation Dependencies.testing_robolectric
testImplementation Dependencies.testing_mockito
......
......@@ -17,8 +17,12 @@ import java.util.Locale
* [CustomDomains].
*/
// FIXME delete this https://github.com/mozilla-mobile/android-components/issues/1358
@Deprecated("Use [Providers.ShippedDomainsProvider] or [Providers.CustomDomainsProvider]")
@Deprecated("Use `ShippedDomainsProvider` or `CustomDomainsProvider`",
ReplaceWith("ShippedDomainsProvider()/CustomDomainsProvider()",
"mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider",
"mozilla.components.browser.domains.autocomplete.CustomDomainsProvider"))
class DomainAutoCompleteProvider {
object AutocompleteSource {
const val DEFAULT_LIST = "default"
const val CUSTOM_LIST = "custom"
......
......@@ -23,40 +23,42 @@ enum class DomainList(val listName: String) {
/**
* Provides autocomplete functionality for domains based on provided list of assets (see [Domains]).
*/
class ShippedDomainsProvider : BaseDomainAutocompleteProvider(DomainList.DEFAULT) {
override fun initialize(context: Context) {
scope.launch {
domains = async { Domains.load(context).into() }.await()
}
}
}
class ShippedDomainsProvider : BaseDomainAutocompleteProvider(DomainList.DEFAULT, Domains.asLoader())
/**
* Provides autocomplete functionality for domains based on a list managed by [CustomDomains].
*/
class CustomDomainsProvider : BaseDomainAutocompleteProvider(DomainList.CUSTOM) {
override fun initialize(context: Context) {
scope.launch {
domains = async { CustomDomains.load(context).into() }.await()
}
}
}
class CustomDomainsProvider : BaseDomainAutocompleteProvider(DomainList.CUSTOM, CustomDomains.asLoader())
interface DomainAutocompleteProvider {
fun getAutocompleteSuggestion(query: String): DomainAutocompleteResult?
}
typealias DomainsLoader = (Context) -> List<Domain>
private fun Domains.asLoader(): DomainsLoader = { context: Context -> load(context).into() }
private fun CustomDomains.asLoader(): DomainsLoader = { context: Context -> load(context).into() }
/**
* Provides common autocomplete functionality powered by domain lists.
*
* @param list source of domains
* @param domainsLoader provider for all available domains
*/
abstract class BaseDomainAutocompleteProvider(private val list: DomainList) :
DomainAutocompleteProvider {
internal val scope = CoroutineScope(Dispatchers.IO)
open class BaseDomainAutocompleteProvider(
private val list: DomainList,
private val domainsLoader: DomainsLoader
) : DomainAutocompleteProvider, CoroutineScope by CoroutineScope(Dispatchers.IO) {
// We compute 'domains' on the worker thread; make sure it's immediately visible on the UI thread.
@Volatile
var domains: List<Domain> = emptyList()
abstract fun initialize(context: Context)
fun initialize(context: Context) {
launch {
domains = async { domainsLoader(context) }.await()
}
}
/**
* Computes an autocomplete suggestion for the given text, and invokes the
......@@ -103,12 +105,12 @@ abstract class BaseDomainAutocompleteProvider(private val list: DomainList) :
* that exactly matches the search text - which is what this method is for:
*/
private fun getResultText(rawSearchText: String, autocomplete: String) =
rawSearchText + autocomplete.substring(rawSearchText.length)
rawSearchText + autocomplete.substring(rawSearchText.length)
}
/**
* Describes an autocompletion result against a list of domains.
* @property input Input for which this result is being provided.
* @property input Input for which this result is being provided.
* @property text Result of autocompletion, text to be displayed.
* @property url Result of autocompletion, full matching url.
* @property source Name of the autocompletion source.
......
package mozilla.components.browser.domains
import android.content.Context
import android.preference.PreferenceManager
import kotlinx.coroutines.Dispatchers
import mozilla.components.browser.domains.autocomplete.BaseDomainAutocompleteProvider
import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
import mozilla.components.browser.domains.autocomplete.DomainList
import mozilla.components.browser.domains.autocomplete.DomainsLoader
import mozilla.components.support.test.robolectric.testContext
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class BaseDomainAutocompleteProviderTest {
@After
fun tearDown() {
PreferenceManager.getDefaultSharedPreferences(testContext)
.edit()
.clear()
.apply()
}
@Test
fun `empty provider with DEFAULT list returns nothing`() {
val provider = createAndInitProvider(testContext, DomainList.DEFAULT) {
emptyList()
}
assertNoCompletion(provider, "m")
assertNoCompletion(provider, "mo")
assertNoCompletion(provider, "moz")
assertNoCompletion(provider, "g")
assertNoCompletion(provider, "go")
assertNoCompletion(provider, "goo")
assertNoCompletion(provider, "w")
assertNoCompletion(provider, "www")
}
@Test
fun `empty provider with CUSTOM list returns nothing`() {
val provider = createAndInitProvider(testContext, DomainList.CUSTOM) {
emptyList()
}
assertNoCompletion(provider, "m")
assertNoCompletion(provider, "mo")
assertNoCompletion(provider, "moz")
assertNoCompletion(provider, "g")
assertNoCompletion(provider, "go")
assertNoCompletion(provider, "goo")
assertNoCompletion(provider, "w")
assertNoCompletion(provider, "www")
}
@Test
fun `non-empty provider with DEFAULT list returns completion`() {
val domains = listOf("mozilla.org", "google.com", "facebook.com").into()
val list = DomainList.DEFAULT
val domainsCount = domains.size
val provider = createAndInitProvider(testContext, list) { domains }
assertCompletion(provider, list, domainsCount, "m", "m", "mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "moz", "moz", "mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "www", "www", "www.mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "www.face", "www.face", "www.facebook.com", "http://facebook.com")
assertCompletion(provider, list, domainsCount, "M", "m", "Mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "MOZ", "moz", "MOZilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "www.GOO", "www.goo", "www.GOOgle.com", "http://google.com")
assertCompletion(provider, list, domainsCount, "WWW.GOOGLE.", "www.google.", "WWW.GOOGLE.com", "http://google.com")
assertCompletion(provider, list, domainsCount, "www.facebook.com", "www.facebook.com", "www.facebook.com", "http://facebook.com")
assertCompletion(provider, list, domainsCount, "facebook.com", "facebook.com", "facebook.com", "http://facebook.com")
assertNoCompletion(provider, "wwww")
assertNoCompletion(provider, "yahoo")
}
@Test
fun `non-empty provider with CUSTOM list returns completion`() {
val domains = listOf("mozilla.org", "google.com", "facebook.com").into()
val list = DomainList.CUSTOM
val domainsCount = domains.size
val provider = createAndInitProvider(testContext, list) { domains }
assertCompletion(provider, list, domainsCount, "m", "m", "mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "moz", "moz", "mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "www", "www", "www.mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "www.face", "www.face", "www.facebook.com", "http://facebook.com")
assertCompletion(provider, list, domainsCount, "M", "m", "Mozilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "MOZ", "moz", "MOZilla.org", "http://mozilla.org")
assertCompletion(provider, list, domainsCount, "www.GOO", "www.goo", "www.GOOgle.com", "http://google.com")
assertCompletion(provider, list, domainsCount, "WWW.GOOGLE.", "www.google.", "WWW.GOOGLE.com", "http://google.com")
assertCompletion(provider, list, domainsCount, "www.facebook.com", "www.facebook.com", "www.facebook.com", "http://facebook.com")
assertCompletion(provider, list, domainsCount, "facebook.com", "facebook.com", "facebook.com", "http://facebook.com")
assertNoCompletion(provider, "wwww")
assertNoCompletion(provider, "yahoo")
}
}
private fun assertCompletion(
provider: DomainAutocompleteProvider,
domainSource: DomainList,
sourceSize: Int,
input: String,
expectedInput: String,
completion: String,
expectedUrl: String
) {
val result = provider.getAutocompleteSuggestion(input)!!
assertTrue("Autocompletion shouldn't be empty", result.text.isNotEmpty())
assertEquals("Autocompletion input", expectedInput, result.input)
assertEquals("Autocompletion completion", completion, result.text)
assertEquals("Autocompletion source list", domainSource.listName, result.source)
assertEquals("Autocompletion url", expectedUrl, result.url)
assertEquals("Autocompletion source list size", sourceSize, result.totalItems)
}
private fun assertNoCompletion(provider: DomainAutocompleteProvider, input: String) {
val result = provider.getAutocompleteSuggestion(input)
assertNull("Result should be null", result)
}
private fun createAndInitProvider(context: Context, list: DomainList, loader: DomainsLoader): DomainAutocompleteProvider =
object : BaseDomainAutocompleteProvider(list, loader) {
override val coroutineContext = super.coroutineContext + Dispatchers.Main
}.apply { initialize(context) }
\ No newline at end of file
......@@ -6,28 +6,28 @@ package mozilla.components.browser.domains
import android.content.Context
import kotlinx.coroutines.runBlocking
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
@RunWith(RobolectricTestRunner::class)
class CustomDomainsTest {
@Before
fun setUp() {
RuntimeEnvironment.application
.getSharedPreferences("custom_autocomplete", Context.MODE_PRIVATE)
.edit()
.clear()
.apply()
testContext.getSharedPreferences("custom_autocomplete", Context.MODE_PRIVATE)
.edit()
.clear()
.apply()
}
@Test
fun customListIsEmptyByDefault() {
val domains = runBlocking {
CustomDomains.load(RuntimeEnvironment.application)
CustomDomains.load(testContext)
}
assertEquals(0, domains.size)
......@@ -35,38 +35,38 @@ class CustomDomainsTest {
@Test
fun saveAndRemoveDomains() {
CustomDomains.save(RuntimeEnvironment.application, listOf(
"mozilla.org",
"example.org",
"example.com"
CustomDomains.save(testContext, listOf(
"mozilla.org",
"example.org",
"example.com"
))
var domains = CustomDomains.load(RuntimeEnvironment.application)
var domains = CustomDomains.load(testContext)
assertEquals(3, domains.size)
CustomDomains.remove(RuntimeEnvironment.application, listOf("example.org", "example.com"))
domains = CustomDomains.load(RuntimeEnvironment.application)
CustomDomains.remove(testContext, listOf("example.org", "example.com"))
domains = CustomDomains.load(testContext)
assertEquals(1, domains.size)
assertEquals("mozilla.org", domains.elementAt(0))
}
@Test
fun addAndLoadDomains() {
CustomDomains.add(RuntimeEnvironment.application, "mozilla.org")
val domains = CustomDomains.load(RuntimeEnvironment.application)
CustomDomains.add(testContext, "mozilla.org")
val domains = CustomDomains.load(testContext)
assertEquals(1, domains.size)
assertEquals("mozilla.org", domains.elementAt(0))
}
@Test
fun saveAndLoadDomains() {
CustomDomains.save(RuntimeEnvironment.application, listOf(
"mozilla.org",
"example.org",
"example.com"
CustomDomains.save(testContext, listOf(
"mozilla.org",
"example.org",
"example.com"
))
val domains = CustomDomains.load(RuntimeEnvironment.application)
val domains = CustomDomains.load(testContext)
assertEquals(3, domains.size)
assertEquals("mozilla.org", domains.elementAt(0))
......
......@@ -2,11 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@file:Suppress("DEPRECATION")
package mozilla.components.browser.domains
import android.preference.PreferenceManager
import mozilla.components.browser.domains.DomainAutoCompleteProvider.AutocompleteSource.CUSTOM_LIST
import mozilla.components.browser.domains.DomainAutoCompleteProvider.AutocompleteSource.DEFAULT_LIST
import mozilla.components.support.test.robolectric.testContext
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
......@@ -14,26 +17,31 @@ import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
/**
* While [DomainAutoCompleteProvider] exists (even if it's deprecated) we need to test it.
*/
@RunWith(RobolectricTestRunner::class)
class DomainAutoCompleteProviderTest {
@After
fun tearDown() {
PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application)
.edit()
.clear()
.apply()
PreferenceManager.getDefaultSharedPreferences(testContext)
.edit()
.clear()
.apply()
}
@Test
fun autocompletionWithShippedDomains() {
val provider = DomainAutoCompleteProvider()
provider.initialize(RuntimeEnvironment.application, true, false, false)
val provider = DomainAutoCompleteProvider().also {
it.initialize(testContext,
useShippedDomains = true, useCustomDomains = false,
loadDomainsFromDisk = false)
provider.shippedDomains = listOf("mozilla.org", "google.com", "facebook.com").into()
provider.customDomains = emptyList()
it.shippedDomains = listOf("mozilla.org", "google.com", "facebook.com").into()
it.customDomains = emptyList()
}
val size = provider.shippedDomains.size
......@@ -55,10 +63,13 @@ class DomainAutoCompleteProviderTest {
val domains = listOf("facebook.com", "google.com", "mozilla.org")
val customDomains = listOf("gap.com", "www.fanfiction.com", "https://mobile.de")
val provider = DomainAutoCompleteProvider()
provider.initialize(RuntimeEnvironment.application, true, true, false)
provider.shippedDomains = domains.into()
provider.customDomains = customDomains.into()
val provider = DomainAutoCompleteProvider().also {
it.initialize(testContext,
useShippedDomains = true, useCustomDomains = true,
loadDomainsFromDisk = false)
it.shippedDomains = domains.into()
it.customDomains = customDomains.into()
}
assertCompletion(provider, "f", CUSTOM_LIST, customDomains.size, "fanfiction.com", "http://www.fanfiction.com")
assertCompletion(provider, "fa", CUSTOM_LIST, customDomains.size, "fanfiction.com", "http://www.fanfiction.com")
......@@ -89,6 +100,7 @@ class DomainAutoCompleteProviderTest {
expectedUrl: String
) {
val result = provider.autocomplete(text)
assertFalse(result.text.isEmpty())
assertEquals(completion, result.text)
......@@ -99,6 +111,7 @@ class DomainAutoCompleteProviderTest {
private fun assertNoCompletion(provider: DomainAutoCompleteProvider, text: String) {
val result = provider.autocomplete(text)
assertTrue(result.text.isEmpty())
assertTrue(result.url.isEmpty())
assertTrue(result.source.isEmpty())
......
......@@ -4,25 +4,25 @@
package mozilla.components.browser.domains
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
@RunWith(RobolectricTestRunner::class)
class DomainsTest {
@Test
fun loadDomains() {
val domains = Domains.load(RuntimeEnvironment.application, setOf("us"))
val domains = Domains.load(testContext, setOf("us"))
Assert.assertFalse(domains.isEmpty())
Assert.assertTrue(domains.contains("reddit.com"))
}
@Test
fun loadDomainsWithDefaultCountries() {
val domains = Domains.load(RuntimeEnvironment.application)
val domains = Domains.load(testContext)
Assert.assertFalse(domains.isEmpty())
// From the global list
Assert.assertTrue(domains.contains("mozilla.org"))
......
......@@ -4,7 +4,6 @@
package mozilla.components.feature.toolbar
import android.content.Context
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.domains.Domain
import mozilla.components.browser.domains.autocomplete.BaseDomainAutocompleteProvider
......@@ -111,8 +110,7 @@ class ToolbarAutocompleteFeatureTest {
val autocompleteDelegate: AutocompleteDelegate = mock()
var history: HistoryStorage = InMemoryHistoryStorage()
val domains = object : BaseDomainAutocompleteProvider(DomainList.CUSTOM) {
override fun initialize(context: Context) {}
val domains = object : BaseDomainAutocompleteProvider(DomainList.CUSTOM, { emptyList() }) {
fun testDomains(list: List<Domain>) {
domains = list
}
......
......@@ -20,6 +20,10 @@ permalink: /changelog/
* **samples-firefox-accounts**
* Switch FxA sample to production servers, fix pairing.
* **browser-domains**
* New domain autocomplete providers `ShippedDomainsProvider` and `CustomDomainsProvider` that
should be used instead of deprecated `DomainAutoCompleteProvider`.
# 0.55.0
* [Commits](https://github.com/mozilla-mobile/android-components/compare/v0.54.0...v0.55.0)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment