[go: nahoru, domu]

Migrate snackbar tests and clean up TabTest.

I have also introduced APIs to assert DPs directly as it turns out that
quite often we need to perfom assertions on calculated numbers. This
will make the tolerance to be used everywhere.

Test: Added
Bug: 157657482
Change-Id: Ifb131a940a74763d1daf0a9554f5a8bb108e3fbe
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/MaterialTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/MaterialTest.kt
index 2c35fdfa..f6bbaf81 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/MaterialTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/MaterialTest.kt
@@ -18,14 +18,20 @@
 
 import androidx.compose.Composable
 import androidx.ui.core.Modifier
+import androidx.ui.geometry.Size
 import androidx.ui.layout.DpConstraints
+import androidx.ui.layout.Stack
+import androidx.ui.layout.preferredSizeIn
 import androidx.ui.test.BigTestConstraints
 import androidx.ui.test.CollectedSizes
 import androidx.ui.test.ComposeTestRule
+import androidx.ui.test.SemanticsNodeInteraction
+import androidx.ui.test.getAlignmentLinePosition
 import androidx.ui.test.runOnIdleCompose
 import androidx.ui.test.setContentAndGetPixelSize
+import androidx.ui.text.FirstBaseline
+import androidx.ui.text.LastBaseline
 import androidx.ui.unit.Density
-import androidx.ui.geometry.Size
 
 fun ComposeTestRule.setMaterialContent(
     modifier: Modifier = Modifier,
@@ -37,6 +43,20 @@
         }
     }
 }
+fun ComposeTestRule.setMaterialContentWithConstraints(
+    parentConstraints: DpConstraints,
+    composable: @Composable () -> Unit
+) {
+    setContent {
+        MaterialTheme {
+            Stack {
+                Stack(Modifier.preferredSizeIn(parentConstraints)) {
+                    composable()
+                }
+            }
+        }
+    }
+}
 fun <T> ComposeTestRule.runOnIdleComposeWithDensity(action: Density.() -> T): T {
     return runOnIdleCompose {
         density.action()
@@ -62,4 +82,8 @@
     MaterialTheme {
         Surface(modifier = modifier, content = children)
     }
-}
\ No newline at end of file
+}
+
+fun SemanticsNodeInteraction.getFirstBaselinePosition() = getAlignmentLinePosition(FirstBaseline)
+
+fun SemanticsNodeInteraction.getLastBaselinePosition() = getAlignmentLinePosition(LastBaseline)
\ No newline at end of file
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt
index fd947c2..7bb9b38 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt
@@ -20,35 +20,38 @@
 import androidx.compose.Providers
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
-import androidx.ui.text.FirstBaseline
-import androidx.ui.text.LastBaseline
-import androidx.ui.core.LayoutCoordinates
 import androidx.ui.core.Modifier
-import androidx.ui.core.globalPosition
-import androidx.ui.core.onPositioned
-import androidx.ui.core.positionInParent
 import androidx.ui.core.semantics.semantics
 import androidx.ui.core.testTag
 import androidx.ui.foundation.Text
 import androidx.ui.foundation.shape.corner.CutCornerShape
-import androidx.ui.geometry.Offset
 import androidx.ui.graphics.Color
 import androidx.ui.graphics.compositeOver
 import androidx.ui.layout.DpConstraints
 import androidx.ui.layout.Stack
+import androidx.ui.test.assertHeightIsEqualTo
+import androidx.ui.test.assertIsEqualTo
+import androidx.ui.test.assertIsNotEqualTo
 import androidx.ui.test.assertShape
+import androidx.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.ui.test.assertWidthIsEqualTo
 import androidx.ui.test.captureToBitmap
 import androidx.ui.test.createComposeRule
 import androidx.ui.test.doClick
 import androidx.ui.test.findByTag
 import androidx.ui.test.findByText
+import androidx.ui.test.getAlignmentLinePosition
+import androidx.ui.test.getBoundsInRoot
+import androidx.ui.text.FirstBaseline
+import androidx.ui.text.LastBaseline
 import androidx.ui.unit.dp
+import androidx.ui.unit.height
+import androidx.ui.unit.width
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import kotlin.math.roundToInt
 
 @MediumTest
 @RunWith(JUnit4::class)
