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

Commit 0b790d2d authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

Modernizes RepeatWhenAttachedTest.

This may or may not fix the cause for the flakiness of this test as seen
in the attached bug.

Fix: 274992372
Test: N/A
Change-Id: I95e596e0a1ab08dde4589ef0f4693202f344dfca
parent 5f1f784b
Loading
Loading
Loading
Loading
+181 −138
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@


package com.android.systemui.lifecycle
package com.android.systemui.lifecycle


import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.view.View
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle
@@ -28,8 +27,16 @@ import com.android.systemui.util.Assert
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.argumentCaptor
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before
import org.junit.Before
import org.junit.Rule
import org.junit.Rule
import org.junit.Test
import org.junit.Test
@@ -41,9 +48,9 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoJUnit


@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@SmallTest
@RunWith(JUnit4::class)
@RunWith(JUnit4::class)
@RunWithLooper
class RepeatWhenAttachedTest : SysuiTestCase() {
class RepeatWhenAttachedTest : SysuiTestCase() {


    @JvmField @Rule val mockito = MockitoJUnit.rule()
    @JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -54,9 +61,13 @@ class RepeatWhenAttachedTest : SysuiTestCase() {


    private lateinit var block: Block
    private lateinit var block: Block
    private lateinit var attachListeners: MutableList<View.OnAttachStateChangeListener>
    private lateinit var attachListeners: MutableList<View.OnAttachStateChangeListener>
    private lateinit var testScope: TestScope


    @Before
    @Before
    fun setUp() {
    fun setUp() {
        val testDispatcher = StandardTestDispatcher()
        testScope = TestScope(testDispatcher)
        Dispatchers.setMain(testDispatcher)
        Assert.setTestThread(Thread.currentThread())
        Assert.setTestThread(Thread.currentThread())
        whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)
        whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)
        whenever(view.windowVisibility).thenReturn(View.GONE)
        whenever(view.windowVisibility).thenReturn(View.GONE)
@@ -71,15 +82,22 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
        block = Block()
        block = Block()
    }
    }


    @After
    fun tearDown() {
        Dispatchers.resetMain()
    }

    @Test(expected = IllegalStateException::class)
    @Test(expected = IllegalStateException::class)
    fun `repeatWhenAttached - enforces main thread`() = runBlockingTest {
    fun `repeatWhenAttached - enforces main thread`() =
        testScope.runTest {
            Assert.setTestThread(null)
            Assert.setTestThread(null)


            repeatWhenAttached()
            repeatWhenAttached()
        }
        }


