You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/test/java/org/mozilla/fenix/components/toolbar/EngineViewClippingBehaviorT...

293 lines
12 KiB
Kotlin

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components.toolbar
import android.view.View
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.engine.EngineView
import mozilla.components.support.test.fakes.engine.FakeEngineView
import mozilla.components.support.test.mock
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mozilla.fenix.components.toolbar.navbar.EngineViewClippingBehavior
import org.mozilla.fenix.components.toolbar.navbar.ToolbarContainerView
@RunWith(AndroidJUnit4::class)
class EngineViewClippingBehaviorTest {
// Bottom toolbar position tests
@Test
fun `GIVEN the toolbar is at the bottom WHEN toolbar is being shifted THEN EngineView adjusts bottom clipping && EngineViewParent position doesn't change`() {
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: BrowserToolbar = mock()
doReturn(Y_DOWN_TRANSITION).`when`(toolbar).translationY
assertEquals(0f, engineParentView.translationY)
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = 0,
).apply {
this.engineView = engineView
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
}
// We want to position the engine view popup content
// right above the bottom toolbar when the toolbar
// is being shifted down. The top of the bottom toolbar
// is either positive or zero, but for clipping
// the values should be negative because the baseline
// for clipping is bottom toolbar height.
val bottomClipping = -Y_DOWN_TRANSITION.toInt()
verify(engineView).setVerticalClipping(bottomClipping)
assertEquals(0f, engineParentView.translationY)
}
@Test
fun `GIVEN the toolbar is at the bottom && the navbar is enabled WHEN toolbar is being shifted THEN EngineView adjusts bottom clipping && EngineViewParent position doesn't change`() {
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: ToolbarContainerView = mock()
doReturn(Y_DOWN_TRANSITION).`when`(toolbar).translationY
assertEquals(0f, engineParentView.translationY)
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = 0,
).apply {
this.engineView = engineView
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
}
// We want to position the engine view popup content
// right above the bottom toolbar when the toolbar
// is being shifted down. The top of the bottom toolbar
// is either positive or zero, but for clipping
// the values should be negative because the baseline
// for clipping is bottom toolbar height.
val bottomClipping = -Y_DOWN_TRANSITION.toInt()
verify(engineView).setVerticalClipping(bottomClipping)
assertEquals(0f, engineParentView.translationY)
}
// Top toolbar position tests
@Test
fun `GIVEN the toolbar is at the top WHEN toolbar is being shifted THEN EngineView adjusts bottom clipping && EngineViewParent shifts as well`() {
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: BrowserToolbar = mock()
doReturn(Y_UP_TRANSITION).`when`(toolbar).translationY
assertEquals(0f, engineParentView.translationY)
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = TOOLBAR_HEIGHT.toInt(),
).apply {
this.engineView = engineView
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
}
verify(engineView).setVerticalClipping(Y_UP_TRANSITION.toInt())
// Here we are adjusting the vertical position of
// the engine view container to be directly under
// the toolbar. The top toolbar is shifting up, so
// its translation will be either negative or zero.
val bottomClipping = Y_UP_TRANSITION + TOOLBAR_HEIGHT
assertEquals(bottomClipping, engineParentView.translationY)
}
// Combined toolbar position tests
@Test
fun `WHEN both of the toolbars are being shifted GIVEN the toolbar is at the top && the navbar is enabled THEN EngineView adjusts bottom clipping`() {
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: BrowserToolbar = mock()
val toolbarContainerView: ToolbarContainerView = mock()
doReturn(Y_UP_TRANSITION).`when`(toolbar).translationY
doReturn(Y_DOWN_TRANSITION).`when`(toolbarContainerView).translationY
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = TOOLBAR_HEIGHT.toInt(),
).apply {
this.engineView = engineView
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
onDependentViewChanged(mock(), mock(), toolbarContainerView)
}
val doubleClipping = Y_UP_TRANSITION - Y_DOWN_TRANSITION
verify(engineView).setVerticalClipping(doubleClipping.toInt())
}
@Test
fun `WHEN both of the toolbars are being shifted GIVEN the toolbar is at the top && the navbar is enabled THEN EngineViewParent shifts as well`() {
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: BrowserToolbar = mock()
val toolbarContainerView: ToolbarContainerView = mock()
doReturn(Y_UP_TRANSITION).`when`(toolbar).translationY
doReturn(Y_DOWN_TRANSITION).`when`(toolbarContainerView).translationY
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = TOOLBAR_HEIGHT.toInt(),
).apply {
this.engineView = engineView
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
onDependentViewChanged(mock(), mock(), toolbarContainerView)
}
// The top of the parent should be positioned right below the toolbar,
// so when we are given the new Y position of the top of the toolbar,
// which is always negative as the element is being "scrolled" out of
// the screen, the bottom of the toolbar is just a toolbar height away
// from it.
val parentTranslation = Y_UP_TRANSITION + TOOLBAR_HEIGHT
assertEquals(parentTranslation, engineParentView.translationY)
}
// Edge cases
@Test
fun `GIVEN top toolbar is much bigger than bottom WHEN bottom stopped shifting && top is shifting THEN bottom clipping && engineParentView shifting is still accurate`() {
val largeYUpTransition = -500f
val largeTopToolbarHeight = 500
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: BrowserToolbar = mock()
doReturn(largeYUpTransition).`when`(toolbar).translationY
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = largeTopToolbarHeight,
).apply {
this.engineView = engineView
this.recentBottomToolbarTranslation = Y_DOWN_TRANSITION
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
}
val doubleClipping = largeYUpTransition - Y_DOWN_TRANSITION
verify(engineView).setVerticalClipping(doubleClipping.toInt())
val parentTranslation = largeYUpTransition + largeTopToolbarHeight
assertEquals(parentTranslation, engineParentView.translationY)
}
@Test
fun `GIVEN bottom toolbar is much bigger than top WHEN top stopped shifting && bottom is shifting THEN bottom clipping && engineParentView shifting is still accurate`() {
val largeYBottomTransition = 500f
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbarContainerView: ToolbarContainerView = mock()
doReturn(largeYBottomTransition).`when`(toolbarContainerView).translationY
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = TOOLBAR_HEIGHT.toInt(),
).apply {
this.engineView = engineView
this.recentTopToolbarTranslation = Y_UP_TRANSITION
}.run {
onDependentViewChanged(mock(), mock(), toolbarContainerView)
}
val doubleClipping = Y_UP_TRANSITION - largeYBottomTransition
verify(engineView).setVerticalClipping(doubleClipping.toInt())
val parentTranslation = Y_UP_TRANSITION + TOOLBAR_HEIGHT
assertEquals(parentTranslation, engineParentView.translationY)
}
@Test
fun `GIVEN a bottom toolbar WHEN translation returns NaN THEN no exception thrown`() {
val engineView: EngineView = spy(FakeEngineView(testContext))
val engineParentView: View = spy(View(testContext))
val toolbar: View = mock()
doReturn(100).`when`(toolbar).height
doReturn(Float.NaN).`when`(toolbar).translationY
EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = engineParentView,
topToolbarHeight = 0,
).apply {
this.engineView = engineView
}.run {
onDependentViewChanged(mock(), mock(), toolbar)
}
assertEquals(0f, engineView.asView().translationY)
}
// General tests
@Test
fun `WHEN layoutDependsOn receives a class that isn't a ScrollableToolbar THEN it ignores it`() {
val behavior = EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = mock(),
topToolbarHeight = 0,
)
assertFalse(behavior.layoutDependsOn(mock(), mock(), TextView(testContext)))
assertFalse(behavior.layoutDependsOn(mock(), mock(), EditText(testContext)))
assertFalse(behavior.layoutDependsOn(mock(), mock(), ImageView(testContext)))
}
@Test
fun `WHEN layoutDependsOn receives a class that is a ScrollableToolbar THEN it recognizes it as a dependency`() {
val behavior = EngineViewClippingBehavior(
context = mock(),
attrs = null,
engineViewParent = mock(),
topToolbarHeight = 0,
)
assertTrue(behavior.layoutDependsOn(mock(), mock(), BrowserToolbar(testContext)))
assertTrue(behavior.layoutDependsOn(mock(), mock(), ToolbarContainerView(testContext)))
}
}
private const val TOOLBAR_HEIGHT = 100f
private const val Y_UP_TRANSITION = -42f
private const val Y_DOWN_TRANSITION = -42f