[go: nahoru, domu]

blob: 3bac43f400b9ebc54bb440691a599b2b4a322bc6 [file] [log] [blame]
Mihai Burlaciuc478fae62019-08-08 10:00:06 +01001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Siyamed Sinirfc059292019-11-21 13:39:17 -080016package androidx.ui.core
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010017
18import android.view.View
Siyamed Sinirfc059292019-11-21 13:39:17 -080019import androidx.compose.Composable
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000020import androidx.compose.emptyContent
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010021import androidx.test.espresso.Espresso
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +010022import androidx.test.espresso.Root
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010023import androidx.test.espresso.assertion.ViewAssertions.matches
24import androidx.test.espresso.matcher.BoundedMatcher
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010025import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
26import androidx.test.filters.MediumTest
Siyamed Sinirfd8bc422019-11-21 18:23:58 -080027import androidx.ui.core.selection.SimpleContainer
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010028import androidx.ui.test.createComposeRule
George Mount842c8c12020-01-08 16:03:42 -080029import androidx.ui.unit.IntPx
30import androidx.ui.unit.IntPxPosition
31import androidx.ui.unit.IntPxSize
Mihai Popad9d535072020-01-15 12:58:15 +000032import androidx.ui.unit.ipx
George Mount842c8c12020-01-08 16:03:42 -080033import androidx.ui.unit.isFinite
34import androidx.ui.unit.toPxPosition
35import androidx.ui.unit.toPxSize
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010036import com.google.common.truth.Truth
37import org.hamcrest.CoreMatchers.instanceOf
38import org.hamcrest.Description
39import org.hamcrest.Matcher
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +010040import org.hamcrest.TypeSafeMatcher
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010041import org.junit.Rule
42import org.junit.Test
43import org.junit.runner.RunWith
44import org.junit.runners.JUnit4
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +010045import java.util.concurrent.CountDownLatch
46import java.util.concurrent.TimeUnit
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010047
48@MediumTest
49@RunWith(JUnit4::class)
50class PopupTest {
51 @get:Rule
52 val composeTestRule = createComposeRule(disableTransitions = true)
53 private val popupText = "popupText"
Filip Pavlisbea89ec2019-10-02 17:28:06 +010054 private val testTag = "testedPopup"
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010055
56 private val parentGlobalPosition = IntPxPosition(IntPx(50), IntPx(50))
57 private val offset = IntPxPosition(IntPx(10), IntPx(10))
58 private val parentSize = IntPxSize(IntPx(100), IntPx(100))
59 private val popupSize = IntPxSize(IntPx(40), IntPx(20))
60
George Mount203056e2019-08-30 16:17:48 -070061 private var composeViewAbsolutePosition = IntPxPosition(IntPx(0), IntPx(0))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +010062
63 // TODO(b/140215440): Some tests are calling the OnChildPosition method inside the Popup too
64 // many times
65 private fun createPopupWithAlignmentRule(alignment: Alignment, measureLatch: CountDownLatch) {
Andrey Kulikov47f0e1a2020-01-28 13:52:46 +000066 with(composeTestRule.density) {
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010067 val popupWidthDp = popupSize.width.toDp()
68 val popupHeightDp = popupSize.height.toDp()
69 val parentWidthDp = parentSize.width.toDp()
70 val parentHeightDp = parentSize.height.toDp()
71
72 composeTestRule.setContent {
Filip Pavlisbea89ec2019-10-02 17:28:06 +010073 // Get the compose view position on screen
Chuck Jazdzewskifb6db652019-11-25 08:30:51 -080074 val composeView = AndroidComposeViewAmbient.current
Filip Pavlisbea89ec2019-10-02 17:28:06 +010075 val positionArray = IntArray(2)
76 composeView.getLocationOnScreen(positionArray)
77 composeViewAbsolutePosition = IntPxPosition(
78 IntPx(positionArray[0]),
79 IntPx(positionArray[1])
80 )
81
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010082 // Align the parent of the popup on the TopLeft corner, this results in the global
83 // position of the parent to be (0, 0)
Siyamed Sinirfc059292019-11-21 13:39:17 -080084 TestAlign {
Siyamed Sinirfd8bc422019-11-21 18:23:58 -080085 SimpleContainer(width = parentWidthDp, height = parentHeightDp) {
Ryan Mentley7865a632019-08-20 20:10:29 -070086 PopupTestTag(testTag) {
Filip Pavlisbea89ec2019-10-02 17:28:06 +010087 Popup(alignment = alignment, offset = offset) {
88 // This is called after the OnChildPosition method in Popup() which
89 // updates the popup to its final position
90 OnPositioned {
91 measureLatch.countDown()
92 }
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000093 SimpleContainer(
94 width = popupWidthDp,
95 height = popupHeightDp,
96 children = emptyContent()
97 )
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +010098 }
Mihai Burlaciuc478fae62019-08-08 10:00:06 +010099 }
100 }
101 }
102 }
103 }
104 }
105
Filip Pavlisbea89ec2019-10-02 17:28:06 +0100106 // TODO(b/139861182): Remove all of this and provide helpers on ComposeTestRule
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100107 private fun popupMatches(viewMatcher: Matcher<in View>) {
George Mount203056e2019-08-30 16:17:48 -0700108 Espresso.onView(instanceOf(AndroidComposeView::class.java))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100109 .inRoot(PopupLayoutMatcher())
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100110 .check(matches(viewMatcher))
111 }
112
Filip Pavlisbea89ec2019-10-02 17:28:06 +0100113 private inner class PopupLayoutMatcher : TypeSafeMatcher<Root>() {
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100114 override fun describeTo(description: Description?) {
115 description?.appendText("PopupLayoutMatcher")
116 }
117
118 // TODO(b/141101446): Find a way to match the window used by the popup
119 override fun matchesSafely(item: Root?): Boolean {
Filip Pavlisbea89ec2019-10-02 17:28:06 +0100120 return item != null && isPopupLayout(item.decorView, testTag)
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100121 }
122 }
123
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100124 @Test
125 fun popup_isShowing() {
126 composeTestRule.setContent {
Siyamed Sinirfd8bc422019-11-21 18:23:58 -0800127 SimpleContainer {
Ryan Mentley7865a632019-08-20 20:10:29 -0700128 PopupTestTag(testTag) {
Filip Pavlisbea89ec2019-10-02 17:28:06 +0100129 Popup(alignment = Alignment.Center) {
130 Text(popupText)
131 }
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100132 }
133 }
134 }
135
136 popupMatches(isDisplayed())
137 }
138
139 @Test
140 fun popup_hasActualSize() {
Andrey Kulikov47f0e1a2020-01-28 13:52:46 +0000141 val popupWidthDp = with(composeTestRule.density) {
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100142 popupSize.width.toDp()
143 }
Andrey Kulikov47f0e1a2020-01-28 13:52:46 +0000144 val popupHeightDp = with(composeTestRule.density) {
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100145 popupSize.height.toDp()
146 }
147
148 composeTestRule.setContent {
Siyamed Sinirfd8bc422019-11-21 18:23:58 -0800149 SimpleContainer {
Ryan Mentley7865a632019-08-20 20:10:29 -0700150 PopupTestTag(testTag) {
Filip Pavlisbea89ec2019-10-02 17:28:06 +0100151 Popup(alignment = Alignment.Center) {
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +0000152 SimpleContainer(
153 width = popupWidthDp,
154 height = popupHeightDp,
155 children = emptyContent()
156 )
Filip Pavlisbea89ec2019-10-02 17:28:06 +0100157 }
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100158 }
159 }
160 }
161
162 popupMatches(matchesSize(popupSize.width.value, popupSize.height.value))
163 }
164
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100165 @Test
166 fun popup_correctPosition_alignmentTopLeft() {
167 /* Expected TopLeft Position
168 x = offset.x
169 y = offset.y
170 */
171 val expectedPositionTopLeft = IntPxPosition(IntPx(10), IntPx(10))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100172 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100173
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100174 createPopupWithAlignmentRule(alignment = Alignment.TopLeft, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100175
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100176 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700177 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionTopLeft))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100178 }
179
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100180 @Test
181 fun popup_correctPosition_alignmentTopCenter() {
182 /* Expected TopCenter Position
183 x = offset.x + parentSize.x / 2 - popupSize.x / 2
184 y = offset.y
185 */
186 val expectedPositionTopCenter = IntPxPosition(IntPx(40), IntPx(10))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100187 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100188
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100189 createPopupWithAlignmentRule(alignment = Alignment.TopCenter, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100190
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100191 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700192 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionTopCenter))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100193 }
194
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100195 @Test
196 fun popup_correctPosition_alignmentTopRight() {
197 /* Expected TopRight Position
198 x = offset.x + parentSize.x - popupSize.x
199 y = offset.y
200 */
201 val expectedPositionTopRight = IntPxPosition(IntPx(70), IntPx(10))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100202 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100203
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100204 createPopupWithAlignmentRule(alignment = Alignment.TopRight, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100205
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100206 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700207 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionTopRight))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100208 }
209
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100210 @Test
211 fun popup_correctPosition_alignmentCenterRight() {
212 /* Expected CenterRight Position
213 x = offset.x + parentSize.x - popupSize.x
214 y = offset.y + parentSize.y / 2 - popupSize.y / 2
215 */
216 val expectedPositionCenterRight = IntPxPosition(IntPx(70), IntPx(50))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100217 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100218
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100219 createPopupWithAlignmentRule(alignment = Alignment.CenterRight, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100220
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100221 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700222 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionCenterRight))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100223 }
224
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100225 @Test
226 fun popup_correctPosition_alignmentBottomRight() {
227 /* Expected BottomRight Position
228 x = offset.x + parentSize.x - popupSize.x
229 y = offset.y + parentSize.y - popupSize.y
230 */
231 val expectedPositionBottomRight = IntPxPosition(IntPx(70), IntPx(90))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100232 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100233
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100234 createPopupWithAlignmentRule(alignment = Alignment.BottomRight, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100235
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100236 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700237 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionBottomRight))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100238 }
239
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100240 @Test
241 fun popup_correctPosition_alignmentBottomCenter() {
242 /* Expected BottomCenter Position
243 x = offset.x + parentSize.x / 2 - popupSize.x / 2
244 y = offset.y + parentSize.y - popupSize.y
245 */
246 val expectedPositionBottomCenter = IntPxPosition(IntPx(40), IntPx(90))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100247 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100248
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100249 createPopupWithAlignmentRule(
250 alignment = Alignment.BottomCenter,
251 measureLatch = measureLatch
252 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100253
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100254 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700255 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionBottomCenter))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100256 }
257
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100258 @Test
259 fun popup_correctPosition_alignmentBottomLeft() {
260 /* Expected BottomLeft Position
261 x = offset.x
262 y = offset.y + parentSize.y - popupSize.y
263 */
264 val expectedPositionBottomLeft = IntPxPosition(IntPx(10), IntPx(90))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100265 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100266
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100267 createPopupWithAlignmentRule(alignment = Alignment.BottomLeft, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100268
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100269 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700270 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionBottomLeft))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100271 }
272
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100273 @Test
274 fun popup_correctPosition_alignmentCenterLeft() {
275 /* Expected CenterLeft Position
276 x = offset.x
277 y = offset.y + parentSize.y / 2 - popupSize.y / 2
278 */
279 val expectedPositionCenterLeft = IntPxPosition(IntPx(10), IntPx(50))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100280 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100281
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100282 createPopupWithAlignmentRule(alignment = Alignment.CenterLeft, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100283
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100284 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700285 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionCenterLeft))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100286 }
287
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100288 @Test
289 fun popup_correctPosition_alignmentCenter() {
290 /* Expected Center Position
291 x = offset.x + parentSize.x / 2 - popupSize.x / 2
292 y = offset.y + parentSize.y / 2 - popupSize.y / 2
293 */
294 val expectedPositionCenter = IntPxPosition(IntPx(40), IntPx(50))
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100295 val measureLatch = CountDownLatch(1)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100296
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100297 createPopupWithAlignmentRule(alignment = Alignment.Center, measureLatch = measureLatch)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100298
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100299 measureLatch.await(1, TimeUnit.SECONDS)
George Mount203056e2019-08-30 16:17:48 -0700300 popupMatches(matchesPosition(composeViewAbsolutePosition + expectedPositionCenter))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100301 }
302
303 @Test
304 fun popup_calculateGlobalPositionTopLeft() {
305 /* Expected TopLeft Position
306 x = parentGlobalPosition.x + offset.x
307 y = parentGlobalPosition.y + offset.y
308 */
309 val expectedPositionTopLeft = IntPxPosition(IntPx(60), IntPx(60))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100310 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100311 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100312 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100313 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
314 popupPositionProperties.parentSize = parentSize.toPxSize()
315 popupPositionProperties.childrenSize = popupSize.toPxSize()
316
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100317 val positionTopLeft = calculatePopupGlobalPosition(
318 popupPositionProperties,
319 Alignment.TopLeft
320 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100321
322 Truth.assertThat(positionTopLeft).isEqualTo(expectedPositionTopLeft)
323 }
324
325 @Test
326 fun popup_calculateGlobalPositionTopCenter() {
327 /* Expected TopCenter Position
328 x = parentGlobalPosition.x + offset.x + parentSize.x / 2 - popupSize.x / 2
329 y = parentGlobalPosition.y + offset.y
330 */
331 val expectedPositionTopCenter = IntPxPosition(IntPx(90), IntPx(60))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100332 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100333 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100334 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100335 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
336 popupPositionProperties.parentSize = parentSize.toPxSize()
337 popupPositionProperties.childrenSize = popupSize.toPxSize()
338
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100339 val positionTopCenter = calculatePopupGlobalPosition(
340 popupPositionProperties,
341 Alignment.TopCenter
342 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100343
344 Truth.assertThat(positionTopCenter).isEqualTo(expectedPositionTopCenter)
345 }
346
347 @Test
348 fun popup_calculateGlobalPositionTopRight() {
349 /* Expected TopRight Position
350 x = parentGlobalPosition.x + offset.x + parentSize.x - popupSize.x
351 y = parentGlobalPosition.y + offset.y
352 */
353 val expectedPositionTopRight = IntPxPosition(IntPx(120), IntPx(60))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100354 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100355 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100356 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100357 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
358 popupPositionProperties.parentSize = parentSize.toPxSize()
359 popupPositionProperties.childrenSize = popupSize.toPxSize()
360
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100361 val positionTopRight = calculatePopupGlobalPosition(
362 popupPositionProperties,
363 Alignment.TopRight
364 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100365
366 Truth.assertThat(positionTopRight).isEqualTo(expectedPositionTopRight)
367 }
368
369 @Test
370 fun popup_calculateGlobalPositionCenterRight() {
371 /* Expected CenterRight Position
372 x = parentGlobalPosition.x + offset.x + parentSize.x - popupSize.x
373 y = parentGlobalPosition.y + offset.y + parentSize.y / 2 - popupSize.y / 2
374 */
375 val expectedPositionCenterRight = IntPxPosition(IntPx(120), IntPx(100))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100376 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100377 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100378 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100379 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
380 popupPositionProperties.parentSize = parentSize.toPxSize()
381 popupPositionProperties.childrenSize = popupSize.toPxSize()
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100382
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100383 val positionBottomRight = calculatePopupGlobalPosition(
384 popupPositionProperties,
385 Alignment.CenterRight
386 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100387
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100388 Truth.assertThat(positionBottomRight).isEqualTo(expectedPositionCenterRight)
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100389 }
390
391 @Test
392 fun popup_calculateGlobalPositionBottomCenter() {
393 /* Expected BottomCenter Position
394 x = parentGlobalPosition.x + offset.x + parentSize.x / 2 - popupSize.x / 2
395 y = parentGlobalPosition.y + offset.y + parentSize.y - popupSize.y
396 */
397 val expectedPositionBottomCenter = IntPxPosition(IntPx(90), IntPx(140))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100398 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100399 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100400 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100401 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
402 popupPositionProperties.parentSize = parentSize.toPxSize()
403 popupPositionProperties.childrenSize = popupSize.toPxSize()
404
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100405 val positionBottomCenter = calculatePopupGlobalPosition(
406 popupPositionProperties,
407 Alignment.BottomCenter
408 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100409
410 Truth.assertThat(positionBottomCenter).isEqualTo(expectedPositionBottomCenter)
411 }
412
413 @Test
414 fun popup_calculateGlobalPositionBottomLeft() {
415 /* Expected BottomLeft Position
416 x = parentGlobalPosition.x + offset.x
417 y = parentGlobalPosition.y + offset.y + parentSize.y - popupSize.y
418 */
419 val expectedPositionBottomLeft = IntPxPosition(IntPx(60), IntPx(140))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100420 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100421 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100422 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100423 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
424 popupPositionProperties.parentSize = parentSize.toPxSize()
425 popupPositionProperties.childrenSize = popupSize.toPxSize()
426
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100427 val positionBottomLeft = calculatePopupGlobalPosition(
428 popupPositionProperties,
429 Alignment.BottomLeft
430 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100431
432 Truth.assertThat(positionBottomLeft).isEqualTo(expectedPositionBottomLeft)
433 }
434
435 @Test
436 fun popup_calculateGlobalPositionCenterLeft() {
437 /* Expected CenterLeft Position
438 x = parentGlobalPosition.x + offset.x
439 y = parentGlobalPosition.y + offset.y + parentSize.y / 2 - popupSize.y / 2
440 */
441 val expectedPositionCenterLeft = IntPxPosition(IntPx(60), IntPx(100))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100442 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100443 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100444 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100445 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
446 popupPositionProperties.parentSize = parentSize.toPxSize()
447 popupPositionProperties.childrenSize = popupSize.toPxSize()
448
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100449 val positionCenterLeft = calculatePopupGlobalPosition(
450 popupPositionProperties,
451 Alignment.CenterLeft
452 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100453
454 Truth.assertThat(positionCenterLeft).isEqualTo(expectedPositionCenterLeft)
455 }
456
457 @Test
458 fun popup_calculateGlobalPositionCenter() {
459 /* Expected Center Position
460 x = parentGlobalPosition.x + offset.x + parentSize.x / 2 - popupSize.x / 2
461 y = parentGlobalPosition.y + offset.y + parentSize.y / 2 - popupSize.y / 2
462 */
463 val expectedPositionCenter = IntPxPosition(IntPx(90), IntPx(100))
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100464 val popupPositionProperties = PopupPositionProperties(
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100465 offset = offset
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100466 )
Mihai Burlaciuc27e8f542019-09-16 11:19:33 +0100467 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
468 popupPositionProperties.parentSize = parentSize.toPxSize()
469 popupPositionProperties.childrenSize = popupSize.toPxSize()
470
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100471 val positionCenter = calculatePopupGlobalPosition(
472 popupPositionProperties,
473 Alignment.Center
474 )
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100475
476 Truth.assertThat(positionCenter).isEqualTo(expectedPositionCenter)
477 }
478
Mihai Burlaciuc49000c62019-09-17 11:15:47 +0100479 @Test
480 fun dropdownAlignment_calculateGlobalPositionLeft() {
481 /* Expected Dropdown Start Position
482 x = parentGlobalPosition.x + offset.x
483 y = parentGlobalPosition.y + offset.y + parentSize.y
484 */
485 val expectedPositionLeft = IntPxPosition(IntPx(60), IntPx(160))
486 val popupPositionProperties = PopupPositionProperties(offset = offset)
487 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
488 popupPositionProperties.parentSize = parentSize.toPxSize()
489 popupPositionProperties.childrenSize = popupSize.toPxSize()
490
491 val positionLeft = calculateDropdownPopupPosition(
492 popupPositionProperties,
493 DropDownAlignment.Left
494 )
495
496 Truth.assertThat(positionLeft).isEqualTo(expectedPositionLeft)
497 }
498
499 @Test
500 fun dropdownAlignment_calculateGlobalPositionRight() {
501 /* Expected Dropdown End Position
502 x = parentGlobalPosition.x + offset.x + parentSize.x
503 y = parentGlobalPosition.y + offset.y + parentSize.y
504 */
505 val expectedPositionRight = IntPxPosition(IntPx(160), IntPx(160))
506 val popupPositionProperties = PopupPositionProperties(offset = offset)
507 popupPositionProperties.parentPosition = parentGlobalPosition.toPxPosition()
508 popupPositionProperties.parentSize = parentSize.toPxSize()
509 popupPositionProperties.childrenSize = popupSize.toPxSize()
510
511 val positionRight = calculateDropdownPopupPosition(
512 popupPositionProperties,
513 DropDownAlignment.Right
514 )
515
516 Truth.assertThat(positionRight).isEqualTo(expectedPositionRight)
517 }
518
George Mount203056e2019-08-30 16:17:48 -0700519 private fun matchesAndroidComposeView(): BoundedMatcher<View, View> {
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100520 return object : BoundedMatcher<View, View>(View::class.java) {
521 override fun matchesSafely(item: View?): Boolean {
George Mount203056e2019-08-30 16:17:48 -0700522 return (item is AndroidComposeView)
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100523 }
524
525 override fun describeTo(description: Description?) {
George Mount203056e2019-08-30 16:17:48 -0700526 description?.appendText("with no AndroidComposeView")
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100527 }
528 }
529 }
530
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100531 private fun matchesSize(width: Int, height: Int): BoundedMatcher<View, View> {
532 return object : BoundedMatcher<View, View>(View::class.java) {
533 override fun matchesSafely(item: View?): Boolean {
534 return item?.width == width && item.height == height
535 }
536
537 override fun describeTo(description: Description?) {
538 description?.appendText("with width = $width height = $height")
539 }
540 }
541 }
542
543 private fun matchesPosition(expectedPosition: IntPxPosition): BoundedMatcher<View, View> {
544 return object : BoundedMatcher<View, View>(View::class.java) {
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100545 // (-1, -1) no position found
546 var positionFound = IntPxPosition(IntPx(-1), IntPx(-1))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100547 override fun matchesSafely(item: View?): Boolean {
548 val position = IntArray(2)
549 item?.getLocationOnScreen(position)
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100550 positionFound = IntPxPosition(IntPx(position[0]), IntPx(position[1]))
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100551
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100552 return expectedPosition == positionFound
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100553 }
554
555 override fun describeTo(description: Description?) {
Mihai Burlaciuc96f747c2019-08-23 14:15:43 +0100556 description?.appendText("with expected position: $expectedPosition" +
557 " but position found: $positionFound")
Mihai Burlaciuc478fae62019-08-08 10:00:06 +0100558 }
559 }
560 }
Siyamed Sinirfc059292019-11-21 13:39:17 -0800561}
562
563@Composable
564private fun TestAlign(children: @Composable() () -> Unit) {
565 Layout(children) { measurables, constraints ->
566 val measurable = measurables.firstOrNull()
567 // The child cannot be larger than our max constraints, but we ignore min constraints.
Mihai Popad9d535072020-01-15 12:58:15 +0000568 val placeable = measurable?.measure(constraints.copy(minWidth = 0.ipx, minHeight = 0.ipx))
Siyamed Sinirfc059292019-11-21 13:39:17 -0800569
570 // The layout is as large as possible for bounded constraints,
571 // or wrap content otherwise.
572 val layoutWidth = if (constraints.maxWidth.isFinite()) {
573 constraints.maxWidth
574 } else {
575 placeable?.width ?: constraints.minWidth
576 }
577 val layoutHeight = if (constraints.maxHeight.isFinite()) {
578 constraints.maxHeight
579 } else {
580 placeable?.height ?: constraints.minHeight
581 }
582
583 layout(layoutWidth, layoutHeight) {
584 if (placeable != null) {
585 val position = Alignment.TopLeft.align(
586 IntPxSize(layoutWidth - placeable.width, layoutHeight - placeable.height)
587 )
588 placeable.place(position.x, position.y)
589 }
590 }
591 }
592}