@@ -86,138 +89,100 @@
 
     @Test
     fun snackbar_shortTextOnly_sizes() {
-        var textCoords: LayoutCoordinates? = null
-        val sizes = composeTestRule.setMaterialContentAndCollectSizes(
-            parentConstraints = DpConstraints(maxWidth = 300.dp)
-        ) {
+        composeTestRule.setMaterialContentWithConstraints(DpConstraints(maxWidth = 300.dp)) {
             Snackbar(
+                modifier = Modifier.testTag("snackbar"),
                 text = {
-                    Text("Message",
-                        Modifier.onPositioned { textCoords = it }
-                    )
+                    Text("Message")
                 }
             )
         }
-        sizes
-            .assertHeightEqualsTo(48.dp)
-            .assertWidthEqualsTo(300.dp)
-        assertThat(textCoords).isNotNull()
-        textCoords?.let {
-            with(composeTestRule.density) {
-                assertThat(it[FirstBaseline]).isNotEqualTo(0)
-                assertThat(it[FirstBaseline])
-                    .isEqualTo(it[LastBaseline])
-                assertThat(it.positionInParent.y.roundToInt() + it[FirstBaseline])
-                    .isEqualTo(30.dp.toIntPx())
-            }
-        }
+
+        findByTag("snackbar")
+            .assertWidthIsEqualTo(300.dp)
+            .assertHeightIsEqualTo(48.dp)
+
+        val fistBaseLine = findByText("Message").getAlignmentLinePosition(FirstBaseline)
+        val lastBaseLine = findByText("Message").getAlignmentLinePosition(LastBaseline)
+        fistBaseLine.assertIsNotEqualTo(0.dp, "first baseline")
+        fistBaseLine.assertIsEqualTo(lastBaseLine, "first baseline")
+
+        findByText("Message")
+            .assertTopPositionInRootIsEqualTo(30.dp - fistBaseLine)
     }
 
     @Test
     fun snackbar_shortTextAndButton_alignment() {
-        var snackCoords: LayoutCoordinates? = null
-        var textCoords: LayoutCoordinates? = null
-        var buttonCoords: LayoutCoordinates? = null
-        var buttonTextCoords: LayoutCoordinates? = null
-        val sizes = composeTestRule.setMaterialContentAndCollectSizes(
-            parentConstraints = DpConstraints(maxWidth = 300.dp)
-        ) {
+        composeTestRule.setMaterialContentWithConstraints(DpConstraints(maxWidth = 300.dp)) {
             Snackbar(
-                modifier = Modifier.onPositioned { snackCoords = it },
+                modifier = Modifier.testTag("snackbar"),
                 text = {
-                    Text("Message",
-                        Modifier.onPositioned { textCoords = it }
-                    )
+                    Text("Message")
                 },
                 action = {
                     TextButton(
                         >
-                        modifier = Modifier.onPositioned { buttonCoords = it }
+                        modifier = Modifier.testTag("button")
                     ) {
-                        Text("Undo",
-                            Modifier.onPositioned { buttonTextCoords = it }
-                        )
+                        Text("Undo")
                     }
                 }
             )
         }
-        sizes
-            .assertHeightEqualsTo(48.dp)
-            .assertWidthEqualsTo(300.dp)
-        assertThat(textCoords).isNotNull()
-        assertThat(buttonCoords).isNotNull()
-        assertThat(buttonTextCoords).isNotNull()
-        assertThat(snackCoords).isNotNull()
-        val localTextCoords = textCoords
-        val localButtonCoords = buttonCoords
-        val localButtonTextCoords = buttonTextCoords
-        val localSnackCoords = snackCoords
 
-        if (localTextCoords != null &&
-            localButtonCoords != null &&
-            localButtonTextCoords != null &&
-            localSnackCoords != null
-        ) {
-            with(composeTestRule.density) {
-                val buttonTextPos =
-                    localSnackCoords.childToLocal(localButtonTextCoords, Offset.Zero)
-                assertThat(localTextCoords[FirstBaseline]).isNotEqualTo(0)
-                assertThat(localButtonTextCoords[FirstBaseline]).isNotEqualTo(0)
-                assertThat(
-                    localTextCoords.globalPosition.y.roundToInt() + localTextCoords[FirstBaseline]
-                ).isEqualTo(30.dp.toIntPx())
-                assertThat(
-                    buttonTextPos.y.roundToInt() + localButtonTextCoords[FirstBaseline]
-                ).isEqualTo(30.dp.toIntPx())
-            }
-        }
+        findByTag("snackbar")
+            .assertWidthIsEqualTo(300.dp)
+            .assertHeightIsEqualTo(48.dp)
+
+        val textBaseLine = findByText("Message").getAlignmentLinePosition(FirstBaseline)
+        val buttonBaseLine = findByTag("button").getAlignmentLinePosition(FirstBaseline)
+        textBaseLine.assertIsNotEqualTo(0.dp, "text baseline")
+        buttonBaseLine.assertIsNotEqualTo(0.dp, "button baseline")
+
+        findByText("Message")
+            .assertTopPositionInRootIsEqualTo(30.dp - textBaseLine)
+
+        findByTag("button")
+            .assertTopPositionInRootIsEqualTo(30.dp - buttonBaseLine)
     }
 
     @Test
     fun snackbar_longText_sizes() {
-        var textCoords: LayoutCoordinates? = null
-        val sizes = composeTestRule.setMaterialContentAndCollectSizes(
-            parentConstraints = DpConstraints(maxWidth = 300.dp)
-        ) {
+        composeTestRule.setMaterialContentWithConstraints(DpConstraints(maxWidth = 300.dp)) {
             Snackbar(
+                modifier = Modifier.testTag("snackbar"),
                 text = {
-                    Text(longText,
-                        Modifier.onPositioned { textCoords = it }, maxLines = 2)
+                    Text(longText, Modifier.testTag("text"), maxLines = 2)
                 }
             )
         }
-        sizes
-            .assertHeightEqualsTo(68.dp)
-            .assertWidthEqualsTo(300.dp)
-        assertThat(textCoords).isNotNull()
-        textCoords?.let {
-            with(composeTestRule.density) {
-                assertThat(it[FirstBaseline]).isNotEqualTo(0)
-                assertThat(it[LastBaseline]).isNotEqualTo(0)
-                assertThat(it[FirstBaseline]).isNotEqualTo(it[LastBaseline])
-                assertThat(it.positionInParent.y.roundToInt() + it[FirstBaseline])
-                    .isEqualTo(30.dp.toIntPx())
-            }
-        }
+
+        findByTag("snackbar")
+            .assertWidthIsEqualTo(300.dp)
+            .assertHeightIsEqualTo(68.dp)
+
+        val firstBaseline = findByTag("text").getFirstBaselinePosition()
+        val lastBaseline = findByTag("text").getLastBaselinePosition()
+
+        firstBaseline.assertIsNotEqualTo(0.dp, "first baseline")
+        lastBaseline.assertIsNotEqualTo(0.dp, "last baseline")
+        firstBaseline.assertIsNotEqualTo(lastBaseline, "first baseline")
+
+        findByTag("text")
+            .assertTopPositionInRootIsEqualTo(30.dp - firstBaseline)
     }
 
     @Test
     fun snackbar_longTextAndButton_alignment() {
-        var snackCoords: LayoutCoordinates? = null
-        var textCoords: LayoutCoordinates? = null
-        var buttonCoords: LayoutCoordinates? = null
-        val sizes = composeTestRule.setMaterialContentAndCollectSizes(
-            parentConstraints = DpConstraints(maxWidth = 300.dp)
-        ) {
+        composeTestRule.setMaterialContentWithConstraints(DpConstraints(maxWidth = 300.dp)) {
             Snackbar(
-                modifier = Modifier.onPositioned { snackCoords = it },
+                modifier = Modifier.testTag("snackbar"),
                 text = {
-                    Text(longText,
-                        Modifier.onPositioned { textCoords = it }, maxLines = 2)
+                    Text(longText, Modifier.testTag("text"), maxLines = 2)
                 },
                 action = {
                     TextButton(
-                        modifier = Modifier.onPositioned { buttonCoords = it },
+                        modifier = Modifier.testTag("button"),
                         >
                     ) {
                         Text("Undo")
@@ -225,58 +190,40 @@
                 }
             )
         }
-        sizes
-            .assertHeightEqualsTo(68.dp)
-            .assertWidthEqualsTo(300.dp)
-        assertThat(textCoords).isNotNull()
-        assertThat(buttonCoords).isNotNull()
-        assertThat(snackCoords).isNotNull()
-        val localTextCoords = textCoords
-        val localButtonCoords = buttonCoords
-        val localSnackCoords = snackCoords
 
-        if (localTextCoords != null && localButtonCoords != null && localSnackCoords != null) {
-            with(composeTestRule.density) {
-                val buttonPositionInSnack =
-                    localSnackCoords.childToLocal(localButtonCoords, Offset.Zero)
-                val buttonCenter =
-                    buttonPositionInSnack.y.roundToInt() +
-                            (localButtonCoords.size.height / 2).toFloat()
+        findByTag("snackbar")
+            .assertWidthIsEqualTo(300.dp)
+            .assertHeightIsEqualTo(68.dp)
 
-                assertThat(localTextCoords[FirstBaseline]).isNotEqualTo(0)
-                assertThat(localTextCoords[LastBaseline]).isNotEqualTo(0)
-                assertThat(localTextCoords[FirstBaseline])
-                    .isNotEqualTo(localTextCoords[LastBaseline])
-                assertThat(
-                    localTextCoords.globalPosition.y.roundToInt() + localTextCoords[FirstBaseline]
-                ).isEqualTo(30.dp.toIntPx())
+        val textFirstBaseLine = findByTag("text").getFirstBaselinePosition()
+        val textLastBaseLine = findByTag("text").getLastBaselinePosition()
 
-                assertThat(buttonCenter).isEqualTo(
-                    (localSnackCoords.size.height / 2).toFloat()
-                )
-            }
-        }
+        textFirstBaseLine.assertIsNotEqualTo(0.dp, "first baseline")
+        textLastBaseLine.assertIsNotEqualTo(0.dp, "last baseline")
+        textFirstBaseLine.assertIsNotEqualTo(textLastBaseLine, "first baseline")
+
+        findByTag("text")
+            .assertTopPositionInRootIsEqualTo(30.dp - textFirstBaseLine)
+
+        val buttonBounds = findByTag("button").getBoundsInRoot()
+        val snackBounds = findByTag("snackbar").getBoundsInRoot()
+
+        val buttonCenter = buttonBounds.top + (buttonBounds.height / 2)
+        buttonCenter.assertIsEqualTo(snackBounds.height / 2, "button center")
     }
 
     @Test
     fun snackbar_textAndButtonOnSeparateLine_alignment() {
-        var snackCoords: LayoutCoordinates? = null
-        var textCoords: LayoutCoordinates? = null
-        var buttonCoords: LayoutCoordinates? = null
-        composeTestRule.setMaterialContentAndCollectSizes(
-            parentConstraints = DpConstraints(maxWidth = 300.dp)
-        ) {
+        composeTestRule.setMaterialContentWithConstraints(DpConstraints(maxWidth = 300.dp)) {
             Snackbar(
-                modifier = Modifier.onPositioned { snackCoords = it },
+                modifier = Modifier.testTag("snackbar"),
                 text = {
-                    Text("Message",
-                        Modifier.onPositioned { textCoords = it }
-                    )
+                    Text("Message")
                 },
                 action = {
                     TextButton(
                         >
-                        modifier = Modifier.onPositioned { buttonCoords = it }
+                        modifier = Modifier.testTag("button")
                     ) {
                         Text("Undo")
                     }
@@ -284,41 +231,21 @@
                 actionOnNewLine = true
             )
         }
-        assertThat(textCoords).isNotNull()
-        assertThat(buttonCoords).isNotNull()
-        assertThat(snackCoords).isNotNull()
-        val localTextCoords = textCoords
-        val localButtonCoords = buttonCoords
-        val localSnackCoords = snackCoords
 
-        if (localTextCoords != null && localButtonCoords != null && localSnackCoords != null) {
-            with(composeTestRule.density) {
-                val buttonPositionInSnack =
-                    localSnackCoords.childToLocal(localButtonCoords, Offset.Zero)
-                val textPositionInSnack =
-                    localSnackCoords.childToLocal(localTextCoords, Offset.Zero)
+        val textFirstBaseLine = findByText("Message").getFirstBaselinePosition()
+        val textLastBaseLine = findByText("Message").getLastBaselinePosition()
+        val textBounds = findByText("Message").getBoundsInRoot()
+        val buttonBounds = findByTag("button").getBoundsInRoot()
 
-                assertThat(
-                    textPositionInSnack.y.roundToInt() + localTextCoords[FirstBaseline]
-                ).isEqualTo(30.dp.toIntPx())
+        findByText("Message")
+            .assertTopPositionInRootIsEqualTo(30.dp - textFirstBaseLine)
 
-                assertThat(
-                    buttonPositionInSnack.y.roundToInt() -
-                            textPositionInSnack.y.roundToInt() -
-                            localTextCoords[LastBaseline]
-                ).isEqualTo(18.dp.toIntPx())
+        findByTag("button")
+            .assertTopPositionInRootIsEqualTo(18.dp + textBounds.top + textLastBaseLine)
 
-                assertThat(
-                    localSnackCoords.size.height - buttonPositionInSnack.y.roundToInt() -
-                            localButtonCoords.size.height
-                ).isEqualTo(8.dp.toIntPx())
-
-                assertThat(
-                    localSnackCoords.size.width - buttonPositionInSnack.x.roundToInt() -
-                            localButtonCoords.size.width
-                ).isEqualTo(8.dp.toIntPx())
-            }
-        }
+        findByTag("snackbar")
+            .assertHeightIsEqualTo(8.dp + buttonBounds.top + buttonBounds.height)
+            .assertWidthIsEqualTo(8.dp + buttonBounds.left + buttonBounds.width)
     }
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/TabTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/TabTest.kt
index 24f5c3f..568116e 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/TabTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/TabTest.kt
@@ -34,6 +34,8 @@
 import androidx.ui.material.samples.ScrollingTextTabs
 import androidx.ui.material.samples.TextTabs
 import androidx.ui.test.assertCountEquals
+import androidx.ui.test.assertHeightIsEqualTo
+import androidx.ui.test.assertIsEqualTo
 import androidx.ui.test.assertIsSelected
 import androidx.ui.test.assertIsUnselected
 import androidx.ui.test.assertPositionInRootIsEqualTo
@@ -41,14 +43,11 @@
 import androidx.ui.test.doClick
 import androidx.ui.test.findAll
 import androidx.ui.test.findByTag
-import androidx.ui.test.getAlignmentLinePosition
 import androidx.ui.test.getBoundsInRoot
 import androidx.ui.test.isInMutuallyExclusiveGroup
-import androidx.ui.text.LastBaseline
 import androidx.ui.unit.dp
 import androidx.ui.unit.height
 import androidx.ui.unit.width
-import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -68,42 +67,45 @@
 
     @Test
     fun textTab_height() {
-        composeTestRule
-            .setMaterialContentAndCollectSizes {
-                Box {
-                    Tab(text = { Text("Text") }, selected = true, >
-                }
+        composeTestRule.setMaterialContent {
+            Box(Modifier.testTag("tab")) {
+                Tab(text = { Text("Text") }, selected = true, >
             }
-            .assertHeightEqualsTo(ExpectedSmallTabHeight)
+        }
+
+        findByTag("tab")
+            .assertHeightIsEqualTo(ExpectedSmallTabHeight)
     }
 
     @Test
     fun iconTab_height() {
-        composeTestRule
-            .setMaterialContentAndCollectSizes {
-                Box {
-                    Tab(icon = { Icon(icon) }, selected = true, >
-                }
+        composeTestRule.setMaterialContent {
+            Box(Modifier.testTag("tab")) {
+                Tab(icon = { Icon(icon) }, selected = true, >
             }
-            .assertHeightEqualsTo(ExpectedSmallTabHeight)
+        }
+
+        findByTag("tab")
+            .assertHeightIsEqualTo(ExpectedSmallTabHeight)
     }
 
     @Test
     fun textAndIconTab_height() {
-        composeTestRule
-            .setMaterialContentAndCollectSizes {
-                Box {
-                    Surface {
-                        Tab(
-                            text = { Text("Text and Icon") },
-                            icon = { Icon(icon) },
-                            selected = true,
-                            >
-                        )
-                    }
+        composeTestRule.setMaterialContent {
+            Box(Modifier.testTag("tab")) {
+                Surface {
+                    Tab(
+                        text = { Text("Text and Icon") },
+                        icon = { Icon(icon) },
+                        selected = true,
+                        >
+                    )
                 }
             }
-            .assertHeightEqualsTo(ExpectedLargeTabHeight)
+        }
+
+        findByTag("tab")
+            .assertHeightIsEqualTo(ExpectedLargeTabHeight)
     }
 
     @Test
@@ -189,12 +191,11 @@
 
         val tabRowBounds = findByTag("tabRow").getBoundsInRoot()
         val textBounds = findByTag("text").getBoundsInRoot()
-        val textBaselinePos = findByTag("text").getAlignmentLinePosition(LastBaseline)
+        val textBaselinePos = findByTag("text").getLastBaselinePosition()
 
         val baselinePositionY = textBounds.top + textBaselinePos
         val expectedPositionY = tabRowBounds.height - expectedBaselineDistance
-
-        assertThat(baselinePositionY.value).isWithin(0.5f).of(expectedPositionY.value)
+        baselinePositionY.assertIsEqualTo(expectedPositionY, "baseline y-position")
     }
 
     @Test
@@ -227,11 +228,11 @@
 
         val tabRowBounds = findByTag("tabRow").getBoundsInRoot()
         val textBounds = findByTag("text").getBoundsInRoot()
-        val textBaselinePos = findByTag("text").getAlignmentLinePosition(LastBaseline)
+        val textBaselinePos = findByTag("text").getLastBaselinePosition()
 
         val baselinePositionY = textBounds.top + textBaselinePos
         val expectedPositionY = tabRowBounds.height - expectedBaselineDistance
-        assertThat(baselinePositionY).isEqualTo(expectedPositionY)
+        baselinePositionY.assertIsEqualTo(expectedPositionY, "baseline y-position")
     }
 
     @Test
@@ -262,13 +263,13 @@
 
         val tabRowBounds = findByTag("tabRow").getBoundsInRoot()
         val textBounds = findByTag("text").getBoundsInRoot()
-        val textBaselinePos = findByTag("text").getAlignmentLinePosition(LastBaseline)
+        val textBaselinePos = findByTag("text").getLastBaselinePosition()
 
         val expectedBaselineDistance = expectedBaseline + indicatorHeight
 
         val baselinePositionY = textBounds.top + textBaselinePos
         val expectedPositionY = (tabRowBounds.height - expectedBaselineDistance)
-        assertThat(baselinePositionY.value).isWithin(0.5f).of(expectedPositionY.value)
+        baselinePositionY.assertIsEqualTo(expectedPositionY, "baseline y-position")
     }
 
     @Test
diff --git a/ui/ui-test/api/0.1.0-dev15.txt b/ui/ui-test/api/0.1.0-dev15.txt
index ca50fe9..649780f 100644
--- a/ui/ui-test/api/0.1.0-dev15.txt
+++ b/ui/ui-test/api/0.1.0-dev15.txt
@@ -64,7 +64,11 @@
   public final class BoundsAssertionsKt {
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinHeight);
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedHeight);
+    method public static void assertIsEqualTo-552lcfo(float, float expected, String subject = "", float tolerance = null(0.5));
+    method public static void assertIsNotEqualTo-552lcfo(float, float unexpected, String subject = "", float tolerance = null(0.5));
+    method public static androidx.ui.test.SemanticsNodeInteraction assertLeftPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertPositionInRootIsEqualTo-jINh5Q8(androidx.ui.test.SemanticsNodeInteraction, float expectedLeft, float expectedTop);
+    method public static androidx.ui.test.SemanticsNodeInteraction assertTopPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinWidth);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedWidth);
     method public static float getAlignmentLinePosition(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.core.AlignmentLine line);
diff --git a/ui/ui-test/api/current.txt b/ui/ui-test/api/current.txt
index ca50fe9..649780f 100644
--- a/ui/ui-test/api/current.txt
+++ b/ui/ui-test/api/current.txt
@@ -64,7 +64,11 @@
   public final class BoundsAssertionsKt {
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinHeight);
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedHeight);
+    method public static void assertIsEqualTo-552lcfo(float, float expected, String subject = "", float tolerance = null(0.5));
+    method public static void assertIsNotEqualTo-552lcfo(float, float unexpected, String subject = "", float tolerance = null(0.5));
+    method public static androidx.ui.test.SemanticsNodeInteraction assertLeftPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertPositionInRootIsEqualTo-jINh5Q8(androidx.ui.test.SemanticsNodeInteraction, float expectedLeft, float expectedTop);
+    method public static androidx.ui.test.SemanticsNodeInteraction assertTopPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinWidth);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedWidth);
     method public static float getAlignmentLinePosition(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.core.AlignmentLine line);
diff --git a/ui/ui-test/api/public_plus_experimental_0.1.0-dev15.txt b/ui/ui-test/api/public_plus_experimental_0.1.0-dev15.txt
index ca50fe9..649780f 100644
--- a/ui/ui-test/api/public_plus_experimental_0.1.0-dev15.txt
+++ b/ui/ui-test/api/public_plus_experimental_0.1.0-dev15.txt
@@ -64,7 +64,11 @@
   public final class BoundsAssertionsKt {
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinHeight);
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedHeight);
+    method public static void assertIsEqualTo-552lcfo(float, float expected, String subject = "", float tolerance = null(0.5));
+    method public static void assertIsNotEqualTo-552lcfo(float, float unexpected, String subject = "", float tolerance = null(0.5));
+    method public static androidx.ui.test.SemanticsNodeInteraction assertLeftPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertPositionInRootIsEqualTo-jINh5Q8(androidx.ui.test.SemanticsNodeInteraction, float expectedLeft, float expectedTop);
+    method public static androidx.ui.test.SemanticsNodeInteraction assertTopPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinWidth);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedWidth);
     method public static float getAlignmentLinePosition(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.core.AlignmentLine line);
diff --git a/ui/ui-test/api/public_plus_experimental_current.txt b/ui/ui-test/api/public_plus_experimental_current.txt
index ca50fe9..649780f 100644
--- a/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/ui/ui-test/api/public_plus_experimental_current.txt
@@ -64,7 +64,11 @@
   public final class BoundsAssertionsKt {
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinHeight);
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedHeight);
+    method public static void assertIsEqualTo-552lcfo(float, float expected, String subject = "", float tolerance = null(0.5));
+    method public static void assertIsNotEqualTo-552lcfo(float, float unexpected, String subject = "", float tolerance = null(0.5));
+    method public static androidx.ui.test.SemanticsNodeInteraction assertLeftPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertPositionInRootIsEqualTo-jINh5Q8(androidx.ui.test.SemanticsNodeInteraction, float expectedLeft, float expectedTop);
+    method public static androidx.ui.test.SemanticsNodeInteraction assertTopPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinWidth);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedWidth);
     method public static float getAlignmentLinePosition(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.core.AlignmentLine line);
