blob: 722b0c5de7f4a9954d9c8c253da1f04c716647c8 [file] [log] [blame]
// Copyright 2018 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.
#include "components/omnibox/browser/location_bar_model_impl.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/dom_distiller/core/url_constants.h"
#include "components/dom_distiller/core/url_utils.h"
#include "components/omnibox/browser/location_bar_model_delegate.h"
#include "components/omnibox/browser/test_omnibox_client.h"
#include "components/omnibox/common/omnibox_features.h"
#include "components/security_state/core/features.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/paint_vector_icon.h"
#include "url/gurl.h"
#if !defined(OS_ANDROID) && !defined(OS_IOS)
#include "components/omnibox/browser/vector_icons.h" // nogncheck
#include "components/vector_icons/vector_icons.h" // nogncheck
#endif
namespace {
class FakeLocationBarModelDelegate : public LocationBarModelDelegate {
public:
void SetURL(const GURL& url) { url_ = url; }
void SetShouldPreventElision(bool should_prevent_elision) {
should_prevent_elision_ = should_prevent_elision;
}
void SetSecurityLevel(security_state::SecurityLevel level) {
security_level_ = level;
}
void SetVisibleSecurityStateConnectionInfoUninitialized() {
connection_info_initialized_ = false;
}
// LocationBarModelDelegate:
base::string16 FormattedStringWithEquivalentMeaning(
const GURL& url,
const base::string16& formatted_url) const override {
return formatted_url + base::ASCIIToUTF16("/TestSuffix");
}
bool GetURL(GURL* url) const override {
*url = url_;
return true;
}
bool ShouldPreventElision() override { return should_prevent_elision_; }
security_state::SecurityLevel GetSecurityLevel() const override {
return security_level_;
}
std::unique_ptr<security_state::VisibleSecurityState>
GetVisibleSecurityState() const override {
std::unique_ptr<security_state::VisibleSecurityState> state =
std::make_unique<security_state::VisibleSecurityState>();
state->connection_info_initialized = connection_info_initialized_;
return state;
}
bool IsNewTabPage() const override { return false; }
bool IsNewTabPageURL(const GURL& url) const override { return false; }
bool IsHomePage(const GURL& url) const override { return false; }
AutocompleteClassifier* GetAutocompleteClassifier() override {
return omnibox_client_.GetAutocompleteClassifier();
}
TemplateURLService* GetTemplateURLService() override {
return omnibox_client_.GetTemplateURLService();
}
private:
GURL url_;
security_state::SecurityLevel security_level_;
TestOmniboxClient omnibox_client_;
bool should_prevent_elision_ = false;
bool connection_info_initialized_ = true;
};
class LocationBarModelImplTest : public testing::Test {
protected:
const GURL kValidSearchResultsPage =
GURL("https://www.google.com/search?q=foo+query");
LocationBarModelImplTest() : model_(&delegate_, 1024) {}
FakeLocationBarModelDelegate* delegate() { return &delegate_; }
LocationBarModelImpl* model() { return &model_; }
private:
base::test::TaskEnvironment task_environment_;
FakeLocationBarModelDelegate delegate_;
LocationBarModelImpl model_;
};
// A test fixture that enables the
// #omnibox-ui-reveal-steady-state-url-path-query-and-ref-on-hover field trial.
class LocationBarModelImplRevealOnHoverTest : public LocationBarModelImplTest {
public:
LocationBarModelImplRevealOnHoverTest() = default;
LocationBarModelImplRevealOnHoverTest(
const LocationBarModelImplRevealOnHoverTest&) = delete;
LocationBarModelImplRevealOnHoverTest& operator=(
const LocationBarModelImplRevealOnHoverTest&) = delete;
protected:
// testing::Test:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover);
LocationBarModelImplTest::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// A test fixture that enables the
// #omnibox-ui-hide-steady-state-url-path-query-and-ref-on-interaction field
// trial.
class LocationBarModelImplHideOnInteractionTest
: public LocationBarModelImplTest {
public:
LocationBarModelImplHideOnInteractionTest() = default;
LocationBarModelImplHideOnInteractionTest(
const LocationBarModelImplHideOnInteractionTest&) = delete;
LocationBarModelImplHideOnInteractionTest& operator=(
const LocationBarModelImplHideOnInteractionTest&) = delete;
protected:
// testing::Test:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(
omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction);
LocationBarModelImplTest::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// Tests that in the
// #omnibox-ui-reveal-steady-state-url-path-query-and-ref-on-hover, the display
// URL does not elide scheme or trivial subdomains.
TEST_F(LocationBarModelImplRevealOnHoverTest, DisplayUrl) {
delegate()->SetURL(GURL("http://www.example.test/foo"));
#if defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("http://www.example.test/TestSuffix"),
model()->GetURLForDisplay());
#else // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("http://www.example.test/foo/TestSuffix"),
model()->GetURLForDisplay());
#endif // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("http://www.example.test/foo/TestSuffix"),
model()->GetFormattedFullURL());
delegate()->SetURL(GURL("https://www.example.test/foo"));
#if defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/TestSuffix"),
model()->GetURLForDisplay());
#else // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo/TestSuffix"),
model()->GetURLForDisplay());
#endif // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo/TestSuffix"),
model()->GetFormattedFullURL());
}
// Tests that in the
// #omnibox-ui-hide-steady-state-url-path-query-and-ref-on-interaction, the
// display URL does not elide scheme or trivial subdomains.
TEST_F(LocationBarModelImplHideOnInteractionTest, DisplayUrl) {
delegate()->SetURL(GURL("http://www.example.test/foo"));
#if defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("http://www.example.test/TestSuffix"),
model()->GetURLForDisplay());
#else // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("http://www.example.test/foo/TestSuffix"),
model()->GetURLForDisplay());
#endif // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("http://www.example.test/foo/TestSuffix"),
model()->GetFormattedFullURL());
delegate()->SetURL(GURL("https://www.example.test/foo"));
#if defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/TestSuffix"),
model()->GetURLForDisplay());
#else // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo/TestSuffix"),
model()->GetURLForDisplay());
#endif // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo/TestSuffix"),
model()->GetFormattedFullURL());
}
TEST_F(LocationBarModelImplTest,
DisplayUrlAppliesFormattedStringWithEquivalentMeaning) {
delegate()->SetURL(GURL("http://www.google.com/"));
// Verify that both the full formatted URL and the display URL add the test
// suffix.
EXPECT_EQ(base::ASCIIToUTF16("www.google.com/TestSuffix"),
model()->GetFormattedFullURL());
EXPECT_EQ(base::ASCIIToUTF16("google.com/TestSuffix"),
model()->GetURLForDisplay());
}
TEST_F(LocationBarModelImplTest, FormatsReaderModeUrls) {
const GURL http_url("http://www.example.com/article.html");
// Get the real article's URL shown to the user.
delegate()->SetURL(http_url);
base::string16 originalDisplayUrl = model()->GetURLForDisplay();
base::string16 originalFormattedFullUrl = model()->GetFormattedFullURL();
// We expect that they don't start with "http://." We want the reader mode
// URL shown to the user to be the same as this original URL.
#if defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("example.com/TestSuffix"), originalDisplayUrl);
#else // #!defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("example.com/article.html/TestSuffix"),
originalDisplayUrl);
#endif // #defined (OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("www.example.com/article.html/TestSuffix"),
originalFormattedFullUrl);
GURL distilled = dom_distiller::url_utils::GetDistillerViewUrlFromUrl(
dom_distiller::kDomDistillerScheme, http_url, "title");
// Ensure the test is set up properly by checking the reader mode URL has
// the reader mode scheme.
EXPECT_EQ(dom_distiller::kDomDistillerScheme, distilled.scheme());
delegate()->SetURL(distilled);
// The user should see the same URL seen for the original article.
EXPECT_EQ(originalDisplayUrl, model()->GetURLForDisplay());
EXPECT_EQ(originalFormattedFullUrl, model()->GetFormattedFullURL());
// Similarly, https scheme should also be hidden, except from
// GetFormattedFullURL, because kFormatUrlOmitDefaults does not omit https.
const GURL https_url("https://www.example.com/article.html");
distilled = dom_distiller::url_utils::GetDistillerViewUrlFromUrl(
dom_distiller::kDomDistillerScheme, https_url, "title");
delegate()->SetURL(distilled);
EXPECT_EQ(originalDisplayUrl, model()->GetURLForDisplay());
EXPECT_EQ(
base::ASCIIToUTF16("https://www.example.com/article.html/TestSuffix"),
model()->GetFormattedFullURL());
// Invalid dom-distiller:// URLs should be shown, because they do not
// correspond to any article.
delegate()->SetURL(GURL(("chrome-distiller://abc/?url=invalid")));
#if defined(OS_IOS)
EXPECT_EQ(base::ASCIIToUTF16("chrome-distiller://abc/TestSuffix"),
model()->GetURLForDisplay());
#else // #!defined(OS_IOS)
EXPECT_EQ(
base::ASCIIToUTF16("chrome-distiller://abc/?url=invalid/TestSuffix"),
model()->GetURLForDisplay());
#endif // #defined (OS_IOS)
EXPECT_EQ(
base::ASCIIToUTF16("chrome-distiller://abc/?url=invalid/TestSuffix"),
model()->GetFormattedFullURL());
}
// TODO(https://crbug.com/1010418): Fix flakes on linux_chromium_asan_rel_ng and
// re-enable this test.
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#define MAYBE_PreventElisionWorks DISABLED_PreventElisionWorks
#else
#define MAYBE_PreventElisionWorks PreventElisionWorks
#endif
TEST_F(LocationBarModelImplTest, MAYBE_PreventElisionWorks) {
delegate()->SetShouldPreventElision(true);
delegate()->SetURL(GURL("https://www.google.com/search?q=foo+query+unelide"));
EXPECT_EQ(base::ASCIIToUTF16(
"https://www.google.com/search?q=foo+query+unelide/TestSuffix"),
model()->GetURLForDisplay());
// Test that HTTP elisions are prevented.
delegate()->SetURL(GURL("http://www.google.com/search?q=foo+query+unelide"));
EXPECT_EQ(base::ASCIIToUTF16(
"http://www.google.com/search?q=foo+query+unelide/TestSuffix"),
model()->GetURLForDisplay());
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Tests GetVectorIcon returns the correct security indicator icon.
TEST_F(LocationBarModelImplTest, GetVectorIcon) {
delegate()->SetSecurityLevel(security_state::SecurityLevel::WARNING);
gfx::ImageSkia expected_icon =
gfx::CreateVectorIcon(omnibox::kNotSecureWarningIcon, gfx::kFaviconSize,
gfx::kPlaceholderColor);
gfx::ImageSkia icon = gfx::CreateVectorIcon(
model()->GetVectorIcon(), gfx::kFaviconSize, gfx::kPlaceholderColor);
EXPECT_EQ(icon.bitmap(), expected_icon.bitmap());
}
#endif // !defined(OS_IOS)
#if defined(OS_IOS)
// Test that blob:http://example.test/foobar is displayed as "example.test" on
// iOS.
TEST_F(LocationBarModelImplTest, BlobDisplayURLIOS) {
delegate()->SetURL(GURL("blob:http://example.test/foo"));
EXPECT_EQ(base::ASCIIToUTF16("example.test/TestSuffix"),
model()->GetURLForDisplay());
}
#endif // defined(OS_IOS)
} // namespace