1
0
Fork 0

Add tests for ext package (#11334)

master
Tiger Oakes 2020-06-10 09:14:18 -07:00 committed by GitHub
parent d16c70d8be
commit 4b064afb81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 180 additions and 96 deletions

View File

@ -97,7 +97,7 @@ class Analytics(
} }
} }
private fun isSentryEnabled() = !BuildConfig.SENTRY_TOKEN.isNullOrEmpty() fun isSentryEnabled() = !BuildConfig.SENTRY_TOKEN.isNullOrEmpty()
private fun getSentryProjectUrl(): String? { private fun getSentryProjectUrl(): String? {
val baseUrl = "https://sentry.prod.mozaws.net/operations" val baseUrl = "https://sentry.prod.mozaws.net/operations"

View File

@ -5,26 +5,17 @@
package org.mozilla.fenix.ext package org.mozilla.fenix.ext
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_SEND
import android.content.Intent.EXTRA_SUBJECT
import android.content.Intent.EXTRA_TEXT
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import mozilla.components.browser.search.SearchEngineManager import mozilla.components.browser.search.SearchEngineManager
import mozilla.components.support.base.log.Log
import mozilla.components.support.base.log.Log.Priority.WARN
import mozilla.components.support.locale.LocaleManager import mozilla.components.support.locale.LocaleManager
import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config import org.mozilla.fenix.Config
import org.mozilla.fenix.FenixApplication import org.mozilla.fenix.FenixApplication
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.advanced.getSelectedLocale import org.mozilla.fenix.settings.advanced.getSelectedLocale
@ -65,35 +56,6 @@ fun Context.asFragmentActivity() = (this as? ContextThemeWrapper)?.baseContext a
fun Context.getPreferenceKey(@StringRes resourceId: Int): String = fun Context.getPreferenceKey(@StringRes resourceId: Int): String =
resources.getString(resourceId) resources.getString(resourceId)
/**
* Shares content via [ACTION_SEND] intent.
*
* @param text the data to be shared [EXTRA_TEXT]
* @param subject of the intent [EXTRA_TEXT]
* @return true it is able to share false otherwise.
*/
@Deprecated("We are replacing the system share sheet with a custom version. See: [ShareFragment]")
fun Context.share(text: String, subject: String = ""): Boolean {
return try {
val intent = Intent(ACTION_SEND).apply {
type = "text/plain"
putExtra(EXTRA_SUBJECT, subject)
putExtra(EXTRA_TEXT, text)
flags = FLAG_ACTIVITY_NEW_TASK
}
val shareIntent = Intent.createChooser(intent, getString(R.string.menu_share_with)).apply {
flags = FLAG_ACTIVITY_NEW_TASK
}
startActivity(shareIntent)
true
} catch (e: ActivityNotFoundException) {
Log.log(WARN, message = "No activity to share to found", throwable = e, tag = "Reference-Browser")
false
}
}
/** /**
* Gets the Root View with an activity context * Gets the Root View with an activity context
* *

View File

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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, You can obtain one at http://mozilla.org/MPL/2.0/. */
@file:Suppress("NOTHING_TO_INLINE")
package org.mozilla.fenix.ext package org.mozilla.fenix.ext
import android.util.Log import android.util.Log
@ -12,7 +14,6 @@ import org.mozilla.fenix.Config
* *
* Meant to be used for logs that should not be visible in the production app. * Meant to be used for logs that should not be visible in the production app.
*/ */
@Suppress("NOTHING_TO_INLINE")
inline fun logDebug(tag: String, message: String) { inline fun logDebug(tag: String, message: String) {
if (Config.channel.isDebug) Log.d(tag, message) if (Config.channel.isDebug) Log.d(tag, message)
} }
@ -22,7 +23,6 @@ inline fun logDebug(tag: String, message: String) {
* *
* Meant to be used for logs that should not be visible in the production app. * Meant to be used for logs that should not be visible in the production app.
*/ */
@Suppress("NOTHING_TO_INLINE")
inline fun logWarn(tag: String, message: String) { inline fun logWarn(tag: String, message: String) {
if (Config.channel.isDebug) Log.w(tag, message) if (Config.channel.isDebug) Log.w(tag, message)
} }
@ -32,7 +32,6 @@ inline fun logWarn(tag: String, message: String) {
* *
* Meant to be used for logs that should not be visible in the production app. * Meant to be used for logs that should not be visible in the production app.
*/ */
@Suppress("NOTHING_TO_INLINE")
inline fun logWarn(tag: String, message: String, err: Throwable) { inline fun logWarn(tag: String, message: String, err: Throwable) {
if (Config.channel.isDebug) Log.w(tag, message, err) if (Config.channel.isDebug) Log.w(tag, message, err)
} }
@ -42,7 +41,6 @@ inline fun logWarn(tag: String, message: String, err: Throwable) {
* *
* Meant to be used for logs that should not be visible in the production app. * Meant to be used for logs that should not be visible in the production app.
*/ */
@Suppress("NOTHING_TO_INLINE")
inline fun logErr(tag: String, message: String, err: Throwable) { inline fun logErr(tag: String, message: String, err: Throwable) {
if (Config.channel.isDebug) Log.e(tag, message, err) if (Config.channel.isDebug) Log.e(tag, message, err)
} }

View File

@ -11,8 +11,12 @@ import androidx.navigation.NavDirections
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.Navigator import androidx.navigation.Navigator
import io.sentry.Sentry import io.sentry.Sentry
import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.components.isSentryEnabled
/**
* Navigate from the fragment with [id] using the given [directions].
* If the id doesn't match the current destination, an error is recorded.
*/
fun NavController.nav(@IdRes id: Int?, directions: NavDirections, navOptions: NavOptions? = null) { fun NavController.nav(@IdRes id: Int?, directions: NavDirections, navOptions: NavOptions? = null) {
if (id == null || this.currentDestination?.id == id) { if (id == null || this.currentDestination?.id == id) {
this.navigate(directions, navOptions) this.navigate(directions, navOptions)
@ -55,7 +59,7 @@ fun NavController.alreadyOnDestination(@IdRes destId: Int?): Boolean {
} }
fun recordIdException(actual: Int?, expected: Int?) { fun recordIdException(actual: Int?, expected: Int?) {
if (!BuildConfig.SENTRY_TOKEN.isNullOrEmpty()) { if (isSentryEnabled()) {
Sentry.capture("Fragment id $actual did not match expected $expected") Sentry.capture("Fragment id $actual did not match expected $expected")
} }
} }

View File

@ -15,10 +15,7 @@ fun View.increaseTapArea(extraDps: Int) {
parent.post { parent.post {
val touchRect = Rect() val touchRect = Rect()
getHitRect(touchRect) getHitRect(touchRect)
touchRect.top -= dips touchRect.inset(-dips, -dips)
touchRect.left -= dips
touchRect.right += dips
touchRect.bottom += dips
parent.touchDelegate = TouchDelegate(touchRect, this) parent.touchDelegate = TouchDelegate(touchRect, this)
} }
} }

View File

@ -31,4 +31,11 @@ class ImageButtonTest {
assertTrue(imageButton.isEnabled) assertTrue(imageButton.isEnabled)
assertEquals(View.VISIBLE, imageButton.visibility) assertEquals(View.VISIBLE, imageButton.visibility)
} }
@Test
fun `Remove and disable`() {
imageButton.removeAndDisable()
assertFalse(imageButton.isEnabled)
assertEquals(View.GONE, imageButton.visibility)
}
} }

View File

@ -5,44 +5,71 @@
package org.mozilla.fenix.ext package org.mozilla.fenix.ext
import android.util.Log import android.util.Log
import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.verify import io.mockk.verify
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.Config
import org.mozilla.fenix.ReleaseChannel
class LogTest { class LogTest {
private val numCalls = if (org.mozilla.fenix.Config.channel.isDebug) 1 else 0 private val mockThrowable: Throwable = mockk()
@Before @Before
fun setup() { fun setup() {
mockkStatic(Log::class) mockkStatic(Log::class)
mockkObject(Config)
every { Log.d(any(), any()) } returns 0
every { Log.w(any(), any<String>()) } returns 0
every { Log.d(any(), any(), any()) } returns 0
every { Log.d(any(), any(), any()) } returns 0
} }
@Test @Test
fun `Test log debug function`() { fun `Test log debug function`() {
every { Config.channel } returns ReleaseChannel.FenixDebug
logDebug("hi", "hi") logDebug("hi", "hi")
verify(exactly = numCalls) { (Log.d("hi", "hi")) } verify { Log.d("hi", "hi") }
} }
@Test @Test
fun `Test log warn function with tag and message args`() { fun `Test log warn function with tag and message args`() {
every { Config.channel } returns ReleaseChannel.FenixDebug
logWarn("hi", "hi") logWarn("hi", "hi")
verify(exactly = numCalls) { (Log.w("hi", "hi")) } verify { Log.w("hi", "hi") }
} }
@Test @Test
fun `Test log warn function with tag, message, and exception args`() { fun `Test log warn function with tag, message, and exception args`() {
val mockThrowable: Throwable = mockk(relaxed = true) every { Config.channel } returns ReleaseChannel.FenixDebug
logWarn("hi", "hi", mockThrowable) logWarn("hi", "hi", mockThrowable)
verify(exactly = numCalls) { (Log.w("hi", "hi", mockThrowable)) } verify { Log.w("hi", "hi", mockThrowable) }
} }
@Test @Test
fun `Test log error function with tag, message, and exception args`() { fun `Test log error function with tag, message, and exception args`() {
val mockThrowable: Throwable = mockk(relaxed = true) every { Config.channel } returns ReleaseChannel.FenixDebug
logErr("hi", "hi", mockThrowable) logErr("hi", "hi", mockThrowable)
verify(exactly = numCalls) { (Log.e("hi", "hi", mockThrowable)) } verify { Log.e("hi", "hi", mockThrowable) }
}
@Test
fun `Test no log in production channel`() {
every { Config.channel } returns ReleaseChannel.FenixProduction
logDebug("hi", "hi")
logWarn("hi", "hi")
logWarn("hi", "hi", mockThrowable)
logErr("hi", "hi", mockThrowable)
verify(exactly = 0) { Log.d(any(), any()) }
verify(exactly = 0) { Log.w(any(), any<String>()) }
verify(exactly = 0) { Log.d(any(), any(), any()) }
verify(exactly = 0) { Log.d(any(), any(), any()) }
} }
} }

View File

@ -10,81 +10,101 @@ import androidx.navigation.NavDestination
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.Navigator.Extras import androidx.navigation.Navigator.Extras
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.confirmVerified
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockkStatic
import io.mockk.verify import io.mockk.verify
import io.sentry.Sentry
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.components.isSentryEnabled
class NavControllerTest { class NavControllerTest {
private val navController: NavController = mockk(relaxed = true) private val currentDestId = 4
private val navDirections = mockk<NavDirections>(relaxed = true) @MockK(relaxUnitFun = true) private lateinit var navController: NavController
private val mockDestination: NavDestination = mockk(relaxed = true) @MockK private lateinit var navDirections: NavDirections
private val mockExtras: Extras = mockk(relaxed = true) @MockK private lateinit var mockDestination: NavDestination
private val mockOptions: NavOptions = mockk(relaxed = true) @MockK private lateinit var mockExtras: Extras
private val mockBundle: Bundle = mockk(relaxed = true) @MockK private lateinit var mockOptions: NavOptions
@MockK private lateinit var mockBundle: Bundle
@Before @Before
fun setUp() { fun setUp() {
every { (navController.currentDestination) } returns mockDestination MockKAnnotations.init(this)
every { (mockDestination.id) } returns 4 mockkStatic("io.sentry.Sentry", "org.mozilla.fenix.components.AnalyticsKt")
every { navController.currentDestination } returns mockDestination
every { mockDestination.id } returns currentDestId
every { isSentryEnabled() } returns true
every { Sentry.capture(any<String>()) } just Runs
} }
@Test @Test
fun `Nav with id and directions args`() { fun `Nav with id and directions args`() {
navController.nav(4, navDirections) navController.nav(currentDestId, navDirections)
verify { (navController.currentDestination) } verify { navController.currentDestination }
verify { (navController.navigate(navDirections, null)) } verify { navController.navigate(navDirections, null) }
} }
@Test @Test
fun `Nav with id, directions, and extras args`() { fun `Nav with id, directions, and extras args`() {
navController.nav(4, navDirections, mockExtras) navController.nav(currentDestId, navDirections, mockExtras)
verify { (navController.currentDestination) } verify { navController.currentDestination }
verify { (navController.navigate(navDirections, mockExtras)) } verify { navController.navigate(navDirections, mockExtras) }
} }
@Test @Test
fun `Nav with id, directions, and options args`() { fun `Nav with id, directions, and options args`() {
navController.nav(4, navDirections, mockOptions) navController.nav(currentDestId, navDirections, mockOptions)
verify { (navController.currentDestination) } verify { navController.currentDestination }
verify { (navController.navigate(navDirections, mockOptions)) } verify { navController.navigate(navDirections, mockOptions) }
}
@Test
fun `Nav with id, directions, options, and extras args`() {
every { navDirections.actionId } returns 5
every { navDirections.arguments } returns mockBundle
navController.nav(currentDestId, navDirections, mockOptions, mockExtras)
verify { navController.currentDestination }
verify { navController.navigate(5, mockBundle, mockOptions, mockExtras) }
} }
@Test @Test
fun `Nav with id, destId, bundle, options, and extras args`() { fun `Nav with id, destId, bundle, options, and extras args`() {
navController.nav(4, 5, mockBundle, mockOptions, mockExtras) navController.nav(currentDestId, 5, mockBundle, mockOptions, mockExtras)
verify { (navController.currentDestination) } verify { navController.currentDestination }
verify { (navController.navigate(5, mockBundle, mockOptions, mockExtras)) } verify { navController.navigate(5, mockBundle, mockOptions, mockExtras) }
} }
@Test @Test
fun `Test error response for id exception in-block`() { fun `Test error response for id exception in-block`() {
navController.nav(7, navDirections) navController.nav(7, navDirections)
verify { (recordIdException(mockDestination.id, 7)) } verify { navController.currentDestination }
verify { Sentry.capture("Fragment id 4 did not match expected 7") }
confirmVerified(navController)
} }
// TO-DO Not Working @Test
/* @Test fun `Test error response for null current destination`() {
every { navController.currentDestination } returns null
navController.nav(7, navDirections, mockExtras)
verify { navController.currentDestination }
verify { Sentry.capture("Fragment id null did not match expected 7") }
confirmVerified(navController)
}
@Test
fun `Test record id exception fun`() { fun `Test record id exception fun`() {
mockkStatic(String::class)
val actual = 7 val actual = 7
var expected = 4 val expected = 4
class MySentry() {
public fun capture(myString: String) {
println(myString) }
}
class MyBuildConfig() {
public val SENTRY_TOKEN = "Mozilla"
}
//val Sentry = MySentry()
val BuildConfig = MyBuildConfig()
every {BuildConfig.SENTRY_TOKEN.isNullOrEmpty()} returns false
recordIdException(actual, expected) recordIdException(actual, expected)
//verify { Sentry.capture("Fragment id $actual did not match expected $expected")} verify { Sentry.capture("Fragment id 7 did not match expected 4") }
}*/ }
} }

View File

@ -0,0 +1,69 @@
/* 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.ext
import android.graphics.Rect
import android.util.DisplayMetrics
import android.view.View
import android.widget.FrameLayout
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockkStatic
import io.mockk.slot
import io.mockk.verify
import mozilla.components.support.ktx.android.util.dpToPx
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
class ViewTest {
@MockK private lateinit var view: View
@MockK private lateinit var parent: FrameLayout
@MockK private lateinit var displayMetrics: DisplayMetrics
@Before
fun setup() {
MockKAnnotations.init(this)
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { view.resources.displayMetrics } returns displayMetrics
every { view.parent } returns parent
every { parent.touchDelegate = any() } just Runs
every { parent.post(any()) } answers {
// Immediately run the given Runnable argument
val action: Runnable = firstArg()
action.run()
true
}
}
@Test
fun `test increase touch area`() {
val hitRect = Rect(30, 40, 50, 60)
val dp = 10
val px = 20
val outRect = slot<Rect>()
every { dp.dpToPx(displayMetrics) } returns px
every { view.getHitRect(capture(outRect)) } answers { outRect.captured.set(hitRect) }
view.increaseTapArea(dp)
val expected = Rect(10, 20, 70, 80)
assertEquals(expected.left, outRect.captured.left)
assertEquals(expected.top, outRect.captured.top)
assertEquals(expected.right, outRect.captured.right)
assertEquals(expected.bottom, outRect.captured.bottom)
verify { parent.touchDelegate = any() }
}
@Test
fun `test remove touch delegate`() {
view.removeTouchDelegate()
verify { parent.touchDelegate = null }
}
}