blob: 99df0b6d2295f49270ffbf44065afe44cdf19ba2 [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 org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.support.test.filters.SmallTest;
import android.view.View;
import android.widget.TextView;
import com.google.protobuf.ByteString;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.tab.MockTab;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.feed.proto.FeedUiProto.Slice;
import org.chromium.components.feed.proto.FeedUiProto.StreamUpdate;
import org.chromium.components.feed.proto.FeedUiProto.StreamUpdate.SliceUpdate;
import org.chromium.components.feed.proto.FeedUiProto.XSurfaceSlice;
import org.chromium.ui.mojom.WindowOpenDisposition;
import java.util.Arrays;
/** Unit tests for {@link FeedStreamSurface}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class FeedStreamSurfaceTest {
private static final String TEST_DATA = "test";
private static final String TEST_URL = "https://www.chromium.org";
private FeedStreamSurface mFeedStreamSurface;
private Activity mActivity;
@Mock
private SnackbarManager mSnackbarManager;
@Mock
private FeedActionsHandler.SnackbarController mSnackbarController;
@Mock
private BottomSheetController mBottomSheetController;
@Mock
private NativePageNavigationDelegate mPageNavigationDelegate;
@Mock
private HelpAndFeedback mHelpAndFeedback;
@Rule
public JniMocker mocker = new JniMocker();
// Enable the Features class, so we can call code which checks to see if features are enabled
// without crashing.
@Rule
public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
@Mock
private FeedStreamSurface.Natives mFeedStreamSurfaceJniMock;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mActivity = Robolectric.buildActivity(Activity.class).get();
mocker.mock(FeedStreamSurfaceJni.TEST_HOOKS, mFeedStreamSurfaceJniMock);
mFeedStreamSurface = new FeedStreamSurface(mActivity, false, mSnackbarManager,
mPageNavigationDelegate, mBottomSheetController, mHelpAndFeedback);
}
@Test
@SmallTest
public void testAddSlicesOnStreamUpdated() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Add 3 new slices at first.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("c"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(3, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
assertEquals(2, contentManager.findContentPositionByKey("c"));
// Add 2 more slices.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForExistingSlice("a"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("b"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("c"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("d"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("e"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(5, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
assertEquals(2, contentManager.findContentPositionByKey("c"));
assertEquals(3, contentManager.findContentPositionByKey("d"));
assertEquals(4, contentManager.findContentPositionByKey("e"));
}
@Test
@SmallTest
public void testAddNewSlicesWithSameIds() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Add 2 new slices at first.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(2, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
// Add 2 new slice with same ids as before.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(2, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("b"));
assertEquals(1, contentManager.findContentPositionByKey("a"));
}
@Test
@SmallTest
public void testRemoveSlicesOnStreamUpdated() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Add 3 new slices at first.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("c"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(3, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
assertEquals(2, contentManager.findContentPositionByKey("c"));
// Remove 1 slice.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForExistingSlice("a"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("c"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(2, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("c"));
// Remove 2 slices.
update = StreamUpdate.newBuilder().build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(0, contentManager.getItemCount());
}
@Test
@SmallTest
public void testReorderSlicesOnStreamUpdated() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Add 3 new slices at first.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("c"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(3, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
assertEquals(2, contentManager.findContentPositionByKey("c"));
// Reorder 1 slice.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForExistingSlice("c"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("a"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("b"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(3, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("c"));
assertEquals(1, contentManager.findContentPositionByKey("a"));
assertEquals(2, contentManager.findContentPositionByKey("b"));
// Reorder 2 slices.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForExistingSlice("a"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("b"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("c"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(3, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
assertEquals(2, contentManager.findContentPositionByKey("c"));
}
@Test
@SmallTest
public void testComplexOperationsOnStreamUpdated() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Add 3 new slices at first.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("c"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("d"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("e"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(5, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("a"));
assertEquals(1, contentManager.findContentPositionByKey("b"));
assertEquals(2, contentManager.findContentPositionByKey("c"));
assertEquals(3, contentManager.findContentPositionByKey("d"));
assertEquals(4, contentManager.findContentPositionByKey("e"));
// Combo of add, remove and reorder operations.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("f"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("g"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("h"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("c"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("e"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("i"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(7, contentManager.getItemCount());
assertEquals(0, contentManager.findContentPositionByKey("f"));
assertEquals(1, contentManager.findContentPositionByKey("g"));
assertEquals(2, contentManager.findContentPositionByKey("a"));
assertEquals(3, contentManager.findContentPositionByKey("h"));
assertEquals(4, contentManager.findContentPositionByKey("c"));
assertEquals(5, contentManager.findContentPositionByKey("e"));
assertEquals(6, contentManager.findContentPositionByKey("i"));
}
@Test
@SmallTest
public void testAddHeaderViews() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
View v0 = new View(mActivity);
View v1 = new View(mActivity);
mFeedStreamSurface.setHeaderViews(Arrays.asList(v0, v1));
assertEquals(2, contentManager.getItemCount());
assertEquals(v0,
((FeedListContentManager.NativeViewContent) contentManager.getContent(0))
.getNativeView(null));
assertEquals(v1,
((FeedListContentManager.NativeViewContent) contentManager.getContent(1))
.getNativeView(null));
}
@Test
@SmallTest
public void testUpdateHeaderViews() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
View v0 = new View(mActivity);
View v1 = new View(mActivity);
mFeedStreamSurface.setHeaderViews(Arrays.asList(v0, v1));
assertEquals(2, contentManager.getItemCount());
assertEquals(v0,
((FeedListContentManager.NativeViewContent) contentManager.getContent(0))
.getNativeView(null));
assertEquals(v1,
((FeedListContentManager.NativeViewContent) contentManager.getContent(1))
.getNativeView(null));
View v2 = new View(mActivity);
View v3 = new View(mActivity);
mFeedStreamSurface.setHeaderViews(Arrays.asList(v2, v0, v3));
assertEquals(3, contentManager.getItemCount());
assertEquals(v2,
((FeedListContentManager.NativeViewContent) contentManager.getContent(0))
.getNativeView(null));
assertEquals(v0,
((FeedListContentManager.NativeViewContent) contentManager.getContent(1))
.getNativeView(null));
assertEquals(v3,
((FeedListContentManager.NativeViewContent) contentManager.getContent(2))
.getNativeView(null));
}
@Test
@SmallTest
public void testComplexOperationsOnStreamUpdatedAfterSetHeaderViews() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Set 2 header views first. These should always be there throughout stream update.
View v0 = new View(mActivity);
View v1 = new View(mActivity);
mFeedStreamSurface.setHeaderViews(Arrays.asList(v0, v1));
assertEquals(2, contentManager.getItemCount());
assertEquals(v0,
((FeedListContentManager.NativeViewContent) contentManager.getContent(0))
.getNativeView(null));
assertEquals(v1,
((FeedListContentManager.NativeViewContent) contentManager.getContent(1))
.getNativeView(null));
final int headers = 2;
// Add 3 new slices at first.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("c"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("d"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("e"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(headers + 5, contentManager.getItemCount());
assertEquals(headers + 0, contentManager.findContentPositionByKey("a"));
assertEquals(headers + 1, contentManager.findContentPositionByKey("b"));
assertEquals(headers + 2, contentManager.findContentPositionByKey("c"));
assertEquals(headers + 3, contentManager.findContentPositionByKey("d"));
assertEquals(headers + 4, contentManager.findContentPositionByKey("e"));
// Combo of add, remove and reorder operations.
update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("f"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("g"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("h"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("c"))
.addUpdatedSlices(createSliceUpdateForExistingSlice("e"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("i"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(headers + 7, contentManager.getItemCount());
assertEquals(headers + 0, contentManager.findContentPositionByKey("f"));
assertEquals(headers + 1, contentManager.findContentPositionByKey("g"));
assertEquals(headers + 2, contentManager.findContentPositionByKey("a"));
assertEquals(headers + 3, contentManager.findContentPositionByKey("h"));
assertEquals(headers + 4, contentManager.findContentPositionByKey("c"));
assertEquals(headers + 5, contentManager.findContentPositionByKey("e"));
assertEquals(headers + 6, contentManager.findContentPositionByKey("i"));
}
@Test
@SmallTest
public void testNavigateTab() {
when(mPageNavigationDelegate.openUrl(anyInt(), any())).thenReturn(new MockTab(1, false));
mFeedStreamSurface.navigateTab(TEST_URL);
verify(mPageNavigationDelegate)
.openUrl(ArgumentMatchers.eq(WindowOpenDisposition.CURRENT_TAB), any());
}
@Test
@SmallTest
public void testNavigateNewTab() {
when(mPageNavigationDelegate.openUrl(anyInt(), any())).thenReturn(new MockTab(1, false));
mFeedStreamSurface.navigateNewTab(TEST_URL);
verify(mPageNavigationDelegate)
.openUrl(ArgumentMatchers.eq(WindowOpenDisposition.NEW_FOREGROUND_TAB), any());
}
@Test
@SmallTest
public void testNavigateIncognitoTab() {
when(mPageNavigationDelegate.openUrl(anyInt(), any())).thenReturn(new MockTab(1, false));
mFeedStreamSurface.navigateIncognitoTab(TEST_URL);
verify(mPageNavigationDelegate)
.openUrl(ArgumentMatchers.eq(WindowOpenDisposition.OFF_THE_RECORD), any());
}
@Test
@SmallTest
public void testShowSnackbar() {
mFeedStreamSurface.showSnackbar(
"message", "Undo", FeedActionsHandler.SnackbarDuration.SHORT, mSnackbarController);
verify(mSnackbarManager).showSnackbar(any());
}
@Test
@SmallTest
public void testShowBottomSheet() {
mFeedStreamSurface.showBottomSheet(new TextView(mActivity));
verify(mBottomSheetController).requestShowContent(any(), anyBoolean());
}
@Test
@SmallTest
public void testDismissBottomSheet() {
mFeedStreamSurface.showBottomSheet(new TextView(mActivity));
mFeedStreamSurface.dismissBottomSheet();
verify(mBottomSheetController).hideContent(any(), anyBoolean());
}
@Test
@SmallTest
public void testSurfaceClosed() {
FeedListContentManager contentManager =
mFeedStreamSurface.getFeedListContentManagerForTesting();
// Set 2 header views first.
View v0 = new View(mActivity);
View v1 = new View(mActivity);
mFeedStreamSurface.setHeaderViews(Arrays.asList(v0, v1));
assertEquals(2, contentManager.getItemCount());
assertEquals(v0,
((FeedListContentManager.NativeViewContent) contentManager.getContent(0))
.getNativeView(null));
assertEquals(v1,
((FeedListContentManager.NativeViewContent) contentManager.getContent(1))
.getNativeView(null));
final int headers = 2;
// Add 3 new slices.
StreamUpdate update = StreamUpdate.newBuilder()
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("a"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("b"))
.addUpdatedSlices(createSliceUpdateForNewXSurfaceSlice("c"))
.build();
mFeedStreamSurface.onStreamUpdated(update.toByteArray());
assertEquals(headers + 3, contentManager.getItemCount());
// Closing the surface should remove all non-header contents.
mFeedStreamSurface.surfaceClosed();
assertEquals(headers, contentManager.getItemCount());
assertEquals(v0,
((FeedListContentManager.NativeViewContent) contentManager.getContent(0))
.getNativeView(null));
assertEquals(v1,
((FeedListContentManager.NativeViewContent) contentManager.getContent(1))
.getNativeView(null));
}
private SliceUpdate createSliceUpdateForExistingSlice(String sliceId) {
return SliceUpdate.newBuilder().setSliceId(sliceId).build();
}
private SliceUpdate createSliceUpdateForNewXSurfaceSlice(String sliceId) {
return SliceUpdate.newBuilder().setSlice(createXSurfaceSSlice(sliceId)).build();
}
private Slice createXSurfaceSSlice(String sliceId) {
return Slice.newBuilder()
.setSliceId(sliceId)
.setXsurfaceSlice(XSurfaceSlice.newBuilder()
.setXsurfaceFrame(ByteString.copyFromUtf8(TEST_DATA))
.build())
.build();
}
}