1// Copyright (c) 2012 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 "base/strings/utf_string_conversions.h" 6#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" 7#include "chrome/browser/search_engines/template_url_service_factory.h" 8#include "chrome/browser/ui/omnibox/omnibox_edit_controller.h" 9#include "chrome/browser/ui/omnibox/omnibox_edit_model.h" 10#include "chrome/browser/ui/omnibox/omnibox_view.h" 11#include "chrome/browser/ui/toolbar/test_toolbar_model.h" 12#include "chrome/test/base/testing_profile.h" 13#include "testing/gtest/include/gtest/gtest.h" 14 15using base::ASCIIToUTF16; 16using base::UTF8ToUTF16; 17using content::WebContents; 18 19namespace { 20 21class TestingOmniboxView : public OmniboxView { 22 public: 23 explicit TestingOmniboxView(OmniboxEditController* controller) 24 : OmniboxView(NULL, controller, NULL) {} 25 26 // OmniboxView: 27 virtual void SaveStateToTab(WebContents* tab) OVERRIDE {} 28 virtual void OnTabChanged(const WebContents* web_contents) OVERRIDE {} 29 virtual void Update() OVERRIDE {} 30 virtual void UpdatePlaceholderText() OVERRIDE {} 31 virtual void OpenMatch(const AutocompleteMatch& match, 32 WindowOpenDisposition disposition, 33 const GURL& alternate_nav_url, 34 const base::string16& pasted_text, 35 size_t selected_line) OVERRIDE {} 36 virtual base::string16 GetText() const OVERRIDE { return text_; } 37 virtual void SetUserText(const base::string16& text, 38 const base::string16& display_text, 39 bool update_popup) OVERRIDE { 40 text_ = display_text; 41 } 42 virtual void SetWindowTextAndCaretPos(const base::string16& text, 43 size_t caret_pos, 44 bool update_popup, 45 bool notify_text_changed) OVERRIDE { 46 text_ = text; 47 } 48 virtual void SetForcedQuery() OVERRIDE {} 49 virtual bool IsSelectAll() const OVERRIDE { return false; } 50 virtual bool DeleteAtEndPressed() OVERRIDE { return false; } 51 virtual void GetSelectionBounds(size_t* start, size_t* end) const OVERRIDE {} 52 virtual void SelectAll(bool reversed) OVERRIDE {} 53 virtual void RevertAll() OVERRIDE {} 54 virtual void UpdatePopup() OVERRIDE {} 55 virtual void SetFocus() OVERRIDE {} 56 virtual void ApplyCaretVisibility() OVERRIDE {} 57 virtual void OnTemporaryTextMaybeChanged( 58 const base::string16& display_text, 59 bool save_original_selection, 60 bool notify_text_changed) OVERRIDE { 61 text_ = display_text; 62 } 63 virtual bool OnInlineAutocompleteTextMaybeChanged( 64 const base::string16& display_text, size_t user_text_length) OVERRIDE { 65 const bool text_changed = text_ != display_text; 66 text_ = display_text; 67 inline_autocomplete_text_ = display_text.substr(user_text_length); 68 return text_changed; 69 } 70 virtual void OnInlineAutocompleteTextCleared() OVERRIDE { 71 inline_autocomplete_text_.clear(); 72 } 73 virtual void OnRevertTemporaryText() OVERRIDE {} 74 virtual void OnBeforePossibleChange() OVERRIDE {} 75 virtual bool OnAfterPossibleChange() OVERRIDE { return false; } 76 virtual gfx::NativeView GetNativeView() const OVERRIDE { return NULL; } 77 virtual gfx::NativeView GetRelativeWindowForPopup() const OVERRIDE { 78 return NULL; 79 } 80 virtual void SetGrayTextAutocompletion( 81 const base::string16& input) OVERRIDE {} 82 virtual base::string16 GetGrayTextAutocompletion() const OVERRIDE { 83 return base::string16(); 84 } 85 virtual int GetTextWidth() const OVERRIDE { return 0; } 86 virtual int GetWidth() const OVERRIDE { return 0; } 87 virtual bool IsImeComposing() const OVERRIDE { return false; } 88 virtual int GetOmniboxTextLength() const OVERRIDE { return 0; } 89 virtual void EmphasizeURLComponents() OVERRIDE { } 90 91 const base::string16& inline_autocomplete_text() const { 92 return inline_autocomplete_text_; 93 } 94 95 private: 96 base::string16 text_; 97 base::string16 inline_autocomplete_text_; 98 99 DISALLOW_COPY_AND_ASSIGN(TestingOmniboxView); 100}; 101 102class TestingOmniboxEditController : public OmniboxEditController { 103 public: 104 explicit TestingOmniboxEditController(ToolbarModel* toolbar_model) 105 : OmniboxEditController(NULL), 106 toolbar_model_(toolbar_model) { 107 } 108 109 protected: 110 // OmniboxEditController: 111 virtual void Update(const content::WebContents* contents) OVERRIDE {} 112 virtual void OnChanged() OVERRIDE {} 113 virtual void OnSetFocus() OVERRIDE {} 114 virtual void ShowURL() OVERRIDE {} 115 virtual void HideURL() OVERRIDE {} 116 virtual void EndOriginChipAnimations(bool cancel_fade) OVERRIDE {} 117 virtual InstantController* GetInstant() OVERRIDE { return NULL; } 118 virtual WebContents* GetWebContents() OVERRIDE { return NULL; } 119 virtual ToolbarModel* GetToolbarModel() OVERRIDE { return toolbar_model_; } 120 virtual const ToolbarModel* GetToolbarModel() const OVERRIDE { 121 return toolbar_model_; 122 } 123 124 private: 125 ToolbarModel* toolbar_model_; 126 127 DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController); 128}; 129 130} // namespace 131 132class AutocompleteEditTest : public ::testing::Test { 133 public: 134 TestToolbarModel* toolbar_model() { return &toolbar_model_; } 135 136 private: 137 TestToolbarModel toolbar_model_; 138}; 139 140// Tests various permutations of AutocompleteModel::AdjustTextForCopy. 141TEST_F(AutocompleteEditTest, AdjustTextForCopy) { 142 struct Data { 143 const char* perm_text; 144 const int sel_start; 145 const bool is_all_selected; 146 const char* input; 147 const char* expected_output; 148 const bool write_url; 149 const char* expected_url; 150 const bool extracted_search_terms; 151 } input[] = { 152 // Test that http:// is inserted if all text is selected. 153 { "a.de/b", 0, true, "a.de/b", "http://a.de/b", true, "http://a.de/b", 154 false }, 155 156 // Test that http:// is inserted if the host is selected. 157 { "a.de/b", 0, false, "a.de/", "http://a.de/", true, "http://a.de/", 158 false }, 159 160 // Tests that http:// is inserted if the path is modified. 161 { "a.de/b", 0, false, "a.de/c", "http://a.de/c", true, "http://a.de/c", 162 false }, 163 164 // Tests that http:// isn't inserted if the host is modified. 165 { "a.de/b", 0, false, "a.com/b", "a.com/b", false, "", false }, 166 167 // Tests that http:// isn't inserted if the start of the selection is 1. 168 { "a.de/b", 1, false, "a.de/b", "a.de/b", false, "", false }, 169 170 // Tests that http:// isn't inserted if a portion of the host is selected. 171 { "a.de/", 0, false, "a.d", "a.d", false, "", false }, 172 173 // Tests that http:// isn't inserted for an https url after the user nukes 174 // https. 175 { "https://a.com/", 0, false, "a.com/", "a.com/", false, "", false }, 176 177 // Tests that http:// isn't inserted if the user adds to the host. 178 { "a.de/", 0, false, "a.de.com/", "a.de.com/", false, "", false }, 179 180 // Tests that we don't get double http if the user manually inserts http. 181 { "a.de/", 0, false, "http://a.de/", "http://a.de/", true, "http://a.de/", 182 false }, 183 184 // Makes sure intranet urls get 'http://' prefixed to them. 185 { "b/foo", 0, true, "b/foo", "http://b/foo", true, "http://b/foo", false }, 186 187 // Verifies a search term 'foo' doesn't end up with http. 188 { "www.google.com/search?", 0, false, "foo", "foo", false, "", false }, 189 190 // Makes sure extracted search terms are not modified. 191 { "www.google.com/webhp?", 0, true, "hello world", "hello world", false, 192 "", true }, 193 }; 194 TestingOmniboxEditController controller(toolbar_model()); 195 TestingOmniboxView view(&controller); 196 TestingProfile profile; 197 // NOTE: The TemplateURLService must be created before the 198 // AutocompleteClassifier so that the SearchProvider gets a non-NULL 199 // TemplateURLService at construction time. 200 TemplateURLServiceFactory::GetInstance()->SetTestingFactory( 201 &profile, &TemplateURLServiceFactory::BuildInstanceFor); 202 AutocompleteClassifierFactory::GetInstance()->SetTestingFactory( 203 &profile, &AutocompleteClassifierFactory::BuildInstanceFor); 204 OmniboxEditModel model(&view, &controller, &profile); 205 206 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input); ++i) { 207 toolbar_model()->set_text(ASCIIToUTF16(input[i].perm_text)); 208 model.UpdatePermanentText(); 209 210 toolbar_model()->set_perform_search_term_replacement( 211 input[i].extracted_search_terms); 212 213 base::string16 result = ASCIIToUTF16(input[i].input); 214 GURL url; 215 bool write_url; 216 model.AdjustTextForCopy(input[i].sel_start, input[i].is_all_selected, 217 &result, &url, &write_url); 218 EXPECT_EQ(ASCIIToUTF16(input[i].expected_output), result) << "@: " << i; 219 EXPECT_EQ(input[i].write_url, write_url) << " @" << i; 220 if (write_url) 221 EXPECT_EQ(input[i].expected_url, url.spec()) << " @" << i; 222 } 223} 224 225TEST_F(AutocompleteEditTest, InlineAutocompleteText) { 226 TestingOmniboxEditController controller(toolbar_model()); 227 TestingOmniboxView view(&controller); 228 TestingProfile profile; 229 // NOTE: The TemplateURLService must be created before the 230 // AutocompleteClassifier so that the SearchProvider gets a non-NULL 231 // TemplateURLService at construction time. 232 TemplateURLServiceFactory::GetInstance()->SetTestingFactory( 233 &profile, &TemplateURLServiceFactory::BuildInstanceFor); 234 AutocompleteClassifierFactory::GetInstance()->SetTestingFactory( 235 &profile, &AutocompleteClassifierFactory::BuildInstanceFor); 236 OmniboxEditModel model(&view, &controller, &profile); 237 238 // Test if the model updates the inline autocomplete text in the view. 239 EXPECT_EQ(base::string16(), view.inline_autocomplete_text()); 240 model.SetUserText(UTF8ToUTF16("he")); 241 model.OnPopupDataChanged(UTF8ToUTF16("llo"), NULL, base::string16(), false); 242 EXPECT_EQ(UTF8ToUTF16("hello"), view.GetText()); 243 EXPECT_EQ(UTF8ToUTF16("llo"), view.inline_autocomplete_text()); 244 245 model.OnAfterPossibleChange(UTF8ToUTF16("he"), UTF8ToUTF16("hel"), 3, 3, 246 false, true, false, true); 247 EXPECT_EQ(base::string16(), view.inline_autocomplete_text()); 248 model.OnPopupDataChanged(UTF8ToUTF16("lo"), NULL, base::string16(), false); 249 EXPECT_EQ(UTF8ToUTF16("hello"), view.GetText()); 250 EXPECT_EQ(UTF8ToUTF16("lo"), view.inline_autocomplete_text()); 251 252 model.Revert(); 253 EXPECT_EQ(base::string16(), view.GetText()); 254 EXPECT_EQ(base::string16(), view.inline_autocomplete_text()); 255 256 model.SetUserText(UTF8ToUTF16("he")); 257 model.OnPopupDataChanged(UTF8ToUTF16("llo"), NULL, base::string16(), false); 258 EXPECT_EQ(UTF8ToUTF16("hello"), view.GetText()); 259 EXPECT_EQ(UTF8ToUTF16("llo"), view.inline_autocomplete_text()); 260 261 model.AcceptTemporaryTextAsUserText(); 262 EXPECT_EQ(UTF8ToUTF16("hello"), view.GetText()); 263 EXPECT_EQ(base::string16(), view.inline_autocomplete_text()); 264} 265