Merge "Update LazyListFocusMoveTest to use ParameterizedComposeTestRule" into androidx-main
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyListFocusMoveTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyListFocusMoveTest.kt
index 98952e5..403f3d5 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyListFocusMoveTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyListFocusMoveTest.kt
@@ -27,8 +27,11 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.testutils.ParameterizedComposeTestRule
+import androidx.compose.testutils.createParameterizedComposeTestRule
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
@@ -46,8 +49,6 @@
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.test.junit4.ComposeContentTestRule
-import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.LayoutDirection.Ltr
@@ -65,83 +66,101 @@
@OptIn(ExperimentalComposeUiApi::class)
@MediumTest
@RunWith(Parameterized::class)
-class LazyListFocusMoveTest(param: Param) {
+class LazyListFocusMoveTest(param: FocusDirectionWrapper) {
+
@get:Rule
- val rule = createComposeRule()
+ val rule = createParameterizedComposeTestRule<Param>()
// We need to wrap the inline class parameter in another class because Java can't instantiate
// the inline class.
+ class FocusDirectionWrapper(val direction: FocusDirection)
+
class Param(
- val focusDirection: FocusDirection,
val reverseLayout: Boolean,
val layoutDirection: LayoutDirection
) {
- override fun toString() = "focusDirection=$focusDirection " +
+ override fun toString() =
"reverseLayout=$reverseLayout " +
- "layoutDirection=$layoutDirection"
+ "layoutDirection=$layoutDirection"
}
- private val focusDirection = param.focusDirection
- private val reverseLayout = param.reverseLayout
- private val layoutDirection = param.layoutDirection
- private val initiallyFocused: FocusRequester = FocusRequester()
+ private val focusDirection = param.direction
+ private var initiallyFocused: FocusRequester = FocusRequester()
private var isLazyListFocused by mutableStateOf(false)
private val isFocused = mutableMapOf<Int, Boolean>()
private lateinit var lazyListState: LazyListState
private lateinit var focusManager: FocusManager
companion object {
- @JvmStatic
- @Parameterized.Parameters(name = "{0}")
- fun initParameters() = buildList {
- for (direction in listOf(Previous, Next, Left, Right, Up, Down, Enter, Exit)) {
- for (reverseLayout in listOf(true, false)) {
- for (layoutDirection in listOf(Ltr, Rtl)) {
- add(Param(direction, reverseLayout, layoutDirection))
- }
+ val ParamsToRun = buildList {
+ for (reverseLayout in listOf(true, false)) {
+ for (layoutDirection in listOf(Ltr, Rtl)) {
+ add(Param(reverseLayout, layoutDirection))
}
}
}
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun initParameters() = buildList {
+ for (direction in arrayOf(Previous, Next, Left, Right, Up, Down, Enter, Exit)) {
+ add(FocusDirectionWrapper(direction))
+ }
+ }
+ }
+
+ private fun resetTestCase() {
+ isLazyListFocused = false
+ isFocused.clear()
+ initiallyFocused = FocusRequester()
}
@Test
fun moveFocusAmongVisibleItems() {
// Arrange.
rule.setTestContent {
- lazyList(50.dp, lazyListState) {
+ lazyList(50.dp, it, lazyListState) {
item { FocusableBox(0) }
item { FocusableBox(1, initiallyFocused) }
item { FocusableBox(2) }
}
}
- rule.runOnIdle { initiallyFocused.requestFocus() }
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle { initiallyFocused.requestFocus() }
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 2 else 0]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 0 else 2]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 0 else 2]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 2 else 0]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 2 else 0]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 0 else 2]).isTrue()
+ }
- Up -> assertThat(isFocused[if (reverseLayout) 2 else 0]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 0 else 2]).isTrue()
- Previous -> assertThat(isFocused[0]).isTrue()
- Next -> assertThat(isFocused[2]).isTrue()
- Enter -> assertThat(isFocused[1]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Right -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 0 else 2]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 2 else 0]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 2 else 0]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 0 else 2]).isTrue()
+ Previous -> assertThat(isFocused[0]).isTrue()
+ Next -> assertThat(isFocused[2]).isTrue()
+ Enter -> assertThat(isFocused[1]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
}
@@ -150,40 +169,49 @@
fun moveFocusAmongVisibleItems_userScrollIsOff() {
// Arrange.
rule.setTestContent {
- lazyList(50.dp, lazyListState, userScrollEnabled = false) {
+ lazyList(50.dp, it, lazyListState, userScrollEnabled = false) {
item { FocusableBox(0) }
item { FocusableBox(1, initiallyFocused) }
item { FocusableBox(2) }
}
}
- rule.runOnIdle { initiallyFocused.requestFocus() }
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle { initiallyFocused.requestFocus() }
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 2 else 0]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 0 else 2]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 0 else 2]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 2 else 0]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 2 else 0]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 0 else 2]).isTrue()
+ }
- Up -> assertThat(isFocused[if (reverseLayout) 2 else 0]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 0 else 2]).isTrue()
- Previous -> assertThat(isFocused[0]).isTrue()
- Next -> assertThat(isFocused[2]).isTrue()
- Enter -> assertThat(isFocused[1]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Right -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 0 else 2]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 2 else 0]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 2 else 0]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 0 else 2]).isTrue()
+ Previous -> assertThat(isFocused[0]).isTrue()
+ Next -> assertThat(isFocused[2]).isTrue()
+ Enter -> assertThat(isFocused[1]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
+ rule.waitForIdle()
}
}
}
@@ -192,54 +220,65 @@
fun moveFocusToItemThatIsJustBeyondBounds() {
// Arrange.
rule.setTestContent {
- lazyList(30.dp, lazyListState) {
+ lazyList(30.dp, it, lazyListState) {
items(5) { FocusableBox(it) }
item { FocusableBox(5, initiallyFocused) }
items(5) { FocusableBox(it + 6) }
}
}
- rule.runOnIdle {
- // Scroll so that the focused item is in the middle.
- runBlocking { lazyListState.scrollToItem(4) }
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle {
+ // Scroll so that the focused item is in the middle.
+ runBlocking { lazyListState.scrollToItem(4) }
- // Move focus to the last visible item.
- initiallyFocused.requestFocus()
- when (focusDirection) {
- Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(focusDirection)
- Enter, Exit -> {
- // Do nothing
+ // Move focus to the last visible item.
+ initiallyFocused.requestFocus()
+ when (focusDirection) {
+ Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(
+ focusDirection
+ )
+
+ Enter, Exit -> {
+ // Do nothing
+ }
+
+ else -> unsupportedDirection()
+ }
}
- else -> unsupportedDirection()
- }
- }
-
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 7 else 3]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 3 else 7]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 3 else 7]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 7 else 3]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 7 else 3]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 3 else 7]).isTrue()
+ }
- Up -> assertThat(isFocused[if (reverseLayout) 7 else 3]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 3 else 7]).isTrue()
- Previous -> assertThat(isFocused[3]).isTrue()
- Next -> assertThat(isFocused[7]).isTrue()
- Enter -> assertThat(isFocused[5]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Right -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 3 else 7]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 7 else 3]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 7 else 3]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 3 else 7]).isTrue()
+ Previous -> assertThat(isFocused[3]).isTrue()
+ Next -> assertThat(isFocused[7]).isTrue()
+ Enter -> assertThat(isFocused[5]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
}
@@ -248,44 +287,53 @@
fun moveFocusToItemThatIsJustBeyondBounds_userScrollIsOff() {
// Arrange.
rule.setTestContent {
- lazyList(30.dp, lazyListState, userScrollEnabled = false) {
+ lazyList(30.dp, it, lazyListState, userScrollEnabled = false) {
items(5) { FocusableBox(it) }
item { FocusableBox(5, initiallyFocused) }
items(5) { FocusableBox(it + 6) }
}
}
- rule.runOnIdle {
- // Scroll so that the focused item is in the middle.
- runBlocking { lazyListState.scrollToItem(4) }
+ with(rule) {
+ forEachParameter(ParamsToRun) {
+ runOnIdle {
+ // Scroll so that the focused item is in the middle.
+ runBlocking { lazyListState.scrollToItem(4) }
- // Move focus to the last visible item.
- initiallyFocused.requestFocus()
- when (focusDirection) {
- Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(focusDirection)
- Enter, Exit -> {
- // Do nothing
+ // Move focus to the last visible item.
+ initiallyFocused.requestFocus()
+ when (focusDirection) {
+ Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(
+ focusDirection
+ )
+
+ Enter, Exit -> {
+ // Do nothing
+ }
+
+ else -> unsupportedDirection()
+ }
+ }
+ val firstVisibleItemIndex = lazyListState.firstVisibleItemIndex
+ // Act.
+ runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- else -> unsupportedDirection()
+ // Assert We Did Not Move
+ runOnIdle {
+ assertThat(lazyListState.firstVisibleItemIndex).isEqualTo(firstVisibleItemIndex)
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
- val firstVisibleItemIndex = lazyListState.firstVisibleItemIndex
- // Act.
- rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert We Did Not Move
- rule.runOnIdle {
- assertThat(lazyListState.firstVisibleItemIndex).isEqualTo(firstVisibleItemIndex)
- }
}
@Test
fun moveFocusToItemThatIsFarBeyondBounds() {
// Arrange.
rule.setTestContent {
- lazyList(30.dp, lazyListState) {
+ lazyList(30.dp, it, lazyListState) {
items(5) { FocusableBox(it) }
items(100) { Box(Modifier.size(10.dp)) }
item { FocusableBox(105) }
@@ -295,48 +343,65 @@
items(5) { FocusableBox(it + 208) }
}
}
- rule.runOnIdle {
- // Scroll so that the focused item is in the middle.
- runBlocking { lazyListState.scrollToItem(105) }
- initiallyFocused.requestFocus()
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle {
+ // Scroll so that the focused item is in the middle.
+ runBlocking { lazyListState.scrollToItem(105) }
+ initiallyFocused.requestFocus()
- // Move focus to the last visible item.
- when (focusDirection) {
- Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(focusDirection)
- Enter, Exit -> {
- // Do nothing
+ // Move focus to the last visible item.
+ when (focusDirection) {
+ Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(
+ focusDirection
+ )
+
+ Enter, Exit -> {
+ // Do nothing
+ }
+
+ else -> unsupportedDirection()
+ }
}
- else -> unsupportedDirection()
- }
- }
-
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 208 else 4]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 4 else 208]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 4 else 208]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 208 else 4]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr ->
+ assertThat(isFocused[if (param.reverseLayout) 208 else 4]).isTrue()
- Up -> assertThat(isFocused[if (reverseLayout) 208 else 4]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 4 else 208]).isTrue()
- Previous -> assertThat(isFocused[4]).isTrue()
- Next -> assertThat(isFocused[208]).isTrue()
- Enter -> assertThat(isFocused[106]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Rtl ->
+ assertThat(isFocused[if (param.reverseLayout) 4 else 208]).isTrue()
+ }
+
+ Right -> when (param.layoutDirection) {
+ Ltr ->
+ assertThat(isFocused[if (param.reverseLayout) 4 else 208]).isTrue()
+
+ Rtl ->
+ assertThat(isFocused[if (param.reverseLayout) 208 else 4]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 208 else 4]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 4 else 208]).isTrue()
+ Previous -> assertThat(isFocused[4]).isTrue()
+ Next -> assertThat(isFocused[208]).isTrue()
+ Enter -> assertThat(isFocused[106]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
}
@@ -345,56 +410,77 @@
fun moveFocusToItemThatIsBeyondBoundsAndInANestedLazyList() {
// Arrange.
rule.setTestContent {
- lazyList(30.dp, lazyListState) {
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 0) } } }
+ lazyList(30.dp, it, lazyListState) {
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 0) } }
+ }
item { FocusableBox(3) }
item { FocusableBox(4, initiallyFocused) }
item { FocusableBox(5) }
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 6) } } }
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 6) } }
+ }
}
}
- rule.runOnIdle {
- // Scroll so that the focused item is in the middle.
- runBlocking { lazyListState.scrollToItem(1) }
- initiallyFocused.requestFocus()
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle {
+ // Scroll so that the focused item is in the middle.
+ runBlocking { lazyListState.scrollToItem(1) }
+ initiallyFocused.requestFocus()
- // Move focus to the last visible item.
- when (focusDirection) {
- Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(focusDirection)
- Enter, Exit -> {
- // Do nothing
+ // Move focus to the last visible item.
+ when (focusDirection) {
+ Left, Right, Up, Down, Previous, Next -> focusManager.moveFocus(
+ focusDirection
+ )
+
+ Enter, Exit -> {
+ // Do nothing
+ }
+
+ else -> unsupportedDirection()
+ }
}
- else -> unsupportedDirection()
- }
- }
-
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 8 else 0]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 2 else 6]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 2 else 6]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 8 else 0]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 8 else 0]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 2 else 6]).isTrue()
+ }
- Up -> assertThat(isFocused[if (reverseLayout) 8 else 0]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 2 else 6]).isTrue()
- Previous -> assertThat(isFocused[2]).isTrue()
- Next -> assertThat(isFocused[6]).isTrue()
- Enter -> assertThat(isFocused[4]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Right -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 2 else 6]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 8 else 0]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 8 else 0]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 2 else 6]).isTrue()
+ Previous -> assertThat(isFocused[2]).isTrue()
+ Next -> assertThat(isFocused[6]).isTrue()
+ Enter -> assertThat(isFocused[4]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
}
@@ -407,57 +493,75 @@
// Arrange.
rule.setTestContent {
- lazyList(30.dp, lazyListState) {
+ lazyList(30.dp, it, lazyListState) {
item { FocusableBox(0) }
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 1) } } }
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 1) } }
+ }
item { FocusableBox(4, initiallyFocused) }
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 5) } } }
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 5) } }
+ }
item { FocusableBox(8) }
}
}
- rule.runOnIdle {
- // Scroll so that the focused item is in the middle.
- runBlocking { lazyListState.scrollToItem(1, 10) }
- initiallyFocused.requestFocus()
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle {
+ // Scroll so that the focused item is in the middle.
+ runBlocking { lazyListState.scrollToItem(1, 10) }
+ initiallyFocused.requestFocus()
- // Move focus to the last visible item.
- when (focusDirection) {
- Left, Right, Up, Down -> focusManager.moveFocus(focusDirection)
- Previous, Next -> repeat(3) { focusManager.moveFocus(focusDirection) }
- Enter, Exit -> {
- // Do nothing
+ // Move focus to the last visible item.
+ when (focusDirection) {
+ Left, Right, Up, Down -> focusManager.moveFocus(focusDirection)
+ Previous, Next -> repeat(3) { focusManager.moveFocus(focusDirection) }
+ Enter, Exit -> {
+ // Do nothing
+ }
+
+ else -> unsupportedDirection()
+ }
}
- else -> unsupportedDirection()
- }
- }
-
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 8 else 0]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 0 else 8]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 0 else 8]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 8 else 0]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 8 else 0]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 0 else 8]).isTrue()
+ }
- Up -> assertThat(isFocused[if (reverseLayout) 8 else 0]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 0 else 8]).isTrue()
- Previous -> assertThat(isFocused[0]).isTrue()
- Next -> assertThat(isFocused[8]).isTrue()
- Enter -> assertThat(isFocused[4]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Right -> when (param.layoutDirection) {
+ Ltr -> assertThat(isFocused[if (param.reverseLayout) 0 else 8]).isTrue()
+ Rtl -> assertThat(isFocused[if (param.reverseLayout) 8 else 0]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 8 else 0]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 0 else 8]).isTrue()
+ Previous -> assertThat(isFocused[0]).isTrue()
+ Next -> assertThat(isFocused[8]).isTrue()
+ Enter -> assertThat(isFocused[4]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
}
@@ -470,57 +574,91 @@
// Arrange.
rule.setTestContent {
- lazyList(30.dp, lazyListState) {
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 0) } } }
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 3) } } }
+ lazyList(30.dp, it, lazyListState) {
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 0) } }
+ }
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 3) } }
+ }
item { FocusableBox(6, initiallyFocused) }
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 7) } } }
- item { lazyListCrossAxis(30.dp) { items(3) { FocusableBox(it + 10) } } }
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 7) } }
+ }
+ item {
+ lazyListCrossAxis(
+ 30.dp,
+ it
+ ) { items(3) { FocusableBox(it + 10) } }
+ }
}
}
- rule.runOnIdle {
- // Scroll so that the focused item is in the middle.
- runBlocking { lazyListState.scrollToItem(2, 0) }
- initiallyFocused.requestFocus()
+ with(rule) {
+ forEachParameter(ParamsToRun) { param ->
+ runOnIdle {
+ // Scroll so that the focused item is in the middle.
+ runBlocking { lazyListState.scrollToItem(2, 0) }
+ initiallyFocused.requestFocus()
- // Move focus to the last visible item.
- when (focusDirection) {
- Left, Right, Up, Down -> focusManager.moveFocus(focusDirection)
- Previous, Next -> repeat(3) { focusManager.moveFocus(focusDirection) }
- Enter, Exit -> {
- // Do nothing
+ // Move focus to the last visible item.
+ when (focusDirection) {
+ Left, Right, Up, Down -> focusManager.moveFocus(focusDirection)
+ Previous, Next -> repeat(3) { focusManager.moveFocus(focusDirection) }
+ Enter, Exit -> {
+ // Do nothing
+ }
+
+ else -> unsupportedDirection()
+ }
}
- else -> unsupportedDirection()
- }
- }
-
- // Act.
- val success = rule.runOnIdle {
- focusManager.moveFocus(focusDirection)
- }
-
- // Assert.
- rule.runOnIdle {
- assertThat(success).apply { if (focusDirection == Enter) isFalse() else isTrue() }
- when (focusDirection) {
- Left -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 12 else 0]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 2 else 10]).isTrue()
+ // Act.
+ val success = runOnIdle {
+ focusManager.moveFocus(focusDirection)
}
- Right -> when (layoutDirection) {
- Ltr -> assertThat(isFocused[if (reverseLayout) 2 else 10]).isTrue()
- Rtl -> assertThat(isFocused[if (reverseLayout) 12 else 0]).isTrue()
- }
+ // Assert.
+ runOnIdle {
+ assertThat(success).apply {
+ if (focusDirection == Enter) isFalse() else isTrue()
+ }
+ when (focusDirection) {
+ Left -> when (param.layoutDirection) {
+ Ltr ->
+ assertThat(isFocused[if (param.reverseLayout) 12 else 0]).isTrue()
- Up -> assertThat(isFocused[if (reverseLayout) 12 else 0]).isTrue()
- Down -> assertThat(isFocused[if (reverseLayout) 2 else 10]).isTrue()
- Previous -> assertThat(isFocused[2]).isTrue()
- Next -> assertThat(isFocused[10]).isTrue()
- Enter -> assertThat(isFocused[6]).isTrue()
- Exit -> assertThat(isLazyListFocused).isTrue()
- else -> unsupportedDirection()
+ Rtl ->
+ assertThat(isFocused[if (param.reverseLayout) 2 else 10]).isTrue()
+ }
+
+ Right -> when (param.layoutDirection) {
+ Ltr ->
+ assertThat(isFocused[if (param.reverseLayout) 2 else 10]).isTrue()
+
+ Rtl ->
+ assertThat(isFocused[if (param.reverseLayout) 12 else 0]).isTrue()
+ }
+
+ Up -> assertThat(isFocused[if (param.reverseLayout) 12 else 0]).isTrue()
+ Down -> assertThat(isFocused[if (param.reverseLayout) 2 else 10]).isTrue()
+ Previous -> assertThat(isFocused[2]).isTrue()
+ Next -> assertThat(isFocused[10]).isTrue()
+ Enter -> assertThat(isFocused[6]).isTrue()
+ Exit -> assertThat(isLazyListFocused).isTrue()
+ else -> unsupportedDirection()
+ }
+ }
+ runOnIdle { runBlocking { lazyListState.scrollToItem(0) } }
+ resetTestCase()
}
}
}
@@ -536,12 +674,16 @@
)
}
- private fun ComposeContentTestRule.setTestContent(composable: @Composable () -> Unit) {
+ private fun ParameterizedComposeTestRule<Param>.setTestContent(
+ composable: @Composable (param: Param) -> Unit
+ ) {
setContent {
- CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
- focusManager = LocalFocusManager.current
- lazyListState = rememberLazyListState()
- composable()
+ key(it) {
+ CompositionLocalProvider(LocalLayoutDirection provides it.layoutDirection) {
+ focusManager = LocalFocusManager.current
+ lazyListState = rememberLazyListState()
+ composable(it)
+ }
}
}
}
@@ -549,9 +691,10 @@
@Composable
private fun lazyList(
size: Dp,
+ param: Param,
state: LazyListState = rememberLazyListState(),
userScrollEnabled: Boolean = true,
- content: LazyListScope.() -> Unit
+ content: LazyListScope.() -> Unit,
) {
when (focusDirection) {
Left, Right, Enter, Exit, Next, Previous -> LazyRow(
@@ -560,7 +703,7 @@
.onFocusChanged { isLazyListFocused = it.isFocused }
.focusable(),
state = state,
- reverseLayout = reverseLayout,
+ reverseLayout = param.reverseLayout,
content = content,
userScrollEnabled = userScrollEnabled
)
@@ -571,7 +714,7 @@
.onFocusChanged { isLazyListFocused = it.isFocused }
.focusable(),
state = state,
- reverseLayout = reverseLayout,
+ reverseLayout = param.reverseLayout,
content = content,
userScrollEnabled = userScrollEnabled
)
@@ -583,6 +726,7 @@
@Composable
private fun lazyListCrossAxis(
size: Dp,
+ param: Param,
state: LazyListState = rememberLazyListState(),
content: LazyListScope.() -> Unit
) {
@@ -590,14 +734,14 @@
Left, Right, Enter, Exit, Next, Previous -> LazyColumn(
modifier = Modifier.size(size),
state = state,
- reverseLayout = reverseLayout,
+ reverseLayout = param.reverseLayout,
content = content
)
Up, Down -> LazyRow(
modifier = Modifier.size(size),
state = state,
- reverseLayout = reverseLayout,
+ reverseLayout = param.reverseLayout,
content = content
)