Commit d3ff9881 authored by Severin Rudie's avatar Severin Rudie Committed by Jeff Boek
Browse files

No issue: begin moving FenixSearchEngineProvider into a testing harness

parent 7191aec7
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
package org.mozilla.fenix.components.searchengine

import android.content.Context
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -21,16 +22,15 @@ import org.mozilla.fenix.ext.settings
import java.util.Locale

@SuppressWarnings("TooManyFunctions")
class FenixSearchEngineProvider(
open class FenixSearchEngineProvider(
    private val context: Context
) : SearchEngineProvider, CoroutineScope by CoroutineScope(Job() + Dispatchers.IO) {
    private val baseSearchEngines = async {
    open val baseSearchEngines = async {
        AssetsSearchEngineProvider(LocaleSearchLocalizationProvider()).loadSearchEngines(context)
    }

    private val bundledSearchEngines = async {
    open val bundledSearchEngines = async {
        val defaultEngineIdentifiers = baseSearchEngines.await().list.map { it.identifier }.toSet()

        AssetsSearchEngineProvider(
            LocaleSearchLocalizationProvider(),
            filters = listOf(object : SearchEngineFilter {
@@ -43,7 +43,7 @@ class FenixSearchEngineProvider(
        ).loadSearchEngines(context)
    }

    private var customSearchEngines = async {
    open var customSearchEngines = async {
        CustomSearchEngineProvider().loadSearchEngines(context)
    }

@@ -56,6 +56,10 @@ class FenixSearchEngineProvider(
        return engines.list.find { it.name == selectedName } ?: engines.default ?: engines.list.first()
    }

    /**
     * @return a list of all SearchEngines that are currently active. These are the engines that
     * are readily available throughout the app.
     */
    fun installedSearchEngines(context: Context): SearchEngineList = runBlocking {
        val engineList = loadedSearchEngines.await()
        val installedIdentifiers = installedSearchEngineIdentifiers(context)
@@ -141,16 +145,17 @@ class FenixSearchEngineProvider(
            prefs.edit().putStringSet(INSTALLED_ENGINES_KEY, defaultSet).apply()
            defaultSet
        } else {
            prefs(context).getStringSet(INSTALLED_ENGINES_KEY, setOf()) ?: setOf()
            prefs.getStringSet(INSTALLED_ENGINES_KEY, setOf()) ?: setOf()
        }

        val customEngineIdentifiers = customSearchEngines.await().list.map { it.identifier }.toSet()
        return identifiers + customEngineIdentifiers
    }

    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    companion object {
        private val BUNDLED_SEARCH_ENGINES = listOf("ecosia", "reddit", "startpage", "yahoo", "youtube")
        private const val PREF_FILE = "fenix-search-engine-provider"
        const val PREF_FILE = "fenix-search-engine-provider"
        private const val INSTALLED_ENGINES_KEY = "fenix-installed-search-engines"
    }
}
+109 −0
Original line number Diff line number Diff line
package org.mozilla.fenix.components.searchengine

import android.content.Context
import android.graphics.Bitmap
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.search.provider.SearchEngineList
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import java.util.UUID

@ExperimentalCoroutinesApi
class FenixSearchEngineProviderTest {

    private val testContext = mockk<Context>()

    private lateinit var fenixSearchEngineProvider: FenixSearchEngineProvider

    @Before
    fun before() {
        fenixSearchEngineProvider = FakeFenixSearchEngineProvider(testContext)

        every {
            testContext.getSharedPreferences(FenixSearchEngineProvider.PREF_FILE, Context.MODE_PRIVATE)
        } returns mockk(relaxed = true)
    }

    /*
    TODO TEST:
        - public API happy path
        - list ordering
        - deduping
        - the above after adding/removing
     */

    @Test
    fun `temp test class inits`() = runBlockingTest {
        val t = fenixSearchEngineProvider.loadSearchEngines(testContext)

        println(t)
    }



}

class FakeFenixSearchEngineProvider(context: Context) : FenixSearchEngineProvider(context) {
    override val defaultEngines: Deferred<SearchEngineList>
        get() {
            val google = mockSearchEngine(id = "google-b-1-m", n = "Google")

            return CompletableDeferred(
                SearchEngineList(
                    listOf(
                        google,
                        mockSearchEngine("bing", "Bing"),
                        mockSearchEngine("amazondotcom", "Amazon.com")
                    ), default = google
                )
            )
        }

    override val bundledEngines = CompletableDeferred(
        SearchEngineList(
            listOf(
                mockSearchEngine("ecosia", "Ecosia"),
                mockSearchEngine("reddit", "Reddit"),
                mockSearchEngine("startpage", "Startpage.com")
            ), default = null
        )
    )

    override var customEngines: Deferred<SearchEngineList>
        get() {
            return CompletableDeferred(
                SearchEngineList(
                    listOf(
                        mockSearchEngine("my custom site", "my custom site")
                    ), default = null
                )
            )
        }
        set(_) = throw RuntimeException("Setting not currently supported on this fake")

    private fun mockSearchEngine(
        id: String,
        n: String = id
        // TODO this fails with `Missing calls inside every { ... } block`. Not sure why
//    ) = mockk<SearchEngine> {
//        every { identifier } returns id
//        every { name } returns n
//        every { icon } returns mockk()
//    }
    ): SearchEngine {
        return mock(SearchEngine::class.java).apply {
            `when`(identifier).thenReturn(id)
            `when`(name).thenReturn(n)
            `when`(icon).thenReturn(mock(Bitmap::class.java))
        }
    }
}