diff --git a/ui/ui-test/api/restricted_0.1.0-dev15.txt b/ui/ui-test/api/restricted_0.1.0-dev15.txt
index ca50fe9..649780f 100644
--- a/ui/ui-test/api/restricted_0.1.0-dev15.txt
+++ b/ui/ui-test/api/restricted_0.1.0-dev15.txt
@@ -64,7 +64,11 @@
   public final class BoundsAssertionsKt {
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinHeight);
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedHeight);
+    method public static void assertIsEqualTo-552lcfo(float, float expected, String subject = "", float tolerance = null(0.5));
+    method public static void assertIsNotEqualTo-552lcfo(float, float unexpected, String subject = "", float tolerance = null(0.5));
+    method public static androidx.ui.test.SemanticsNodeInteraction assertLeftPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertPositionInRootIsEqualTo-jINh5Q8(androidx.ui.test.SemanticsNodeInteraction, float expectedLeft, float expectedTop);
+    method public static androidx.ui.test.SemanticsNodeInteraction assertTopPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinWidth);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedWidth);
     method public static float getAlignmentLinePosition(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.core.AlignmentLine line);
diff --git a/ui/ui-test/api/restricted_current.txt b/ui/ui-test/api/restricted_current.txt
index ca50fe9..649780f 100644
--- a/ui/ui-test/api/restricted_current.txt
+++ b/ui/ui-test/api/restricted_current.txt
@@ -64,7 +64,11 @@
   public final class BoundsAssertionsKt {
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinHeight);
     method public static androidx.ui.test.SemanticsNodeInteraction assertHeightIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedHeight);
