blob: 8ea584a76ba917dbb39738536907693e5d242c95 [file] [log] [blame]
// Copyright 2015 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.toolbar;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.support.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
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.ContextUtils;
import org.chromium.base.test.params.ParameterAnnotations;
import org.chromium.base.test.params.ParameterProvider;
import org.chromium.base.test.params.ParameterSet;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
import org.chromium.chrome.browser.omnibox.NewTabPageDelegate;
import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
import org.chromium.chrome.browser.omnibox.UrlBarData;
import org.chromium.chrome.browser.tab.MockTab;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabSelectionType;
import org.chromium.chrome.browser.toolbar.top.ToolbarLayout;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Tests for LocationBarModel.
*/
@RunWith(ParameterizedRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class LocationBarModelTest {
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@Before
public void setUp() throws InterruptedException {
mActivityTestRule.startMainActivityOnBlankPage();
}
/**
* After closing all {@link Tab}s, the {@link LocationBarModel} should know that it is not
* showing any {@link Tab}.
*/
@Test
@Feature({"Android-Toolbar"})
@MediumTest
public void testClosingLastTabReflectedInModel() {
Assert.assertNotSame("No current tab", Tab.INVALID_TAB_ID,
getCurrentTabId(mActivityTestRule.getActivity()));
ChromeTabUtils.closeCurrentTab(
InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
assertEquals("Didn't close all tabs.", 0,
ChromeTabUtils.getNumOpenTabs(mActivityTestRule.getActivity()));
assertEquals("LocationBarModel is still trying to show a tab.", Tab.INVALID_TAB_ID,
getCurrentTabId(mActivityTestRule.getActivity()));
}
@Test
@SmallTest
public void testDisplayAndEditText() {
TestThreadUtils.runOnUiThreadBlocking(() -> {
TestLocationBarModel model = new TestLocationBarModel();
model.mUrl = UrlConstants.NTP_URL;
assertDisplayAndEditText(model, "", null);
model.mUrl = "chrome://about";
model.mDisplayUrl = "chrome://about";
model.mFullUrl = "chrome://about";
assertDisplayAndEditText(model, "chrome://about", "chrome://about");
model.mUrl = "https://www.foo.com";
model.mDisplayUrl = "https://foo.com";
model.mFullUrl = "https://foo.com";
assertDisplayAndEditText(model, "https://foo.com", "https://foo.com");
model.mUrl = "https://www.foo.com";
model.mDisplayUrl = "foo.com";
model.mFullUrl = "https://foo.com";
assertDisplayAndEditText(model, "foo.com", "https://foo.com");
// https://crbug.com/1214481
model.mUrl = "";
model.mDisplayUrl = "about:blank";
model.mFullUrl = "about:blank";
assertDisplayAndEditText(model, "about:blank", "about:blank");
});
}
/** Provides parameters for different types of transitions between tabs. */
public static class IncognitoTransitionParamProvider implements ParameterProvider {
@Override
public Iterable<ParameterSet> getParameters() {
List<ParameterSet> result = new ArrayList<>(8);
for (boolean fromIncognito : Arrays.asList(true, false)) {
for (boolean toIncognito : Arrays.asList(true, false)) {
result.add(new ParameterSet()
.value(fromIncognito, toIncognito)
.name(String.format(
"from_%b_to_%b", fromIncognito, toIncognito)));
}
}
return result;
}
}
@Test
@MediumTest
@ParameterAnnotations.UseMethodParameter(IncognitoTransitionParamProvider.class)
public void testOnIncognitoStateChange_switchTab(boolean fromIncognito, boolean toIncognito) {
// Add a regular tab next to the one created in setup.
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/false);
// Add two incognito tabs.
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/true);
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/true);
ChromeTabbedActivity activity = mActivityTestRule.getActivity();
LocationBarModel locationBarModel =
activity.getToolbarManager().getLocationBarModelForTesting();
LocationBarDataProvider.Observer observer = mock(LocationBarDataProvider.Observer.class);
doAnswer((invocation) -> {
assertEquals(toIncognito, locationBarModel.isIncognito());
return null;
})
.when(observer)
.onIncognitoStateChanged();
TestThreadUtils.runOnUiThreadBlocking(() -> {
mActivityTestRule.getActivity().getTabModelSelector().selectModel(fromIncognito);
locationBarModel.addObserver(observer);
// Switch to an existing tab.
mActivityTestRule.getActivity().getTabModelSelector().selectModel(/*incognito=*/
toIncognito);
mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel().setIndex(
0, TabSelectionType.FROM_USER);
});
assertEquals(toIncognito, locationBarModel.isIncognito());
if (fromIncognito != toIncognito) {
verify(observer).onIncognitoStateChanged();
} else {
verify(observer, times(0)).onIncognitoStateChanged();
}
}
@Test
@MediumTest
@ParameterAnnotations.UseMethodParameter(IncognitoTransitionParamProvider.class)
public void testOnIncognitoStateChange_newTab(boolean fromIncognito, boolean toIncognito) {
// Add a regular tab next to the one created in setup.
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/false);
// Add two incognito tabs.
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/true);
mActivityTestRule.loadUrlInNewTab("about:blank", /*incognito=*/true);
ChromeTabbedActivity activity = mActivityTestRule.getActivity();
LocationBarModel locationBarModel =
activity.getToolbarManager().getLocationBarModelForTesting();
LocationBarDataProvider.Observer observer = mock(LocationBarDataProvider.Observer.class);
doAnswer((invocation) -> {
assertEquals(toIncognito, locationBarModel.isIncognito());
return null;
})
.when(observer)
.onIncognitoStateChanged();
TestThreadUtils.runOnUiThreadBlocking(() -> {
mActivityTestRule.getActivity().getTabModelSelector().selectModel(fromIncognito);
locationBarModel.addObserver(observer);
});
// Switch to a new tab.
mActivityTestRule.loadUrlInNewTab("about:blank", toIncognito);
assertEquals(toIncognito, locationBarModel.isIncognito());
if (fromIncognito != toIncognito) {
verify(observer).onIncognitoStateChanged();
} else {
verify(observer, times(0)).onIncognitoStateChanged();
}
}
@Test
@MediumTest
public void testOnSecurityStateChanged() {
LocationBarModel locationBarModel =
mActivityTestRule.getActivity().getToolbarManager().getLocationBarModelForTesting();
LocationBarDataProvider.Observer observer = mock(LocationBarDataProvider.Observer.class);
TestThreadUtils.runOnUiThreadBlocking(() -> { locationBarModel.addObserver(observer); });
mActivityTestRule.loadUrl(UrlUtils.encodeHtmlDataUri("test content"));
verify(observer, atLeast(1)).onSecurityStateChanged();
}
private void assertDisplayAndEditText(
ToolbarDataProvider dataProvider, String displayText, String editText) {
TestThreadUtils.runOnUiThreadBlocking(() -> {
UrlBarData urlBarData = dataProvider.getUrlBarData();
assertEquals(
"Display text did not match", displayText, urlBarData.displayText.toString());
assertEquals("Editing text did not match", editText, urlBarData.editingText);
});
}
/**
* @param activity A reference to {@link ChromeTabbedActivity} to pull
* {@link android.view.View} data from.
* @return The id of the current {@link Tab} as far as the {@link LocationBarModel} sees it.
*/
public static int getCurrentTabId(final ChromeTabbedActivity activity) {
ToolbarLayout toolbar = (ToolbarLayout) activity.findViewById(R.id.toolbar);
Assert.assertNotNull("Toolbar is null", toolbar);
ToolbarDataProvider dataProvider = toolbar.getToolbarDataProvider();
Tab tab = dataProvider.getTab();
return tab != null ? tab.getId() : Tab.INVALID_TAB_ID;
}
private class TestLocationBarModel extends LocationBarModel {
private String mDisplayUrl;
private String mFullUrl;
private String mUrl;
public TestLocationBarModel() {
// clang-format off
super(ContextUtils.getApplicationContext(), NewTabPageDelegate.EMPTY,
DomDistillerTabUtils::getFormattedUrlFromOriginalDistillerUrl,
window -> null, new LocationBarModel.OfflineStatus() {},
SearchEngineLogoUtils.getInstance());
// clang-format on
initializeWithNative();
Tab tab = new MockTab(0, false) {
@Override
public boolean isInitialized() {
return true;
}
@Override
public boolean isFrozen() {
return false;
}
};
setTab(tab, false);
}
@Override
public String getCurrentUrl() {
return mUrl == null ? super.getCurrentUrl() : mUrl;
}
@Override
public String getFormattedFullUrl() {
return mFullUrl == null ? super.getFormattedFullUrl() : mFullUrl;
}
@Override
public String getUrlForDisplay() {
return mDisplayUrl == null ? super.getUrlForDisplay() : mDisplayUrl;
}
}
}