324 lines
17 KiB
Kotlin
324 lines
17 KiB
Kotlin
/* 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.settings.quicksettings
|
|
|
|
import android.content.pm.PackageManager
|
|
import assertk.assertAll
|
|
import assertk.assertThat
|
|
import assertk.assertions.isEqualTo
|
|
import assertk.assertions.isFalse
|
|
import assertk.assertions.isInstanceOf
|
|
import assertk.assertions.isNotEqualTo
|
|
import assertk.assertions.isNotNull
|
|
import assertk.assertions.isNotSameAs
|
|
import assertk.assertions.isSameAs
|
|
import assertk.assertions.isTrue
|
|
import io.mockk.every
|
|
import io.mockk.mockk
|
|
import io.mockk.spyk
|
|
import io.mockk.verify
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
import kotlinx.coroutines.runBlocking
|
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
|
import mozilla.components.support.test.robolectric.testContext
|
|
import org.junit.Test
|
|
import org.junit.runner.RunWith
|
|
import org.mozilla.fenix.R
|
|
import org.mozilla.fenix.TestApplication
|
|
import org.mozilla.fenix.settings.PhoneFeature
|
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.getInsecureWebsiteUiValues
|
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.getPermissionStatus
|
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.getSecuredWebsiteUiValues
|
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.toWebsitePermission
|
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
|
import org.mozilla.fenix.utils.Settings
|
|
import org.robolectric.RobolectricTestRunner
|
|
import org.robolectric.annotation.Config
|
|
|
|
@RunWith(RobolectricTestRunner::class)
|
|
@UseExperimental(kotlinx.coroutines.ObsoleteCoroutinesApi::class)
|
|
@Config(application = TestApplication::class)
|
|
class QuickSettingsFragmentStoreTest {
|
|
private val context = spyk(testContext)
|
|
private val permissions = mockk<SitePermissions>()
|
|
private val appSettings = mockk<Settings>()
|
|
private val secureStringRes = R.string.quick_settings_sheet_secure_connection
|
|
private val secureDrawableRes = R.drawable.mozac_ic_lock
|
|
private val secureColorRes = R.color.photonGreen50
|
|
private val insecureStringRes = R.string.quick_settings_sheet_insecure_connection
|
|
private val insecureDrawableRes = R.drawable.mozac_ic_globe
|
|
private val insecureColorRes = R.color.photonRed50
|
|
|
|
@Test
|
|
fun `createStore constructs a QuickSettingsFragmentState`() {
|
|
val settings = mockk<Settings>(relaxed = true)
|
|
val permissions = mockk<SitePermissions>(relaxed = true)
|
|
every { settings.shouldUseTrackingProtection } returns true
|
|
|
|
val store = QuickSettingsFragmentStore.createStore(
|
|
context, "url", true, true, permissions, settings
|
|
)
|
|
|
|
assertAll {
|
|
assertThat(store).isNotNull()
|
|
assertThat(store.state).isNotNull()
|
|
assertThat(store.state.webInfoState).isNotNull()
|
|
assertThat(store.state.trackingProtectionState).isNotNull()
|
|
assertThat(store.state.websitePermissionsState).isNotNull()
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `createWebsiteInfoState constructs a WebsiteInfoState with the right values for a secure connection`() {
|
|
val websiteUrl = "https://host.com/page1"
|
|
val securedStatus = true
|
|
|
|
val state = QuickSettingsFragmentStore.createWebsiteInfoState(websiteUrl, securedStatus)
|
|
|
|
assertAll {
|
|
assertThat(state).isNotNull()
|
|
assertThat(state.websiteUrl).isSameAs(websiteUrl)
|
|
assertThat(state.securityInfoRes).isEqualTo(secureStringRes)
|
|
assertThat(state.iconRes).isEqualTo(secureDrawableRes)
|
|
assertThat(state.iconTintRes).isEqualTo(secureColorRes)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `createWebsiteInfoState constructs a WebsiteInfoState with the right values for an insecure connection`() {
|
|
val websiteUrl = "https://host.com/page1"
|
|
val securedStatus = false
|
|
|
|
val state = QuickSettingsFragmentStore.createWebsiteInfoState(websiteUrl, securedStatus)
|
|
|
|
assertAll {
|
|
assertThat(state).isNotNull()
|
|
assertThat(state.websiteUrl).isSameAs(websiteUrl)
|
|
assertThat(state.securityInfoRes).isEqualTo(insecureStringRes)
|
|
assertThat(state.iconRes).isEqualTo(insecureDrawableRes)
|
|
assertThat(state.iconTintRes).isEqualTo(insecureColorRes)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `createTrackingProtectionState helps in constructing an initial TrackingProtectionState for it's Store`() {
|
|
val websiteUrl = "https://host.com/pageThatShouldUseTrackingProtection"
|
|
val trackingPerWebsiteStatus = true
|
|
val trackingPerAppStatus = true
|
|
every { appSettings.shouldUseTrackingProtection } returns trackingPerAppStatus
|
|
|
|
val state = QuickSettingsFragmentStore.createTrackingProtectionState(
|
|
websiteUrl, trackingPerWebsiteStatus, appSettings
|
|
)
|
|
|
|
assertAll {
|
|
assertThat(state).isNotNull()
|
|
assertThat(state).isNotNull()
|
|
assertThat(state.websiteUrl).isSameAs(websiteUrl)
|
|
assertThat(state.isTrackingProtectionEnabledPerWebsite).isSameAs(trackingPerWebsiteStatus)
|
|
assertThat(state.isTrackingProtectionEnabledPerApp).isEqualTo(trackingPerAppStatus)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `createWebsitePermissionState helps in constructing an initial WebsitePermissionState for it's Store`() {
|
|
every { context.checkPermission(any(), any(), any()) }.returns(PackageManager.PERMISSION_GRANTED)
|
|
every { permissions.camera } returns SitePermissions.Status.ALLOWED
|
|
every { permissions.microphone } returns SitePermissions.Status.NO_DECISION
|
|
every { permissions.notification } returns SitePermissions.Status.BLOCKED
|
|
every { permissions.location } returns SitePermissions.Status.ALLOWED
|
|
|
|
val state = QuickSettingsFragmentStore.createWebsitePermissionState(
|
|
context, permissions, appSettings
|
|
)
|
|
|
|
// Just need to know that the WebsitePermissionsState properties are initialized.
|
|
// Making sure they are correctly initialized is tested in the `initWebsitePermission` test.
|
|
assertAll {
|
|
assertThat(state).isNotNull()
|
|
assertThat(state.camera).isNotNull()
|
|
assertThat(state.microphone).isNotNull()
|
|
assertThat(state.notification).isNotNull()
|
|
assertThat(state.location).isNotNull()
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `PhoneFeature#toWebsitePermission helps in constructing the right WebsitePermission`() {
|
|
val cameraFeature = PhoneFeature.CAMERA
|
|
val allowedStatus = testContext.getString(R.string.preference_option_phone_feature_allowed)
|
|
every { context.checkPermission(any(), any(), any()) }.returns(PackageManager.PERMISSION_GRANTED)
|
|
every { permissions.camera } returns SitePermissions.Status.ALLOWED
|
|
|
|
val websitePermission = cameraFeature.toWebsitePermission(context, permissions, appSettings)
|
|
|
|
assertAll {
|
|
assertThat(websitePermission).isNotNull()
|
|
assertThat(websitePermission).isInstanceOf(WebsitePermission.Camera::class)
|
|
assertThat(websitePermission.status).isEqualTo(allowedStatus)
|
|
assertThat(websitePermission.isVisible).isTrue()
|
|
assertThat(websitePermission.isEnabled).isTrue()
|
|
assertThat(websitePermission.isBlockedByAndroid).isFalse()
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `PhoneFeature#getPermissionStatus gets the permission properties from delegates`() {
|
|
val phoneFeature = PhoneFeature.CAMERA
|
|
every { permissions.camera } returns SitePermissions.Status.NO_DECISION
|
|
|
|
val permissionsStatus = phoneFeature.getPermissionStatus(context, permissions, appSettings)
|
|
|
|
verify {
|
|
// Verifying phoneFeature.getActionLabel gets "Status(child of #2#4).ordinal()) was not called"
|
|
// phoneFeature.getActionLabel(context, permissions, appSettings)
|
|
phoneFeature.shouldBeVisible(permissions, appSettings)
|
|
phoneFeature.shouldBeEnabled(context, permissions, appSettings)
|
|
phoneFeature.isAndroidPermissionGranted(context)
|
|
}
|
|
assertAll {
|
|
// Check that we only have a non-null permission status.
|
|
// Having each property calculated in a separate delegate means their correctness is
|
|
// to be tested in that delegated method.
|
|
assertThat(permissionsStatus).isNotNull()
|
|
}
|
|
}
|
|
|
|
@ExperimentalCoroutinesApi
|
|
@Test
|
|
fun `TrackingProtectionToggled should update only the tracking enabled status`() = runBlocking {
|
|
val initialUrl = "https://host.com/page1"
|
|
val initialTrackingPerApp = true
|
|
val initialTrackingPerWebsite = true
|
|
val updatedTrackingPerWebsite = false
|
|
val appSettings = mockk<Settings>()
|
|
every { appSettings.shouldUseTrackingProtection } returns initialTrackingPerApp
|
|
val initialTrackingProtectionState = QuickSettingsFragmentStore.createTrackingProtectionState(
|
|
initialUrl, initialTrackingPerWebsite, appSettings
|
|
)
|
|
val initialWebsiteInfoState = mockk<WebsiteInfoState>()
|
|
val initialWebsitePermissionsState = mockk<WebsitePermissionsState>()
|
|
val store = QuickSettingsFragmentStore(QuickSettingsFragmentState(
|
|
initialTrackingProtectionState, initialWebsiteInfoState, initialWebsitePermissionsState
|
|
))
|
|
|
|
store.dispatch(TrackingProtectionAction.TrackingProtectionToggled(updatedTrackingPerWebsite)).join()
|
|
|
|
assertAll {
|
|
assertThat(store.state.webInfoState).isSameAs(initialWebsiteInfoState)
|
|
assertThat(store.state.websitePermissionsState).isSameAs(initialWebsitePermissionsState)
|
|
assertThat(store.state.trackingProtectionState).isNotSameAs(initialTrackingProtectionState)
|
|
|
|
assertThat(store.state.trackingProtectionState.isTrackingProtectionEnabledPerWebsite)
|
|
.isNotEqualTo(initialTrackingPerWebsite)
|
|
assertThat(store.state.trackingProtectionState.isTrackingProtectionEnabledPerWebsite)
|
|
.isEqualTo(updatedTrackingPerWebsite)
|
|
assertThat(store.state.trackingProtectionState.isTrackingProtectionEnabledPerApp)
|
|
.isSameAs(initialTrackingPerApp)
|
|
assertThat(store.state.trackingProtectionState.websiteUrl).isSameAs(initialUrl)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
@ExperimentalCoroutinesApi
|
|
fun `TogglePermission should only modify status and visibility of a specific WebsitePermissionsState`() = runBlocking {
|
|
val cameraPermissionName = "Camera"
|
|
val microphonePermissionName = "Microphone"
|
|
val notificationPermissionName = "Notification"
|
|
val locationPermissionName = "Location"
|
|
val initialCameraStatus = "initialCameraStatus"
|
|
val initialMicStatus = "initialMicStatus"
|
|
val initialNotificationStatus = "initialNotificationStatus"
|
|
val initialLocationStatus = "initialLocationStatus"
|
|
val updatedMicrophoneStatus = "updatedNotificationStatus"
|
|
val updatedMicrophoneEnabledStatus = false
|
|
val defaultVisibilityStatus = true
|
|
val defaultEnabledStatus = true
|
|
val defaultBlockedByAndroidStatus = true
|
|
val websiteInfoState = mockk<WebsiteInfoState>()
|
|
val trackingProtectionState = mockk<TrackingProtectionState>()
|
|
val initialWebsitePermissionsState = WebsitePermissionsState(
|
|
isVisible = true,
|
|
camera = WebsitePermission.Camera(initialCameraStatus, defaultVisibilityStatus,
|
|
defaultEnabledStatus, defaultBlockedByAndroidStatus, cameraPermissionName),
|
|
microphone = WebsitePermission.Microphone(initialMicStatus, defaultVisibilityStatus,
|
|
defaultEnabledStatus, defaultBlockedByAndroidStatus, microphonePermissionName),
|
|
notification = WebsitePermission.Notification(initialNotificationStatus, defaultVisibilityStatus,
|
|
defaultEnabledStatus, defaultBlockedByAndroidStatus, notificationPermissionName),
|
|
location = WebsitePermission.Location(initialLocationStatus, defaultVisibilityStatus,
|
|
defaultEnabledStatus, defaultBlockedByAndroidStatus, locationPermissionName)
|
|
)
|
|
val initialState = QuickSettingsFragmentState(
|
|
trackingProtectionState, websiteInfoState, initialWebsitePermissionsState
|
|
)
|
|
val store = QuickSettingsFragmentStore(initialState)
|
|
|
|
store.dispatch(WebsitePermissionAction.TogglePermission(
|
|
mockk<WebsitePermission.Microphone>(), updatedMicrophoneStatus, updatedMicrophoneEnabledStatus)
|
|
).join()
|
|
|
|
assertAll {
|
|
assertThat(store.state).isNotNull()
|
|
assertThat(store.state).isNotSameAs(initialState)
|
|
assertThat(store.state.websitePermissionsState).isNotSameAs(initialWebsitePermissionsState)
|
|
assertThat(store.state.webInfoState).isSameAs(websiteInfoState)
|
|
assertThat(store.state.trackingProtectionState).isSameAs(trackingProtectionState)
|
|
|
|
assertThat(store.state.websitePermissionsState.camera).isNotNull()
|
|
assertThat((store.state.websitePermissionsState.camera as WebsitePermission.Camera).name).isEqualTo(cameraPermissionName)
|
|
assertThat(store.state.websitePermissionsState.camera.status).isEqualTo(initialCameraStatus)
|
|
assertThat(store.state.websitePermissionsState.camera.isVisible).isEqualTo(defaultVisibilityStatus)
|
|
assertThat(store.state.websitePermissionsState.camera.isEnabled).isEqualTo(defaultEnabledStatus)
|
|
assertThat(store.state.websitePermissionsState.camera.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
|
|
|
|
assertThat(store.state.websitePermissionsState.microphone).isNotNull()
|
|
assertThat((store.state.websitePermissionsState.microphone as WebsitePermission.Microphone).name).isEqualTo(microphonePermissionName)
|
|
// Only the following two properties must have been changed!
|
|
assertThat(store.state.websitePermissionsState.microphone.status).isEqualTo(updatedMicrophoneStatus)
|
|
assertThat(store.state.websitePermissionsState.microphone.isEnabled).isEqualTo(updatedMicrophoneEnabledStatus)
|
|
|
|
assertThat(store.state.websitePermissionsState.microphone.isVisible).isEqualTo(defaultVisibilityStatus)
|
|
assertThat(store.state.websitePermissionsState.microphone.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
|
|
|
|
assertThat(store.state.websitePermissionsState.notification).isNotNull()
|
|
assertThat((store.state.websitePermissionsState.notification as WebsitePermission.Notification).name).isEqualTo(notificationPermissionName)
|
|
assertThat(store.state.websitePermissionsState.notification.status).isEqualTo(initialNotificationStatus)
|
|
assertThat(store.state.websitePermissionsState.notification.isVisible).isEqualTo(defaultVisibilityStatus)
|
|
assertThat(store.state.websitePermissionsState.notification.isEnabled).isEqualTo(defaultEnabledStatus)
|
|
assertThat(store.state.websitePermissionsState.notification.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
|
|
|
|
assertThat(store.state.websitePermissionsState.location).isNotNull()
|
|
assertThat((store.state.websitePermissionsState.location as WebsitePermission.Location).name).isEqualTo(locationPermissionName)
|
|
assertThat(store.state.websitePermissionsState.location.status).isEqualTo(initialLocationStatus)
|
|
assertThat(store.state.websitePermissionsState.location.isVisible).isEqualTo(defaultVisibilityStatus)
|
|
assertThat(store.state.websitePermissionsState.location.isEnabled).isEqualTo(defaultEnabledStatus)
|
|
assertThat(store.state.websitePermissionsState.location.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `getSecuredWebsiteUiValues() should return the right values`() {
|
|
val uiValues = getSecuredWebsiteUiValues
|
|
|
|
assertAll {
|
|
assertThat(uiValues.first).isEqualTo(secureStringRes)
|
|
assertThat(uiValues.second).isEqualTo(secureDrawableRes)
|
|
assertThat(uiValues.third).isEqualTo(secureColorRes)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `getInsecureWebsiteUiValues() should return the right values`() {
|
|
val uiValues = getInsecureWebsiteUiValues
|
|
|
|
assertAll {
|
|
assertThat(uiValues.first).isEqualTo(insecureStringRes)
|
|
assertThat(uiValues.second).isEqualTo(insecureDrawableRes)
|
|
assertThat(uiValues.third).isEqualTo(insecureColorRes)
|
|
}
|
|
}
|
|
}
|