+    method public static void assertIsEqualTo-552lcfo(float, float expected, String subject = "", float tolerance = null(0.5));
+    method public static void assertIsNotEqualTo-552lcfo(float, float unexpected, String subject = "", float tolerance = null(0.5));
+    method public static androidx.ui.test.SemanticsNodeInteraction assertLeftPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertPositionInRootIsEqualTo-jINh5Q8(androidx.ui.test.SemanticsNodeInteraction, float expectedLeft, float expectedTop);
+    method public static androidx.ui.test.SemanticsNodeInteraction assertTopPositionInRootIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedTop);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsAtLeast-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedMinWidth);
     method public static androidx.ui.test.SemanticsNodeInteraction assertWidthIsEqualTo-Gf70O4E(androidx.ui.test.SemanticsNodeInteraction, float expectedWidth);
     method public static float getAlignmentLinePosition(androidx.ui.test.SemanticsNodeInteraction, androidx.ui.core.AlignmentLine line);
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/assertions/BoundsAssertionsTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/assertions/BoundsAssertionsTest.kt
index 64a2ccd..c4234df 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/assertions/BoundsAssertionsTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/assertions/BoundsAssertionsTest.kt
@@ -29,7 +29,11 @@
 import androidx.ui.layout.wrapContentSize
 import androidx.ui.test.assertHeightIsAtLeast
 import androidx.ui.test.assertHeightIsEqualTo
