1
0
Fork 0

Add tests for widget

master
Tiger Oakes 2020-06-02 17:57:55 -07:00 committed by Emily Kager
parent 434a737abf
commit 96d2307df0
3 changed files with 200 additions and 27 deletions

View File

@ -17,6 +17,7 @@ import android.view.View
import android.widget.RemoteViews
import androidx.annotation.Dimension
import androidx.annotation.Dimension.DP
import androidx.annotation.VisibleForTesting
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.drawable.toBitmap
import org.mozilla.fenix.HomeActivity
@ -27,7 +28,6 @@ import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
import org.mozilla.fenix.widget.VoiceSearchActivity
import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_PROCESSING
@Suppress("TooManyFunctions")
class SearchWidgetProvider : AppWidgetProvider() {
// Implementation note:
// This class name (SearchWidgetProvider) and package name (org.mozilla.gecko.search) should
@ -79,31 +79,9 @@ class SearchWidgetProvider : AppWidgetProvider() {
appWidgetManager.updateAppWidget(appWidgetId, views)
}
private fun getLayoutSize(@Dimension(unit = DP) dp: Int) = when {
dp >= DP_LARGE -> SearchWidgetProviderSize.LARGE
dp >= DP_MEDIUM -> SearchWidgetProviderSize.MEDIUM
dp >= DP_SMALL -> SearchWidgetProviderSize.SMALL
dp >= DP_EXTRA_SMALL -> SearchWidgetProviderSize.EXTRA_SMALL_V2
else -> SearchWidgetProviderSize.EXTRA_SMALL_V1
}
private fun getLayout(size: SearchWidgetProviderSize, showMic: Boolean) = when (size) {
SearchWidgetProviderSize.LARGE -> R.layout.search_widget_large
SearchWidgetProviderSize.MEDIUM -> R.layout.search_widget_medium
SearchWidgetProviderSize.SMALL -> {
if (showMic) R.layout.search_widget_small
else R.layout.search_widget_small_no_mic
}
SearchWidgetProviderSize.EXTRA_SMALL_V2 -> R.layout.search_widget_extra_small_v2
SearchWidgetProviderSize.EXTRA_SMALL_V1 -> R.layout.search_widget_extra_small_v1
}
private fun getText(layout: SearchWidgetProviderSize, context: Context) = when (layout) {
SearchWidgetProviderSize.MEDIUM -> context.getString(R.string.search_widget_text_short)
SearchWidgetProviderSize.LARGE -> context.getString(R.string.search_widget_text_long)
else -> null
}
/**
* Builds pending intent that opens the browser and starts a new text search.
*/
private fun createTextSearchIntent(context: Context): PendingIntent {
return Intent(context, IntentReceiverActivity::class.java)
.let { intent ->
@ -114,6 +92,9 @@ class SearchWidgetProvider : AppWidgetProvider() {
}
}
/**
* Builds pending intent that starts a new voice search.
*/
private fun createVoiceSearchIntent(context: Context): PendingIntent? {
val voiceIntent = Intent(context, VoiceSearchActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
@ -156,7 +137,7 @@ class SearchWidgetProvider : AppWidgetProvider() {
// Unlike "small" widget, "medium" and "large" sizes do not have separate layouts
// that exclude the microphone icon, which is why we must hide it accordingly here.
if (voiceSearchIntent == null) {
this.setViewVisibility(R.id.button_search_widget_voice, View.GONE)
setViewVisibility(R.id.button_search_widget_voice, View.GONE)
}
}
}
@ -187,6 +168,40 @@ class SearchWidgetProvider : AppWidgetProvider() {
private const val DP_LARGE = 256
private const val REQUEST_CODE_NEW_TAB = 0
private const val REQUEST_CODE_VOICE = 1
@VisibleForTesting
internal fun getLayoutSize(@Dimension(unit = DP) dp: Int) = when {
dp >= DP_LARGE -> SearchWidgetProviderSize.LARGE
dp >= DP_MEDIUM -> SearchWidgetProviderSize.MEDIUM
dp >= DP_SMALL -> SearchWidgetProviderSize.SMALL
dp >= DP_EXTRA_SMALL -> SearchWidgetProviderSize.EXTRA_SMALL_V2
else -> SearchWidgetProviderSize.EXTRA_SMALL_V1
}
/**
* Get the layout resource to use for the search widget.
*/
@VisibleForTesting
internal fun getLayout(size: SearchWidgetProviderSize, showMic: Boolean) = when (size) {
SearchWidgetProviderSize.LARGE -> R.layout.search_widget_large
SearchWidgetProviderSize.MEDIUM -> R.layout.search_widget_medium
SearchWidgetProviderSize.SMALL -> {
if (showMic) R.layout.search_widget_small
else R.layout.search_widget_small_no_mic
}
SearchWidgetProviderSize.EXTRA_SMALL_V2 -> R.layout.search_widget_extra_small_v2
SearchWidgetProviderSize.EXTRA_SMALL_V1 -> R.layout.search_widget_extra_small_v1
}
/**
* Get the text to place in the search widget
*/
@VisibleForTesting
internal fun getText(layout: SearchWidgetProviderSize, context: Context) = when (layout) {
SearchWidgetProviderSize.MEDIUM -> context.getString(R.string.search_widget_text_short)
SearchWidgetProviderSize.LARGE -> context.getString(R.string.search_widget_text_long)
else -> null
}
}
}

View File

@ -0,0 +1,118 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
package org.mozilla.fenix.widget
import android.content.Context
import io.mockk.every
import io.mockk.mockk
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.mozilla.fenix.R
import org.mozilla.gecko.search.SearchWidgetProvider
import org.mozilla.gecko.search.SearchWidgetProviderSize
class SearchWidgetProviderTest {
@Test
fun testGetLayoutSize() {
val sizes = mapOf(
0 to SearchWidgetProviderSize.EXTRA_SMALL_V1,
10 to SearchWidgetProviderSize.EXTRA_SMALL_V1,
63 to SearchWidgetProviderSize.EXTRA_SMALL_V1,
64 to SearchWidgetProviderSize.EXTRA_SMALL_V2,
99 to SearchWidgetProviderSize.EXTRA_SMALL_V2,
100 to SearchWidgetProviderSize.SMALL,
191 to SearchWidgetProviderSize.SMALL,
192 to SearchWidgetProviderSize.MEDIUM,
255 to SearchWidgetProviderSize.MEDIUM,
256 to SearchWidgetProviderSize.LARGE,
1000 to SearchWidgetProviderSize.LARGE
)
for ((dp, layoutSize) in sizes) {
assertEquals(layoutSize, SearchWidgetProvider.getLayoutSize(dp))
}
}
@Test
fun testGetLargeLayout() {
assertEquals(
R.layout.search_widget_large,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.LARGE, showMic = false)
)
assertEquals(
R.layout.search_widget_large,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.LARGE, showMic = true)
)
}
@Test
fun testGetMediumLayout() {
assertEquals(
R.layout.search_widget_medium,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.MEDIUM, showMic = false)
)
assertEquals(
R.layout.search_widget_medium,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.MEDIUM, showMic = true)
)
}
@Test
fun testGetSmallLayout() {
assertEquals(
R.layout.search_widget_small_no_mic,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.SMALL, showMic = false)
)
assertEquals(
R.layout.search_widget_small,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.SMALL, showMic = true)
)
}
@Test
fun testGetExtraSmall2Layout() {
assertEquals(
R.layout.search_widget_extra_small_v2,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.EXTRA_SMALL_V2, showMic = false)
)
assertEquals(
R.layout.search_widget_extra_small_v2,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.EXTRA_SMALL_V2, showMic = true)
)
}
@Test
fun testGetExtraSmall1Layout() {
assertEquals(
R.layout.search_widget_extra_small_v1,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.EXTRA_SMALL_V1, showMic = false)
)
assertEquals(
R.layout.search_widget_extra_small_v1,
SearchWidgetProvider.getLayout(SearchWidgetProviderSize.EXTRA_SMALL_V1, showMic = true)
)
}
@Test
fun testGetText() {
val context = mockk<Context>()
every { context.getString(R.string.search_widget_text_short) } returns "Search"
every { context.getString(R.string.search_widget_text_long) } returns "Search the web"
assertEquals(
"Search the web",
SearchWidgetProvider.getText(SearchWidgetProviderSize.LARGE, context)
)
assertEquals(
"Search",
SearchWidgetProvider.getText(SearchWidgetProviderSize.MEDIUM, context)
)
assertNull(SearchWidgetProvider.getText(SearchWidgetProviderSize.SMALL, context))
assertNull(SearchWidgetProvider.getText(SearchWidgetProviderSize.EXTRA_SMALL_V1, context))
assertNull(SearchWidgetProvider.getText(SearchWidgetProviderSize.EXTRA_SMALL_V2, context))
}
}

