| // 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() const 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 IsInstantNTP() const override { return false; } |
| |
| bool IsNewTabPage(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_; |
| }; |
| |
| TEST_F(LocationBarModelImplTest, |
| DisplayUrlAppliesFormattedStringWithEquivalentMeaning) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures({omnibox::kHideSteadyStateUrlScheme, |
| omnibox::kHideSteadyStateUrlTrivialSubdomains}, |
| {}); |
| |
| 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. |
| 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(originalFormattedFullUrl, 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) |
| #define MAYBE_PreventElisionWorks DISABLED_PreventElisionWorks |
| #else |
| #define MAYBE_PreventElisionWorks PreventElisionWorks |
| #endif |
| TEST_F(LocationBarModelImplTest, MAYBE_PreventElisionWorks) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| {omnibox::kHideSteadyStateUrlScheme, |
| omnibox::kHideSteadyStateUrlTrivialSubdomains, omnibox::kQueryInOmnibox}, |
| {}); |
| |
| 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()); |
| |
| // Verify that query in omnibox is turned off. |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE); |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); |
| |
| // Also 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()); |
| } |
| |
| TEST_F(LocationBarModelImplTest, QueryInOmniboxFeatureFlagWorks) { |
| delegate()->SetURL(kValidSearchResultsPage); |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE); |
| |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); |
| |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); |
| |
| EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); |
| } |
| |
| TEST_F(LocationBarModelImplTest, QueryInOmniboxSecurityLevel) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); |
| |
| delegate()->SetURL(kValidSearchResultsPage); |
| |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE); |
| EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); |
| |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::EV_SECURE); |
| EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); |
| |
| // Insecure levels should not be allowed to display search terms. |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::NONE); |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); |
| |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::DANGEROUS); |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); |
| |
| // But ignore the level if the connection info has not been initialized. |
| delegate()->SetVisibleSecurityStateConnectionInfoUninitialized(); |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::NONE); |
| EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); |
| } |
| |
| TEST_F(LocationBarModelImplTest, |
| QueryInOmniboxDefaultSearchProviderWithAndWithoutQuery) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE); |
| |
| delegate()->SetURL(kValidSearchResultsPage); |
| base::string16 result; |
| EXPECT_TRUE(model()->GetDisplaySearchTerms(&result)); |
| EXPECT_EQ(base::ASCIIToUTF16("foo query"), result); |
| |
| const GURL kDefaultSearchProviderURLWithNoQuery( |
| "https://www.google.com/maps"); |
| result.clear(); |
| delegate()->SetURL(kDefaultSearchProviderURLWithNoQuery); |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(&result)); |
| EXPECT_EQ(base::string16(), result); |
| } |
| |
| TEST_F(LocationBarModelImplTest, QueryInOmniboxNonDefaultSearchProvider) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); |
| |
| const GURL kNonDefaultSearchProvider( |
| "https://search.yahoo.com/search?ei=UTF-8&fr=crmas&p=foo+query"); |
| delegate()->SetURL(kNonDefaultSearchProvider); |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE); |
| |
| base::string16 result; |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(&result)); |
| EXPECT_EQ(base::string16(), result); |
| } |
| |
| TEST_F(LocationBarModelImplTest, QueryInOmniboxLookalikeURL) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); |
| |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE); |
| |
| const GURL kLookalikeURLQuery( |
| "https://www.google.com/search?q=lookalike.com"); |
| delegate()->SetURL(kLookalikeURLQuery); |
| |
| base::string16 result; |
| EXPECT_FALSE(model()->GetDisplaySearchTerms(&result)); |
| EXPECT_EQ(base::string16(), result); |
| } |
| |
| #if !defined(OS_ANDROID) && !defined(OS_IOS) |
| // Tests GetVectorIcon returns the correct security indicator icon when the |
| // danger-warning experiment is disabled. |
| TEST_F(LocationBarModelImplTest, GetVectorIcon_DefaultWarning) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndDisableFeature( |
| security_state::features::kMarkHttpAsFeature); |
| |
| delegate()->SetSecurityLevel(security_state::SecurityLevel::WARNING); |
| |
| gfx::ImageSkia expected_icon = gfx::CreateVectorIcon( |
| omnibox::kHttpIcon, gfx::kFaviconSize, gfx::kPlaceholderColor); |
| |
| gfx::ImageSkia icon = gfx::CreateVectorIcon( |
| model()->GetVectorIcon(), gfx::kFaviconSize, gfx::kPlaceholderColor); |
| |
| EXPECT_EQ(icon.bitmap(), expected_icon.bitmap()); |
| } |
| |
| // Tests GetVectorIcon returns the correct security indicator icon when the |
| // danger-warning experiment is enabled. |
| TEST_F(LocationBarModelImplTest, GetVectorIcon_DangerWarning) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeatureWithParameters( |
| security_state::features::kMarkHttpAsFeature, |
| {{security_state::features::kMarkHttpAsFeatureParameterName, |
| security_state::features::kMarkHttpAsParameterDangerWarning}}); |
| |
| 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) |
| |
| } // namespace |