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 Original line 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.mock
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.nullable
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.TestCoroutineScheduler
import org.junit.Before
import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
@@ -55,7 +56,7 @@ class FooterActionsInteractorTest : SysuiTestCase() {


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


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


    @Before
    @Before
    fun setUp() {
    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
    @Test
    fun settingsButton() = runBlockingTest {
    fun settingsButton() = runTest {
        val underTest = utils.footerActionsViewModel(showPowerButton = false)
        val underTest = utils.footerActionsViewModel(showPowerButton = false)
        val settings = underTest.settings
        val settings = underTest.settings


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


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


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


        // Collect the user switcher into currentUserSwitcher.
        // Collect the user switcher into currentUserSwitcher.
        var currentUserSwitcher: FooterActionsButtonViewModel? = null
        val currentUserSwitcher = collectLastValue(underTest.userSwitcher)
        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
        }


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

        job.cancel()
    }
    }


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


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


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


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

        job.cancel()
    }
    }


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


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


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

        job.cancel()
    }
    }


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


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


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

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