View File

@ -73,6 +73,32 @@ class VoiceSearchActivityTest {
assertTrue(activity.isFinishing)
}
@Test
fun `process null intent`() {
val controller = Robolectric.buildActivity(VoiceSearchActivity::class.java, null)
val activity = controller.get()
controller.create()
assertTrue(activity.isFinishing)
}
@Test
fun `save previous intent to instance state`() {
val previousIntent = Intent().apply {
putExtra(SPEECH_PROCESSING, true)
}
val savedInstanceState = Bundle().apply {
putParcelable(PREVIOUS_INTENT, previousIntent)
}
val outState = Bundle()
controller.create(savedInstanceState)
controller.saveInstanceState(outState)
assertEquals(previousIntent, outState.getParcelable(PREVIOUS_INTENT) as Intent)
}
@Test
fun `process intent with speech processing in previous intent set to true`() {
val savedInstanceState = Bundle()
@ -107,4 +133,18 @@ class VoiceSearchActivityTest {
assertEquals("hello world", browserIntent.getStringExtra(SPEECH_PROCESSING))
assertTrue(browserIntent.getBooleanExtra(OPEN_TO_BROWSER_AND_LOAD, false))
}
@Test
fun `handle invalid result code`() {
controller.create()
val resultIntent = Intent()
shadow.receiveResult(
shadow.peekNextStartedActivityForResult().intent,
Activity.RESULT_CANCELED,
resultIntent
)
assertTrue(activity.isFinishing)
}
}