+import androidx.ui.test.assertIsEqualTo
+import androidx.ui.test.assertIsNotEqualTo
+import androidx.ui.test.assertLeftPositionInRootIsEqualTo
 import androidx.ui.test.assertPositionInRootIsEqualTo
+import androidx.ui.test.assertTopPositionInRootIsEqualTo
 import androidx.ui.test.assertWidthIsAtLeast
 import androidx.ui.test.assertWidthIsEqualTo
 import androidx.ui.test.createComposeRule
@@ -68,6 +72,33 @@
     }
 
     @Test
+    fun dp_assertEquals() {
+        5.dp.assertIsEqualTo(5.dp)
+        5.dp.assertIsEqualTo(4.6.dp)
+        5.dp.assertIsEqualTo(5.4.dp)
+    }
+
+    @Test
+    fun dp_assertNotEquals() {
+        5.dp.assertIsNotEqualTo(6.dp)
+    }
+
+    @Test
+    fun dp_assertEquals_fail() {
+        expectError<AssertionError> {
+            5.dp.assertIsEqualTo(6.dp)
+        }
+    }
+
+    @Test
+    fun dp_assertNotEquals_fail() {
+        expectError<AssertionError> {
+            5.dp.assertIsNotEqualTo(5.dp)
+            5.dp.assertIsNotEqualTo(5.4.dp)
+        }
+    }
+
+    @Test
     fun assertEquals() {
         composeBox()
 
@@ -123,6 +154,8 @@
 
         findByTag(tag)
             .assertPositionInRootIsEqualTo(expectedLeft = 50.dp, expectedTop = 100.dp)
+            .assertLeftPositionInRootIsEqualTo(50.dp)
+            .assertTopPositionInRootIsEqualTo(100.dp)
     }
 
     @Test
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/BoundsAssertions.kt b/ui/ui-test/src/main/java/androidx/ui/test/BoundsAssertions.kt
index a16fd1f..07895a3 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/BoundsAssertions.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/BoundsAssertions.kt
@@ -36,7 +36,7 @@
  */
 fun SemanticsNodeInteraction.assertWidthIsEqualTo(expectedWidth: Dp): SemanticsNodeInteraction {
     return withBoundsInRoot {
-        areEqualOrThrow("width", it.width, expectedWidth)
+        it.width.toDp().assertIsEqualTo(expectedWidth, "width")
     }
 }
 
