blob: a5dc7243308e9c56d0e2790f5b49817774c681b8 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.omnibox.suggestions.base;
import android.app.Activity;
import android.view.View;
import android.view.View.MeasureSpec;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.chromium.chrome.R;
import org.chromium.testing.local.LocalRobolectricTestRunner;
/**
* Tests for {@link BaseSuggestionView}.
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class BaseSuggestionViewTest {
// Used as a (fixed) margin between screen edge and refine icon.
private int mSuggestionPaddingEndPx;
// Used as a (fixed) width of a refine icon.
private int mActionIconWidthPx;
private BaseSuggestionViewForTest mView;
private Activity mActivity;
private View mRefineView;
private View mDecoratedView;
private View mContentView;
// IMPORTANT: We need to extend the tested class here to support functionality currently
// omitted by Robolectric, that is relevant to the tests below (layout direction change).
//
// TODO(https://github.com/robolectric/robolectric/issues/3910) Remove the class below once
// the above issue is resolved and our robolectric version is rolled forward to the version
// that supports layout direction changes.
class BaseSuggestionViewForTest extends BaseSuggestionView {
private int mCurrentDirection = View.LAYOUT_DIRECTION_LTR;
BaseSuggestionViewForTest(View childView) {
super(childView);
}
@Override
public void setLayoutDirection(int newDirection) {
mCurrentDirection = newDirection;
}
@Override
public int getLayoutDirection() {
return mCurrentDirection;
}
/**
* Test method to force layout update based on specified view dimensions.
*/
void performLayoutForTest(int width) {
onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.UNSPECIFIED);
// Note: height is computed by onMeasure call.
final int height = getMeasuredHeight();
onLayout(true, 0, 0, width, height);
}
View getDecoratedView() {
return mContentView;
}
View getRefineView() {
return mRefineView;
}
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mActivity = Robolectric.buildActivity(Activity.class).setup().get();
mContentView = new View(mActivity);
mView = new BaseSuggestionViewForTest(mContentView);
mSuggestionPaddingEndPx = mActivity.getResources().getDimensionPixelSize(
R.dimen.omnibox_suggestion_refine_view_modern_end_padding);
mActionIconWidthPx = mActivity.getResources().getDimensionPixelSize(
R.dimen.omnibox_suggestion_refine_width);
mRefineView = mView.getRefineView();
mDecoratedView = mView.getDecoratedView();
}
/**
* Perform the measure and layout pass on the BaseSuggestionView.
* This method sets up the basic properties of the Suggestion container, specifies height of the
* content view and executes the measure and layout pass.
*/
private void executeLayoutTest(int containerWidth, int contentHeight, int layoutDirection) {
mView.setLayoutDirection(layoutDirection);
Assert.assertEquals(
"layout direction not supported", layoutDirection, mView.getLayoutDirection());
// Let ContentView drive the height of the Suggestion. The dummy view could shrink, so let's
// prevent that from happening. We don't technically have any content, so we need to prevent
// the view from shrinking, too.
mContentView.setMinimumHeight(contentHeight);
mView.performLayoutForTest(containerWidth);
}
/**
* Confirm that specified view is positioned at specific coordinates.
*/
private void verifyViewLayout(View v, int left, int top, int right, int bottom) {
Assert.assertEquals("left view edge", left, v.getLeft());
Assert.assertEquals("top view edge", top, v.getTop());
Assert.assertEquals("right view edge", right, v.getRight());
Assert.assertEquals("bottom view edge", bottom, v.getBottom());
Assert.assertEquals("view width", right - left, v.getMeasuredWidth());
Assert.assertEquals("view height", bottom - top, v.getMeasuredHeight());
}
@Test
public void layout_LtrRefineVisible() {
final int useContentWidth = 120;
// Expectations (edge to edge):
//
// +----------------+----+-+ ^
// | CONTENT |ACT1|#| giveContentHeight
// +----------------+----+-+ v
//
// <- giveSuggestionWidth ->
//
// where ACT is action button and # is final padding.
final int giveSuggestionWidth =
useContentWidth + mActionIconWidthPx + mSuggestionPaddingEndPx;
final int giveContentHeight = 15;
final int expectedContentLeft = 0;
final int expectedContentRight = useContentWidth;
final int expectedRefineLeft = expectedContentRight;
final int expectedRefineRight = useContentWidth + mActionIconWidthPx;
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
verifyViewLayout(
mRefineView, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight);
verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
}
@Test
public void layout_RtlRefineVisible() {
final int useContentWidth = 120;
// Expectations (edge to edge):
//
// +----+----------------+-+ ^
// |ACT1| CONTENT |#| giveContentHeight
// +----+----------------+-+ v
//
// <- giveSuggestionWidth ->
//
// where ACT is action button and # is final padding.
final int giveSuggestionWidth =
useContentWidth + mActionIconWidthPx + mSuggestionPaddingEndPx;
final int giveContentHeight = 25;
final int expectedRefineLeft = 0;
final int expectedRefineRight = mActionIconWidthPx;
final int expectedContentLeft = expectedRefineRight;
final int expectedContentRight = giveSuggestionWidth - mSuggestionPaddingEndPx;
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
verifyViewLayout(
mRefineView, expectedRefineLeft, 0, expectedRefineRight, giveContentHeight);
verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
}
@Test
public void layout_LtrRefineInvisible() {
// Expectations (edge to edge):
//
// +---------------------+-+ ^
// |CONTENT |#| giveContentHeight
// +---------------------+-+ v
//
// <- giveSuggestionWidth ->
//
// The reason for this is that we want content to align correctly with the end of the
// omnibox field. Otherwise, content would end at the right screen edge.
final int giveSuggestionWidth = 250;
final int giveContentHeight = 15;
final int expectedContentLeft = 0;
final int expectedContentRight = giveSuggestionWidth - mSuggestionPaddingEndPx;
mRefineView.setVisibility(View.GONE);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_LTR);
verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
}
@Test
public void layout_RtlRefineInvisible() {
// Expectations (edge to edge):
//
// +---------------------+-+ ^
// |CONTENT |#| giveContentHeight
// +---------------------+-+ v
//
// <- giveSuggestionWidth ->
//
// The reason for this is that we want content to align correctly with the end of the
// omnibox field. Otherwise, content would end (RTL) at the left screen edge.
final int giveSuggestionWidth = 250;
final int giveContentHeight = 15;
final int expectedContentLeft = 0;
final int expectedContentRight = giveSuggestionWidth - mSuggestionPaddingEndPx;
mRefineView.setVisibility(View.GONE);
executeLayoutTest(giveSuggestionWidth, giveContentHeight, View.LAYOUT_DIRECTION_RTL);
verifyViewLayout(
mDecoratedView, expectedContentLeft, 0, expectedContentRight, giveContentHeight);
}
}