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