1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/bind.h"
14 #include "base/i18n/rtl.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "base/test/simple_test_clock.h"
17 #include "base/test/simple_test_tick_clock.h"
18 #include "build/build_config.h"
19 #include "chrome/app/chrome_command_ids.h"
20 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
21 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
22 #include "chrome/browser/command_updater.h"
23 #include "chrome/browser/command_updater_impl.h"
24 #include "chrome/browser/search_engines/template_url_service_factory_test_util.h"
25 #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
26 #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
27 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "chrome/test/base/testing_profile.h"
30 #include "chrome/test/views/chrome_views_test_base.h"
31 #include "components/omnibox/browser/omnibox_edit_model.h"
32 #include "components/omnibox/browser/test_location_bar_model.h"
33 #include "components/omnibox/common/omnibox_features.h"
34 #include "components/reputation/core/safety_tip_test_utils.h"
35 #include "content/public/browser/focused_node_details.h"
36 #include "content/public/test/browser_task_environment.h"
37 #include "content/public/test/mock_navigation_handle.h"
38 #include "content/public/test/test_renderer_host.h"
39 #include "content/public/test/web_contents_tester.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 #include "third_party/blink/public/common/input/web_input_event.h"
42 #include "third_party/blink/public/common/input/web_keyboard_event.h"
43 #include "third_party/blink/public/common/input/web_mouse_event.h"
44 #include "third_party/metrics_proto/omnibox_event.pb.h"
45 #include "ui/base/clipboard/clipboard.h"
46 #include "ui/base/clipboard/scoped_clipboard_writer.h"
47 #include "ui/base/ime/input_method.h"
48 #include "ui/base/ime/text_edit_commands.h"
49 #include "ui/events/event_utils.h"
50 #include "ui/events/keycodes/dom/dom_code.h"
51 #include "ui/gfx/animation/animation_container_element.h"
52 #include "ui/gfx/geometry/rect.h"
53 #include "ui/gfx/render_text.h"
54 #include "ui/gfx/render_text_test_api.h"
55 #include "ui/views/controls/textfield/textfield_test_api.h"
56 
57 #if defined(OS_CHROMEOS)
58 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
59 #include "chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h"
60 #endif
61 
62 using FeatureAndParams = base::test::ScopedFeatureList::FeatureAndParams;
63 using gfx::Range;
64 using metrics::OmniboxEventProto;
65 
66 namespace {
67 
68 class TestingOmniboxView;
69 
70 void ExpectElidedToSimplifiedDomain(TestingOmniboxView* view,
71                                     const base::string16& scheme,
72                                     const base::string16& subdomain,
73                                     const base::string16& hostname_and_scheme,
74                                     const base::string16& path,
75                                     bool should_elide_to_registrable_domain);
76 
77 void ExpectUnelidedFromSimplifiedDomain(gfx::RenderText* render_text,
78                                         const gfx::Range& display_url);
79 
80 // TestingOmniboxView ---------------------------------------------------------
81 
82 class TestingOmniboxView : public OmniboxViewViews {
83  public:
84   TestingOmniboxView(OmniboxEditController* controller,
85                      TestLocationBarModel* location_bar_model,
86                      std::unique_ptr<OmniboxClient> client);
87   TestingOmniboxView(const TestingOmniboxView&) = delete;
88   TestingOmniboxView& operator=(const TestingOmniboxView&) = delete;
89 
90   using views::Textfield::GetRenderText;
91 
92   void ResetEmphasisTestState();
93 
94   void CheckUpdatePopupCallInfo(size_t call_count,
95                                 const base::string16& text,
96                                 const Range& selection_range);
97 
98   void CheckUpdatePopupNotCalled();
99 
scheme_range() const100   Range scheme_range() const { return scheme_range_; }
emphasis_range() const101   Range emphasis_range() const { return emphasis_range_; }
base_text_emphasis() const102   bool base_text_emphasis() const { return base_text_emphasis_; }
103 
104   // Returns the latest color applied to |range| via ApplyColor(), or
105   // base::nullopt if no color has been applied to |range|.
106   base::Optional<SkColor> GetLatestColorForRange(const gfx::Range& range);
107 
108   // OmniboxViewViews:
GetAccessibleNodeData(ui::AXNodeData * node_data)109   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {}
110   void OnThemeChanged() override;
111 
112   // In the simplified domain field trials, these methods advance through
113   // elision/unelision animations (triggered by hovering over the omnibox and
114   // interacting with the web contents, respectively) by |step_ms|.
115   void StepSimplifiedDomainHoverAnimation(int64_t step_ms);
116   void StepSimplifiedDomainInteractionAnimation(int64_t step_ms);
117 
118   // Simulates a navigation and checks that the URL is elided to the simplified
119   // domain afterwards. This simulates a renderer-initiated navigation, in which
120   // the display URL is updated between DidStartNavigation() and
121   // DidFinishNavigation() calls.
122   void NavigateAndExpectElided(const GURL& url,
123                                bool is_same_document,
124                                const GURL& previous_url,
125                                const base::string16& scheme,
126                                const base::string16& subdomain,
127                                const base::string16& hostname_and_scheme,
128                                const base::string16& path,
129                                bool should_elide_to_registrable_domain);
130 
131   // Simluates a navigation and checks that the URL is unelided from the
132   // simplified domain afterwards. This simulates a renderer-initiated
133   // navigation, in which the display URL is updated between
134   // DidStartNavigation() and DidFinishNavigation() calls.
135   void NavigateAndExpectUnelided(const base::string16& url,
136                                  bool is_same_document,
137                                  const GURL& previous_url,
138                                  const base::string16& scheme);
139 
140   using OmniboxView::OnInlineAutocompleteTextMaybeChanged;
141 
142  private:
143   // OmniboxViewViews:
144   // There is no popup and it doesn't actually matter whether we change the
145   // visual style of the text, so these methods are all overridden merely to
146   // capture relevant state at the time of the call, to be checked by test code.
147   void UpdatePopup() override;
148   void SetEmphasis(bool emphasize, const Range& range) override;
149   void UpdateSchemeStyle(const Range& range) override;
150   void ApplyColor(SkColor color, const gfx::Range& range) override;
151 
152   size_t update_popup_call_count_ = 0;
153   base::string16 update_popup_text_;
154   Range update_popup_selection_range_;
155 
156   // Range of the last scheme logged by UpdateSchemeStyle().
157   Range scheme_range_;
158 
159   // Range of the last text emphasized by SetEmphasis().
160   Range emphasis_range_;
161 
162   // Stores the colors applied to ranges via ApplyColor(), in chronological
163   // order.
164   std::vector<std::pair<SkColor, gfx::Range>> range_colors_;
165 
166   TestLocationBarModel* location_bar_model_;
167 
168   // SetEmphasis() logs whether the base color of the text is emphasized.
169   bool base_text_emphasis_;
170 };
171 
TestingOmniboxView(OmniboxEditController * controller,TestLocationBarModel * location_bar_model,std::unique_ptr<OmniboxClient> client)172 TestingOmniboxView::TestingOmniboxView(OmniboxEditController* controller,
173                                        TestLocationBarModel* location_bar_model,
174                                        std::unique_ptr<OmniboxClient> client)
175     : OmniboxViewViews(controller,
176                        std::move(client),
177                        false,
178                        nullptr,
179                        gfx::FontList()),
180       location_bar_model_(location_bar_model) {}
181 
ResetEmphasisTestState()182 void TestingOmniboxView::ResetEmphasisTestState() {
183   base_text_emphasis_ = false;
184   emphasis_range_ = Range::InvalidRange();
185   scheme_range_ = Range::InvalidRange();
186 }
187 
CheckUpdatePopupCallInfo(size_t call_count,const base::string16 & text,const Range & selection_range)188 void TestingOmniboxView::CheckUpdatePopupCallInfo(
189     size_t call_count,
190     const base::string16& text,
191     const Range& selection_range) {
192   EXPECT_EQ(call_count, update_popup_call_count_);
193   EXPECT_EQ(text, update_popup_text_);
194   EXPECT_EQ(selection_range, update_popup_selection_range_);
195 }
196 
CheckUpdatePopupNotCalled()197 void TestingOmniboxView::CheckUpdatePopupNotCalled() {
198   EXPECT_EQ(update_popup_call_count_, 0U);
199 }
200 
GetLatestColorForRange(const gfx::Range & range)201 base::Optional<SkColor> TestingOmniboxView::GetLatestColorForRange(
202     const gfx::Range& range) {
203   // Iterate backwards to get the most recently applied color for |range|.
204   for (auto range_color = range_colors_.rbegin();
205        range_color != range_colors_.rend(); range_color++) {
206     if (range == range_color->second)
207       return range_color->first;
208   }
209   return base::nullopt;
210 }
211 
OnThemeChanged()212 void TestingOmniboxView::OnThemeChanged() {
213   // This method is overridden simply to expose this protected method for tests
214   // to call.
215   OmniboxViewViews::OnThemeChanged();
216 }
217 
UpdatePopup()218 void TestingOmniboxView::UpdatePopup() {
219   ++update_popup_call_count_;
220   update_popup_text_ = GetText();
221   update_popup_selection_range_ = GetSelectedRange();
222 
223   // The real view calls OmniboxEditModel::UpdateInput(), which sets input in
224   // progress and starts autocomplete.  Triggering autocomplete and the popup is
225   // beyond the scope of this test, but setting input in progress is important
226   // for making some sequences (e.g. uneliding on taking an action) behave
227   // correctly.
228   model()->SetInputInProgress(true);
229 }
230 
SetEmphasis(bool emphasize,const Range & range)231 void TestingOmniboxView::SetEmphasis(bool emphasize, const Range& range) {
232   if (range == Range::InvalidRange()) {
233     base_text_emphasis_ = emphasize;
234     return;
235   }
236 
237   EXPECT_TRUE(emphasize);
238   emphasis_range_ = range;
239 }
240 
UpdateSchemeStyle(const Range & range)241 void TestingOmniboxView::UpdateSchemeStyle(const Range& range) {
242   scheme_range_ = range;
243 }
244 
ApplyColor(SkColor color,const gfx::Range & range)245 void TestingOmniboxView::ApplyColor(SkColor color, const gfx::Range& range) {
246   range_colors_.emplace_back(std::pair<SkColor, gfx::Range>(color, range));
247   OmniboxViewViews::ApplyColor(color, range);
248 }
249 
StepSimplifiedDomainHoverAnimation(int64_t step_ms)250 void TestingOmniboxView::StepSimplifiedDomainHoverAnimation(int64_t step_ms) {
251   OmniboxViewViews::ElideAnimation* hover_animation =
252       GetHoverElideOrUnelideAnimationForTesting();
253   ASSERT_TRUE(hover_animation);
254   EXPECT_TRUE(hover_animation->IsAnimating());
255   gfx::AnimationContainerElement* hover_animation_as_element =
256       static_cast<gfx::AnimationContainerElement*>(
257           hover_animation->GetAnimationForTesting());
258   hover_animation_as_element->SetStartTime(base::TimeTicks());
259   hover_animation_as_element->Step(base::TimeTicks() +
260                                    base::TimeDelta::FromMilliseconds(step_ms));
261 }
262 
StepSimplifiedDomainInteractionAnimation(int64_t step_ms)263 void TestingOmniboxView::StepSimplifiedDomainInteractionAnimation(
264     int64_t step_ms) {
265   OmniboxViewViews::ElideAnimation* interaction_animation =
266       GetElideAfterInteractionAnimationForTesting();
267   ASSERT_TRUE(interaction_animation);
268   EXPECT_TRUE(interaction_animation->IsAnimating());
269   gfx::AnimationContainerElement* interaction_animation_as_element =
270       static_cast<gfx::AnimationContainerElement*>(
271           interaction_animation->GetAnimationForTesting());
272   interaction_animation_as_element->SetStartTime(base::TimeTicks());
273   interaction_animation_as_element->Step(
274       base::TimeTicks() + base::TimeDelta::FromMilliseconds(step_ms));
275 }
276 
NavigateAndExpectElided(const GURL & url,bool is_same_document,const GURL & previous_url,const base::string16 & scheme,const base::string16 & subdomain,const base::string16 & hostname_and_scheme,const base::string16 & path,bool should_elide_to_registrable_domain)277 void TestingOmniboxView::NavigateAndExpectElided(
278     const GURL& url,
279     bool is_same_document,
280     const GURL& previous_url,
281     const base::string16& scheme,
282     const base::string16& subdomain,
283     const base::string16& hostname_and_scheme,
284     const base::string16& path,
285     bool should_elide_to_registrable_domain) {
286   content::MockNavigationHandle navigation;
287   navigation.set_is_same_document(is_same_document);
288   navigation.set_url(url);
289   navigation.set_previous_url(previous_url);
290   DidStartNavigation(&navigation);
291   location_bar_model_->set_url(url);
292   location_bar_model_->set_url_for_display(base::ASCIIToUTF16(url.spec()));
293   model()->ResetDisplayTexts();
294   RevertAll();
295   navigation.set_has_committed(true);
296   DidFinishNavigation(&navigation);
297   ExpectElidedToSimplifiedDomain(this, scheme, subdomain, hostname_and_scheme,
298                                  path, should_elide_to_registrable_domain);
299 }
300 
NavigateAndExpectUnelided(const base::string16 & url,bool is_same_document,const GURL & previous_url,const base::string16 & scheme)301 void TestingOmniboxView::NavigateAndExpectUnelided(
302     const base::string16& url,
303     bool is_same_document,
304     const GURL& previous_url,
305     const base::string16& scheme) {
306   content::MockNavigationHandle navigation;
307   navigation.set_is_same_document(is_same_document);
308   navigation.set_url(GURL(url));
309   navigation.set_previous_url(previous_url);
310   DidStartNavigation(&navigation);
311   location_bar_model_->set_url(GURL(url));
312   location_bar_model_->set_url_for_display(url);
313   model()->ResetDisplayTexts();
314   RevertAll();
315   navigation.set_has_committed(true);
316   DidFinishNavigation(&navigation);
317   ExpectUnelidedFromSimplifiedDomain(this->GetRenderText(),
318                                      gfx::Range(scheme.size(), url.size()));
319 }
320 
321 // TODO(crbug.com/1112536): With RTL UI, the URL is sometimes off by one pixel
322 // of the right edge. Investigate if this is expected, otherwise replace this
323 // with equality checks in tests that use it. Checks |a| is within 1 of |b|.
CheckEqualsWithMarginOne(int a,int b)324 void CheckEqualsWithMarginOne(int a, int b) {
325   EXPECT_LE(std::abs(a - b), 1);
326 }
327 
328 // Checks that |view|'s current display rect and offset does not display
329 // |path|, and also does not display |subdomain_and_scheme| if
330 // |should_elide_to_registrable_domain| is true.
331 //
332 // |subdomain_and_scheme| is assumed to be a prefix of |hostname_and_scheme|.
333 // |subdomain_and_scheme| and |subdomain| should include a trailing ".", and
334 // |path| should include a leading "/".
ExpectElidedToSimplifiedDomain(TestingOmniboxView * view,const base::string16 & scheme,const base::string16 & subdomain,const base::string16 & hostname_and_scheme,const base::string16 & path,bool should_elide_to_registrable_domain)335 void ExpectElidedToSimplifiedDomain(TestingOmniboxView* view,
336                                     const base::string16& scheme,
337                                     const base::string16& subdomain,
338                                     const base::string16& hostname_and_scheme,
339                                     const base::string16& path,
340                                     bool should_elide_to_registrable_domain) {
341   gfx::RenderText* render_text = view->GetRenderText();
342   gfx::Rect subdomain_and_scheme_rect;
343   for (const auto& rect : render_text->GetSubstringBounds(
344            gfx::Range(0, scheme.size() + subdomain.size()))) {
345     subdomain_and_scheme_rect.Union(rect);
346   }
347   gfx::Rect path_rect;
348   for (const auto& rect : render_text->GetSubstringBounds(
349            gfx::Range(hostname_and_scheme.size(),
350                       hostname_and_scheme.size() + path.size()))) {
351     path_rect.Union(rect);
352   }
353   EXPECT_FALSE(render_text->display_rect().Contains(path_rect));
354   if (should_elide_to_registrable_domain) {
355     EXPECT_FALSE(
356         render_text->display_rect().Contains(subdomain_and_scheme_rect));
357     gfx::Rect registrable_domain_rect;
358     for (const auto& rect : render_text->GetSubstringBounds(gfx::Range(
359              scheme.size() + subdomain.size(), hostname_and_scheme.size()))) {
360       registrable_domain_rect.Union(rect);
361     }
362     EXPECT_TRUE(render_text->display_rect().Contains(registrable_domain_rect));
363     // The text should be scrolled to push the scheme and subdomain offscreen,
364     // so that the text starts at the registrable domain. Note that this code
365     // computes the expected offset by comparing x() values rather than
366     // comparing based on widths (for example, it wouldn't work to check that
367     // the display offset is equal to |subdomain_and_scheme_rect|'s width). This
368     // is because GetSubstringBounds() rounds outward, so the width of
369     // |subdomain_and_scheme_rect| could slightly overlap
370     // |registrable_domain_rect|.
371     // In the RTL UI case, the offset instead has to push the path offscreen to
372     // the right, so we check offset equals the width of the path rectangle.
373     if (base::i18n::IsRTL()) {
374       CheckEqualsWithMarginOne(path_rect.width(),
375                                render_text->GetUpdatedDisplayOffset().x());
376     } else {
377       EXPECT_EQ(registrable_domain_rect.x() - subdomain_and_scheme_rect.x(),
378                 -1 * render_text->GetUpdatedDisplayOffset().x());
379     }
380     // The scheme and subdomain should be transparent.
381     EXPECT_EQ(SK_ColorTRANSPARENT, view->GetLatestColorForRange(gfx::Range(
382                                        0, scheme.size() + subdomain.size())));
383   } else {
384     // When elision to registrable domain is disabled, the scheme should be
385     // hidden but the subdomain should not be.
386     EXPECT_FALSE(
387         render_text->display_rect().Contains(subdomain_and_scheme_rect));
388     gfx::Rect hostname_rect;
389     for (const auto& rect : render_text->GetSubstringBounds(
390              gfx::Range(scheme.size(), hostname_and_scheme.size()))) {
391       hostname_rect.Union(rect);
392     }
393     // The text should be scrolled to push the scheme offscreen, so that the
394     // text starts at the subdomain. As above, it's important to compute the
395     // expected offset with x() values instead of width()s, since the width()s
396     // of different adjacent substring bounds could overlap.
397     // In the RTL UI case, the offset instead has to push the path offscreen to
398     // the right, so we check offset equals the width of the path rectangle.
399     if (base::i18n::IsRTL()) {
400       CheckEqualsWithMarginOne(path_rect.width(),
401                                render_text->GetUpdatedDisplayOffset().x());
402     } else {
403       EXPECT_EQ(hostname_rect.x() - subdomain_and_scheme_rect.x(),
404                 -1 * render_text->GetUpdatedDisplayOffset().x());
405     }
406     // The scheme should be transparent.
407     EXPECT_EQ(SK_ColorTRANSPARENT,
408               view->GetLatestColorForRange(gfx::Range(0, scheme.size())));
409   }
410   // The path should be transparent.
411   EXPECT_EQ(SK_ColorTRANSPARENT,
412             view->GetLatestColorForRange(
413                 gfx::Range(hostname_and_scheme.size(),
414                            hostname_and_scheme.size() + path.size())));
415 }
416 
417 // Checks that |render_text|'s current display rect and offset displays all of
418 // |display_url|, starting at the leading edge.
ExpectUnelidedFromSimplifiedDomain(gfx::RenderText * render_text,const gfx::Range & display_url)419 void ExpectUnelidedFromSimplifiedDomain(gfx::RenderText* render_text,
420                                         const gfx::Range& display_url) {
421   gfx::Rect unelided_rect;
422   for (const auto& rect : render_text->GetSubstringBounds(display_url)) {
423     unelided_rect.Union(rect);
424   }
425   EXPECT_TRUE(render_text->display_rect().Contains(unelided_rect));
426   // |display_url| should be at the leading edge of |render_text|'s display
427   // rect for LTR UI, or at the rightmost side of the omnibox for RTL UI.
428   if (base::i18n::IsRTL()) {
429     CheckEqualsWithMarginOne(
430         unelided_rect.x(),
431         render_text->display_rect().right() - unelided_rect.width());
432   } else {
433     EXPECT_EQ(unelided_rect.x(), render_text->display_rect().x());
434   }
435 }
436 
437 // TestingOmniboxEditController -----------------------------------------------
438 
439 class TestingOmniboxEditController : public ChromeOmniboxEditController {
440  public:
TestingOmniboxEditController(CommandUpdater * command_updater,LocationBarModel * location_bar_model)441   TestingOmniboxEditController(CommandUpdater* command_updater,
442                                LocationBarModel* location_bar_model)
443       : ChromeOmniboxEditController(command_updater),
444         location_bar_model_(location_bar_model) {}
445   TestingOmniboxEditController(const TestingOmniboxEditController&) = delete;
446   TestingOmniboxEditController& operator=(const TestingOmniboxEditController&) =
447       delete;
448 
set_omnibox_view(OmniboxViewViews * view)449   void set_omnibox_view(OmniboxViewViews* view) { omnibox_view_ = view; }
450 
451  private:
452   // ChromeOmniboxEditController:
GetLocationBarModel()453   LocationBarModel* GetLocationBarModel() override {
454     return location_bar_model_;
455   }
GetLocationBarModel() const456   const LocationBarModel* GetLocationBarModel() const override {
457     return location_bar_model_;
458   }
UpdateWithoutTabRestore()459   void UpdateWithoutTabRestore() override {
460     // This is a minimal amount of what LocationBarView does. Not all tests
461     // set |omnibox_view_|.
462     if (omnibox_view_)
463       omnibox_view_->Update();
464   }
465 
466   LocationBarModel* location_bar_model_;
467   OmniboxViewViews* omnibox_view_ = nullptr;
468 };
469 
470 }  // namespace
471 
472 // OmniboxViewViewsTest -------------------------------------------------------
473 
474 // Base class that ensures ScopedFeatureList is initialized first.
475 class OmniboxViewViewsTestBase : public ChromeViewsTestBase {
476  public:
OmniboxViewViewsTestBase(const std::vector<FeatureAndParams> & enabled_features,const std::vector<base::Feature> & disabled_features,bool is_rtl_ui_test=false)477   OmniboxViewViewsTestBase(
478       const std::vector<FeatureAndParams>& enabled_features,
479       const std::vector<base::Feature>& disabled_features,
480       bool is_rtl_ui_test = false) {
481     scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features,
482                                                        disabled_features);
483     base::i18n::SetRTLForTesting(is_rtl_ui_test);
484   }
485 
486  protected:
487   base::test::ScopedFeatureList scoped_feature_list_;
488 };
489 
490 // The display URL used in simplified domain display tests.
491 const base::string16 kSimplifiedDomainDisplayUrl =
492     base::ASCIIToUTF16("https://foo.example.test/bar");
493 const base::string16 kSimplifiedDomainDisplayUrlHostnameAndScheme =
494     base::ASCIIToUTF16("https://foo.example.test");
495 const base::string16 kSimplifiedDomainDisplayUrlSubdomainAndScheme =
496     base::ASCIIToUTF16("https://foo.");
497 const base::string16 kSimplifiedDomainDisplayUrlSubdomain =
498     base::ASCIIToUTF16("foo.");
499 const base::string16 kSimplifiedDomainDisplayUrlPath =
500     base::ASCIIToUTF16("/bar");
501 const base::string16 kSimplifiedDomainDisplayUrlScheme =
502     base::ASCIIToUTF16("https://");
503 
504 class OmniboxViewViewsTest : public OmniboxViewViewsTestBase {
505  public:
506   OmniboxViewViewsTest(const std::vector<FeatureAndParams>& enabled_features,
507                        const std::vector<base::Feature>& disabled_features,
508                        bool is_rtl_ui_test = false);
509 
OmniboxViewViewsTest()510   OmniboxViewViewsTest()
511       : OmniboxViewViewsTest(std::vector<FeatureAndParams>(),
512                              std::vector<base::Feature>()) {}
513   OmniboxViewViewsTest(const OmniboxViewViewsTest&) = delete;
514   OmniboxViewViewsTest& operator=(const OmniboxViewViewsTest&) = delete;
515 
location_bar_model()516   TestLocationBarModel* location_bar_model() { return &location_bar_model_; }
command_updater()517   CommandUpdaterImpl* command_updater() { return &command_updater_; }
omnibox_view() const518   TestingOmniboxView* omnibox_view() const { return omnibox_view_; }
519 
520   // TODO(tommycli): These base class accessors exist because Textfield and
521   // OmniboxView both hide member functions that were public in base classes.
522   // Remove these after we stop doing that.
omnibox_textfield() const523   views::Textfield* omnibox_textfield() const { return omnibox_view(); }
omnibox_textfield_view() const524   views::View* omnibox_textfield_view() const { return omnibox_view(); }
525 
textfield_test_api()526   views::TextfieldTestApi* textfield_test_api() { return test_api_.get(); }
527 
528   // Sets |new_text| as the omnibox text, and emphasizes it appropriately.  If
529   // |accept_input| is true, pretends that the user has accepted this input
530   // (i.e. it's been navigated to).
531   void SetAndEmphasizeText(const std::string& new_text, bool accept_input);
532 
IsCursorEnabled() const533   bool IsCursorEnabled() const {
534     return test_api_->GetRenderText()->cursor_enabled();
535   }
536 
CreateMouseEvent(ui::EventType type,const gfx::Point & point,int event_flags=ui::EF_LEFT_MOUSE_BUTTON)537   ui::MouseEvent CreateMouseEvent(ui::EventType type,
538                                   const gfx::Point& point,
539                                   int event_flags = ui::EF_LEFT_MOUSE_BUTTON) {
540     return ui::MouseEvent(type, point, point, ui::EventTimeForNow(),
541                           event_flags, event_flags);
542   }
543 
544  protected:
profile()545   Profile* profile() { return profile_.get(); }
omnibox_edit_controller()546   TestingOmniboxEditController* omnibox_edit_controller() {
547     return &omnibox_edit_controller_;
548   }
549 
550   // Updates the models' URL and display text to |new_url|.
UpdateDisplayURL(const base::string16 & new_url)551   void UpdateDisplayURL(const base::string16& new_url) {
552     location_bar_model()->set_url(GURL(new_url));
553     location_bar_model()->set_url_for_display(new_url);
554     omnibox_view()->model()->ResetDisplayTexts();
555     omnibox_view()->RevertAll();
556   }
557 
558   // Sets up tests for the simplified domain field trials.
SetUpSimplifiedDomainTest()559   void SetUpSimplifiedDomainTest() {
560     UpdateDisplayURL(kSimplifiedDomainDisplayUrl);
561     // Call OnThemeChanged() to create the animations.
562     omnibox_view()->OnThemeChanged();
563   }
564 
565   // testing::Test:
566   void SetUp() override;
567   void TearDown() override;
568 
CreateEvent(ui::EventType type,int flags)569   ui::MouseEvent CreateEvent(ui::EventType type, int flags) {
570     return ui::MouseEvent(type, gfx::Point(0, 0), gfx::Point(),
571                           ui::EventTimeForNow(), flags, 0);
572   }
573 
574  private:
575   std::unique_ptr<TestingProfile> profile_;
576   std::unique_ptr<TemplateURLServiceFactoryTestUtil> util_;
577   CommandUpdaterImpl command_updater_;
578   TestLocationBarModel location_bar_model_;
579   TestingOmniboxEditController omnibox_edit_controller_;
580   content::RenderViewHostTestEnabler rvh_test_enabler_;
581 
582   std::unique_ptr<views::Widget> widget_;
583 
584   // Owned by |widget_|.
585   TestingOmniboxView* omnibox_view_;
586 
587   std::unique_ptr<views::TextfieldTestApi> test_api_;
588 };
589 
OmniboxViewViewsTest(const std::vector<FeatureAndParams> & enabled_features,const std::vector<base::Feature> & disabled_features,bool is_rtl_ui_test)590 OmniboxViewViewsTest::OmniboxViewViewsTest(
591     const std::vector<FeatureAndParams>& enabled_features,
592     const std::vector<base::Feature>& disabled_features,
593     bool is_rtl_ui_test)
594     : OmniboxViewViewsTestBase(enabled_features,
595                                disabled_features,
596                                is_rtl_ui_test),
597       command_updater_(nullptr),
598       omnibox_edit_controller_(&command_updater_, &location_bar_model_) {}
599 
SetAndEmphasizeText(const std::string & new_text,bool accept_input)600 void OmniboxViewViewsTest::SetAndEmphasizeText(const std::string& new_text,
601                                                bool accept_input) {
602   omnibox_view()->ResetEmphasisTestState();
603   omnibox_view()->SetUserText(base::ASCIIToUTF16(new_text));
604   if (accept_input) {
605     // We don't need to actually navigate in this case (and doing so in a test
606     // would be difficult); it's sufficient to mark input as "no longer in
607     // progress", and the edit model will assume the current text is a URL.
608     omnibox_view()->model()->SetInputInProgress(false);
609   }
610   omnibox_view()->EmphasizeURLComponents();
611 }
612 
SetUp()613 void OmniboxViewViewsTest::SetUp() {
614   ChromeViewsTestBase::SetUp();
615 
616   profile_ = std::make_unique<TestingProfile>();
617   util_ = std::make_unique<TemplateURLServiceFactoryTestUtil>(profile_.get());
618 
619   // We need a widget so OmniboxView can be correctly focused and unfocused.
620   widget_ = CreateTestWidget();
621   widget_->Show();
622 
623 #if defined(OS_CHROMEOS)
624   chromeos::input_method::InitializeForTesting(
625       new chromeos::input_method::MockInputMethodManagerImpl);
626 #endif
627   AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
628       profile_.get(),
629       base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor));
630   auto omnibox_view = std::make_unique<TestingOmniboxView>(
631       &omnibox_edit_controller_, location_bar_model(),
632       std::make_unique<ChromeOmniboxClient>(&omnibox_edit_controller_,
633                                             profile_.get()));
634   test_api_ = std::make_unique<views::TextfieldTestApi>(omnibox_view.get());
635   omnibox_view->Init();
636 
637   omnibox_view_ = widget_->SetContentsView(std::move(omnibox_view));
638 }
639 
TearDown()640 void OmniboxViewViewsTest::TearDown() {
641   // Clean ourselves up as the text input client.
642   if (omnibox_view_->GetInputMethod())
643     omnibox_view_->GetInputMethod()->DetachTextInputClient(omnibox_view_);
644 
645   widget_.reset();
646   util_.reset();
647   profile_.reset();
648 
649 #if defined(OS_CHROMEOS)
650   chromeos::input_method::Shutdown();
651 #endif
652   ChromeViewsTestBase::TearDown();
653 }
654 
655 // Actual tests ---------------------------------------------------------------
656 
657 // Checks that a single change of the text in the omnibox invokes
658 // only one call to OmniboxViewViews::UpdatePopup().
TEST_F(OmniboxViewViewsTest,UpdatePopupCall)659 TEST_F(OmniboxViewViewsTest, UpdatePopupCall) {
660   ui::KeyEvent char_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, 0,
661                           ui::DomKey::FromCharacter('a'),
662                           ui::EventTimeForNow());
663   omnibox_textfield()->InsertChar(char_event);
664   omnibox_view()->CheckUpdatePopupCallInfo(1, base::ASCIIToUTF16("a"),
665                                            Range(1));
666 
667   char_event =
668       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_B, ui::DomCode::US_B, 0,
669                    ui::DomKey::FromCharacter('b'), ui::EventTimeForNow());
670   omnibox_textfield()->InsertChar(char_event);
671   omnibox_view()->CheckUpdatePopupCallInfo(2, base::ASCIIToUTF16("ab"),
672                                            Range(2));
673 
674   ui::KeyEvent pressed(ui::ET_KEY_PRESSED, ui::VKEY_BACK, 0);
675   omnibox_textfield()->OnKeyEvent(&pressed);
676   omnibox_view()->CheckUpdatePopupCallInfo(3, base::ASCIIToUTF16("a"),
677                                            Range(1));
678 }
679 
680 // Test that text cursor is shown in the omnibox after entering any single
681 // character in NTP 'Search box'. Test for crbug.com/698172.
TEST_F(OmniboxViewViewsTest,EditTextfield)682 TEST_F(OmniboxViewViewsTest, EditTextfield) {
683   omnibox_textfield()->SetCursorEnabled(false);
684   ui::KeyEvent char_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, 0,
685                           ui::DomKey::FromCharacter('a'),
686                           ui::EventTimeForNow());
687   omnibox_textfield()->InsertChar(char_event);
688   EXPECT_TRUE(IsCursorEnabled());
689 }
690 
691 // Test that the scheduled text edit command is cleared when Textfield receives
692 // a key press event. This ensures that the scheduled text edit command property
693 // is always in the correct state. Test for http://crbug.com/613948.
TEST_F(OmniboxViewViewsTest,ScheduledTextEditCommand)694 TEST_F(OmniboxViewViewsTest, ScheduledTextEditCommand) {
695   omnibox_textfield()->SetTextEditCommandForNextKeyEvent(
696       ui::TextEditCommand::MOVE_UP);
697   EXPECT_EQ(ui::TextEditCommand::MOVE_UP,
698             textfield_test_api()->scheduled_text_edit_command());
699 
700   ui::KeyEvent up_pressed(ui::ET_KEY_PRESSED, ui::VKEY_UP, 0);
701   omnibox_textfield()->OnKeyEvent(&up_pressed);
702   EXPECT_EQ(ui::TextEditCommand::INVALID_COMMAND,
703             textfield_test_api()->scheduled_text_edit_command());
704 }
705 
706 // Test that Shift+Up and Shift+Down are not captured and let selection mode
707 // take over. Test for crbug.com/863543 and crbug.com/892216.
TEST_F(OmniboxViewViewsTest,SelectWithShift_863543)708 TEST_F(OmniboxViewViewsTest, SelectWithShift_863543) {
709   location_bar_model()->set_url(GURL("http://www.example.com/?query=1"));
710   const base::string16 text =
711       base::ASCIIToUTF16("http://www.example.com/?query=1");
712   omnibox_view()->SetWindowTextAndCaretPos(text, 23U, false, false);
713 
714   ui::KeyEvent shift_up_pressed(ui::ET_KEY_PRESSED, ui::VKEY_UP,
715                                 ui::EF_SHIFT_DOWN);
716   omnibox_textfield()->OnKeyEvent(&shift_up_pressed);
717 
718   size_t start, end;
719   omnibox_view()->GetSelectionBounds(&start, &end);
720   EXPECT_EQ(23U, start);
721   EXPECT_EQ(0U, end);
722   omnibox_view()->CheckUpdatePopupNotCalled();
723 
724   omnibox_view()->SetWindowTextAndCaretPos(text, 18U, false, false);
725 
726   ui::KeyEvent shift_down_pressed(ui::ET_KEY_PRESSED, ui::VKEY_DOWN,
727                                   ui::EF_SHIFT_DOWN);
728   omnibox_textfield()->OnKeyEvent(&shift_down_pressed);
729 
730   omnibox_view()->GetSelectionBounds(&start, &end);
731   EXPECT_EQ(18U, start);
732   EXPECT_EQ(31U, end);
733   omnibox_view()->CheckUpdatePopupNotCalled();
734 }
735 
TEST_F(OmniboxViewViewsTest,OnBlur)736 TEST_F(OmniboxViewViewsTest, OnBlur) {
737   // Make the Omnibox very narrow (so it couldn't fit the whole string).
738   int kOmniboxWidth = 60;
739   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
740   render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
741   render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
742 
743   // (In this example, uppercase Latin letters represent Hebrew letters.)
744   // The string |kContentsRtl| is equivalent to:
745   //     RA.QWM/0123/abcd
746   // This is displayed as:
747   //     0123/MWQ.AR/abcd
748   // Enter focused mode, where the text should *not* be elided, and we expect
749   // SetWindowTextAndCaretPos to scroll such that the start of the string is
750   // on-screen. Because the domain is RTL, this scrolls to an offset greater
751   // than 0.
752   omnibox_textfield()->OnFocus();
753   const base::string16 kContentsRtl =
754       base::WideToUTF16(L"\x05e8\x05e2.\x05e7\x05d5\x05dd/0123/abcd");
755   omnibox_view()->SetWindowTextAndCaretPos(kContentsRtl, 0, false, false);
756   EXPECT_EQ(gfx::NO_ELIDE, render_text->elide_behavior());
757 
758   // TODO(https://crbug.com/1094386): this assertion fails because
759   // EmphasizeURLComponents() sets the textfield's directionality to
760   // DIRECTIONALITY_AS_URL. This should be either fixed or the assertion
761   // removed.
762   //
763   // NOTE: Technically (depending on the font), this expectation could fail if
764   // the entire domain fits in 60 pixels. However, 60px is so small it should
765   // never happen with any font.
766   // EXPECT_GT(0, render_text->GetUpdatedDisplayOffset().x());
767 
768   omnibox_view()->SelectAll(false);
769   EXPECT_TRUE(omnibox_view()->IsSelectAll());
770 
771   // Now enter blurred mode, where the text should be elided to 60px. This means
772   // the string itself is truncated. Scrolling would therefore mean the text is
773   // off-screen. Ensure that the horizontal scrolling has been reset to 0.
774   omnibox_textfield()->OnBlur();
775   EXPECT_EQ(gfx::ELIDE_TAIL, render_text->elide_behavior());
776   EXPECT_EQ(0, render_text->GetUpdatedDisplayOffset().x());
777   EXPECT_FALSE(omnibox_view()->IsSelectAll());
778 }
779 
780 // Verifies that https://crbug.com/45260 doesn't regress.
TEST_F(OmniboxViewViewsTest,RendererInitiatedFocusSelectsAllWhenStartingBlurred)781 TEST_F(OmniboxViewViewsTest,
782        RendererInitiatedFocusSelectsAllWhenStartingBlurred) {
783   location_bar_model()->set_url(GURL("about:blank"));
784   omnibox_view()->model()->ResetDisplayTexts();
785   omnibox_view()->RevertAll();
786 
787   // Simulate a renderer-initated focus event. Expect that everything is
788   // selected now.
789   omnibox_view()->SetFocus(/*is_user_initiated=*/false);
790   EXPECT_TRUE(omnibox_view()->IsSelectAll());
791 }
792 
793 // Verifies that https://crbug.com/924935 doesn't regress.
TEST_F(OmniboxViewViewsTest,RendererInitiatedFocusPreservesCursorWhenStartingFocused)794 TEST_F(OmniboxViewViewsTest,
795        RendererInitiatedFocusPreservesCursorWhenStartingFocused) {
796   // Simulate the user focusing the omnibox and typing something. This is just
797   // the test setup, not the actual focus event we are testing.
798   omnibox_view()->SetFocus(/*is_user_initiated*/ true);
799   omnibox_view()->SetTextAndSelectedRanges(base::ASCIIToUTF16("user text"),
800                                            {gfx::Range(9, 9)});
801   ASSERT_FALSE(omnibox_view()->IsSelectAll());
802   ASSERT_TRUE(omnibox_view()->SelectionAtEnd());
803 
804   // Simulate a renderer-initated focus event. Expect the cursor position to be
805   // preserved, and that the omnibox did not select-all the text.
806   omnibox_view()->SetFocus(/*is_user_initiated=*/false);
807   EXPECT_FALSE(omnibox_view()->IsSelectAll());
808   EXPECT_TRUE(omnibox_view()->SelectionAtEnd());
809 }
810 
TEST_F(OmniboxViewViewsTest,Emphasis)811 TEST_F(OmniboxViewViewsTest, Emphasis) {
812   constexpr struct {
813     const char* input;
814     bool expected_base_text_emphasized;
815     Range expected_emphasis_range;
816     Range expected_scheme_range;
817   } test_cases[] = {
818       {"data:text/html,Hello%20World", false, Range(0, 4), Range(0, 4)},
819       {"http://www.example.com/path/file.htm", false, Range(7, 22),
820        Range(0, 4)},
821       {"https://www.example.com/path/file.htm", false, Range(8, 23),
822        Range(0, 5)},
823       {"chrome-extension://ldfbacdbackkjhclmhnjabngnppnkagl", false,
824        Range::InvalidRange(), Range(0, 16)},
825       {"nosuchscheme://opaque/string", true, Range::InvalidRange(),
826        Range(0, 12)},
827       {"nosuchscheme:opaquestring", true, Range::InvalidRange(), Range(0, 12)},
828       {"host.com/path/file", false, Range(0, 8), Range::InvalidRange()},
829       {"This is plain text", true, Range::InvalidRange(),
830        Range::InvalidRange()},
831   };
832 
833   for (const auto& test_case : test_cases) {
834     SCOPED_TRACE(test_case.input);
835 
836     SetAndEmphasizeText(test_case.input, false);
837     EXPECT_EQ(test_case.expected_base_text_emphasized,
838               omnibox_view()->base_text_emphasis());
839     EXPECT_EQ(test_case.expected_emphasis_range,
840               omnibox_view()->emphasis_range());
841     EXPECT_FALSE(omnibox_view()->scheme_range().IsValid());
842 
843     if (test_case.expected_scheme_range.IsValid()) {
844       SetAndEmphasizeText(test_case.input, true);
845       EXPECT_EQ(test_case.expected_base_text_emphasized,
846                 omnibox_view()->base_text_emphasis());
847       EXPECT_EQ(test_case.expected_emphasis_range,
848                 omnibox_view()->emphasis_range());
849       EXPECT_EQ(test_case.expected_scheme_range,
850                 omnibox_view()->scheme_range());
851     }
852   }
853 }
854 
TEST_F(OmniboxViewViewsTest,RevertOnBlur)855 TEST_F(OmniboxViewViewsTest, RevertOnBlur) {
856   location_bar_model()->set_url(GURL("https://example.com/"));
857   omnibox_view()->model()->ResetDisplayTexts();
858   omnibox_view()->RevertAll();
859 
860   EXPECT_EQ(base::ASCIIToUTF16("https://example.com/"),
861             omnibox_view()->GetText());
862   EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
863 
864   // Set the view text without updating the model's user text. This usually
865   // occurs when the omnibox unapplies Steady State Elisions to temporarily show
866   // the full URL to the user.
867   omnibox_view()->SetWindowTextAndCaretPos(base::ASCIIToUTF16("view text"), 0,
868                                            false, false);
869   EXPECT_EQ(base::ASCIIToUTF16("view text"), omnibox_view()->GetText());
870   EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
871 
872   // Expect that on blur, we revert to the original text and are not in user
873   // input mode.
874   omnibox_textfield()->OnBlur();
875   EXPECT_EQ(base::ASCIIToUTF16("https://example.com/"),
876             omnibox_view()->GetText());
877   EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
878 
879   // Now set user text, which is reflected into the model as well.
880   omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
881   EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->GetText());
882   EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
883 
884   // Expect that on blur, if the text has been edited, stay in user input mode.
885   omnibox_textfield()->OnBlur();
886   EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->GetText());
887   EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
888 }
889 
TEST_F(OmniboxViewViewsTest,RevertOnEscape)890 TEST_F(OmniboxViewViewsTest, RevertOnEscape) {
891   location_bar_model()->set_url(GURL("https://permanent-text.com/"));
892   omnibox_view()->model()->ResetDisplayTexts();
893   omnibox_view()->RevertAll();
894 
895   EXPECT_EQ(base::ASCIIToUTF16("https://permanent-text.com/"),
896             omnibox_view()->GetText());
897   EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
898 
899   omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
900   EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->GetText());
901   EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
902 
903   // Expect that on Escape, the text is reverted to the permanent URL.
904   ui::KeyEvent escape(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
905   omnibox_textfield()->OnKeyEvent(&escape);
906 
907   EXPECT_EQ(base::ASCIIToUTF16("https://permanent-text.com/"),
908             omnibox_view()->GetText());
909   EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
910 }
911 
TEST_F(OmniboxViewViewsTest,BackspaceExitsKeywordMode)912 TEST_F(OmniboxViewViewsTest, BackspaceExitsKeywordMode) {
913   omnibox_view()->SetUserText(base::UTF8ToUTF16("user text"));
914   omnibox_view()->model()->EnterKeywordModeForDefaultSearchProvider(
915       OmniboxEventProto::KEYBOARD_SHORTCUT);
916 
917   ASSERT_EQ(base::UTF8ToUTF16("user text"), omnibox_view()->GetText());
918   ASSERT_TRUE(omnibox_view()->IsSelectAll());
919   ASSERT_FALSE(omnibox_view()->model()->keyword().empty());
920 
921   // First backspace should clear the user text but not exit keyword mode.
922   ui::KeyEvent backspace(ui::ET_KEY_PRESSED, ui::VKEY_BACK, 0);
923   omnibox_textfield()->OnKeyEvent(&backspace);
924   EXPECT_TRUE(omnibox_view()->GetText().empty());
925   EXPECT_FALSE(omnibox_view()->model()->keyword().empty());
926 
927   // Second backspace should exit keyword mode.
928   omnibox_textfield()->OnKeyEvent(&backspace);
929   EXPECT_TRUE(omnibox_view()->GetText().empty());
930   EXPECT_TRUE(omnibox_view()->model()->keyword().empty());
931 }
932 
TEST_F(OmniboxViewViewsTest,BlurNeverExitsKeywordMode)933 TEST_F(OmniboxViewViewsTest, BlurNeverExitsKeywordMode) {
934   location_bar_model()->set_url(GURL());
935   omnibox_view()->model()->ResetDisplayTexts();
936   omnibox_view()->RevertAll();
937 
938   // Enter keyword mode, but with no user text.
939   omnibox_view()->model()->EnterKeywordModeForDefaultSearchProvider(
940       OmniboxEventProto::KEYBOARD_SHORTCUT);
941   EXPECT_TRUE(omnibox_view()->GetText().empty());
942   EXPECT_FALSE(omnibox_view()->model()->keyword().empty());
943 
944   // Expect that on blur, stay in keyword mode.
945   omnibox_textfield()->OnBlur();
946   EXPECT_TRUE(omnibox_view()->GetText().empty());
947   EXPECT_FALSE(omnibox_view()->model()->keyword().empty());
948 }
949 
TEST_F(OmniboxViewViewsTest,PasteAndGoToUrlOrSearchCommand)950 TEST_F(OmniboxViewViewsTest, PasteAndGoToUrlOrSearchCommand) {
951   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
952   ui::ClipboardBuffer clipboard_buffer = ui::ClipboardBuffer::kCopyPaste;
953   command_updater()->UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, true);
954 
955   // Test command is disabled for an empty clipboard.
956   clipboard->Clear(clipboard_buffer);
957   EXPECT_FALSE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
958 
959   // Test input that's a valid URL.
960   base::string16 expected_text =
961 #if defined(OS_MAC)
962       base::ASCIIToUTF16("Pa&ste and Go to https://test.com");
963 #else
964       base::ASCIIToUTF16("Pa&ste and go to https://test.com");
965 #endif
966   ui::ScopedClipboardWriter(clipboard_buffer)
967       .WriteText(base::ASCIIToUTF16("https://test.com/"));
968   base::string16 returned_text =
969       omnibox_view()->GetLabelForCommandId(IDC_PASTE_AND_GO);
970   EXPECT_TRUE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
971   EXPECT_EQ(expected_text, returned_text);
972 
973   // Test input that's URL-like. (crbug.com/980002).
974   expected_text =
975 #if defined(OS_MAC)
976       base::ASCIIToUTF16("Pa&ste and Go to test.com");
977 #else
978       base::ASCIIToUTF16("Pa&ste and go to test.com");
979 #endif
980   ui::ScopedClipboardWriter(clipboard_buffer)
981       .WriteText(base::ASCIIToUTF16("test.com"));
982   returned_text = omnibox_view()->GetLabelForCommandId(IDC_PASTE_AND_GO);
983   EXPECT_TRUE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
984   EXPECT_EQ(expected_text, returned_text);
985 
986   // Test input that's search-like.
987   expected_text =
988 #if defined(OS_MAC)
989       base::WideToUTF16(
990           L"Pa&ste and Search for \x201Cthis is a test sentence\x201D");
991 #else
992       base::WideToUTF16(
993           L"Pa&ste and search for \x201Cthis is a test sentence\x201D");
994 #endif
995   ui::ScopedClipboardWriter(clipboard_buffer)
996       .WriteText(base::ASCIIToUTF16("this is a test sentence"));
997   returned_text = omnibox_view()->GetLabelForCommandId(IDC_PASTE_AND_GO);
998   EXPECT_TRUE(omnibox_view()->IsCommandIdEnabled(IDC_PASTE_AND_GO));
999   EXPECT_EQ(expected_text, returned_text);
1000 }
1001 
1002 // Verifies |OmniboxEditModel::State::needs_revert_and_select_all|, and verifies
1003 // a recent regression in this logic (see https://crbug.com/923290).
TEST_F(OmniboxViewViewsTest,SelectAllOnReactivateTabAfterDeleteAll)1004 TEST_F(OmniboxViewViewsTest, SelectAllOnReactivateTabAfterDeleteAll) {
1005   omnibox_edit_controller()->set_omnibox_view(omnibox_view());
1006 
1007   auto web_contents1 =
1008       content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
1009 
1010   // Simulate a new tab with "about:blank".
1011   const GURL url_1("about:blank/");
1012   location_bar_model()->set_url(url_1);
1013   omnibox_view()->model()->ResetDisplayTexts();
1014   omnibox_view()->RevertAll();
1015   omnibox_view()->SaveStateToTab(web_contents1.get());
1016 
1017   // Simulate creating another tab at "chrome://history". The second url should
1018   // be longer than the first (to trigger the bug).
1019   auto web_contents2 =
1020       content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
1021   const GURL url_2("chrome://history/");
1022   EXPECT_GT(url_2.spec().size(), url_1.spec().size());
1023   // Notice the url is set before ResetDisplayTexts(), this matches what
1024   // actually happens in code.
1025   location_bar_model()->set_url(url_2);
1026   omnibox_view()->model()->ResetDisplayTexts();
1027   omnibox_view()->RevertAll();
1028 
1029   // Delete all the text.
1030   omnibox_view()->SetUserText(base::string16());
1031   EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
1032 
1033   // Switch back to the first url.
1034   location_bar_model()->set_url(url_1);
1035   omnibox_view()->SaveStateToTab(web_contents2.get());
1036   omnibox_view()->OnTabChanged(web_contents1.get());
1037 
1038   // Switch back to the second url. Even though the text was deleted earlier,
1039   // the previous text (|url_2|) should be restored *and* all the text selected.
1040   location_bar_model()->set_url(url_2);
1041   omnibox_view()->SaveStateToTab(web_contents1.get());
1042   omnibox_view()->OnTabChanged(web_contents2.get());
1043   EXPECT_EQ(url_2, GURL(base::UTF16ToUTF8(omnibox_view()->GetText())));
1044   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1045 }
1046 
TEST_F(OmniboxViewViewsTest,SelectAllDuringMouseDown)1047 TEST_F(OmniboxViewViewsTest, SelectAllDuringMouseDown) {
1048   omnibox_textfield()->OnMousePressed(
1049       CreateMouseEvent(ui::ET_MOUSE_PRESSED, {0, 0}));
1050   omnibox_view()->SetUserText(base::ASCIIToUTF16("abc"));
1051   ui::KeyEvent event_a(ui::ET_KEY_PRESSED, ui::VKEY_A, 0);
1052   EXPECT_FALSE(omnibox_view()->IsSelectAll());
1053   omnibox_textfield_view()->OnKeyPressed(event_a);
1054   // Normally SelectAll happens after OnMouseRelease. Verifying this happens
1055   // during OnKeyPress when the mouse is down.
1056   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1057 }
1058 
TEST_F(OmniboxViewViewsTest,SetWindowTextAndCaretPos)1059 TEST_F(OmniboxViewViewsTest, SetWindowTextAndCaretPos) {
1060   // googl|e.com
1061   omnibox_view()->SetWindowTextAndCaretPos(base::UTF8ToUTF16("google.com"), 5,
1062                                            false, false);
1063   EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
1064   EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1065             (std::vector<Range>{{5, 5}}));
1066 }
1067 
TEST_F(OmniboxViewViewsTest,OnInlineAutocompleteTextMaybeChanged)1068 TEST_F(OmniboxViewViewsTest, OnInlineAutocompleteTextMaybeChanged) {
1069   // No selection, google.com|
1070   omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1071       base::UTF8ToUTF16("google.com"), {{10, 10}}, 10);
1072   EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
1073   EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1074             (std::vector<Range>{{10, 10}}));
1075 
1076   // Single selection, gmai[l.com]
1077   omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1078       base::UTF8ToUTF16("gmail.com"), {{9, 4}}, 4);
1079   EXPECT_EQ(base::ASCIIToUTF16("gmail.com"), omnibox_view()->GetText());
1080   EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1081             (std::vector<Range>{{9, 4}}));
1082 
1083   // Multiselection, [go]ogl[e.com]
1084   omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1085       base::UTF8ToUTF16("google.com"), {{10, 5}, {0, 2}}, 3);
1086   EXPECT_EQ(base::ASCIIToUTF16("google.com"), omnibox_view()->GetText());
1087   EXPECT_EQ(omnibox_view()->GetRenderText()->GetAllSelections(),
1088             (std::vector<Range>{{10, 5}, {0, 2}}));
1089 }
1090 
TEST_F(OmniboxViewViewsTest,OverflowingAutocompleteText)1091 TEST_F(OmniboxViewViewsTest, OverflowingAutocompleteText) {
1092   // Make the Omnibox narrow so it can't fit the entire string (~650px), but
1093   // wide enough to fit the user text (~65px).
1094   int kOmniboxWidth = 100;
1095   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1096   render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
1097 
1098   omnibox_textfield()->OnFocus();
1099   omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
1100       base::ASCIIToUTF16("user text. Followed by very long autocompleted text "
1101                          "that is unlikely to fit in |kOmniboxWidth|"),
1102       {{94, 10}}, 10);
1103 
1104   // NOTE: Technically (depending on the font), this expectation could fail if
1105   // 'user text' doesn't fit in 100px or the entire string fits in 100px.
1106   EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
1107   EXPECT_FALSE(omnibox_view()->IsSelectAll());
1108 
1109   // On blur, the display should remain to the start of the text.
1110   omnibox_textfield()->OnBlur();
1111   EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
1112   EXPECT_FALSE(omnibox_view()->IsSelectAll());
1113 }
1114 
TEST_F(OmniboxViewViewsTest,ElideAnimationDoesntStartIfNoVisibleChange)1115 TEST_F(OmniboxViewViewsTest, ElideAnimationDoesntStartIfNoVisibleChange) {
1116   SetUpSimplifiedDomainTest();
1117   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1118   OmniboxViewViews::ElideAnimation elide_animation(omnibox_view(), render_text);
1119   // Before any animation runs, the elide from rectangle is considered to be
1120   // render_text's DisplayRect, so set it manually to be the current URL length.
1121   gfx::Rect full_url_bounds;
1122   for (auto rect : render_text->GetSubstringBounds(
1123            gfx::Range(0, omnibox_view()->GetOmniboxTextLength()))) {
1124     full_url_bounds.Union(rect);
1125   }
1126   render_text->SetDisplayRect(full_url_bounds);
1127   // Start the animation, and have it animate to the current state.
1128   elide_animation.Start(
1129       gfx::Range(0,
1130                  omnibox_view()->GetOmniboxTextLength()), /* elide_to_bounds */
1131       0,                                                  /* delay_ms */
1132       {gfx::Range(0, 0)}, /* ranges_surrounding_simplified_domain */
1133       SK_ColorBLACK,      /* starting_color */
1134       SK_ColorBLACK);     /* ending_color */
1135   // Animation shouldn't have been started.
1136   EXPECT_FALSE(elide_animation.IsAnimating());
1137 }
1138 
1139 class OmniboxViewViewsClipboardTest
1140     : public OmniboxViewViewsTest,
1141       public ::testing::WithParamInterface<ui::TextEditCommand> {
1142  public:
SetUp()1143   void SetUp() override {
1144     OmniboxViewViewsTest::SetUp();
1145 
1146     location_bar_model()->set_url(GURL("https://test.com/"));
1147     omnibox_view()->model()->ResetDisplayTexts();
1148     omnibox_view()->RevertAll();
1149   }
1150 };
1151 
TEST_P(OmniboxViewViewsClipboardTest,ClipboardCopyOrCutURL)1152 TEST_P(OmniboxViewViewsClipboardTest, ClipboardCopyOrCutURL) {
1153   omnibox_view()->SelectAll(false);
1154   ASSERT_TRUE(omnibox_view()->IsSelectAll());
1155 
1156   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1157   ui::ClipboardBuffer clipboard_buffer = ui::ClipboardBuffer::kCopyPaste;
1158 
1159   clipboard->Clear(clipboard_buffer);
1160   ui::TextEditCommand clipboard_command = GetParam();
1161   textfield_test_api()->ExecuteTextEditCommand(clipboard_command);
1162 
1163   base::string16 expected_text;
1164   if (clipboard_command == ui::TextEditCommand::COPY)
1165     expected_text = base::ASCIIToUTF16("https://test.com/");
1166   EXPECT_EQ(expected_text, omnibox_view()->GetText());
1167 
1168   // Make sure the plain text format is available, but the HTML one isn't.
1169   EXPECT_TRUE(
1170       clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(),
1171                                    clipboard_buffer, /* data_dst = */ nullptr));
1172   EXPECT_FALSE(
1173       clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(),
1174                                    clipboard_buffer, /* data_dst = */ nullptr));
1175 
1176   // Windows clipboard only supports text URLs.
1177   // Mac clipboard not reporting URL format available for some reason.
1178   // crbug.com/751031
1179 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
1180   EXPECT_TRUE(
1181       clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetUrlType(),
1182                                    clipboard_buffer, /* data_dst = */ nullptr));
1183 #endif
1184 
1185   std::string read_from_clipboard;
1186   clipboard->ReadAsciiText(clipboard_buffer, /* data_dst = */ nullptr,
1187                            &read_from_clipboard);
1188   EXPECT_EQ("https://test.com/", read_from_clipboard);
1189 }
1190 
TEST_P(OmniboxViewViewsClipboardTest,ClipboardCopyOrCutUserText)1191 TEST_P(OmniboxViewViewsClipboardTest, ClipboardCopyOrCutUserText) {
1192   omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
1193   omnibox_view()->SelectAll(false);
1194   ASSERT_TRUE(omnibox_view()->IsSelectAll());
1195 
1196   ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1197   ui::ClipboardBuffer clipboard_buffer = ui::ClipboardBuffer::kCopyPaste;
1198 
1199   clipboard->Clear(clipboard_buffer);
1200   ui::TextEditCommand clipboard_command = GetParam();
1201   textfield_test_api()->ExecuteTextEditCommand(clipboard_command);
1202 
1203   if (clipboard_command == ui::TextEditCommand::CUT)
1204     EXPECT_EQ(base::string16(), omnibox_view()->GetText());
1205 
1206   // Make sure HTML format isn't written. See
1207   // BookmarkNodeData::WriteToClipboard() for details.
1208   EXPECT_TRUE(
1209       clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(),
1210                                    clipboard_buffer, /* data_dst = */ nullptr));
1211   EXPECT_FALSE(
1212       clipboard->IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(),
1213                                    clipboard_buffer, /* data_dst = */ nullptr));
1214 
1215   std::string read_from_clipboard;
1216   clipboard->ReadAsciiText(clipboard_buffer, /* data_dst = */ nullptr,
1217                            &read_from_clipboard);
1218   EXPECT_EQ("user text", read_from_clipboard);
1219 }
1220 
1221 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsClipboardTest,
1222                          OmniboxViewViewsClipboardTest,
1223                          ::testing::Values(ui::TextEditCommand::COPY,
1224                                            ui::TextEditCommand::CUT));
1225 
1226 class OmniboxViewViewsSteadyStateElisionsTest : public OmniboxViewViewsTest {
1227  public:
OmniboxViewViewsSteadyStateElisionsTest()1228   OmniboxViewViewsSteadyStateElisionsTest() : OmniboxViewViewsTest({}, {}) {}
1229 
1230  protected:
1231   const int kCharacterWidth = 10;
1232   const GURL kFullUrl = GURL("https://www.example.com/");
1233 
SetUp()1234   void SetUp() override {
1235     OmniboxViewViewsTest::SetUp();
1236 
1237     // Advance 5 seconds from epoch so the time is not considered null.
1238     clock_.Advance(base::TimeDelta::FromSeconds(5));
1239     ui::SetEventTickClockForTesting(&clock_);
1240 
1241     location_bar_model()->set_url(kFullUrl);
1242     location_bar_model()->set_url_for_display(
1243         base::ASCIIToUTF16("example.com"));
1244 
1245     gfx::test::RenderTextTestApi render_text_test_api(
1246         omnibox_view()->GetRenderText());
1247     render_text_test_api.SetGlyphWidth(kCharacterWidth);
1248 
1249     omnibox_view()->model()->ResetDisplayTexts();
1250     omnibox_view()->RevertAll();
1251   }
1252 
TearDown()1253   void TearDown() override {
1254     ui::SetEventTickClockForTesting(nullptr);
1255     OmniboxViewViewsTest::TearDown();
1256   }
1257 
BlurOmnibox()1258   void BlurOmnibox() {
1259     ASSERT_TRUE(omnibox_view()->HasFocus());
1260     omnibox_view()->GetFocusManager()->ClearFocus();
1261     ASSERT_FALSE(omnibox_view()->HasFocus());
1262   }
1263 
ExpectFullUrlDisplayed()1264   void ExpectFullUrlDisplayed() {
1265     EXPECT_EQ(base::UTF8ToUTF16(kFullUrl.spec()), omnibox_view()->GetText());
1266     EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
1267   }
1268 
IsElidedUrlDisplayed()1269   bool IsElidedUrlDisplayed() {
1270     return omnibox_view()->GetText() == base::ASCIIToUTF16("example.com") &&
1271            !omnibox_view()->model()->user_input_in_progress();
1272   }
1273 
1274   // Gets a point at |x_offset| from the beginning of the RenderText.
GetPointInTextAtXOffset(int x_offset)1275   gfx::Point GetPointInTextAtXOffset(int x_offset) {
1276     gfx::Rect bounds = omnibox_view()->GetRenderText()->display_rect();
1277     return gfx::Point(bounds.x() + x_offset, bounds.y() + bounds.height() / 2);
1278   }
1279 
1280   // Sends a mouse down and mouse up event at |x_offset| pixels from the
1281   // beginning of the RenderText.
SendMouseClick(int x_offset)1282   void SendMouseClick(int x_offset) {
1283     gfx::Point point = GetPointInTextAtXOffset(x_offset);
1284     SendMouseClickAtPoint(point, 1);
1285   }
1286 
1287   // Sends a mouse down and mouse up event at a point
1288   // beginning of the RenderText.
SendMouseClickAtPoint(gfx::Point point,int click_count,int event_flags=ui::EF_LEFT_MOUSE_BUTTON)1289   void SendMouseClickAtPoint(gfx::Point point,
1290                              int click_count,
1291                              int event_flags = ui::EF_LEFT_MOUSE_BUTTON) {
1292     auto mouse_pressed =
1293         CreateMouseEvent(ui::ET_MOUSE_PRESSED, point, event_flags);
1294     mouse_pressed.SetClickCount(click_count);
1295     omnibox_textfield()->OnMousePressed(mouse_pressed);
1296     auto mouse_released =
1297         CreateMouseEvent(ui::ET_MOUSE_RELEASED, point, event_flags);
1298     mouse_released.SetClickCount(click_count);
1299     omnibox_textfield()->OnMouseReleased(mouse_released);
1300   }
1301 
1302   // Used to access members that are marked private in views::TextField.
clock()1303   base::SimpleTestTickClock* clock() { return &clock_; }
1304 
1305  private:
1306   base::SimpleTestTickClock clock_;
1307 };
1308 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UrlStartsInElidedState)1309 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UrlStartsInElidedState) {
1310   EXPECT_TRUE(IsElidedUrlDisplayed());
1311 }
1312 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideOnArrowKey)1313 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideOnArrowKey) {
1314   SendMouseClick(0);
1315 
1316   // Right key should unelide and move the cursor to the end.
1317   omnibox_textfield_view()->OnKeyPressed(
1318       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, 0));
1319   ExpectFullUrlDisplayed();
1320   size_t start, end;
1321   omnibox_view()->GetSelectionBounds(&start, &end);
1322   EXPECT_EQ(23U, start);
1323   EXPECT_EQ(23U, end);
1324 
1325   // Blur to restore the elided URL, then click on the Omnibox again to refocus.
1326   BlurOmnibox();
1327   SendMouseClick(0);
1328 
1329   // Left key should unelide and move the cursor to the beginning of the elided
1330   // part.
1331   omnibox_textfield_view()->OnKeyPressed(
1332       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LEFT, 0));
1333   ExpectFullUrlDisplayed();
1334   omnibox_view()->GetSelectionBounds(&start, &end);
1335   EXPECT_EQ(12U, start);
1336   EXPECT_EQ(12U, end);
1337 }
1338 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideOnHomeKey)1339 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideOnHomeKey) {
1340   SendMouseClick(0);
1341 
1342   // Home key should unelide and move the cursor to the beginning of the full
1343   // unelided URL.
1344   omnibox_textfield_view()->OnKeyPressed(
1345       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_HOME, 0));
1346   ExpectFullUrlDisplayed();
1347   size_t start, end;
1348   omnibox_view()->GetSelectionBounds(&start, &end);
1349   EXPECT_EQ(0U, start);
1350   EXPECT_EQ(0U, end);
1351 }
1352 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideViaEndKeyWorksWithIntranetUrls)1353 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1354        UnelideViaEndKeyWorksWithIntranetUrls) {
1355   location_bar_model()->set_url(GURL("https://foobar/"));
1356   location_bar_model()->set_formatted_full_url(
1357       base::ASCIIToUTF16("https://foobar"));
1358   location_bar_model()->set_url_for_display(base::ASCIIToUTF16("foobar/"));
1359 
1360   omnibox_view()->model()->ResetDisplayTexts();
1361   omnibox_view()->RevertAll();
1362 
1363   SendMouseClick(0);
1364 
1365   // End key should unelide and move the cursor to the end of the full URL.
1366   omnibox_textfield_view()->OnKeyPressed(
1367       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_END, 0));
1368 
1369   EXPECT_EQ(base::ASCIIToUTF16("https://foobar"), omnibox_view()->GetText());
1370   EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
1371 
1372   size_t start, end;
1373   omnibox_view()->GetSelectionBounds(&start, &end);
1374   EXPECT_EQ(14U, start);
1375   EXPECT_EQ(14U, end);
1376 }
1377 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,GestureTaps)1378 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, GestureTaps) {
1379   ui::GestureEvent tap_down(0, 0, 0, ui::EventTimeForNow(),
1380                             ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
1381   omnibox_textfield()->OnGestureEvent(&tap_down);
1382 
1383   // Select all on first tap.
1384   ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
1385   tap_details.set_tap_count(1);
1386   ui::GestureEvent tap(0, 0, 0, ui::EventTimeForNow(), tap_details);
1387   omnibox_textfield()->OnGestureEvent(&tap);
1388 
1389   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1390   EXPECT_TRUE(IsElidedUrlDisplayed());
1391 
1392   // Unelide on second tap (cursor placement).
1393   omnibox_textfield()->OnGestureEvent(&tap);
1394   ExpectFullUrlDisplayed();
1395 }
1396 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,FirstMouseClickFocusesOnly)1397 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, FirstMouseClickFocusesOnly) {
1398   EXPECT_FALSE(omnibox_view()->IsSelectAll());
1399 
1400   SendMouseClick(0);
1401 
1402   EXPECT_TRUE(IsElidedUrlDisplayed());
1403   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1404   EXPECT_TRUE(omnibox_view()->HasFocus());
1405 }
1406 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,NegligibleDragKeepsElisions)1407 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, NegligibleDragKeepsElisions) {
1408   gfx::Point click_point = GetPointInTextAtXOffset(2 * kCharacterWidth);
1409   omnibox_textfield()->OnMousePressed(
1410       CreateMouseEvent(ui::ET_MOUSE_PRESSED, click_point));
1411 
1412   // Offset the drag and release point by an insignificant 2 px.
1413   gfx::Point drag_point = click_point;
1414   drag_point.Offset(2, 0);
1415   omnibox_textfield()->OnMouseDragged(
1416       CreateMouseEvent(ui::ET_MOUSE_DRAGGED, drag_point));
1417   omnibox_textfield()->OnMouseReleased(
1418       CreateMouseEvent(ui::ET_MOUSE_RELEASED, drag_point));
1419 
1420   // Expect that after a negligible drag and release, everything is selected.
1421   EXPECT_TRUE(IsElidedUrlDisplayed());
1422   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1423   EXPECT_TRUE(omnibox_view()->HasFocus());
1424 }
1425 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,CaretPlacementByMouse)1426 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, CaretPlacementByMouse) {
1427   SendMouseClick(0);
1428 
1429   // Advance the clock 5 seconds so the second click is not interpreted as a
1430   // double click.
1431   clock()->Advance(base::TimeDelta::FromSeconds(5));
1432 
1433   // Second click should unelide only on mouse release.
1434   omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1435       ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1436   EXPECT_TRUE(IsElidedUrlDisplayed());
1437   omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1438       ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1439   ExpectFullUrlDisplayed();
1440 
1441   // Verify the cursor position is https://www.ex|ample.com. It should be
1442   // between 'x' and 'a', because the click was after the second character of
1443   // the unelided text "example.com".
1444   size_t start, end;
1445   omnibox_view()->GetSelectionBounds(&start, &end);
1446   EXPECT_EQ(14U, start);
1447   EXPECT_EQ(14U, end);
1448 }
1449 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseDoubleClick)1450 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseDoubleClick) {
1451   SendMouseClick(4 * kCharacterWidth);
1452 
1453   // Second click without advancing the clock should be a double-click, which
1454   // should do a single word selection and unelide the text on mousedown.
1455   omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1456       ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1457   ExpectFullUrlDisplayed();
1458 
1459   // Verify that the selection is https://www.|example|.com, since the
1460   // double-click after the fourth character of the unelided text "example.com".
1461   size_t start, end;
1462   omnibox_view()->GetSelectionBounds(&start, &end);
1463   EXPECT_EQ(12U, start);
1464   EXPECT_EQ(19U, end);
1465 }
1466 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseSingleThenDoubleClick)1467 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseSingleThenDoubleClick) {
1468   EXPECT_TRUE(IsElidedUrlDisplayed());
1469   auto point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1470   SendMouseClickAtPoint(point, 1);
1471   EXPECT_TRUE(IsElidedUrlDisplayed());
1472   EXPECT_EQ(base::ASCIIToUTF16("example.com"), omnibox_view()->GetText());
1473 
1474   // Verify that the whole full URL is selected.
1475   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1476 
1477   // Advance the clock 5 seconds so the next click is not interpreted as a
1478   // double click.
1479   clock()->Advance(base::TimeDelta::FromSeconds(5));
1480 
1481   // Double click
1482   SendMouseClickAtPoint(point, 1);
1483   ExpectFullUrlDisplayed();
1484   SendMouseClickAtPoint(point, 2);
1485   ExpectFullUrlDisplayed();
1486 
1487   // Verify that the selection is https://www.|example|.com, since the
1488   // double-click after the fourth character of the unelided text "example.com".
1489   size_t start, end;
1490   omnibox_view()->GetSelectionBounds(&start, &end);
1491   EXPECT_EQ(12U, start);
1492   EXPECT_EQ(19U, end);
1493 }
1494 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseSingleThenRightClick)1495 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseSingleThenRightClick) {
1496   EXPECT_TRUE(IsElidedUrlDisplayed());
1497   auto point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1498   SendMouseClickAtPoint(point, 1);
1499   EXPECT_TRUE(IsElidedUrlDisplayed());
1500   EXPECT_EQ(base::ASCIIToUTF16("example.com"), omnibox_view()->GetText());
1501 
1502   // Verify that the whole full URL is selected.
1503   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1504 
1505   // Advance the clock 5 seconds so the next click is not interpreted as a
1506   // double click.
1507   clock()->Advance(base::TimeDelta::FromSeconds(5));
1508 
1509   // Right click
1510   SendMouseClickAtPoint(point, 1, ui::EF_RIGHT_MOUSE_BUTTON);
1511   EXPECT_TRUE(IsElidedUrlDisplayed());
1512   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1513   EXPECT_TRUE(omnibox_view()->HasFocus());
1514 }
1515 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseTripleClick)1516 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseTripleClick) {
1517   auto point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1518   SendMouseClickAtPoint(point, 1);
1519   SendMouseClickAtPoint(point, 2);
1520   SendMouseClickAtPoint(point, 3);
1521 
1522   ExpectFullUrlDisplayed();
1523 
1524   // Verify that the whole full URL is selected.
1525   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1526   size_t start, end;
1527   omnibox_view()->GetSelectionBounds(&start, &end);
1528   EXPECT_EQ(0U, start);
1529   EXPECT_EQ(24U, end);
1530 }
1531 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseClickDrag)1532 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseClickDrag) {
1533   omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1534       ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1535   EXPECT_TRUE(IsElidedUrlDisplayed());
1536 
1537   // Expect that during the drag, the URL is still elided.
1538   omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1539       ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1540   EXPECT_TRUE(IsElidedUrlDisplayed());
1541 
1542   // Expect that ex|am|ple.com is the drag selected portion while dragging.
1543   size_t start, end;
1544   omnibox_view()->GetSelectionBounds(&start, &end);
1545   EXPECT_EQ(2U, start);
1546   EXPECT_EQ(4U, end);
1547 
1548   omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1549       ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1550   ExpectFullUrlDisplayed();
1551 
1552   // Expect that https://www.ex|am|ple.com is the selected portion after the
1553   // user releases the mouse.
1554   omnibox_view()->GetSelectionBounds(&start, &end);
1555   EXPECT_EQ(14U, start);
1556   EXPECT_EQ(16U, end);
1557 }
1558 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseClickDragToBeginningSelectingText)1559 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1560        MouseClickDragToBeginningSelectingText) {
1561   // Backwards drag-select this portion of the elided URL: |exam|ple.com
1562   omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1563       ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1564   omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1565       ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1566   omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1567       ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1568   ExpectFullUrlDisplayed();
1569 
1570   // Since the selection did not look like a URL, expect the following selected
1571   // selected portion after the user releases the mouse:
1572   // https://www.|exam|ple.com
1573   size_t start, end;
1574   omnibox_view()->GetSelectionBounds(&start, &end);
1575   EXPECT_EQ(16U, start);
1576   EXPECT_EQ(12U, end);
1577 }
1578 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseClickDragToBeginningSelectingURL)1579 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1580        MouseClickDragToBeginningSelectingURL) {
1581   // Backwards drag-select this portion of the elided URL: |example.co|m
1582   omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1583       ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(10 * kCharacterWidth)));
1584   omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1585       ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1586   omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1587       ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(0 * kCharacterWidth)));
1588   ExpectFullUrlDisplayed();
1589 
1590   // Since the selection does look like a URL, expect the following selected
1591   // selected portion after the user releases the mouse:
1592   // |https://www.example.co|m
1593   size_t start, end;
1594   omnibox_view()->GetSelectionBounds(&start, &end);
1595   EXPECT_EQ(22U, start);
1596   EXPECT_EQ(0U, end);
1597 }
1598 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,MouseDoubleClickDrag)1599 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, MouseDoubleClickDrag) {
1600   // Expect that after a double-click after the third character of the elided
1601   // text, the text is unelided, and https://www.|example|.com is selected.
1602   SendMouseClick(4 * kCharacterWidth);
1603   omnibox_textfield()->OnMousePressed(CreateMouseEvent(
1604       ui::ET_MOUSE_PRESSED, GetPointInTextAtXOffset(4 * kCharacterWidth)));
1605   ExpectFullUrlDisplayed();
1606   size_t start, end;
1607   omnibox_view()->GetSelectionBounds(&start, &end);
1608   EXPECT_EQ(12U, start);
1609   EXPECT_EQ(19U, end);
1610 
1611   // Expect that negligible drags are ignored immediately after unelision, as
1612   // the text has likely shifted, and we don't want to accidentally change the
1613   // selection.
1614   gfx::Point drag_point = GetPointInTextAtXOffset(4 * kCharacterWidth);
1615   drag_point.Offset(1, 1);  // Offset test point one pixel in each dimension.
1616   omnibox_textfield()->OnMouseDragged(
1617       CreateMouseEvent(ui::ET_MOUSE_DRAGGED, drag_point));
1618   omnibox_view()->GetSelectionBounds(&start, &end);
1619   EXPECT_EQ(12U, start);
1620   EXPECT_EQ(19U, end);
1621 
1622   // Expect that dragging to the fourth character of the full URL (between the
1623   // the 'p' and the 's' of https), will word-select the scheme, subdomain, and
1624   // domain, so the new selection will be |https://www.example|.com. The
1625   // expected selection is backwards, since we are dragging the mouse from the
1626   // domain to the scheme.
1627   omnibox_textfield()->OnMouseDragged(CreateMouseEvent(
1628       ui::ET_MOUSE_DRAGGED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1629   ExpectFullUrlDisplayed();
1630   omnibox_view()->GetSelectionBounds(&start, &end);
1631   EXPECT_EQ(19U, start);
1632   EXPECT_EQ(0U, end);
1633 
1634   // Expect the selection to stay the same after mouse-release.
1635   omnibox_textfield()->OnMouseReleased(CreateMouseEvent(
1636       ui::ET_MOUSE_RELEASED, GetPointInTextAtXOffset(2 * kCharacterWidth)));
1637   ExpectFullUrlDisplayed();
1638   omnibox_view()->GetSelectionBounds(&start, &end);
1639   EXPECT_EQ(19U, start);
1640   EXPECT_EQ(0U, end);
1641 }
1642 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,ReelideOnBlur)1643 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, ReelideOnBlur) {
1644   // Double-click should unelide the URL by making a partial selection.
1645   SendMouseClick(4 * kCharacterWidth);
1646   SendMouseClick(4 * kCharacterWidth);
1647   ExpectFullUrlDisplayed();
1648 
1649   BlurOmnibox();
1650   EXPECT_TRUE(IsElidedUrlDisplayed());
1651 }
1652 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,DontReelideOnBlurIfEdited)1653 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, DontReelideOnBlurIfEdited) {
1654   // Double-click should unelide the URL by making a partial selection.
1655   SendMouseClick(4 * kCharacterWidth);
1656   SendMouseClick(4 * kCharacterWidth);
1657   ExpectFullUrlDisplayed();
1658 
1659   // Since the domain word is selected, pressing 'a' should replace the domain.
1660   ui::KeyEvent char_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::DomCode::US_A, 0,
1661                           ui::DomKey::FromCharacter('a'),
1662                           ui::EventTimeForNow());
1663   omnibox_textfield()->InsertChar(char_event);
1664   EXPECT_EQ(base::ASCIIToUTF16("https://www.a.com/"),
1665             omnibox_view()->GetText());
1666   EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
1667 
1668   // Now that we've edited the text, blurring should not re-elide the URL.
1669   BlurOmnibox();
1670   EXPECT_EQ(base::ASCIIToUTF16("https://www.a.com/"),
1671             omnibox_view()->GetText());
1672   EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
1673 }
1674 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,DontReelideOnBlurIfWidgetDeactivated)1675 TEST_F(OmniboxViewViewsSteadyStateElisionsTest,
1676        DontReelideOnBlurIfWidgetDeactivated) {
1677   SendMouseClick(0);
1678   SendMouseClick(0);
1679   ExpectFullUrlDisplayed();
1680 
1681   // Create a different Widget that will take focus away from the test widget
1682   // containing our test Omnibox.
1683   std::unique_ptr<views::Widget> other_widget = CreateTestWidget();
1684   other_widget->Show();
1685   ExpectFullUrlDisplayed();
1686 
1687   omnibox_view()->GetWidget()->Activate();
1688   ExpectFullUrlDisplayed();
1689 }
1690 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,SaveSelectAllOnBlurAndRefocus)1691 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, SaveSelectAllOnBlurAndRefocus) {
1692   SendMouseClick(0);
1693   EXPECT_TRUE(IsElidedUrlDisplayed());
1694   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1695 
1696   // Blurring and refocusing should preserve a select-all state.
1697   BlurOmnibox();
1698   omnibox_view()->RequestFocus();
1699   EXPECT_TRUE(omnibox_view()->HasFocus());
1700   EXPECT_TRUE(IsElidedUrlDisplayed());
1701   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1702 }
1703 
TEST_F(OmniboxViewViewsSteadyStateElisionsTest,UnelideFromModel)1704 TEST_F(OmniboxViewViewsSteadyStateElisionsTest, UnelideFromModel) {
1705   EXPECT_TRUE(IsElidedUrlDisplayed());
1706 
1707   omnibox_view()->model()->Unelide();
1708   EXPECT_TRUE(omnibox_view()->IsSelectAll());
1709   size_t start, end;
1710   omnibox_view()->GetSelectionBounds(&start, &end);
1711   EXPECT_EQ(24U, start);
1712   EXPECT_EQ(0U, end);
1713   ExpectFullUrlDisplayed();
1714 }
1715 
1716 // Returns true if |render_text|'s current display rect and offset display at
1717 // least part of |path_bounds|, but not the full |display_url|. This is useful
1718 // for checking the displayed text partway through an animation.
IsPartlyThroughSimplifiedDomainElision(gfx::RenderText * render_text,const base::string16 & display_url,const gfx::Range & path_bounds)1719 bool IsPartlyThroughSimplifiedDomainElision(gfx::RenderText* render_text,
1720                                             const base::string16& display_url,
1721                                             const gfx::Range& path_bounds) {
1722   // First check if all of |display_url| is showing; if it is, we aren't partly
1723   // elided.
1724   gfx::Rect unelided_rect;
1725   for (const auto& rect :
1726        render_text->GetSubstringBounds(gfx::Range(0, display_url.size()))) {
1727     unelided_rect.Union(rect);
1728   }
1729   if (render_text->display_rect().Contains(unelided_rect) &&
1730       render_text->GetUpdatedDisplayOffset().x() == 0) {
1731     return false;
1732   }
1733   // Now check if at least some of |path| is visible.
1734   gfx::Rect path_rect;
1735   for (const auto& rect : render_text->GetSubstringBounds(path_bounds)) {
1736     path_rect.Union(rect);
1737   }
1738   return render_text->display_rect().Intersects(path_rect);
1739 }
1740 
1741 class OmniboxViewViewsNoSimplifiedDomainTest : public OmniboxViewViewsTest {
1742  public:
OmniboxViewViewsNoSimplifiedDomainTest()1743   OmniboxViewViewsNoSimplifiedDomainTest()
1744       : OmniboxViewViewsTest(
1745             {},
1746             {omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction,
1747              omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover}) {}
1748 
1749   OmniboxViewViewsNoSimplifiedDomainTest(
1750       const OmniboxViewViewsNoSimplifiedDomainTest&) = delete;
1751   OmniboxViewViewsNoSimplifiedDomainTest& operator=(
1752       const OmniboxViewViewsNoSimplifiedDomainTest&) = delete;
1753 };
1754 
1755 // Tests that when no simplified domain field trials are enabled, URL components
1756 // are not hidden. Regression test for https://crbug.com/1093748.
TEST_F(OmniboxViewViewsNoSimplifiedDomainTest,UrlNotSimplifiedByDefault)1757 TEST_F(OmniboxViewViewsNoSimplifiedDomainTest, UrlNotSimplifiedByDefault) {
1758   SetUpSimplifiedDomainTest();
1759   omnibox_view()->EmphasizeURLComponents();
1760   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
1761       omnibox_view()->GetRenderText(),
1762       gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
1763 }
1764 
1765 class OmniboxViewViewsRevealOnHoverTest
1766     : public OmniboxViewViewsTest,
1767       public ::testing::WithParamInterface<std::pair<bool, bool>> {
1768  public:
OmniboxViewViewsRevealOnHoverTest()1769   OmniboxViewViewsRevealOnHoverTest()
1770       : OmniboxViewViewsTest(
1771             GetParam().first
1772                 ? std::vector<FeatureAndParams>(
1773                       {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
1774                         {}},
1775                        {omnibox::kMaybeElideToRegistrableDomain,
1776                         // Ensure all domains are elidable by policy.
1777                         {{"max_unelided_host_length", "0"}}}})
1778                 : std::vector<FeatureAndParams>(
1779                       {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
1780                         {}}}),
1781             {},
1782             GetParam().second) {
1783     // The lookalike allowlist is used by the registrable-domain-elision code.
1784     reputation::InitializeBlankLookalikeAllowlistForTesting();
1785   }
1786 
1787   OmniboxViewViewsRevealOnHoverTest(const OmniboxViewViewsRevealOnHoverTest&) =
1788       delete;
1789   OmniboxViewViewsRevealOnHoverTest& operator=(
1790       const OmniboxViewViewsRevealOnHoverTest&) = delete;
1791 
1792  protected:
ShouldElideToRegistrableDomain()1793   bool ShouldElideToRegistrableDomain() { return GetParam().first; }
1794 };
1795 
1796 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsRevealOnHoverTest,
1797                          OmniboxViewViewsRevealOnHoverTest,
1798                          ::testing::ValuesIn({std::make_pair(true, false),
1799                                               std::make_pair(false, false),
1800                                               std::make_pair(true, true),
1801                                               std::make_pair(false, true)}));
1802 
1803 // Tests the field trial variation that shows a simplified domain by default and
1804 // reveals the unsimplified URL on hover.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverAndExit)1805 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExit) {
1806   SetUpSimplifiedDomainTest();
1807   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1808   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1809       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
1810       kSimplifiedDomainDisplayUrlSubdomain,
1811       kSimplifiedDomainDisplayUrlHostnameAndScheme,
1812       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
1813 
1814   // As soon as the mouse hovers over the omnibox, the unelide animation should
1815   // start running.
1816   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
1817   OmniboxViewViews::ElideAnimation* hover_animation =
1818       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
1819   ASSERT_TRUE(hover_animation);
1820   EXPECT_TRUE(hover_animation->IsAnimating());
1821 
1822   // Advance the clock through the animation.
1823   ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation(
1824       OmniboxFieldTrial::UnelideURLOnHoverThresholdMs()));
1825   // After the extended hover threshold has elapsed, the display text shouldn't
1826   // have changed yet.
1827   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1828       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
1829       kSimplifiedDomainDisplayUrlSubdomain,
1830       kSimplifiedDomainDisplayUrlHostnameAndScheme,
1831       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
1832 
1833   // Now advance through the unelision and check the display text. We assume
1834   // that the animation takes less than 1 second.
1835   ASSERT_NO_FATAL_FAILURE(
1836       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1837   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
1838       render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
1839   EXPECT_FALSE(hover_animation->IsAnimating());
1840   // Check that the path and subdomain are not transparent.
1841   EXPECT_NE(SK_ColorTRANSPARENT,
1842             omnibox_view()->GetLatestColorForRange(
1843                 gfx::Range(kSimplifiedDomainDisplayUrlHostnameAndScheme.size(),
1844                            kSimplifiedDomainDisplayUrl.size())));
1845   EXPECT_NE(SK_ColorTRANSPARENT,
1846             omnibox_view()->GetLatestColorForRange(gfx::Range(
1847                 0, kSimplifiedDomainDisplayUrlSubdomainAndScheme.size())));
1848 
1849   // Now exit the mouse. At this point the elision animation should run.
1850   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_EXITED, {0, 0}));
1851   EXPECT_TRUE(hover_animation->IsAnimating());
1852   ASSERT_NO_FATAL_FAILURE(
1853       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1854   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1855       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
1856       kSimplifiedDomainDisplayUrlSubdomain,
1857       kSimplifiedDomainDisplayUrlHostnameAndScheme,
1858       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
1859 }
1860 
1861 // Tests the field trial variation that shows a simplified domain by default and
1862 // reveals the unsimplified URL on hover, using an IDN url.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverAndExitIDN)1863 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExitIDN) {
1864   // The display URL used in simplified domain display tests.
1865   const base::string16 kSimplifiedDomainDisplayIDNUrl =
1866       base::UTF8ToUTF16("https://テスト.住所の例.test/bar");
1867   const base::string16 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme =
1868       base::UTF8ToUTF16("https://テスト.住所の例.test");
1869   const base::string16 kSimplifiedDomainDisplayIDNUrlSubdomainAndScheme =
1870       base::UTF8ToUTF16("https://テスト.");
1871   const base::string16 kSimplifiedDomainDisplayIDNUrlSubdomain =
1872       base::UTF8ToUTF16("テスト.");
1873   const base::string16 kSimplifiedDomainDisplayIDNUrlPath =
1874       base::UTF8ToUTF16("/bar");
1875   const base::string16 kSimplifiedDomainDisplayIDNUrlScheme =
1876       base::UTF8ToUTF16("https://");
1877   UpdateDisplayURL(kSimplifiedDomainDisplayIDNUrl);
1878   // Call OnThemeChanged() to create the animations.
1879   omnibox_view()->OnThemeChanged();
1880 
1881   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
1882   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1883       omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme,
1884       kSimplifiedDomainDisplayIDNUrlSubdomain,
1885       kSimplifiedDomainDisplayIDNUrlHostnameAndScheme,
1886       kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain()));
1887 
1888   // As soon as the mouse hovers over the omnibox, the unelide animation should
1889   // start running.
1890   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
1891   // Advance the clock through the animation.
1892   ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation(
1893       OmniboxFieldTrial::UnelideURLOnHoverThresholdMs()));
1894   // After the extended hover threshold has elapsed, the display text shouldn't
1895   // have changed yet.
1896   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1897       omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme,
1898       kSimplifiedDomainDisplayIDNUrlSubdomain,
1899       kSimplifiedDomainDisplayIDNUrlHostnameAndScheme,
1900       kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain()));
1901 
1902   // Now advance through the unelision and check the display text. We assume
1903   // that the animation takes less than 1 second.
1904   ASSERT_NO_FATAL_FAILURE(
1905       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1906   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
1907       render_text, gfx::Range(0, kSimplifiedDomainDisplayIDNUrl.size())));
1908   OmniboxViewViews::ElideAnimation* hover_animation =
1909       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
1910   ASSERT_TRUE(hover_animation);
1911   EXPECT_FALSE(hover_animation->IsAnimating());
1912   // Check that the path and subdomain are not transparent.
1913   EXPECT_NE(SK_ColorTRANSPARENT,
1914             omnibox_view()->GetLatestColorForRange(gfx::Range(
1915                 kSimplifiedDomainDisplayIDNUrlHostnameAndScheme.size(),
1916                 kSimplifiedDomainDisplayIDNUrl.size())));
1917   EXPECT_NE(SK_ColorTRANSPARENT,
1918             omnibox_view()->GetLatestColorForRange(gfx::Range(
1919                 0, kSimplifiedDomainDisplayIDNUrlSubdomainAndScheme.size())));
1920 
1921   // Now exit the mouse. At this point the elision animation should run.
1922   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_EXITED, {0, 0}));
1923   EXPECT_TRUE(hover_animation->IsAnimating());
1924   ASSERT_NO_FATAL_FAILURE(
1925       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
1926   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1927       omnibox_view(), kSimplifiedDomainDisplayIDNUrlScheme,
1928       kSimplifiedDomainDisplayIDNUrlSubdomain,
1929       kSimplifiedDomainDisplayIDNUrlHostnameAndScheme,
1930       kSimplifiedDomainDisplayIDNUrlPath, ShouldElideToRegistrableDomain()));
1931 }
1932 
1933 // Tests the field trial variation that shows a simplified domain by default
1934 // using a private registry (https://publicsuffix.org/list/). Private registries
1935 // should be ignored when computing the simplified domain, to avoid creating
1936 // incentives for malicious sites to add themselves to the Public Suffix List.
TEST_P(OmniboxViewViewsRevealOnHoverTest,PrivateRegistry)1937 TEST_P(OmniboxViewViewsRevealOnHoverTest, PrivateRegistry) {
1938   // This test is only applicable when we elide to the registrable domain;
1939   // otherwise private vs public registries are irrelevant.
1940   if (!ShouldElideToRegistrableDomain())
1941     return;
1942 
1943   const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrl =
1944       base::UTF8ToUTF16("https://foo.blogspot.com/bar");
1945   const base::string16
1946       kSimplifiedDomainDisplayPrivateRegistryUrlHostnameAndScheme =
1947           base::UTF8ToUTF16("https://foo.blogspot.com");
1948   const base::string16
1949       kSimplifiedDomainDisplayPrivateRegistryUrlSubdomainAndScheme =
1950           base::UTF8ToUTF16("https://foo.");
1951   const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrlSubdomain =
1952       base::UTF8ToUTF16("foo.");
1953   const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrlPath =
1954       base::UTF8ToUTF16("/bar");
1955   const base::string16 kSimplifiedDomainDisplayPrivateRegistryUrlScheme =
1956       base::UTF8ToUTF16("https://");
1957   UpdateDisplayURL(kSimplifiedDomainDisplayPrivateRegistryUrl);
1958   // Call OnThemeChanged() to create the animations.
1959   omnibox_view()->OnThemeChanged();
1960 
1961   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1962       omnibox_view(), kSimplifiedDomainDisplayPrivateRegistryUrlScheme,
1963       kSimplifiedDomainDisplayPrivateRegistryUrlSubdomain,
1964       kSimplifiedDomainDisplayPrivateRegistryUrlHostnameAndScheme,
1965       kSimplifiedDomainDisplayPrivateRegistryUrlPath,
1966       ShouldElideToRegistrableDomain()));
1967 }
1968 
1969 // Tests the field trial variation that shows a simplified domain by default and
1970 // reveals the unsimplified URL on hover, using a URL where the path contains
1971 // the domain name.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverAndExitDomainInPath)1972 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverAndExitDomainInPath) {
1973   // The display URL used in simplified domain display tests.
1974   const base::string16 kSimplifiedDomainDisplayRepeatedUrl =
1975       base::UTF8ToUTF16("https://ex.example.test/example.test");
1976   const base::string16 kSimplifiedDomainDisplayRepeatedUrlHostnameAndScheme =
1977       base::UTF8ToUTF16("https://ex.example.test");
1978   const base::string16 kSimplifiedDomainDisplayRepeatedUrlSubdomainAndScheme =
1979       base::UTF8ToUTF16("https://ex.");
1980   const base::string16 kSimplifiedDomainDisplayRepeatedUrlSubdomain =
1981       base::UTF8ToUTF16("ex.");
1982   const base::string16 kSimplifiedDomainDisplayRepeatedUrlPath =
1983       base::UTF8ToUTF16("/example.test");
1984   const base::string16 kSimplifiedDomainDisplayRepeatedUrlScheme =
1985       base::UTF8ToUTF16("https://");
1986   location_bar_model()->set_url(GURL(kSimplifiedDomainDisplayRepeatedUrl));
1987   location_bar_model()->set_url_for_display(
1988       kSimplifiedDomainDisplayRepeatedUrl);
1989   omnibox_view()->model()->ResetDisplayTexts();
1990   omnibox_view()->RevertAll();
1991   // Call OnThemeChanged() to create the animations.
1992   omnibox_view()->OnThemeChanged();
1993 
1994   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
1995       omnibox_view(), kSimplifiedDomainDisplayRepeatedUrlScheme,
1996       kSimplifiedDomainDisplayRepeatedUrlSubdomain,
1997       kSimplifiedDomainDisplayRepeatedUrlHostnameAndScheme,
1998       kSimplifiedDomainDisplayRepeatedUrlPath,
1999       ShouldElideToRegistrableDomain()));
2000 }
2001 
2002 class OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest
2003     : public OmniboxViewViewsTest,
2004       public ::testing::WithParamInterface<std::pair<bool, bool>> {
2005  public:
OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest()2006   OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest()
2007       : OmniboxViewViewsTest(
2008             GetParam().first
2009                 ? std::vector<FeatureAndParams>(
2010                       {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2011                         {}},
2012                        {omnibox::
2013                             kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2014                         {}},
2015                        {omnibox::kMaybeElideToRegistrableDomain,
2016                         // Ensure all domains are elidable by policy.
2017                         {{"max_unelided_host_length", "0"}}}})
2018                 : std::vector<FeatureAndParams>(
2019                       {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2020                         {}},
2021                        {omnibox::
2022                             kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2023                         {}}}),
2024             {},
2025             GetParam().second) {
2026     // The lookalike allowlist is used by the registrable-domain-elision code.
2027     reputation::InitializeBlankLookalikeAllowlistForTesting();
2028   }
2029 
2030   OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest(
2031       const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete;
2032   OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest& operator=(
2033       const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete;
2034 
2035  protected:
ShouldElideToRegistrableDomain()2036   bool ShouldElideToRegistrableDomain() { return GetParam().first; }
2037 };
2038 
2039 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2040                          OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2041                          ::testing::ValuesIn({std::make_pair(true, false),
2042                                               std::make_pair(false, false),
2043                                               std::make_pair(true, true),
2044                                               std::make_pair(false, true)}));
2045 
2046 // Tests the field trial variation that shows the simplified domain when the
2047 // user interacts with the page and brings back the URL when the user hovers
2048 // over the omnibox.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,UserInteractionAndHover)2049 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2050        UserInteractionAndHover) {
2051   SetUpSimplifiedDomainTest();
2052 
2053   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2054                                             /*is_same_document=*/false, GURL(),
2055                                             kSimplifiedDomainDisplayUrlScheme);
2056 
2057   // Simulate a user interaction and check that the fade-out animation runs.
2058   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2059   // Advance the clock through the fade-out animation; we assume that it takes
2060   // less than 1s.
2061   ASSERT_NO_FATAL_FAILURE(
2062       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2063           /*step_ms=*/1000));
2064   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2065       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2066       kSimplifiedDomainDisplayUrlSubdomain,
2067       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2068       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2069 
2070   // A second user interaction should not run the animation again.
2071   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2072   EXPECT_FALSE(omnibox_view()
2073                    ->GetElideAfterInteractionAnimationForTesting()
2074                    ->IsAnimating());
2075 
2076   // The URL should come back on hover.
2077   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2078   ASSERT_NO_FATAL_FAILURE(
2079       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2080   // The hover should bring back the full URL, including scheme and trivial
2081   // subdomains.
2082   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2083       omnibox_view()->GetRenderText(),
2084       gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
2085   // The path and scheme/subdomain should not be transparent.
2086   EXPECT_NE(SK_ColorTRANSPARENT,
2087             omnibox_view()->GetLatestColorForRange(
2088                 gfx::Range(kSimplifiedDomainDisplayUrlHostnameAndScheme.size(),
2089                            kSimplifiedDomainDisplayUrl.size())));
2090   EXPECT_NE(SK_ColorTRANSPARENT,
2091             omnibox_view()->GetLatestColorForRange(gfx::Range(
2092                 0, kSimplifiedDomainDisplayUrlSubdomainAndScheme.size())));
2093 }
2094 
2095 // Tests that the hide-on-interaction simplified domain field trial handles
2096 // intermediate states during a navigation properly. This test simulates a
2097 // browser-initiated navigation in which the URL updates before the navigation
2098 // commits.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,BrowserInitiatedNavigation)2099 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2100        BrowserInitiatedNavigation) {
2101   SetUpSimplifiedDomainTest();
2102 
2103   ASSERT_NO_FATAL_FAILURE(omnibox_view()->NavigateAndExpectUnelided(
2104       kSimplifiedDomainDisplayUrl,
2105       /*is_same_document=*/false, GURL(), kSimplifiedDomainDisplayUrlScheme));
2106 
2107   // Before a user interaction triggers elision, a browser-initiated navigation
2108   // should show the full URL (minus scheme and trivial subdomain) throughout
2109   // the navigation.
2110 
2111   // Set a longer URL to ensure that the full URL stays visible even if it's
2112   // longer than the previous URL.
2113   const base::string16 kUrlSuffix = base::ASCIIToUTF16("/foobar");
2114   UpdateDisplayURL(kSimplifiedDomainDisplayUrl + kUrlSuffix);
2115   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2116       omnibox_view()->GetRenderText(),
2117       gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2118                  kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2119 
2120   {
2121     // In this test, we create MockNavigationHandles here instead of using the
2122     // NavigateAndExpect* helpers because those helpers simulate
2123     // renderer-initiated navigations, where the display URL isn't updated until
2124     // just before DidFinishNavigation.
2125     content::MockNavigationHandle navigation;
2126     navigation.set_is_renderer_initiated(false);
2127 
2128     omnibox_view()->DidStartNavigation(&navigation);
2129     ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2130         omnibox_view()->GetRenderText(),
2131         gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2132                    kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2133 
2134     omnibox_view()->DidFinishNavigation(&navigation);
2135     ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2136         omnibox_view()->GetRenderText(),
2137         gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2138                    kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2139     OmniboxViewViews::ElideAnimation* elide_animation =
2140         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2141     EXPECT_FALSE(elide_animation);
2142   }
2143 
2144   // Simulate a user interaction and advance all the way through the animation
2145   // until the URL is elided to the simplified domain.
2146   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2147   ASSERT_NO_FATAL_FAILURE(
2148       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2149           /*step_ms=*/1000));
2150   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2151       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2152       kSimplifiedDomainDisplayUrlSubdomain,
2153       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2154       kSimplifiedDomainDisplayUrlPath + kUrlSuffix,
2155       ShouldElideToRegistrableDomain()));
2156 
2157   // Begin simulating a browser-initiated navigation, in which the URL is
2158   // updated before DidStartNavigation() runs.
2159   UpdateDisplayURL(kSimplifiedDomainDisplayUrl + kUrlSuffix);
2160   // Ideally we would actually be unelided at this point, when a
2161   // browser-initiated navigation has begun. But EmphasizeURLComponents()
2162   // doesn't know which type of navigation is in progress, so this is the best
2163   // we can do.
2164   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2165       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2166       kSimplifiedDomainDisplayUrlSubdomain,
2167       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2168       kSimplifiedDomainDisplayUrlPath + kUrlSuffix,
2169       ShouldElideToRegistrableDomain()));
2170   {
2171     content::MockNavigationHandle navigation;
2172     navigation.set_is_renderer_initiated(false);
2173 
2174     // Once the navigation starts and we know that it's a cross-document
2175     // navigation, the URL should be unelided.
2176     omnibox_view()->DidStartNavigation(&navigation);
2177     ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2178         omnibox_view()->GetRenderText(),
2179         gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2180                    kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2181 
2182     omnibox_view()->DidFinishNavigation(&navigation);
2183     ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2184         omnibox_view()->GetRenderText(),
2185         gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2186                    kSimplifiedDomainDisplayUrl.size() + kUrlSuffix.size())));
2187     OmniboxViewViews::ElideAnimation* elide_animation =
2188         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2189     EXPECT_FALSE(elide_animation);
2190   }
2191 }
2192 
2193 // Tests that the hide-on-interaction simplified domain field trial handles
2194 // non-committed navigations properly.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,NonCommittedNavigations)2195 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2196        NonCommittedNavigations) {
2197   SetUpSimplifiedDomainTest();
2198 
2199   ASSERT_NO_FATAL_FAILURE(omnibox_view()->NavigateAndExpectUnelided(
2200       kSimplifiedDomainDisplayUrl,
2201       /*is_same_document=*/false, GURL(), kSimplifiedDomainDisplayUrlScheme));
2202   // Simulate a user interaction to elide the URL.
2203   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2204   ASSERT_NO_FATAL_FAILURE(
2205       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2206           /*step_ms=*/1000));
2207   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2208       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2209       kSimplifiedDomainDisplayUrlSubdomain,
2210       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2211       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2212 
2213   // When a renderer-initiated navigation finishes without committing, the URL
2214   // should remain elided; we don't update the display URL until the navigation
2215   // commits.
2216   {
2217     content::MockNavigationHandle navigation;
2218     navigation.set_is_renderer_initiated(true);
2219     navigation.set_has_committed(false);
2220     omnibox_view()->DidStartNavigation(&navigation);
2221     omnibox_view()->DidFinishNavigation(&navigation);
2222     ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2223         omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2224         kSimplifiedDomainDisplayUrlSubdomain,
2225         kSimplifiedDomainDisplayUrlHostnameAndScheme,
2226         kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2227   }
2228 
2229   // When a browser-initiated navigation finishes without committing, the URL
2230   // updates before commit, so we should reset back to the on-page-load state if
2231   // the navigation doesn't eventually commit.
2232   content::MockNavigationHandle navigation;
2233   navigation.set_is_renderer_initiated(false);
2234   navigation.set_has_committed(false);
2235   omnibox_view()->DidStartNavigation(&navigation);
2236   omnibox_view()->DidFinishNavigation(&navigation);
2237   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2238       omnibox_view()->GetRenderText(),
2239       gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2240                  kSimplifiedDomainDisplayUrl.size())));
2241 }
2242 
2243 // Tests that mouse clicks do not count as user interactions and do not elide
2244 // the URL.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,MouseClick)2245 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, MouseClick) {
2246   SetUpSimplifiedDomainTest();
2247 
2248   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2249                                             /*is_same_document=*/false, GURL(),
2250                                             kSimplifiedDomainDisplayUrlScheme);
2251 
2252   // Simulate a mouse click and check that the fade-out animation does not run.
2253   blink::WebMouseEvent event;
2254   event.SetType(blink::WebInputEvent::Type::kMouseDown);
2255   omnibox_view()->DidGetUserInteraction(event);
2256   OmniboxViewViews::ElideAnimation* elide_animation =
2257       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2258   EXPECT_FALSE(elide_animation);
2259 }
2260 
2261 // Tests that focusing an editable node does count as a user interaction and
2262 // elides the URL.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,FocusingEditableNode)2263 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2264        FocusingEditableNode) {
2265   SetUpSimplifiedDomainTest();
2266 
2267   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2268                                             /*is_same_document=*/false, GURL(),
2269                                             kSimplifiedDomainDisplayUrlScheme);
2270 
2271   // Focusing a non-editable node should not run the fade-out animation.
2272   content::FocusedNodeDetails details;
2273   details.is_editable_node = false;
2274   details.focus_type = blink::mojom::FocusType::kMouse;
2275   omnibox_view()->OnFocusChangedInPage(&details);
2276   OmniboxViewViews::ElideAnimation* elide_animation =
2277       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2278   EXPECT_FALSE(elide_animation);
2279 
2280   // Focusing via keypress should not run the fade-out animation.
2281   details.is_editable_node = true;
2282   details.focus_type = blink::mojom::FocusType::kForward;
2283   omnibox_view()->OnFocusChangedInPage(&details);
2284   elide_animation =
2285       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2286   EXPECT_FALSE(elide_animation);
2287 
2288   // Other ways that an element can be focused, such as element.focus() in
2289   // JavaScript, have a focus type of kNone and should not run the fade-out
2290   // animation.
2291   details.is_editable_node = true;
2292   details.focus_type = blink::mojom::FocusType::kNone;
2293   omnibox_view()->OnFocusChangedInPage(&details);
2294   elide_animation =
2295       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2296   EXPECT_FALSE(elide_animation);
2297 
2298   // Focusing an editable node should run the fade-out animation.
2299   details.is_editable_node = true;
2300   details.focus_type = blink::mojom::FocusType::kMouse;
2301   omnibox_view()->OnFocusChangedInPage(&details);
2302   elide_animation =
2303       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2304   ASSERT_TRUE(elide_animation);
2305   EXPECT_TRUE(elide_animation->IsAnimating());
2306 }
2307 
2308 // Tests that simplified domain elisions are re-applied when the omnibox's
2309 // bounds change.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,BoundsChanged)2310 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest, BoundsChanged) {
2311   SetUpSimplifiedDomainTest();
2312 
2313   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2314                                             /*is_same_document=*/false, GURL(),
2315                                             kSimplifiedDomainDisplayUrlScheme);
2316 
2317   // After the bounds change, the URL should remain unelided.
2318   omnibox_view()->OnBoundsChanged(gfx::Rect());
2319   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2320       omnibox_view()->GetRenderText(),
2321       gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2322                  kSimplifiedDomainDisplayUrl.size())));
2323 
2324   // Hover over the omnibox and change the bounds during the animation. The
2325   // animation should be cancelled and immediately transition back to the
2326   // unelided URL.
2327   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2328   OmniboxViewViews::ElideAnimation* unelide_animation =
2329       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2330   ASSERT_TRUE(unelide_animation);
2331   EXPECT_TRUE(unelide_animation->IsAnimating());
2332   omnibox_view()->OnBoundsChanged(gfx::Rect());
2333   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2334       omnibox_view()->GetRenderText(),
2335       gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2336                  kSimplifiedDomainDisplayUrl.size())));
2337 
2338   // Simulate a user interaction and change the bounds during the animation. The
2339   // animation should be cancelled and immediately transition to the animation's
2340   // end state (simplified domain).
2341   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2342   OmniboxViewViews::ElideAnimation* elide_animation =
2343       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2344   ASSERT_TRUE(elide_animation);
2345   EXPECT_TRUE(elide_animation->IsAnimating());
2346   omnibox_view()->OnBoundsChanged(gfx::Rect());
2347   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2348       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2349       kSimplifiedDomainDisplayUrlSubdomain,
2350       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2351       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2352 }
2353 
2354 // Tests that simplified domain elisions are re-applied when the omnibox's
2355 // bounds change when only reveal-on-hover is enabled.
TEST_P(OmniboxViewViewsRevealOnHoverTest,BoundsChanged)2356 TEST_P(OmniboxViewViewsRevealOnHoverTest, BoundsChanged) {
2357   SetUpSimplifiedDomainTest();
2358 
2359   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2360       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2361       kSimplifiedDomainDisplayUrlSubdomain,
2362       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2363       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2364 
2365   // After the bounds change, the URL should remain elided.
2366   omnibox_view()->OnBoundsChanged(gfx::Rect());
2367   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2368       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2369       kSimplifiedDomainDisplayUrlSubdomain,
2370       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2371       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2372 
2373   // Hover over the omnibox and change the bounds during the animation. The
2374   // animation should be cancelled and immediately transition back to the
2375   // simplified domain.
2376   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2377   OmniboxViewViews::ElideAnimation* unelide_animation =
2378       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2379   ASSERT_TRUE(unelide_animation);
2380   EXPECT_TRUE(unelide_animation->IsAnimating());
2381   omnibox_view()->OnBoundsChanged(gfx::Rect());
2382   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2383       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2384       kSimplifiedDomainDisplayUrlSubdomain,
2385       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2386       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2387 }
2388 
2389 // Tests that simplified domain hover duration histogram is recorded correctly.
TEST_P(OmniboxViewViewsRevealOnHoverTest,HoverHistogram)2390 TEST_P(OmniboxViewViewsRevealOnHoverTest, HoverHistogram) {
2391   base::SimpleTestClock clock;
2392   constexpr int kHoverTimeMs = 1000;
2393   SetUpSimplifiedDomainTest();
2394   clock.SetNow(base::Time::Now());
2395   omnibox_view()->clock_ = &clock;
2396 
2397   // Hover over the omnibox and then exit and check that the histogram is
2398   // recorded correctly.
2399   {
2400     base::HistogramTester histograms;
2401     omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2402     OmniboxViewViews::ElideAnimation* unelide_animation =
2403         omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2404     ASSERT_TRUE(unelide_animation);
2405     EXPECT_TRUE(unelide_animation->IsAnimating());
2406     clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs / 2));
2407     // Call OnMouseMoved() again halfway through the hover time to ensure that
2408     // the histogram is only recorded once per continuous hover.
2409     omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2410     clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs / 2));
2411     omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2412     auto samples = histograms.GetAllSamples("Omnibox.HoverTime");
2413     ASSERT_EQ(1u, samples.size());
2414     histograms.ExpectTimeBucketCount(
2415         "Omnibox.HoverTime", base::TimeDelta::FromMilliseconds(kHoverTimeMs),
2416         1);
2417 
2418     // Focusing the omnibox while not hovering should not record another sample.
2419     omnibox_view()->OnFocus();
2420     samples = histograms.GetAllSamples("Omnibox.HoverTime");
2421     ASSERT_EQ(1u, samples.size());
2422   }
2423 
2424   // Hover over the omnibox and then focus it, and check that the histogram is
2425   // recorded correctly.
2426   {
2427     base::HistogramTester histograms;
2428     omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2429     OmniboxViewViews::ElideAnimation* unelide_animation =
2430         omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2431     ASSERT_TRUE(unelide_animation);
2432     EXPECT_TRUE(unelide_animation->IsAnimating());
2433     clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs));
2434     omnibox_view()->OnFocus();
2435     auto samples = histograms.GetAllSamples("Omnibox.HoverTime");
2436     ASSERT_EQ(1u, samples.size());
2437     histograms.ExpectTimeBucketCount(
2438         "Omnibox.HoverTime", base::TimeDelta::FromMilliseconds(kHoverTimeMs),
2439         1);
2440 
2441     // Moving the mouse, focusing again, and exiting from the omnibox after
2442     // focusing it should not record any more samples.
2443     omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2444     omnibox_view()->OnFocus();
2445     omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2446     samples = histograms.GetAllSamples("Omnibox.HoverTime");
2447     ASSERT_EQ(1u, samples.size());
2448 
2449     // Hovering and exiting again should record another sample.
2450     omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2451     omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2452     samples = histograms.GetAllSamples("Omnibox.HoverTime");
2453     ASSERT_EQ(2u, samples.size());
2454   }
2455 
2456   // Hovering over the omnibox while focused should not record a histogram,
2457   // because no elide animation happens while focused.
2458   {
2459     base::HistogramTester histograms;
2460     omnibox_view()->RequestFocus();
2461     omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2462     OmniboxViewViews::ElideAnimation* unelide_animation =
2463         omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2464     ASSERT_TRUE(unelide_animation);
2465     EXPECT_FALSE(unelide_animation->IsAnimating());
2466     clock.Advance(base::TimeDelta::FromMilliseconds(kHoverTimeMs));
2467     omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2468     auto samples = histograms.GetAllSamples("Omnibox.HoverTime");
2469     ASSERT_EQ(0u, samples.size());
2470   }
2471 }
2472 
2473 // Tests that the simplified domain animation doesn't crash when it's cancelled.
2474 // Regression test for https://crbug.com/1103738.
TEST_P(OmniboxViewViewsRevealOnHoverTest,CancellingAnimationDoesNotCrash)2475 TEST_P(OmniboxViewViewsRevealOnHoverTest, CancellingAnimationDoesNotCrash) {
2476   SetUpSimplifiedDomainTest();
2477 
2478   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2479       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2480       kSimplifiedDomainDisplayUrlSubdomain,
2481       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2482       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2483 
2484   // Hover over the omnibox to begin the unelision animation, then change the
2485   // URL such that the current animation would go out of bounds if it continued
2486   // running.
2487   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2488   // Step through the animation partially so that it has a nonzero current
2489   // value. (A zero current value causes an early return that circumvents the
2490   // crash we are regression-testing.)
2491   ASSERT_NO_FATAL_FAILURE(omnibox_view()->StepSimplifiedDomainHoverAnimation(
2492       OmniboxFieldTrial::UnelideURLOnHoverThresholdMs() + 1));
2493 
2494   // Stopping the animation after changing the underlying display text should
2495   // not crash.
2496   UpdateDisplayURL(base::ASCIIToUTF16("https://foo.test"));
2497   omnibox_view()->GetHoverElideOrUnelideAnimationForTesting()->Stop();
2498 }
2499 
2500 // Tests scheme and trivial subdomain elision when simplified domain field
2501 // trials are enabled.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,SchemeAndTrivialSubdomainElision)2502 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2503        SchemeAndTrivialSubdomainElision) {
2504   // Use custom setup code instead of SetUpSimplifiedDomainTest() to use a URL
2505   // with a "www." prefix (a trivial subdomain).
2506   const base::string16 kFullUrl =
2507       base::ASCIIToUTF16("https://www.example.test/foo");
2508   constexpr size_t kSchemeAndSubdomainSize = 12;  // "https://www."
2509   UpdateDisplayURL(kFullUrl);
2510   omnibox_view()->OnThemeChanged();
2511 
2512   omnibox_view()->NavigateAndExpectUnelided(kFullUrl,
2513                                             /*is_same_document=*/false, GURL(),
2514                                             base::ASCIIToUTF16("htpts://www."));
2515   EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2516                                      gfx::Range(0, kSchemeAndSubdomainSize)));
2517 
2518   // Hovering before user interaction should bring back the scheme and trivial
2519   // subdomain.
2520   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2521   ASSERT_NO_FATAL_FAILURE(
2522       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2523   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2524       omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size())));
2525   EXPECT_NE(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2526                                      gfx::Range(0, kSchemeAndSubdomainSize)));
2527 
2528   // After mousing out, the scheme should fade out again.
2529   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2530   ASSERT_NO_FATAL_FAILURE(
2531       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2532   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2533       omnibox_view()->GetRenderText(),
2534       gfx::Range(kSchemeAndSubdomainSize, kSimplifiedDomainDisplayUrl.size())));
2535   EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2536                                      gfx::Range(0, kSchemeAndSubdomainSize)));
2537 
2538   // Simulate a user interaction and check that the URL gets elided to the
2539   // simplified domain.
2540   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2541   ASSERT_NO_FATAL_FAILURE(
2542       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2543           /*step_ms=*/1000));
2544   // Use should_elide_to_registrable_domain=true here regardless of how the
2545   // field trial is set because the "www." should be elided as a trivial
2546   // subdomain.
2547   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2548       omnibox_view(), base::ASCIIToUTF16("https://"),
2549       base::ASCIIToUTF16("www."),
2550       base::ASCIIToUTF16("https://www.example.test"),
2551       base::ASCIIToUTF16("/foo"),
2552       /* should_elide_to_registrable_domain=*/true));
2553 
2554   // Do another hover and check that the URL gets unelided to the full URL.
2555   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2556   ASSERT_NO_FATAL_FAILURE(
2557       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2558   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2559       omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size())));
2560   EXPECT_NE(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2561                                      gfx::Range(0, kSchemeAndSubdomainSize)));
2562 
2563   // And after another mouse exit, the URL should go back to the simplified
2564   // domain.
2565   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2566   ASSERT_NO_FATAL_FAILURE(
2567       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2568   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2569       omnibox_view(), base::ASCIIToUTF16("https://"),
2570       base::ASCIIToUTF16("www."),
2571       base::ASCIIToUTF16("https://www.example.test"),
2572       base::ASCIIToUTF16("/foo"),
2573       /* should_elide_to_registrable_domain=*/true));
2574   EXPECT_EQ(SK_ColorTRANSPARENT, omnibox_view()->GetLatestColorForRange(
2575                                      gfx::Range(0, kSchemeAndSubdomainSize)));
2576 }
2577 
2578 class OmniboxViewViewsHideOnInteractionTest
2579     : public OmniboxViewViewsTest,
2580       public ::testing::WithParamInterface<std::pair<bool, bool>> {
2581  public:
OmniboxViewViewsHideOnInteractionTest()2582   OmniboxViewViewsHideOnInteractionTest()
2583       : OmniboxViewViewsTest(
2584             GetParam().first
2585                 ? std::vector<FeatureAndParams>(
2586                       {{omnibox::
2587                             kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2588                         {}},
2589                        {omnibox::kMaybeElideToRegistrableDomain,
2590                         // Ensure all domains are elidable by policy.
2591                         {{"max_unelided_host_length", "0"}}}})
2592                 : std::vector<FeatureAndParams>(
2593                       {{omnibox::
2594                             kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2595                         {}}}),
2596             {},
2597             GetParam().second) {
2598     // The lookalike allowlist is used by the registrable-domain-elision code.
2599     reputation::InitializeBlankLookalikeAllowlistForTesting();
2600   }
2601 
2602   OmniboxViewViewsHideOnInteractionTest(
2603       const OmniboxViewViewsHideOnInteractionTest&) = delete;
2604   OmniboxViewViewsHideOnInteractionTest& operator=(
2605       const OmniboxViewViewsHideOnInteractionTest&) = delete;
2606 
2607  protected:
ShouldElideToRegistrableDomain()2608   bool ShouldElideToRegistrableDomain() { return GetParam().first; }
2609 };
2610 
2611 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionTest,
2612                          OmniboxViewViewsHideOnInteractionTest,
2613                          ::testing::ValuesIn({std::make_pair(true, false),
2614                                               std::make_pair(false, false),
2615                                               std::make_pair(true, true),
2616                                               std::make_pair(false, true)}));
2617 
2618 // Tests the the "Always Show Full URLs" option works with the field trial
2619 // variation that shows a simplified domain when the user interacts with the
2620 // page.
TEST_P(OmniboxViewViewsHideOnInteractionTest,AlwaysShowFullURLs)2621 TEST_P(OmniboxViewViewsHideOnInteractionTest, AlwaysShowFullURLs) {
2622   // This test does setup itself and doesn't call SetUpSimplifiedDomainTest()
2623   // because SetUpSimplifiedDomainTest() uses a URL with a foo.example.test
2624   // hostname, and in this test we want to use a "www." subdomain to test that
2625   // the URL is displayed properly when trivial subdomain elision is disabled.
2626   const base::string16 kFullUrl =
2627       base::ASCIIToUTF16("https://www.example.test/foo");
2628   UpdateDisplayURL(kFullUrl);
2629   omnibox_view()->OnThemeChanged();
2630 
2631   // Enable the "Always show full URLs" setting.
2632   location_bar_model()->set_should_prevent_elision(true);
2633   omnibox_view()->OnShouldPreventElisionChanged();
2634   std::unique_ptr<content::WebContents> web_contents =
2635       content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2636   omnibox_view()->OnTabChanged(web_contents.get());
2637   EXPECT_EQ(kFullUrl, omnibox_view()->GetText());
2638   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2639       omnibox_view()->GetRenderText(), gfx::Range(0, kFullUrl.size())));
2640 
2641   // When the Always Show Full URLs pref is enabled, the omnibox view won't
2642   // observe user interactions and elide the URL.
2643   EXPECT_FALSE(omnibox_view()->web_contents());
2644   OmniboxViewViews::ElideAnimation* elide_animation =
2645       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2646   EXPECT_FALSE(elide_animation);
2647 }
2648 
2649 // Tests the the "Always Show Full URLs" option works with the field trial
2650 // variation that shows a simplified domain until the user hovers over the
2651 // omnibox.
TEST_P(OmniboxViewViewsRevealOnHoverTest,AlwaysShowFullURLs)2652 TEST_P(OmniboxViewViewsRevealOnHoverTest, AlwaysShowFullURLs) {
2653   SetUpSimplifiedDomainTest();
2654 
2655   // Enable the "Always show full URLs" setting.
2656   location_bar_model()->set_should_prevent_elision(true);
2657   omnibox_view()->OnShouldPreventElisionChanged();
2658 
2659   // After a hover, there should be no animations running.
2660   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2661   OmniboxViewViews::ElideAnimation* elide_animation =
2662       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2663   EXPECT_FALSE(elide_animation);
2664   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2665   elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2666   EXPECT_FALSE(elide_animation);
2667 }
2668 
2669 // This test fixture enables the reveal-on-hover simplified domain field trial,
2670 // and the hide-on-interaction variation when the parameter is true.
2671 class OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest
2672     : public OmniboxViewViewsTest,
2673       public ::testing::WithParamInterface<std::pair<bool, bool>> {
2674  public:
OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest()2675   OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest()
2676       : OmniboxViewViewsTest(
2677             GetParam().first
2678                 ? std::vector<FeatureAndParams>(
2679                       {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2680                         {}},
2681                        {omnibox::
2682                             kHideSteadyStateUrlPathQueryAndRefOnInteraction,
2683                         {}}})
2684                 : std::vector<FeatureAndParams>(
2685                       {{omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
2686                         {}}}),
2687             {omnibox::kMaybeElideToRegistrableDomain},
2688             GetParam().second) {}
2689 
2690   OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest(
2691       const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) =
2692       delete;
2693   OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest& operator=(
2694       const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) =
2695       delete;
2696 
2697  protected:
IsHideOnInteractionEnabled()2698   bool IsHideOnInteractionEnabled() { return GetParam().first; }
2699 };
2700 
2701 INSTANTIATE_TEST_SUITE_P(
2702     OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
2703     OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
2704     ::testing::ValuesIn({std::make_pair(true, false),
2705                          std::make_pair(false, false),
2706                          std::make_pair(true, true),
2707                          std::make_pair(false, true)}));
2708 
2709 // Tests that unsetting the "Always show full URLs" option begins showing/hiding
2710 // the full URL appropriately when simplified domain field trials are enabled.
2711 // This test has kMaybeElideToRegistrableDomain disabled so that we can check
2712 // that www is elided when the option is unset but other subdomains are not.
TEST_P(OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,UnsetAlwaysShowFullURLs)2713 TEST_P(OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
2714        UnsetAlwaysShowFullURLs) {
2715   // This test does setup itself and doesn't call SetUpSimplifiedDomainTest()
2716   // because SetUpSimplifiedDomainTest() uses a URL with a foo.example.test
2717   // hostname, and in this test we want to use a "www." subdomain to test that
2718   // the URL is displayed properly when trivial subdomain elision is disabled.
2719   const base::string16 kFullUrl =
2720       base::ASCIIToUTF16("https://www.example.test/foo");
2721   UpdateDisplayURL(kFullUrl);
2722   omnibox_view()->OnThemeChanged();
2723   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
2724 
2725   // Enable the "Always show full URLs" setting.
2726   location_bar_model()->set_should_prevent_elision(true);
2727   omnibox_view()->OnShouldPreventElisionChanged();
2728   std::unique_ptr<content::WebContents> web_contents =
2729       content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2730   omnibox_view()->OnTabChanged(web_contents.get());
2731   EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo"),
2732             omnibox_view()->GetText());
2733 
2734   // Now toggle the preference and check that the animations run as expected.
2735   location_bar_model()->set_should_prevent_elision(false);
2736   location_bar_model()->set_url_for_display(
2737       base::ASCIIToUTF16("https://www.example.test/foo"));
2738   omnibox_view()->OnShouldPreventElisionChanged();
2739   // When simplified domain field trials are enabled, LocationBarModelImpl
2740   // doesn't do any elision, leaving it all up to OmniboxViewViews, so the text
2741   // returned from LocationBarModelImpl is the same even though the preference
2742   // has changed.
2743   EXPECT_EQ(base::ASCIIToUTF16("https://www.example.test/foo"),
2744             omnibox_view()->GetText());
2745   if (IsHideOnInteractionEnabled()) {
2746     ExpectUnelidedFromSimplifiedDomain(
2747         render_text,
2748         gfx::Range(std::string("https://www.").size(), kFullUrl.size()));
2749     // Simulate a user interaction and check the fade-out animation.
2750     omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2751     OmniboxViewViews::ElideAnimation* elide_animation =
2752         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2753     ASSERT_TRUE(elide_animation);
2754     EXPECT_TRUE(elide_animation->IsAnimating());
2755   } else {
2756     // Even though kMaybeElideToRegistrableDomain is disabled, we expect to be
2757     // elided to the registrable domain because the www subdomain is considered
2758     // trivial.
2759     ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2760         omnibox_view(), base::ASCIIToUTF16("https://"),
2761         base::ASCIIToUTF16("www."),
2762         base::ASCIIToUTF16("https://www.example.test"),
2763         base::ASCIIToUTF16("/foo"),
2764         true /* should elide to registrable domain */));
2765   }
2766   // Simulate a hover event and check the elide/unelide animations. This
2767   // should happen the same regardless of whether hide-on-interaction is
2768   // enabled.
2769   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2770   ASSERT_NO_FATAL_FAILURE(
2771       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2772   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2773   OmniboxViewViews::ElideAnimation* elide_animation =
2774       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
2775   ASSERT_TRUE(elide_animation);
2776   EXPECT_TRUE(elide_animation->IsAnimating());
2777 }
2778 
2779 // Tests that in the hide-on-interaction field trial, the omnibox is reset to
2780 // the local bounds on tab change when the new text is not eligible for
2781 // simplified domain elision.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,TabChangeWhenNotEligibleForEliding)2782 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2783        TabChangeWhenNotEligibleForEliding) {
2784   SetUpSimplifiedDomainTest();
2785 
2786   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2787                                             /*is_same_document=*/false, GURL(),
2788                                             kSimplifiedDomainDisplayUrlScheme);
2789 
2790   // Simulate a user interaction and advance through the animation to elide the
2791   // URL.
2792   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2793   ASSERT_NO_FATAL_FAILURE(
2794       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2795           /*step_ms=*/1000));
2796   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2797       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2798       kSimplifiedDomainDisplayUrlSubdomain,
2799       kSimplifiedDomainDisplayUrlHostnameAndScheme,
2800       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2801 
2802   // Change the tab and set state such that the current text is not eligible for
2803   // simplified domain eliding (specifically, use an ftp:// URL; only http/https
2804   // URLs are eligible for eliding). The omnibox should take up the full local
2805   // bounds and be reset to tail-eliding behavior, just as if the above
2806   // simplified domain elision had not happened.
2807   UpdateDisplayURL(base::ASCIIToUTF16("ftp://foo.example.test"));
2808   std::unique_ptr<content::WebContents> web_contents =
2809       content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2810   omnibox_view()->SaveStateToTab(web_contents.get());
2811   omnibox_view()->OnTabChanged(web_contents.get());
2812 
2813   EXPECT_EQ(gfx::ELIDE_TAIL, omnibox_view()->GetRenderText()->elide_behavior());
2814   EXPECT_EQ(base::ASCIIToUTF16("ftp://foo.example.test"),
2815             omnibox_view()->GetRenderText()->GetDisplayText());
2816 
2817   // Change the tab and simulate user input in progress. In this case, the
2818   // omnibox should take up the full local bounds but should not be reset to
2819   // tail-eliding behavior, because it should always be in NO_ELIDE mode when
2820   // editing.
2821   UpdateDisplayURL(kSimplifiedDomainDisplayUrl);
2822   omnibox_view()->Focus();
2823   omnibox_view()->model()->SetInputInProgress(true);
2824   std::unique_ptr<content::WebContents> web_contents2 =
2825       content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
2826   omnibox_view()->SaveStateToTab(web_contents2.get());
2827   omnibox_view()->OnTabChanged(web_contents2.get());
2828 
2829   EXPECT_EQ(gfx::NO_ELIDE, omnibox_view()->GetRenderText()->elide_behavior());
2830   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2831       omnibox_view()->GetRenderText(),
2832       gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
2833 }
2834 
2835 // Tests that in the simplified domain field trials, non-http/https and
2836 // localhost URLs are not elided.
TEST_P(OmniboxViewViewsRevealOnHoverTest,UrlsNotEligibleForEliding)2837 TEST_P(OmniboxViewViewsRevealOnHoverTest, UrlsNotEligibleForEliding) {
2838   const base::string16 kTestCases[] = {
2839       // Various URLs that aren't eligible for simplified domain eliding.
2840       base::ASCIIToUTF16("ftp://foo.bar.test/baz"),
2841       base::ASCIIToUTF16("javascript:alert(1)"),
2842       base::ASCIIToUTF16("data:text/html,hello"),
2843       base::ASCIIToUTF16("http://localhost:4000/foo"),
2844       // A smoke test to check that the test code results in
2845       // the URL being elided properly when eligible.
2846       kSimplifiedDomainDisplayUrl,
2847   };
2848 
2849   for (const auto& test_case : kTestCases) {
2850     UpdateDisplayURL(test_case);
2851     omnibox_view()->OnThemeChanged();
2852 
2853     if (test_case == kSimplifiedDomainDisplayUrl) {
2854       // This case is the smoke test to check that the test setup does properly
2855       // elide URLs that are eligible for eliding.
2856       ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
2857           omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
2858           kSimplifiedDomainDisplayUrlSubdomain,
2859           kSimplifiedDomainDisplayUrlHostnameAndScheme,
2860           kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
2861     } else {
2862       EXPECT_EQ(gfx::ELIDE_TAIL,
2863                 omnibox_view()->GetRenderText()->elide_behavior());
2864       EXPECT_EQ(test_case, omnibox_view()->GetRenderText()->GetDisplayText());
2865       EXPECT_EQ(0,
2866                 omnibox_view()->GetRenderText()->GetUpdatedDisplayOffset().x());
2867     }
2868   }
2869 }
2870 
2871 // Tests that in the hide-on-interaction field trial, when the path changes
2872 // while being elided, the animation is stopped.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,PathChangeDuringAnimation)2873 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2874        PathChangeDuringAnimation) {
2875   SetUpSimplifiedDomainTest();
2876 
2877   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2878                                             /*is_same_document=*/false, GURL(),
2879                                             kSimplifiedDomainDisplayUrlScheme);
2880 
2881   // Simulate a user interaction and check that the fade-out animation runs.
2882   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2883   OmniboxViewViews::ElideAnimation* elide_animation =
2884       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2885   EXPECT_TRUE(elide_animation->IsAnimating());
2886 
2887   // Change the path and check that the animation is cancelled.
2888   UpdateDisplayURL(base::ASCIIToUTF16("foo.example.test/bar#bar"));
2889   omnibox_view()->model()->ResetDisplayTexts();
2890   omnibox_view()->RevertAll();
2891   EXPECT_FALSE(elide_animation->IsAnimating());
2892 }
2893 
2894 // Tests that vertical and horizontal positioning doesn't change when eliding
2895 // to/from simplified domain. Regression test for https://crbug.com/1101674.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,VerticalAndHorizontalPosition)2896 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
2897        VerticalAndHorizontalPosition) {
2898   SetUpSimplifiedDomainTest();
2899   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
2900 
2901   const gfx::Rect& original_display_rect = render_text->display_rect();
2902 
2903   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2904                                             /*is_same_document=*/false, GURL(),
2905                                             kSimplifiedDomainDisplayUrlScheme);
2906 
2907   // After a navigation, the URL should not be elided to the simplified domain,
2908   // and the display rect (including vertical and horizontal position) should be
2909   // unchanged.
2910   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2911       omnibox_view()->GetRenderText(),
2912       gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2913                  kSimplifiedDomainDisplayUrl.size())));
2914   EXPECT_EQ(original_display_rect, render_text->display_rect());
2915 
2916   // Simulate a user interaction to elide to simplified domain and advance
2917   // through the animation; the vertical position should still be unchanged, and
2918   // the text should still start at the some position (the same x value).
2919   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2920   ASSERT_NO_FATAL_FAILURE(
2921       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
2922           /*step_ms=*/1000));
2923   const gfx::Rect& elided_display_rect = render_text->display_rect();
2924   EXPECT_EQ(original_display_rect.y(), elided_display_rect.y());
2925   EXPECT_EQ(original_display_rect.height(), elided_display_rect.height());
2926   EXPECT_EQ(original_display_rect.x(), elided_display_rect.x());
2927 
2928   // Now hover over the omnibox to trigger an unelide and check that the display
2929   // rect (including vertical and horizontal position) is back to what it was
2930   // originally.
2931   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
2932   ASSERT_NO_FATAL_FAILURE(
2933       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
2934   const gfx::Rect& unelided_display_rect = render_text->display_rect();
2935   EXPECT_EQ(original_display_rect, unelided_display_rect);
2936 }
2937 
2938 // Tests that modifier keys don't count as user interactions in the
2939 // hide-on-interaction field trial.
TEST_P(OmniboxViewViewsHideOnInteractionTest,ModifierKeys)2940 TEST_P(OmniboxViewViewsHideOnInteractionTest, ModifierKeys) {
2941   SetUpSimplifiedDomainTest();
2942   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
2943 
2944   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2945                                             /*is_same_document=*/false, GURL(),
2946                                             kSimplifiedDomainDisplayUrlScheme);
2947 
2948   // Simulate a user interaction with a modifier key and check that the elide
2949   // animation doesn't run.
2950   blink::WebKeyboardEvent event(
2951       blink::WebInputEvent::Type::kRawKeyDown,
2952       blink::WebInputEvent::kControlKey,
2953       blink::WebInputEvent::GetStaticTimeStampForTests());
2954   omnibox_view()->DidGetUserInteraction(event);
2955   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
2956       render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2957                               kSimplifiedDomainDisplayUrl.size())));
2958   OmniboxViewViews::ElideAnimation* elide_animation =
2959       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2960   EXPECT_FALSE(elide_animation);
2961 }
2962 
2963 // Tests that in the hide-on-interaction field trial, the URL is unelided when
2964 // navigating to an error page.
TEST_P(OmniboxViewViewsHideOnInteractionTest,ErrorPageNavigation)2965 TEST_P(OmniboxViewViewsHideOnInteractionTest, ErrorPageNavigation) {
2966   SetUpSimplifiedDomainTest();
2967   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2968                                             /*is_same_document=*/false, GURL(),
2969                                             kSimplifiedDomainDisplayUrlScheme);
2970 
2971   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2972                                             /*is_same_document=*/false, GURL(),
2973                                             kSimplifiedDomainDisplayUrlScheme);
2974   // Simulate a user interaction to elide to the simplified domain.
2975   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
2976   OmniboxViewViews::ElideAnimation* elide_animation =
2977       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
2978   ASSERT_TRUE(elide_animation);
2979   EXPECT_TRUE(elide_animation->IsAnimating());
2980 
2981   // Now simulate a navigation to an error page and check that the URL is
2982   // unelided.
2983   content::MockNavigationHandle navigation;
2984   navigation.set_url(GURL(kSimplifiedDomainDisplayUrl));
2985   navigation.set_is_error_page(true);
2986   omnibox_view()->DidStartNavigation(&navigation);
2987   omnibox_view()->DidFinishNavigation(&navigation);
2988   ExpectUnelidedFromSimplifiedDomain(
2989       omnibox_view()->GetRenderText(),
2990       gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
2991                  kSimplifiedDomainDisplayUrl.size()));
2992 }
2993 
2994 // Tests that in the hide-on-interaction field trial, the URL is simplified on
2995 // cross-document main-frame navigations, but not on same-document navigations.
TEST_P(OmniboxViewViewsHideOnInteractionTest,SameDocNavigations)2996 TEST_P(OmniboxViewViewsHideOnInteractionTest, SameDocNavigations) {
2997   SetUpSimplifiedDomainTest();
2998   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
2999                                             /*is_same_document=*/false, GURL(),
3000                                             kSimplifiedDomainDisplayUrlScheme);
3001   const base::string16 kUrlSuffix = base::ASCIIToUTF16("/foobar");
3002 
3003   // On a same-document navigation before the URL has been simplified, the URL
3004   // should remain unsimplified after the navigation finishes.
3005 
3006   {
3007     // Set a longer URL to ensure that the full URL stays visible even if it's
3008     // longer than the previous URL.
3009     omnibox_view()->NavigateAndExpectUnelided(
3010         kSimplifiedDomainDisplayUrl + kUrlSuffix, /*is_same_document=*/true,
3011         GURL(), kSimplifiedDomainDisplayUrlScheme);
3012     OmniboxViewViews::ElideAnimation* elide_animation =
3013         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3014     EXPECT_FALSE(elide_animation);
3015   }
3016 
3017   // Simulate a user interaction to elide to the simplified domain.
3018   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3019   OmniboxViewViews::ElideAnimation* elide_animation =
3020       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3021   ASSERT_TRUE(elide_animation);
3022   EXPECT_TRUE(elide_animation->IsAnimating());
3023 
3024   // On a cross-document main-frame navigation, the unsimplified URL should
3025   // remain visible.
3026   {
3027     omnibox_view()->NavigateAndExpectUnelided(
3028         kSimplifiedDomainDisplayUrl, /*is_same_document=*/false, GURL(),
3029         kSimplifiedDomainDisplayUrlScheme);
3030     OmniboxViewViews::ElideAnimation* elide_animation =
3031         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3032     EXPECT_FALSE(elide_animation);
3033   }
3034 
3035   // Simulate another user interaction to elide to the simplified domain, and
3036   // advance the clock all the way through the animation.
3037   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3038   ASSERT_NO_FATAL_FAILURE(
3039       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3040           /*step_ms=*/1000));
3041   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3042       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3043       kSimplifiedDomainDisplayUrlSubdomain,
3044       kSimplifiedDomainDisplayUrlHostnameAndScheme,
3045       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3046 
3047   // On same-document main-frame fragment navigation, the URL should remain
3048   // elided to the simplified domain.
3049   {
3050     omnibox_view()->NavigateAndExpectElided(
3051         GURL(kSimplifiedDomainDisplayUrl + base::ASCIIToUTF16("#foobar")),
3052         /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl),
3053         kSimplifiedDomainDisplayUrlScheme, kSimplifiedDomainDisplayUrlSubdomain,
3054         kSimplifiedDomainDisplayUrlHostnameAndScheme,
3055         kSimplifiedDomainDisplayUrlPath + base::ASCIIToUTF16("#foobar"),
3056         ShouldElideToRegistrableDomain());
3057     OmniboxViewViews::ElideAnimation* elide_animation =
3058         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3059     ASSERT_TRUE(elide_animation);
3060     EXPECT_FALSE(elide_animation->IsAnimating());
3061   }
3062 
3063   // On same-document main-frame non-fragment navigation, the URL shouldn't
3064   // remain elided to the simplified domain.
3065   {
3066     omnibox_view()->NavigateAndExpectUnelided(
3067         kSimplifiedDomainDisplayUrl + kUrlSuffix, /*is_same_document=*/true,
3068         GURL(kSimplifiedDomainDisplayUrl), kSimplifiedDomainDisplayUrlScheme);
3069     OmniboxViewViews::ElideAnimation* elide_animation =
3070         omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3071     EXPECT_FALSE(elide_animation);
3072   }
3073 }
3074 
3075 // Tests that in the hide-on-interaction field trial, a same-document navigation
3076 // cancels a currently-running animation and goes straight to the end state
3077 // (elided to the simplified domain).
TEST_P(OmniboxViewViewsHideOnInteractionTest,SameDocNavigationDuringAnimation)3078 TEST_P(OmniboxViewViewsHideOnInteractionTest,
3079        SameDocNavigationDuringAnimation) {
3080   SetUpSimplifiedDomainTest();
3081   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3082   gfx::Range path_bounds(
3083       kSimplifiedDomainDisplayUrl.find(kSimplifiedDomainDisplayUrlPath),
3084       kSimplifiedDomainDisplayUrl.size());
3085 
3086   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3087                                             /*is_same_document=*/false, GURL(),
3088                                             kSimplifiedDomainDisplayUrlScheme);
3089 
3090   // Simulate a user interaction to begin animating to the simplified domain.
3091   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3092 
3093   // Advance the clock by 1ms until the full URL is no longer showing, but we
3094   // haven't finished eliding to the simplified domain yet. After a
3095   // same-document navigation, we check that the URL has gone straight to the
3096   // end state. In other words, a same-document navigation will cancel a
3097   // currently-running animation but should end up where the animation was
3098   // targeting.
3099   bool is_midway_through_elision = false;
3100   uint32_t step_ms = 1;
3101   while (!is_midway_through_elision) {
3102     ASSERT_NO_FATAL_FAILURE(
3103         omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3104     is_midway_through_elision = IsPartlyThroughSimplifiedDomainElision(
3105         render_text, kSimplifiedDomainDisplayUrl, path_bounds);
3106   }
3107 
3108   omnibox_view()->NavigateAndExpectElided(
3109       GURL(kSimplifiedDomainDisplayUrl),
3110       /*is_same_document=*/true, GURL(kSimplifiedDomainDisplayUrl),
3111       kSimplifiedDomainDisplayUrlScheme, kSimplifiedDomainDisplayUrlSubdomain,
3112       kSimplifiedDomainDisplayUrlHostnameAndScheme,
3113       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain());
3114 
3115   OmniboxViewViews::ElideAnimation* elide_animation =
3116       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3117   ASSERT_TRUE(elide_animation);
3118   EXPECT_FALSE(elide_animation->IsAnimating());
3119 }
3120 
3121 // Tests that gradient mask is set correctly.
TEST_P(OmniboxViewViewsHideOnInteractionTest,GradientMask)3122 TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMask) {
3123   if (base::i18n::IsRTL()) {
3124     // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
3125     // implemented for RTL UI.
3126     return;
3127   }
3128   SetUpSimplifiedDomainTest();
3129   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3130   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3131                                             /*is_same_document=*/false, GURL(),
3132                                             kSimplifiedDomainDisplayUrlScheme);
3133 
3134   // Simulate a user interaction to begin animating to the simplified domain.
3135   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3136   // Advance the clock by 1ms until the full size gradient has been added.
3137   uint32_t step_ms = 1;
3138   int max_gradient_width = OmniboxViewViews::kSmoothingGradientMaxWidth - 1;
3139   while (omnibox_view()->elide_animation_smoothing_rect_right_.width() <
3140          max_gradient_width) {
3141     ASSERT_NO_FATAL_FAILURE(
3142         omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3143   }
3144   // If we are eliding from the left, the other side gradient should also be
3145   // full size at this point, otherwise it should be 0.
3146   if (ShouldElideToRegistrableDomain()) {
3147     EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(),
3148               max_gradient_width);
3149   } else {
3150     EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0);
3151   }
3152 
3153   // Get a bounding box for the unelided section of the URL.
3154   std::vector<gfx::Range> ranges_surrounding_simplified_domain;
3155   gfx::Range simplified_range = omnibox_view()->GetSimplifiedDomainBounds(
3156       &ranges_surrounding_simplified_domain);
3157   gfx::Rect simplified_rect;
3158   for (auto rect : render_text->GetSubstringBounds(simplified_range)) {
3159     simplified_rect.Union(rect - render_text->GetLineOffset(0));
3160   }
3161 
3162   // Advance the animation until both gradients start shrinking.
3163   while (omnibox_view()->elide_animation_smoothing_rect_left_.width() ==
3164              max_gradient_width ||
3165          omnibox_view()->elide_animation_smoothing_rect_right_.width() ==
3166              max_gradient_width) {
3167     ASSERT_NO_FATAL_FAILURE(
3168         omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3169   }
3170   int offset = omnibox_view()
3171                    ->GetElideAfterInteractionAnimationForTesting()
3172                    ->GetCurrentOffsetForTesting();
3173   gfx::Rect display_rect = render_text->display_rect();
3174   // Check the expected size and positions for both gradients.
3175   EXPECT_TRUE(omnibox_view()->elide_animation_smoothing_rect_left_.width() ==
3176                   simplified_rect.x() + offset - 1 ||
3177               omnibox_view()->elide_animation_smoothing_rect_left_.width() ==
3178                   0);
3179   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.x(),
3180             display_rect.x());
3181   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(),
3182             display_rect.right() - (simplified_rect.right() + offset) - 1);
3183   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.x() - 1,
3184             simplified_rect.right() + offset);
3185 }
3186 
3187 // Tests that gradient mask is reset when animation is stopped.
TEST_P(OmniboxViewViewsHideOnInteractionTest,GradientMaskResetAfterStop)3188 TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMaskResetAfterStop) {
3189   if (base::i18n::IsRTL()) {
3190     // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
3191     // implemented for RTL UI.
3192     return;
3193   }
3194   SetUpSimplifiedDomainTest();
3195   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3196                                             /*is_same_document=*/false, GURL(),
3197                                             kSimplifiedDomainDisplayUrlScheme);
3198 
3199   // Simulate a user interaction to begin animating to the simplified domain.
3200   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3201   // Advance animation so it sets the gradient mask, then stop it.
3202   ASSERT_NO_FATAL_FAILURE(
3203       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3204           /*step_ms=*/1000));
3205   omnibox_view()->GetElideAfterInteractionAnimationForTesting()->Stop();
3206 
3207   // Both gradient mask rectangles should have a width of 0 once the animation
3208   // has stopped.
3209   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0);
3210   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), 0);
3211 }
3212 
3213 // Tests that in the hide-on-interaction field trial, a second user interaction
3214 // does not interfere with an animation that is currently running. This is
3215 // similar to SameDocNavigationDuringAnimation except that this test checks that
3216 // a second user interaction (rather than a same-doc navigation) lets the
3217 // animation proceed undisturbed.
TEST_P(OmniboxViewViewsHideOnInteractionTest,UserInteractionDuringAnimation)3218 TEST_P(OmniboxViewViewsHideOnInteractionTest, UserInteractionDuringAnimation) {
3219   SetUpSimplifiedDomainTest();
3220   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3221   gfx::Range path_bounds(
3222       kSimplifiedDomainDisplayUrl.find(kSimplifiedDomainDisplayUrlPath),
3223       kSimplifiedDomainDisplayUrl.size());
3224   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3225                                             /*is_same_document=*/false, GURL(),
3226                                             kSimplifiedDomainDisplayUrlScheme);
3227 
3228   // Simulate a user interaction to begin animating to the simplified domain.
3229   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3230 
3231   // Advance the clock by 1ms until the full URL is no longer showing, but we
3232   // haven't finished eliding to the simplified domain yet. After a subsequent
3233   // user interaction, we check that the URL is still in the same state (midway
3234   // through elision) and that the animation is still running undisturbed. In
3235   // other words, a second user interaction shouldn't change anything when an
3236   // animation is in progress.
3237   bool is_midway_through_elision = false;
3238   uint32_t step_ms = 0;
3239   while (!is_midway_through_elision) {
3240     ASSERT_NO_FATAL_FAILURE(
3241         omnibox_view()->StepSimplifiedDomainInteractionAnimation(++step_ms));
3242     is_midway_through_elision = IsPartlyThroughSimplifiedDomainElision(
3243         render_text, kSimplifiedDomainDisplayUrl, path_bounds);
3244   }
3245   double animation_value = omnibox_view()
3246                                ->GetElideAfterInteractionAnimationForTesting()
3247                                ->GetAnimationForTesting()
3248                                ->GetCurrentValue();
3249 
3250   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3251   OmniboxViewViews::ElideAnimation* elide_animation =
3252       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3253   ASSERT_TRUE(elide_animation);
3254   EXPECT_TRUE(elide_animation->IsAnimating());
3255   EXPECT_EQ(animation_value,
3256             elide_animation->GetAnimationForTesting()->GetCurrentValue());
3257   // The current display text should reflect that the animation in progress: the
3258   // full display URL shouldn't be still visible, but we haven't necessarily
3259   // reached the end state (just the simplified domain visible) yet.
3260   EXPECT_TRUE(IsPartlyThroughSimplifiedDomainElision(
3261       render_text, kSimplifiedDomainDisplayUrl, path_bounds));
3262 }
3263 
3264 // Tests that in the hide-on-interaction field trial, the path is not re-shown
3265 // on subframe navigations.
TEST_P(OmniboxViewViewsHideOnInteractionTest,SubframeNavigations)3266 TEST_P(OmniboxViewViewsHideOnInteractionTest, SubframeNavigations) {
3267   SetUpSimplifiedDomainTest();
3268   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3269                                             /*is_same_document=*/false, GURL(),
3270                                             kSimplifiedDomainDisplayUrlScheme);
3271 
3272   // Simulate a user interaction to elide to the simplified domain, and advance
3273   // the clock all the way through the animation.
3274   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3275   ASSERT_NO_FATAL_FAILURE(
3276       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3277           /*step_ms=*/1000));
3278   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3279       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3280       kSimplifiedDomainDisplayUrlSubdomain,
3281       kSimplifiedDomainDisplayUrlHostnameAndScheme,
3282       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3283 
3284   // On a subframe navigation, the URL should remain elided to a simplified
3285   // domain.
3286   {
3287     content::MockNavigationHandle navigation;
3288     navigation.set_is_same_document(false);
3289     std::unique_ptr<content::WebContents> web_contents =
3290         content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
3291     content::RenderFrameHostTester::For(web_contents->GetMainFrame())
3292         ->InitializeRenderFrameIfNeeded();
3293     content::RenderFrameHost* subframe =
3294         content::RenderFrameHostTester::For(web_contents->GetMainFrame())
3295             ->AppendChild("subframe");
3296     navigation.set_render_frame_host(subframe);
3297     omnibox_view()->DidStartNavigation(&navigation);
3298     ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3299         omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3300         kSimplifiedDomainDisplayUrlSubdomain,
3301         kSimplifiedDomainDisplayUrlHostnameAndScheme,
3302         kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3303     omnibox_view()->DidFinishNavigation(&navigation);
3304     ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3305         omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3306         kSimplifiedDomainDisplayUrlSubdomain,
3307         kSimplifiedDomainDisplayUrlHostnameAndScheme,
3308         kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3309   }
3310 }
3311 
3312 // Tests that in the reveal-on-hover field trial variation, domains are aligned
3313 // to the right (truncated from the left) if the omnibox is too narrow to fit
3314 // the whole domain.
TEST_P(OmniboxViewViewsRevealOnHoverTest,SimplifiedDomainElisionWithNarrowOmnibox)3315 TEST_P(OmniboxViewViewsRevealOnHoverTest,
3316        SimplifiedDomainElisionWithNarrowOmnibox) {
3317   const int kOmniboxWidth = 60;
3318   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3319   gfx::Rect current_bounds = omnibox_view()->GetLocalBounds();
3320   gfx::Rect bounds(current_bounds.x(), current_bounds.y(), kOmniboxWidth,
3321                    current_bounds.height());
3322   omnibox_view()->SetBoundsRect(bounds);
3323   SetUpSimplifiedDomainTest();
3324 
3325   ASSERT_EQ(kSimplifiedDomainDisplayUrl, render_text->GetDisplayText());
3326 
3327   // The omnibox should contain a substring of the domain, aligned to the right.
3328   gfx::Rect hostname_bounds;
3329   for (const auto& rect : render_text->GetSubstringBounds(
3330            gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3331                       kSimplifiedDomainDisplayUrlHostnameAndScheme.size()))) {
3332     hostname_bounds.Union(rect);
3333   }
3334   EXPECT_LT(hostname_bounds.x(), omnibox_view()->GetLocalBounds().x());
3335   EXPECT_FALSE(omnibox_view()->GetLocalBounds().Contains(hostname_bounds));
3336 
3337   // No hover animations should run when the omnibox is too narrow to fit the
3338   // simplified domain.
3339 
3340   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3341   OmniboxViewViews::ElideAnimation* elide_animation =
3342       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
3343   ASSERT_TRUE(elide_animation);
3344   EXPECT_FALSE(elide_animation->IsAnimating());
3345 
3346   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3347   elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
3348   ASSERT_TRUE(elide_animation);
3349   EXPECT_FALSE(elide_animation->IsAnimating());
3350 }
3351 
3352 // Tests that in the reveal-on-hover and hide-on-interaction field trial
3353 // variation, domains are aligned to the right (truncated from the left) if the
3354 // omnibox is too narrow to fit the whole domain.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,SimplifiedDomainElisionWithNarrowOmnibox)3355 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3356        SimplifiedDomainElisionWithNarrowOmnibox) {
3357   const int kOmniboxWidth = 60;
3358   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3359   gfx::Rect current_bounds = omnibox_view()->GetLocalBounds();
3360   gfx::Rect bounds(current_bounds.x(), current_bounds.y(), kOmniboxWidth,
3361                    current_bounds.height());
3362   omnibox_view()->SetBoundsRect(bounds);
3363   SetUpSimplifiedDomainTest();
3364 
3365   content::MockNavigationHandle navigation;
3366   navigation.set_is_same_document(false);
3367   omnibox_view()->DidFinishNavigation(&navigation);
3368 
3369   ASSERT_EQ(kSimplifiedDomainDisplayUrl, render_text->GetDisplayText());
3370 
3371   // The omnibox should contain a substring of the domain, aligned to the right.
3372   gfx::Rect hostname_bounds;
3373   for (const auto& rect : render_text->GetSubstringBounds(
3374            gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3375                       kSimplifiedDomainDisplayUrlHostnameAndScheme.size()))) {
3376     hostname_bounds.Union(rect);
3377   }
3378   EXPECT_LT(hostname_bounds.x(), omnibox_view()->GetLocalBounds().x());
3379   EXPECT_FALSE(omnibox_view()->GetLocalBounds().Contains(hostname_bounds));
3380 }
3381 
3382 // Tests that in the hide-on-interaction field trial variation, the path is
3383 // faded out after omnibox focus and blur.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,HideOnInteractionAfterFocusAndBlur)3384 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3385        HideOnInteractionAfterFocusAndBlur) {
3386   SetUpSimplifiedDomainTest();
3387   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3388                                             /*is_same_document=*/false, GURL(),
3389                                             kSimplifiedDomainDisplayUrlScheme);
3390   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3391 
3392   // Simulate a user interaction to fade out the path.
3393   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3394   ASSERT_NO_FATAL_FAILURE(
3395       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3396           /*step_ms=*/1000));
3397   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3398       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3399       kSimplifiedDomainDisplayUrlSubdomain,
3400       kSimplifiedDomainDisplayUrlHostnameAndScheme,
3401       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3402 
3403   // After focus, the URL should be fully unelided.
3404   omnibox_view()->OnFocus();
3405   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3406       render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
3407   EXPECT_NE(SK_ColorTRANSPARENT,
3408             omnibox_view()->GetLatestColorForRange(
3409                 gfx::Range(0, omnibox_view()->GetText().size())));
3410   EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3411                        kSimplifiedDomainDisplayUrlHostnameAndScheme.size()),
3412             omnibox_view()->emphasis_range());
3413 
3414   // After blur, the URL should return to the same state as page load: only
3415   // scheme and trivial subdomains elided.
3416   omnibox_view()->OnBlur();
3417   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3418       render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3419                               kSimplifiedDomainDisplayUrl.size())));
3420   EXPECT_NE(SK_ColorTRANSPARENT,
3421             omnibox_view()->GetLatestColorForRange(
3422                 gfx::Range(0, omnibox_view()->GetText().size())));
3423   EXPECT_EQ(gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3424                        kSimplifiedDomainDisplayUrlHostnameAndScheme.size()),
3425             omnibox_view()->emphasis_range());
3426 
3427   // After a post-blur user interaction, the URL should animate to the
3428   // simplified domain.
3429   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3430   OmniboxViewViews::ElideAnimation* elide_animation =
3431       omnibox_view()->GetElideAfterInteractionAnimationForTesting();
3432   EXPECT_TRUE(elide_animation->IsAnimating());
3433 }
3434 
3435 // Tests that in the hide-on-interaction field trial variation, the URL is
3436 // aligned as appropriate for LTR and RTL UIs during the different stages
3437 // of elision.
3438 // Regression test for crbug.com/1114332
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,URLPositionWithHideOnInteraction)3439 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3440        URLPositionWithHideOnInteraction) {
3441   SetUpSimplifiedDomainTest();
3442   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
3443   // Initially the display rect of the render text matches the omnibox bounds,
3444   // store a copy of it.
3445   gfx::Rect omnibox_bounds(render_text->display_rect());
3446 
3447   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3448                                             /*is_same_document=*/false, GURL(),
3449                                             kSimplifiedDomainDisplayUrlScheme);
3450 
3451   // Simulate a user interaction to fade out the path.
3452   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3453   ASSERT_NO_FATAL_FAILURE(
3454       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3455           /*step_ms=*/1000));
3456   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3457       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3458       kSimplifiedDomainDisplayUrlSubdomain,
3459       kSimplifiedDomainDisplayUrlHostnameAndScheme,
3460       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3461 
3462   // Check the URL is right aligned if the UI is RTL, or left aligned if it is
3463   // LTR.
3464   if (base::i18n::IsRTL()) {
3465     EXPECT_EQ(render_text->display_rect().x(),
3466               omnibox_bounds.right() - render_text->display_rect().width());
3467   } else {
3468     EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x());
3469   }
3470 
3471   // Call OnFocus to trigger unelision.
3472   omnibox_view()->OnFocus();
3473   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3474       render_text, gfx::Range(0, kSimplifiedDomainDisplayUrl.size())));
3475 
3476   // Check alignment again
3477   if (base::i18n::IsRTL()) {
3478     EXPECT_EQ(render_text->display_rect().x(),
3479               omnibox_bounds.right() - render_text->display_rect().width());
3480   } else {
3481     EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x());
3482   }
3483 
3484   // Call OnBlur to return to the state on page load.
3485   omnibox_view()->OnBlur();
3486   ASSERT_NO_FATAL_FAILURE(ExpectUnelidedFromSimplifiedDomain(
3487       render_text, gfx::Range(kSimplifiedDomainDisplayUrlScheme.size(),
3488                               kSimplifiedDomainDisplayUrl.size())));
3489 
3490   // Check alignment again
3491   if (base::i18n::IsRTL()) {
3492     EXPECT_EQ(render_text->display_rect().x(),
3493               omnibox_bounds.right() - render_text->display_rect().width());
3494   } else {
3495     EXPECT_EQ(render_text->display_rect().x(), omnibox_bounds.x());
3496   }
3497 }
3498 
3499 // Tests that the last gradient mask from a previous animation is no longer
3500 // visible when starting a new animation.
TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,NoStaleGradientMask)3501 TEST_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
3502        NoStaleGradientMask) {
3503   if (base::i18n::IsRTL()) {
3504     // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
3505     // implemented for RTL UI.
3506     return;
3507   }
3508   SetUpSimplifiedDomainTest();
3509   omnibox_view()->NavigateAndExpectUnelided(kSimplifiedDomainDisplayUrl,
3510                                             /*is_same_document=*/false, GURL(),
3511                                             kSimplifiedDomainDisplayUrlScheme);
3512 
3513   // Simulate a user interaction to begin animating to the simplified domain.
3514   omnibox_view()->DidGetUserInteraction(blink::WebKeyboardEvent());
3515   ASSERT_NO_FATAL_FAILURE(
3516       omnibox_view()->StepSimplifiedDomainInteractionAnimation(
3517           /*step_ms=*/1000));
3518 
3519   // Hover over the omnibox to trigger unelide animation.
3520   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3521   ASSERT_NO_FATAL_FAILURE(
3522       omnibox_view()->StepSimplifiedDomainHoverAnimation(/*step_ms=*/1000));
3523 
3524   // Both gradient mask rectangles will be full sized at this point
3525   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(),
3526             OmniboxViewViews::kSmoothingGradientMaxWidth - 1);
3527   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(),
3528             OmniboxViewViews::kSmoothingGradientMaxWidth - 1);
3529 
3530   // Select the text in the omnibox, then click on the page, this will trigger
3531   // an elision with no animation.
3532   omnibox_view()->SelectAll(false);
3533   blink::WebMouseEvent event;
3534   event.SetType(blink::WebInputEvent::Type::kMouseDown);
3535   omnibox_view()->DidGetUserInteraction(event);
3536 
3537   // Hover over the omnibox to trigger the unelide animation.
3538   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3539 
3540   // Even though the unelide animation hasn't advanced, the gradient mask
3541   // rectangles should have been reset.
3542   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(), 0);
3543   EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_right_.width(), 0);
3544 }
3545 
3546 // Tests that in the reveal-on-hover field trial variation (without
3547 // hide-on-interaction), the path is faded back in after focus, then blur, then
3548 // hover.
3549 // TODO(crbug.com/1115551): Test is flaky.
TEST_P(OmniboxViewViewsRevealOnHoverTest,DISABLED_AfterBlur)3550 TEST_P(OmniboxViewViewsRevealOnHoverTest, DISABLED_AfterBlur) {
3551   SetUpSimplifiedDomainTest();
3552 
3553   // Focus and blur the omnibox, then hover over it. The URL should unelide.
3554   omnibox_view()->OnFocus();
3555   omnibox_view()->OnBlur();
3556   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3557       omnibox_view(), kSimplifiedDomainDisplayUrlScheme,
3558       kSimplifiedDomainDisplayUrlSubdomain,
3559       kSimplifiedDomainDisplayUrlHostnameAndScheme,
3560       kSimplifiedDomainDisplayUrlPath, ShouldElideToRegistrableDomain()));
3561   omnibox_view()->OnMouseMoved(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
3562   OmniboxViewViews::ElideAnimation* elide_animation =
3563       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
3564   ASSERT_TRUE(elide_animation);
3565   EXPECT_TRUE(elide_animation->IsAnimating());
3566 }
3567 
3568 // Tests that registrable domain elision properly handles the case when the
3569 // registrable domain appears as a subdomain, e.g. test.com.test.com.
TEST_P(OmniboxViewViewsRevealOnHoverTest,RegistrableDomainRepeated)3570 TEST_P(OmniboxViewViewsRevealOnHoverTest, RegistrableDomainRepeated) {
3571   // This test only applies when the URL is elided to the registrable domain.
3572   if (!ShouldElideToRegistrableDomain())
3573     return;
3574 
3575   const base::string16 kRepeatedRegistrableDomainUrl =
3576       base::ASCIIToUTF16("https://example.com.example.com/foo");
3577   gfx::Range registrable_domain_and_path_range(
3578       20 /* "https://www.example.com." */,
3579       kRepeatedRegistrableDomainUrl.size());
3580 
3581   UpdateDisplayURL(kRepeatedRegistrableDomainUrl);
3582   // Call OnThemeChanged() to create the animations.
3583   omnibox_view()->OnThemeChanged();
3584 
3585   ASSERT_NO_FATAL_FAILURE(ExpectElidedToSimplifiedDomain(
3586       omnibox_view(), base::ASCIIToUTF16("https://"),
3587       base::ASCIIToUTF16("example.com."),
3588       base::ASCIIToUTF16("https://example.com.example.com"),
3589       base::ASCIIToUTF16("/foo"), ShouldElideToRegistrableDomain()));
3590 
3591   // Check that the domain is elided up to the second instance of "example.com",
3592   // not the first.
3593   gfx::Rect registrable_domain_and_path;
3594   for (const auto& rect : omnibox_view()->GetRenderText()->GetSubstringBounds(
3595            registrable_domain_and_path_range)) {
3596     registrable_domain_and_path.Union(rect);
3597   }
3598   EXPECT_EQ(omnibox_view()->GetRenderText()->display_rect().x(),
3599             registrable_domain_and_path.x());
3600 }
3601