Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09e8750a authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Clean-up FooterActionsViewModelTest

This CL cleans up FooterActionsViewModelTest and FooterActionsTestUtils
by making sure that the same TestCoroutineScheduler is used by all
TestDispatchers, and by using the new collectLastValue(Flow) API instead
of manually collecting each Flow.

Bug: 242040009
Test: atest FooterActionsViewModelTest
Change-Id: Ia3b1ae8fba05c2ed9cf3a46d3cc7546161092f42
parent d94681b3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.nullable
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.TestCoroutineScheduler
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,7 +56,7 @@ class FooterActionsInteractorTest : SysuiTestCase() {

    @Before
    fun setUp() {
        utils = FooterActionsTestUtils(context, TestableLooper.get(this))
        utils = FooterActionsTestUtils(context, TestableLooper.get(this), TestCoroutineScheduler())
    }

    @Test
+16 −49
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.qs.FakeFgsManagerController
import com.android.systemui.qs.QSSecurityFooterUtils
import com.android.systemui.qs.footer.FooterActionsTestUtils
@@ -44,12 +45,9 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -62,16 +60,20 @@ import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class FooterActionsViewModelTest : SysuiTestCase() {
    private val testScope = TestScope()
    private lateinit var utils: FooterActionsTestUtils
    private val testDispatcher = UnconfinedTestDispatcher(TestCoroutineScheduler())

    @Before
    fun setUp() {
        utils = FooterActionsTestUtils(context, TestableLooper.get(this))
        utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
    }

    private fun runTest(block: suspend TestScope.() -> Unit) {
        testScope.runTest(testBody = block)
    }

    @Test
    fun settingsButton() = runBlockingTest {
    fun settingsButton() = runTest {
        val underTest = utils.footerActionsViewModel(showPowerButton = false)
        val settings = underTest.settings

@@ -87,7 +89,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {
    }

    @Test
    fun powerButton() = runBlockingTest {
    fun powerButton() = runTest {
        // Without power button.
        val underTestWithoutPower = utils.footerActionsViewModel(showPowerButton = false)
        assertThat(underTestWithoutPower.power).isNull()
@@ -114,7 +116,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {
    }

    @Test
    fun userSwitcher() = runBlockingTest {
    fun userSwitcher() = runTest {
        val picture: Drawable = mock()
        val userInfoController = FakeUserInfoController(FakeInfo(picture = picture))
        val settings = FakeSettings()
@@ -135,7 +137,6 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                showPowerButton = false,
                footerActionsInteractor =
                    utils.footerActionsInteractor(
                        bgDispatcher = testDispatcher,
                        userSwitcherRepository =
                            utils.userSwitcherRepository(
                                userTracker = userTracker,
@@ -143,22 +144,12 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                                userManager = userManager,
                                userInfoController = userInfoController,
                                userSwitcherController = userSwitcherControllerWrapper.controller,
                                bgDispatcher = testDispatcher,
                            ),
                    )
            )

        // Collect the user switcher into currentUserSwitcher.
        var currentUserSwitcher: FooterActionsButtonViewModel? = null
        val job = launch { underTest.userSwitcher.collect { currentUserSwitcher = it } }
        fun currentUserSwitcher(): FooterActionsButtonViewModel? {
            // Make sure we finish collecting the current user switcher. This is necessary because
            // combined flows launch multiple coroutines in the current scope so we need to make
            // sure we process all coroutines triggered by our flow collection before we make
            // assertions on the current buttons.
            advanceUntilIdle()
            return currentUserSwitcher
        }
        val currentUserSwitcher = collectLastValue(underTest.userSwitcher)

        // The user switcher is disabled.
        assertThat(currentUserSwitcher()).isNull()
@@ -203,12 +194,10 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        // in guest mode.
        userInfoController.updateInfo { this.picture = mock<UserIconDrawable>() }
        assertThat(iconTint()).isNull()

        job.cancel()
    }

    @Test
    fun security() = runBlockingTest {
    fun security() = runTest {
        val securityController = FakeSecurityController()
        val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>()

@@ -224,22 +213,15 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                footerActionsInteractor =
                    utils.footerActionsInteractor(
                        qsSecurityFooterUtils = qsSecurityFooterUtils,
                        bgDispatcher = testDispatcher,
                        securityRepository =
                            utils.securityRepository(
                                securityController = securityController,
                                bgDispatcher = testDispatcher,
                            ),
                    ),
            )

        // Collect the security model into currentSecurity.
        var currentSecurity: FooterActionsSecurityButtonViewModel? = null
        val job = launch { underTest.security.collect { currentSecurity = it } }
        fun currentSecurity(): FooterActionsSecurityButtonViewModel? {
            advanceUntilIdle()
            return currentSecurity
        }
        val currentSecurity = collectLastValue(underTest.security)

        // By default, we always return a null SecurityButtonConfig.
        assertThat(currentSecurity()).isNull()
@@ -270,12 +252,10 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        security = currentSecurity()
        assertThat(security).isNotNull()
        assertThat(security!!.onClick).isNull()

        job.cancel()
    }

    @Test
    fun foregroundServices() = runBlockingTest {
    fun foregroundServices() = runTest {
        val securityController = FakeSecurityController()
        val fgsManagerController =
            FakeFgsManagerController(
@@ -300,21 +280,14 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                        securityRepository =
                            utils.securityRepository(
                                securityController,
                                bgDispatcher = testDispatcher,
                            ),
                        foregroundServicesRepository =
                            utils.foregroundServicesRepository(fgsManagerController),
                        bgDispatcher = testDispatcher,
                    ),
            )

        // Collect the security model into currentSecurity.
        var currentForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
        val job = launch { underTest.foregroundServices.collect { currentForegroundServices = it } }
        fun currentForegroundServices(): FooterActionsForegroundServicesButtonViewModel? {
            advanceUntilIdle()
            return currentForegroundServices
        }
        val currentForegroundServices = collectLastValue(underTest.foregroundServices)

        // We don't show the foreground services button if the number of running packages is not
        // > 1.
@@ -356,12 +329,10 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        }
        securityController.updateState {}
        assertThat(currentForegroundServices()?.displayText).isFalse()

        job.cancel()
    }

    @Test
    fun observeDeviceMonitoringDialogRequests() = runBlockingTest {
    fun observeDeviceMonitoringDialogRequests() = runTest {
        val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>()
        val broadcastDispatcher = mock<BroadcastDispatcher>()

@@ -390,7 +361,6 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                    utils.footerActionsInteractor(
                        qsSecurityFooterUtils = qsSecurityFooterUtils,
                        broadcastDispatcher = broadcastDispatcher,
                        bgDispatcher = testDispatcher,
                    ),
            )

@@ -415,7 +385,4 @@ class FooterActionsViewModelTest : SysuiTestCase() {
        underTest.onVisibilityChangeRequested(visible = true)
        assertThat(underTest.isVisible.value).isTrue()
    }

    private fun runBlockingTest(block: suspend TestScope.() -> Unit) =
        runTest(testDispatcher) { block() }
}
+6 −4
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.GlobalSettings
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestCoroutineScheduler

/**
 * Util class to create real implementations of the FooterActions repositories, viewModel and
@@ -65,6 +66,7 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
class FooterActionsTestUtils(
    private val context: Context,
    private val testableLooper: TestableLooper,
    private val scheduler: TestCoroutineScheduler,
) {
    /** Enable or disable the user switcher in the settings. */
    fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) {
@@ -105,7 +107,7 @@ class FooterActionsTestUtils(
        foregroundServicesRepository: ForegroundServicesRepository = foregroundServicesRepository(),
        userSwitcherRepository: UserSwitcherRepository = userSwitcherRepository(),
        broadcastDispatcher: BroadcastDispatcher = mock(),
        bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
        bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
    ): FooterActionsInteractor {
        return FooterActionsInteractorImpl(
            activityStarter,
@@ -126,7 +128,7 @@ class FooterActionsTestUtils(
    /** Create a [SecurityRepository] to be used in tests. */
    fun securityRepository(
        securityController: SecurityController = FakeSecurityController(),
        bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
        bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
    ): SecurityRepository {
        return SecurityRepositoryImpl(
            securityController,
@@ -145,7 +147,7 @@ class FooterActionsTestUtils(
    fun userSwitcherRepository(
        @Application context: Context = this.context.applicationContext,
        bgHandler: Handler = Handler(testableLooper.looper),
        bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
        bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
        userManager: UserManager = mock(),
        userTracker: UserTracker = FakeUserTracker(),
        userSwitcherController: UserSwitcherController = mock(),