@@ -47,7 +47,7 @@
  */
 fun SemanticsNodeInteraction.assertHeightIsEqualTo(expectedHeight: Dp): SemanticsNodeInteraction {
     return withBoundsInRoot {
-        areEqualOrThrow("height", it.height, expectedHeight)
+        it.height.toDp().assertIsEqualTo(expectedHeight, "height")
     }
 }
 /**
@@ -104,8 +104,40 @@
     expectedTop: Dp
 ): SemanticsNodeInteraction {
     return withBoundsInRoot {
-        areEqualOrThrow("left", it.left, expectedLeft)
-        areEqualOrThrow("top", it.top, expectedTop)
+        it.left.toDp().assertIsEqualTo(expectedLeft, "left")
+        it.top.toDp().assertIsEqualTo(expectedTop, "top")
+    }
+}
+
+/**
+ * Asserts that the layout of this node has the top position in the root composable that is equal to
+ * the given position.
+ *
+ * @param expectedTop The top (y) position to assert.
+ *
+ * @throws AssertionError if comparison fails.
+ */
+fun SemanticsNodeInteraction.assertTopPositionInRootIsEqualTo(
+    expectedTop: Dp
+): SemanticsNodeInteraction {
+    return withBoundsInRoot {
+        it.top.toDp().assertIsEqualTo(expectedTop, "top")
+    }
+}
+
+/**
+ * Asserts that the layout of this node has the left position in the root composable that is
+ * equal to the given position.
+ *
+ * @param expectedTop The left (x) position to assert.
+ *
+ * @throws AssertionError if comparison fails.
+ */
+fun SemanticsNodeInteraction.assertLeftPositionInRootIsEqualTo(
+    expectedTop: Dp
+): SemanticsNodeInteraction {
+    return withBoundsInRoot {
+        it.left.toDp().assertIsEqualTo(expectedTop, "left")
     }
 }
 
