chromium/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/NavigationPopupTest.java

// Copyright 2013 The Chromium Authors
// 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.toolbar.top;

import android.graphics.Bitmap;
import android.view.View;
import android.widget.ListPopupWindow;
import android.widget.ListView;
import android.widget.TextView;

import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;

import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.history.HistoryManagerUtils;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.R;
import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.content_public.browser.NavigationHistory;
import org.chromium.content_public.browser.test.mock.MockNavigationController;
import org.chromium.url.GURL;

import java.util.concurrent.ExecutionException;

/** Tests for the navigation popup. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class NavigationPopupTest {
    @Rule
    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();

    private static final int INVALID_NAVIGATION_INDEX = -1;

    @Before
    public void setUp() throws Exception {
        mActivityTestRule.startMainActivityOnBlankPage();
    }

    // Exists solely to expose protected methods to this test.
    private static class TestNavigationEntry extends NavigationEntry {
        public TestNavigationEntry(
                int index,
                GURL url,
                GURL virtualUrl,
                GURL originalUrl,
                String title,
                Bitmap favicon,
                int transition,
                long timestamp) {
            super(
                    index,
                    url,
                    virtualUrl,
                    originalUrl,
                    title,
                    favicon,
                    transition,
                    timestamp,
                    /* isInitialEntry= */ false);
        }
    }

    private static class TestNavigationController extends MockNavigationController {
        private final NavigationHistory mHistory;
        private int mNavigatedIndex = INVALID_NAVIGATION_INDEX;

        public TestNavigationController() {
            mHistory = new NavigationHistory();
            mHistory.addEntry(
                    new TestNavigationEntry(
                            1,
                            new GURL("about:blank"),
                            GURL.emptyGURL(),
                            null,
                            "About Blank",
                            null,
                            0,
                            0));
            mHistory.addEntry(
                    new TestNavigationEntry(
                            5,
                            new GURL(UrlUtils.encodeHtmlDataUri("<html>1</html>")),
                            GURL.emptyGURL(),
                            GURL.emptyGURL(),
                            null,
                            null,
                            0,
                            0));
        }

        @Override
        public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) {
            return mHistory;
        }

        @Override
        public void goToNavigationIndex(int index) {
            mNavigatedIndex = index;
        }

        public int getEntryCount() {
            return mHistory.getEntryCount();
        }
    }

    @Test
    @MediumTest
    @Feature({"Navigation"})
    public void testFaviconFetching() throws ExecutionException {
        final TestNavigationController controller = new TestNavigationController();
        final ListPopupWindow popup = showPopup(controller, false);

        CriteriaHelper.pollUiThread(
                () -> {
                    NavigationHistory history = controller.mHistory;
                    for (int i = 0; i < history.getEntryCount(); i++) {
                        Criteria.checkThat(
                                "Favicon[" + i + "] not updated",
                                history.getEntryAtIndex(i).getFavicon(),
                                Matchers.notNullValue());
                    }
                });

        ThreadUtils.runOnUiThreadBlocking(() -> popup.dismiss());
    }

    @Test
    @SmallTest
    @Feature({"Navigation"})
    public void testItemSelection() throws ExecutionException {
        final TestNavigationController controller = new TestNavigationController();
        final ListPopupWindow popup = showPopup(controller, false);

        ThreadUtils.runOnUiThreadBlocking((Runnable) () -> popup.performItemClick(1));

        Assert.assertFalse("Popup did not hide as expected.", popup.isShowing());
        Assert.assertEquals(
                "Popup attempted to navigate to the wrong index", 5, controller.mNavigatedIndex);
    }

    @Test
    @SmallTest
    @Feature({"Navigation"})
    public void testShowAllHistory() throws ExecutionException {
        final TestNavigationController controller = new TestNavigationController();
        final ListPopupWindow popup = showPopup(controller, false);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    ListView list = popup.getListView();
                    View view =
                            list.getAdapter().getView(list.getAdapter().getCount() - 1, null, list);
                    TextView text = view.findViewById(R.id.entry_title);
                    Assert.assertNotNull(text);
                    Assert.assertEquals(
                            text.getResources().getString(R.string.show_full_history),
                            text.getText().toString());
                });
    }

    @Test
    @SmallTest
    @Feature({"Navigation"})
    public void testPopupForIncognito() throws ExecutionException {
        final TestNavigationController controller = new TestNavigationController();
        final ListPopupWindow popup = showPopup(controller, true);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    ListView list = popup.getListView();
                    View view =
                            list.getAdapter().getView(list.getAdapter().getCount() - 1, null, list);
                    TextView text = view.findViewById(R.id.entry_title);
                    Assert.assertNotNull(text);
                    Assert.assertNotEquals(
                            text.getResources().getString(R.string.show_full_history),
                            text.getText().toString());
                    Assert.assertEquals(controller.getEntryCount(), list.getAdapter().getCount());
                });
    }

    private ListPopupWindow showPopup(NavigationController controller, boolean isOffTheRecord)
            throws ExecutionException {
        return ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    Profile profile = ProfileManager.getLastUsedRegularProfile();
                    if (isOffTheRecord) {
                        profile = profile.getPrimaryOTRProfile(true);
                    }
                    NavigationPopup popup =
                            new NavigationPopup(
                                    profile,
                                    mActivityTestRule.getActivity(),
                                    controller,
                                    NavigationPopup.Type.TABLET_FORWARD,
                                    mActivityTestRule.getActivity().getActivityTabProvider(),
                                    HistoryManagerUtils::showHistoryManager);
                    popup.show(
                            mActivityTestRule
                                    .getActivity()
                                    .getToolbarManager()
                                    .getToolbarLayoutForTesting());
                    return popup.getPopupForTesting();
                });
    }
}