blob: a7d252f47ed7e43acfa44b4da7427cd215fcbf3f [file] [log] [blame]
// Copyright 2020 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.feed.v2;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.chromium.chrome.browser.feed.shared.stream.Stream.POSITION_NOT_KNOWN;
import android.app.Activity;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;
import androidx.recyclerview.widget.RecyclerView;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
/** Unit tests for {@link FeedStream}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class FeedStreamTest {
private static final int LOAD_MORE_TRIGGER_LOOKAHEAD = 5;
private Activity mActivity;
private RecyclerView mRecyclerView;
private FakeLinearLayoutManager mLayoutManager;
private FeedStream mFeedStream;
@Mock
private SnackbarManager mSnackbarManager;
@Mock
private NativePageNavigationDelegate mPageNavigationDelegate;
@Mock
private BottomSheetController mBottomSheetController;
@Mock
private FeedStreamSurface.Natives mFeedStreamSurfaceJniMock;
@Mock
private FeedServiceBridge.Natives mFeedServiceBridgeJniMock;
@Rule
public JniMocker mocker = new JniMocker();
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mActivity = Robolectric.buildActivity(Activity.class).get();
mocker.mock(FeedStreamSurfaceJni.TEST_HOOKS, mFeedStreamSurfaceJniMock);
mocker.mock(FeedServiceBridgeJni.TEST_HOOKS, mFeedServiceBridgeJniMock);
when(mFeedServiceBridgeJniMock.getLoadMoreTriggerLookahead())
.thenReturn(LOAD_MORE_TRIGGER_LOOKAHEAD);
mFeedStream = new FeedStream(mActivity, false, mSnackbarManager, mPageNavigationDelegate,
mBottomSheetController);
mFeedStream.onCreate(null);
mRecyclerView = (RecyclerView) mFeedStream.getView();
mLayoutManager = new FakeLinearLayoutManager(mActivity);
mRecyclerView.setLayoutManager(mLayoutManager);
}
@Test
public void testIsChildAtPositionVisible() {
mLayoutManager.setFirstVisiblePosition(0);
mLayoutManager.setLastVisiblePosition(1);
assertThat(mFeedStream.isChildAtPositionVisible(-2)).isFalse();
assertThat(mFeedStream.isChildAtPositionVisible(-1)).isFalse();
assertThat(mFeedStream.isChildAtPositionVisible(0)).isTrue();
assertThat(mFeedStream.isChildAtPositionVisible(1)).isTrue();
assertThat(mFeedStream.isChildAtPositionVisible(2)).isFalse();
}
@Test
public void testIsChildAtPositionVisible_nothingVisible() {
assertThat(mFeedStream.isChildAtPositionVisible(0)).isFalse();
}
@Test
public void testIsChildAtPositionVisible_validTop() {
mLayoutManager.setFirstVisiblePosition(0);
assertThat(mFeedStream.isChildAtPositionVisible(0)).isFalse();
}
@Test
public void testIsChildAtPositionVisible_validBottom() {
mLayoutManager.setLastVisiblePosition(1);
assertThat(mFeedStream.isChildAtPositionVisible(0)).isFalse();
}
@Test
public void testGetChildTopAt_noVisibleChild() {
assertThat(mFeedStream.getChildTopAt(0)).isEqualTo(POSITION_NOT_KNOWN);
}
@Test
public void testGetChildTopAt_noChild() {
mLayoutManager.setFirstVisiblePosition(0);
mLayoutManager.setLastVisiblePosition(1);
assertThat(mFeedStream.getChildTopAt(0)).isEqualTo(POSITION_NOT_KNOWN);
}
@Test
public void testGetChildTopAt() {
mLayoutManager.setFirstVisiblePosition(0);
mLayoutManager.setLastVisiblePosition(1);
View view = new FrameLayout(mActivity);
mLayoutManager.addChildToPosition(0, view);
assertThat(mFeedStream.getChildTopAt(0)).isEqualTo(view.getTop());
}
@Test
public void testCheckScrollingForLoadMore_StreamContentHidden() {
// By default, stream content is not visible.
final int triggerDistance = getLoadMoreTriggerScrollDistance();
mFeedStream.checkScrollingForLoadMore(triggerDistance);
verify(mFeedStreamSurfaceJniMock, never())
.loadMore(anyLong(), any(FeedStreamSurface.class), any(Callback.class));
}
@Test
public void testCheckScrollingForLoadMore_StreamContentVisible() {
mFeedStream.setStreamContentVisibility(true);
final int triggerDistance = getLoadMoreTriggerScrollDistance();
final int itemCount = 10;
// loadMore not triggered due to not enough accumulated scrolling distance.
mFeedStream.checkScrollingForLoadMore(triggerDistance / 2);
verify(mFeedStreamSurfaceJniMock, never())
.loadMore(anyLong(), any(FeedStreamSurface.class), any(Callback.class));
// loadMore not triggered due to last visible item not falling into lookahead range.
mLayoutManager.setLastVisiblePosition(itemCount - LOAD_MORE_TRIGGER_LOOKAHEAD - 1);
mLayoutManager.setItemCount(itemCount);
mFeedStream.checkScrollingForLoadMore(triggerDistance / 2);
verify(mFeedStreamSurfaceJniMock, never())
.loadMore(anyLong(), any(FeedStreamSurface.class), any(Callback.class));
// loadMore triggered.
mLayoutManager.setLastVisiblePosition(itemCount - LOAD_MORE_TRIGGER_LOOKAHEAD + 1);
mLayoutManager.setItemCount(itemCount);
mFeedStream.checkScrollingForLoadMore(triggerDistance / 2);
verify(mFeedStreamSurfaceJniMock)
.loadMore(anyLong(), any(FeedStreamSurface.class), any(Callback.class));
}
private int getLoadMoreTriggerScrollDistance() {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
FeedStream.LOAD_MORE_TRIGGER_SCROLL_DISTANCE_DP,
mRecyclerView.getResources().getDisplayMetrics());
}
}