@@ -124,6 +156,54 @@
     }
 }
 
+/**
+ * Asserts that this value is equal to the given [expected] value.
+ *
+ * Performs the comparison with the given [tolerance] or the default one if none is provided. It is
+ * recommended to use tolerance when comparing positions and size coming from the framework as there
+ * can be rounding operation performed by individual layouts so the values can be slightly off from
+ * the expected ones.
+ *
+ * @param expected The expected value to which this one should be equal to.
+ * @param subject Used in the error message to identify which item this assertion failed on.
+ * @param tolerance The tolerance within which the values should be treated as equal.
+ *
+ * @throws AssertionError if comparison fails.
+ */
+fun Dp.assertIsEqualTo(expected: Dp, subject: String = "", tolerance: Dp = Dp(.5f)) {
+    val diff = (this - expected).value.absoluteValue
+    if (diff > tolerance.value) {
+        // Comparison failed, report the error in DPs
+        throw AssertionError(
+            "Actual $subject is $this, expected $expected (tolerance: $tolerance)")
+    }
+}
+
+/**
+ * Asserts that this value is not equal to the given [unexpected] value.
+ *
+ * Performs the comparison with the given [tolerance] or the default one if none is provided. It is
+ * recommended to use tolerance when comparing positions and size coming from the framework as there
+ * can be rounding operation performed by individual layouts so the values can be slightly off from
+ * the expected ones.
+ *
+ * @param unexpected The value to which this one should not be equal to.
+ * @param subject Used in the error message to identify which item this assertion failed on.
+ * @param tolerance The tolerance that is expected to be greater than the difference between the
+ * given values to treat them as non-equal.
+ *
+ * @throws AssertionError if comparison fails.
+ */
+fun Dp.assertIsNotEqualTo(unexpected: Dp, subject: String = "", tolerance: Dp = Dp(.5f)) {
+    val diff = (this - unexpected).value.absoluteValue
+    if (diff <= tolerance.value) {
+        // Comparison failed, report the error in DPs
+        throw AssertionError(
+            "Actual $subject is $this, not expected to be equal to $unexpected within a " +
+                    "tolerance of $tolerance")
+    }
+}
+
 private fun <R> SemanticsNodeInteraction.withDensity(
     operation: Density.(SemanticsNode) -> R
 ): R {
@@ -142,19 +222,6 @@
     return this
 }
 
-private fun Density.areEqualOrThrow(
-    subject: String,
-    actualPx: Float,
-    expected: Dp
-) {
-    val diff = (actualPx - expected.toPx()).absoluteValue
-    if (diff > floatTolerance) {
-        // Comparison failed, report the error in DPs
-        throw AssertionError(
-            "Actual $subject is ${actualPx.toDp()}, expected $expected")
-    }
-}
-
 private fun Density.isAtLeastOrThrow(
     subject: String,
     actualPx: Float,