    @Test(expected = IllegalStateException::class)
    @Test(expected = IllegalStateException::class)
    fun `repeatWhenAttached - dispose enforces main thread`() = runBlockingTest {
    fun `repeatWhenAttached - dispose enforces main thread`() =
        testScope.runTest {
            val disposableHandle = repeatWhenAttached()
            val disposableHandle = repeatWhenAttached()
            Assert.setTestThread(null)
            Assert.setTestThread(null)


@@ -87,7 +105,8 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - view starts detached - runs block when attached`() = runBlockingTest {
    fun `repeatWhenAttached - view starts detached - runs block when attached`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(false)
            whenever(view.isAttachedToWindow).thenReturn(false)
            repeatWhenAttached()
            repeatWhenAttached()
            assertThat(block.invocationCount).isEqualTo(0)
            assertThat(block.invocationCount).isEqualTo(0)
@@ -95,56 +114,66 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            attachListeners.last().onViewAttachedToWindow(view)
            attachListeners.last().onViewAttachedToWindow(view)


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - view already attached - immediately runs block`() = runBlockingTest {
    fun `repeatWhenAttached - view already attached - immediately runs block`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)


            repeatWhenAttached()
            repeatWhenAttached()


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - starts visible without focus - STARTED`() = runBlockingTest {
    fun `repeatWhenAttached - starts visible without focus - STARTED`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.windowVisibility).thenReturn(View.VISIBLE)
            whenever(view.windowVisibility).thenReturn(View.VISIBLE)


            repeatWhenAttached()
            repeatWhenAttached()


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - starts with focus but invisible - CREATED`() = runBlockingTest {
    fun `repeatWhenAttached - starts with focus but invisible - CREATED`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.hasWindowFocus()).thenReturn(true)
            whenever(view.hasWindowFocus()).thenReturn(true)


            repeatWhenAttached()
            repeatWhenAttached()


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - starts visible and with focus - RESUMED`() = runBlockingTest {
    fun `repeatWhenAttached - starts visible and with focus - RESUMED`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.windowVisibility).thenReturn(View.VISIBLE)
            whenever(view.windowVisibility).thenReturn(View.VISIBLE)
            whenever(view.hasWindowFocus()).thenReturn(true)
            whenever(view.hasWindowFocus()).thenReturn(true)


            repeatWhenAttached()
            repeatWhenAttached()


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - becomes visible without focus - STARTED`() = runBlockingTest {
    fun `repeatWhenAttached - becomes visible without focus - STARTED`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            repeatWhenAttached()
            repeatWhenAttached()
            val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
            val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
@@ -153,12 +182,14 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
            whenever(view.windowVisibility).thenReturn(View.VISIBLE)
            whenever(view.windowVisibility).thenReturn(View.VISIBLE)
            listenerCaptor.value.onWindowVisibilityChanged(View.VISIBLE)
            listenerCaptor.value.onWindowVisibilityChanged(View.VISIBLE)


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - gains focus but invisible - CREATED`() = runBlockingTest {
    fun `repeatWhenAttached - gains focus but invisible - CREATED`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            repeatWhenAttached()
            repeatWhenAttached()
            val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>()
            val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>()
@@ -167,12 +198,14 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
            whenever(view.hasWindowFocus()).thenReturn(true)
            whenever(view.hasWindowFocus()).thenReturn(true)
            listenerCaptor.value.onWindowFocusChanged(true)
            listenerCaptor.value.onWindowFocusChanged(true)


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - becomes visible and gains focus - RESUMED`() = runBlockingTest {
    fun `repeatWhenAttached - becomes visible and gains focus - RESUMED`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            repeatWhenAttached()
            repeatWhenAttached()
            val visibleCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
            val visibleCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
@@ -185,24 +218,28 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
            whenever(view.hasWindowFocus()).thenReturn(true)
            whenever(view.hasWindowFocus()).thenReturn(true)
            focusCaptor.value.onWindowFocusChanged(true)
            focusCaptor.value.onWindowFocusChanged(true)


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - view gets detached - destroys the lifecycle`() = runBlockingTest {
    fun `repeatWhenAttached - view gets detached - destroys the lifecycle`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            repeatWhenAttached()
            repeatWhenAttached()


            whenever(view.isAttachedToWindow).thenReturn(false)
            whenever(view.isAttachedToWindow).thenReturn(false)
            attachListeners.last().onViewDetachedFromWindow(view)
            attachListeners.last().onViewDetachedFromWindow(view)


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - view gets reattached - recreates a lifecycle`() = runBlockingTest {
    fun `repeatWhenAttached - view gets reattached - recreates a lifecycle`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            repeatWhenAttached()
            repeatWhenAttached()
            whenever(view.isAttachedToWindow).thenReturn(false)
            whenever(view.isAttachedToWindow).thenReturn(false)
@@ -211,25 +248,29 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            attachListeners.last().onViewAttachedToWindow(view)
            attachListeners.last().onViewAttachedToWindow(view)


            runCurrent()
            assertThat(block.invocationCount).isEqualTo(2)
            assertThat(block.invocationCount).isEqualTo(2)
            assertThat(block.invocations[0].lifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
            assertThat(block.invocations[0].lifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
            assertThat(block.invocations[1].lifecycleState).isEqualTo(Lifecycle.State.CREATED)
            assertThat(block.invocations[1].lifecycleState).isEqualTo(Lifecycle.State.CREATED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - dispose attached`() = runBlockingTest {
    fun `repeatWhenAttached - dispose attached`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            val handle = repeatWhenAttached()
            val handle = repeatWhenAttached()


            handle.dispose()
            handle.dispose()


            runCurrent()
            assertThat(attachListeners).isEmpty()
            assertThat(attachListeners).isEmpty()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - dispose never attached`() = runBlockingTest {
    fun `repeatWhenAttached - dispose never attached`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(false)
            whenever(view.isAttachedToWindow).thenReturn(false)
            val handle = repeatWhenAttached()
            val handle = repeatWhenAttached()


@@ -240,13 +281,15 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun `repeatWhenAttached - dispose previously attached now detached`() = runBlockingTest {
    fun `repeatWhenAttached - dispose previously attached now detached`() =
        testScope.runTest {
            whenever(view.isAttachedToWindow).thenReturn(true)
            whenever(view.isAttachedToWindow).thenReturn(true)
            val handle = repeatWhenAttached()
            val handle = repeatWhenAttached()
            attachListeners.last().onViewDetachedFromWindow(view)
            attachListeners.last().onViewDetachedFromWindow(view)


            handle.dispose()
            handle.dispose()


            runCurrent()
            assertThat(attachListeners).isEmpty()
            assertThat(attachListeners).isEmpty()
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.invocationCount).isEqualTo(1)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
            assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)