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? {
val baseUrl = "https://sentry.prod.mozaws.net/operations"

View File

@ -5,26 +5,17 @@
package org.mozilla.fenix.ext
import android.app.Activity
import android.content.ActivityNotFoundException
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.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.fragment.app.FragmentActivity
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 org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config
import org.mozilla.fenix.FenixApplication
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.metrics.MetricController
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 =
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
*

View File

@ -2,6 +2,8 @@
* 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("NOTHING_TO_INLINE")
package org.mozilla.fenix.ext
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.
*/
@Suppress("NOTHING_TO_INLINE")
inline fun logDebug(tag: String, message: String) {
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.
*/
@Suppress("NOTHING_TO_INLINE")
inline fun logWarn(tag: String, message: String) {
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.
*/
@Suppress("NOTHING_TO_INLINE")
inline fun logWarn(tag: String, message: String, err: Throwable) {
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.
*/
@Suppress("NOTHING_TO_INLINE")
inline fun logErr(tag: String, message: String, err: Throwable) {
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.Navigator
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) {
if (id == null || this.currentDestination?.id == id) {
this.navigate(directions, navOptions)
@ -55,7 +59,7 @@ fun NavController.alreadyOnDestination(@IdRes destId: Int?): Boolean {
}
fun recordIdException(actual: Int?, expected: Int?) {
if (!BuildConfig.SENTRY_TOKEN.isNullOrEmpty()) {
if (isSentryEnabled()) {
Sentry.capture("Fragment id $actual did not match expected $expected")
}
}

View File

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

View File

@ -31,4 +31,11 @@ class ImageButtonTest {
assertTrue(imageButton.isEnabled)
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
import android.util.Log
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.verify
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.Config
import org.mozilla.fenix.ReleaseChannel
class LogTest {
private val numCalls = if (org.mozilla.fenix.Config.channel.isDebug) 1 else 0
private val mockThrowable: Throwable = mockk()
@Before
fun setup() {
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
fun `Test log debug function`() {
every { Config.channel } returns ReleaseChannel.FenixDebug
logDebug("hi", "hi")
verify(exactly = numCalls) { (Log.d("hi", "hi")) }
verify { Log.d("hi", "hi") }
}
@Test
fun `Test log warn function with tag and message args`() {
every { Config.channel } returns ReleaseChannel.FenixDebug
logWarn("hi", "hi")
verify(exactly = numCalls) { (Log.w("hi", "hi")) }
verify { Log.w("hi", "hi") }
}
@Test
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)
verify(exactly = numCalls) { (Log.w("hi", "hi", mockThrowable)) }
verify { Log.w("hi", "hi", mockThrowable) }
}
@Test
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)
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.NavOptions
import androidx.navigation.Navigator.Extras
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.confirmVerified
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.sentry.Sentry
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.components.isSentryEnabled
class NavControllerTest {
private val navController: NavController = mockk(relaxed = true)
private val navDirections = mockk<NavDirections>(relaxed = true)
private val mockDestination: NavDestination = mockk(relaxed = true)
private val mockExtras: Extras = mockk(relaxed = true)
private val mockOptions: NavOptions = mockk(relaxed = true)
private val mockBundle: Bundle = mockk(relaxed = true)
private val currentDestId = 4
@MockK(relaxUnitFun = true) private lateinit var navController: NavController
@MockK private lateinit var navDirections: NavDirections
@MockK private lateinit var mockDestination: NavDestination
@MockK private lateinit var mockExtras: Extras
@MockK private lateinit var mockOptions: NavOptions
@MockK private lateinit var mockBundle: Bundle
@Before
fun setUp() {
every { (navController.currentDestination) } returns mockDestination
every { (mockDestination.id) } returns 4
MockKAnnotations.init(this)
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
fun `Nav with id and directions args`() {
navController.nav(4, navDirections)
verify { (navController.currentDestination) }
verify { (navController.navigate(navDirections, null)) }
navController.nav(currentDestId, navDirections)
verify { navController.currentDestination }
verify { navController.navigate(navDirections, null) }
}
@Test
fun `Nav with id, directions, and extras args`() {
navController.nav(4, navDirections, mockExtras)
verify { (navController.currentDestination) }
verify { (navController.navigate(navDirections, mockExtras)) }
navController.nav(currentDestId, navDirections, mockExtras)
verify { navController.currentDestination }
verify { navController.navigate(navDirections, mockExtras) }
}
@Test
fun `Nav with id, directions, and options args`() {
navController.nav(4, navDirections, mockOptions)
verify { (navController.currentDestination) }
verify { (navController.navigate(navDirections, mockOptions)) }
navController.nav(currentDestId, navDirections, mockOptions)
verify { navController.currentDestination }
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
fun `Nav with id, destId, bundle, options, and extras args`() {
navController.nav(4, 5, mockBundle, mockOptions, mockExtras)
verify { (navController.currentDestination) }
verify { (navController.navigate(5, mockBundle, mockOptions, mockExtras)) }
navController.nav(currentDestId, 5, mockBundle, mockOptions, mockExtras)
verify { navController.currentDestination }
verify { navController.navigate(5, mockBundle, mockOptions, mockExtras) }
}
@Test
fun `Test error response for id exception in-block`() {
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`() {
mockkStatic(String::class)
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)
//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 }
}
}