Merge "Modernizes RepeatWhenAttachedTest." into udc-dev
This commit is contained in:
@@ -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,186 +82,218 @@ class RepeatWhenAttachedTest : SysuiTestCase() {
|
|||||||
block = Block()
|
block = Block()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException::class)
|
@After
|
||||||
fun `repeatWhenAttached - enforces main thread`() = runBlockingTest {
|
fun tearDown() {
|
||||||
Assert.setTestThread(null)
|
Dispatchers.resetMain()
|
||||||
|
|
||||||
repeatWhenAttached()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException::class)
|
@Test(expected = IllegalStateException::class)
|
||||||
fun `repeatWhenAttached - dispose enforces main thread`() = runBlockingTest {
|
fun `repeatWhenAttached - enforces main thread`() =
|
||||||
val disposableHandle = repeatWhenAttached()
|
testScope.runTest {
|
||||||
Assert.setTestThread(null)
|
Assert.setTestThread(null)
|
||||||
|
|
||||||
disposableHandle.dispose()
|
repeatWhenAttached()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException::class)
|
||||||
|
fun `repeatWhenAttached - dispose enforces main thread`() =
|
||||||
|
testScope.runTest {
|
||||||
|
val disposableHandle = repeatWhenAttached()
|
||||||
|
Assert.setTestThread(null)
|
||||||
|
|
||||||
|
disposableHandle.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - view starts detached - runs block when attached`() = runBlockingTest {
|
fun `repeatWhenAttached - view starts detached - runs block when attached`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(false)
|
testScope.runTest {
|
||||||
repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(false)
|
||||||
assertThat(block.invocationCount).isEqualTo(0)
|
repeatWhenAttached()
|
||||||
|
assertThat(block.invocationCount).isEqualTo(0)
|
||||||
|
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
attachListeners.last().onViewAttachedToWindow(view)
|
attachListeners.last().onViewAttachedToWindow(view)
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
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`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
|
|
||||||
repeatWhenAttached()
|
repeatWhenAttached()
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - starts visible without focus - STARTED`() = runBlockingTest {
|
fun `repeatWhenAttached - starts visible without focus - STARTED`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
|
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
||||||
|
|
||||||
repeatWhenAttached()
|
repeatWhenAttached()
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
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`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
whenever(view.hasWindowFocus()).thenReturn(true)
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
|
whenever(view.hasWindowFocus()).thenReturn(true)
|
||||||
|
|
||||||
repeatWhenAttached()
|
repeatWhenAttached()
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
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`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
whenever(view.hasWindowFocus()).thenReturn(true)
|
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
||||||
|
whenever(view.hasWindowFocus()).thenReturn(true)
|
||||||
|
|
||||||
repeatWhenAttached()
|
repeatWhenAttached()
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - becomes visible without focus - STARTED`() = runBlockingTest {
|
fun `repeatWhenAttached - becomes visible without focus - STARTED`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
|
repeatWhenAttached()
|
||||||
verify(viewTreeObserver).addOnWindowVisibilityChangeListener(listenerCaptor.capture())
|
val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
|
||||||
|
verify(viewTreeObserver).addOnWindowVisibilityChangeListener(listenerCaptor.capture())
|
||||||
|
|
||||||
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
||||||
listenerCaptor.value.onWindowVisibilityChanged(View.VISIBLE)
|
listenerCaptor.value.onWindowVisibilityChanged(View.VISIBLE)
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.STARTED)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - gains focus but invisible - CREATED`() = runBlockingTest {
|
fun `repeatWhenAttached - gains focus but invisible - CREATED`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>()
|
repeatWhenAttached()
|
||||||
verify(viewTreeObserver).addOnWindowFocusChangeListener(listenerCaptor.capture())
|
val listenerCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>()
|
||||||
|
verify(viewTreeObserver).addOnWindowFocusChangeListener(listenerCaptor.capture())
|
||||||
|
|
||||||
whenever(view.hasWindowFocus()).thenReturn(true)
|
whenever(view.hasWindowFocus()).thenReturn(true)
|
||||||
listenerCaptor.value.onWindowFocusChanged(true)
|
listenerCaptor.value.onWindowFocusChanged(true)
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
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`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
val visibleCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
|
repeatWhenAttached()
|
||||||
verify(viewTreeObserver).addOnWindowVisibilityChangeListener(visibleCaptor.capture())
|
val visibleCaptor = argumentCaptor<ViewTreeObserver.OnWindowVisibilityChangeListener>()
|
||||||
val focusCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>()
|
verify(viewTreeObserver).addOnWindowVisibilityChangeListener(visibleCaptor.capture())
|
||||||
verify(viewTreeObserver).addOnWindowFocusChangeListener(focusCaptor.capture())
|
val focusCaptor = argumentCaptor<ViewTreeObserver.OnWindowFocusChangeListener>()
|
||||||
|
verify(viewTreeObserver).addOnWindowFocusChangeListener(focusCaptor.capture())
|
||||||
|
|
||||||
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
|
||||||
visibleCaptor.value.onWindowVisibilityChanged(View.VISIBLE)
|
visibleCaptor.value.onWindowVisibilityChanged(View.VISIBLE)
|
||||||
whenever(view.hasWindowFocus()).thenReturn(true)
|
whenever(view.hasWindowFocus()).thenReturn(true)
|
||||||
focusCaptor.value.onWindowFocusChanged(true)
|
focusCaptor.value.onWindowFocusChanged(true)
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.RESUMED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
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`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
|
repeatWhenAttached()
|
||||||
|
|
||||||
whenever(view.isAttachedToWindow).thenReturn(false)
|
whenever(view.isAttachedToWindow).thenReturn(false)
|
||||||
attachListeners.last().onViewDetachedFromWindow(view)
|
attachListeners.last().onViewDetachedFromWindow(view)
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
runCurrent()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
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`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
whenever(view.isAttachedToWindow).thenReturn(false)
|
repeatWhenAttached()
|
||||||
attachListeners.last().onViewDetachedFromWindow(view)
|
whenever(view.isAttachedToWindow).thenReturn(false)
|
||||||
|
attachListeners.last().onViewDetachedFromWindow(view)
|
||||||
|
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
attachListeners.last().onViewAttachedToWindow(view)
|
attachListeners.last().onViewAttachedToWindow(view)
|
||||||
|
|
||||||
assertThat(block.invocationCount).isEqualTo(2)
|
runCurrent()
|
||||||
assertThat(block.invocations[0].lifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
assertThat(block.invocationCount).isEqualTo(2)
|
||||||
assertThat(block.invocations[1].lifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
assertThat(block.invocations[0].lifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
||||||
}
|
assertThat(block.invocations[1].lifecycleState).isEqualTo(Lifecycle.State.CREATED)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - dispose attached`() = runBlockingTest {
|
fun `repeatWhenAttached - dispose attached`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
val handle = repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
|
val handle = repeatWhenAttached()
|
||||||
|
|
||||||
handle.dispose()
|
handle.dispose()
|
||||||
|
|
||||||
assertThat(attachListeners).isEmpty()
|
runCurrent()
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
assertThat(attachListeners).isEmpty()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - dispose never attached`() = runBlockingTest {
|
fun `repeatWhenAttached - dispose never attached`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(false)
|
testScope.runTest {
|
||||||
val handle = repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(false)
|
||||||
|
val handle = repeatWhenAttached()
|
||||||
|
|
||||||
handle.dispose()
|
handle.dispose()
|
||||||
|
|
||||||
assertThat(attachListeners).isEmpty()
|
assertThat(attachListeners).isEmpty()
|
||||||
assertThat(block.invocationCount).isEqualTo(0)
|
assertThat(block.invocationCount).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `repeatWhenAttached - dispose previously attached now detached`() = runBlockingTest {
|
fun `repeatWhenAttached - dispose previously attached now detached`() =
|
||||||
whenever(view.isAttachedToWindow).thenReturn(true)
|
testScope.runTest {
|
||||||
val handle = repeatWhenAttached()
|
whenever(view.isAttachedToWindow).thenReturn(true)
|
||||||
attachListeners.last().onViewDetachedFromWindow(view)
|
val handle = repeatWhenAttached()
|
||||||
|
attachListeners.last().onViewDetachedFromWindow(view)
|
||||||
|
|
||||||
handle.dispose()
|
handle.dispose()
|
||||||
|
|
||||||
assertThat(attachListeners).isEmpty()
|
runCurrent()
|
||||||
assertThat(block.invocationCount).isEqualTo(1)
|
assertThat(attachListeners).isEmpty()
|
||||||
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
assertThat(block.invocationCount).isEqualTo(1)
|
||||||
}
|
assertThat(block.latestLifecycleState).isEqualTo(Lifecycle.State.DESTROYED)
|
||||||
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.repeatWhenAttached(): DisposableHandle {
|
private fun CoroutineScope.repeatWhenAttached(): DisposableHandle {
|
||||||
return view.repeatWhenAttached(
|
return view.repeatWhenAttached(
|
||||||
|
|||||||
Reference in New Issue
Block a user