1// Copyright (c) 2011 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/format_macros.h" 6#include "base/string_util.h" 7#include "base/stringprintf.h" 8#include "base/utf_string_conversions.h" 9#include "chrome/browser/autocomplete/autocomplete.h" 10#include "chrome/browser/autocomplete/autocomplete_edit.h" 11#include "chrome/browser/autocomplete/autocomplete_edit_view.h" 12#include "chrome/browser/autocomplete/autocomplete_match.h" 13#include "chrome/browser/autocomplete/autocomplete_popup_model.h" 14#include "chrome/browser/extensions/extension_apitest.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/search_engines/template_url.h" 17#include "chrome/browser/search_engines/template_url_model.h" 18#include "chrome/browser/ui/browser.h" 19#include "chrome/browser/ui/browser_window.h" 20#include "chrome/browser/ui/omnibox/location_bar.h" 21#include "chrome/common/url_constants.h" 22#include "chrome/test/ui_test_utils.h" 23#include "content/common/notification_type.h" 24 25#if defined(TOOLKIT_GTK) 26#include "chrome/browser/ui/gtk/browser_window_gtk.h" 27#endif 28 29// Basic test is flaky on ChromeOS. 30// http://crbug.com/52929 31#if defined(OS_CHROMEOS) 32#define MAYBE_Basic FLAKY_Basic 33#else 34#define MAYBE_Basic Basic 35#endif 36 37namespace { 38 39string16 AutocompleteResultAsString(const AutocompleteResult& result) { 40 std::string output(base::StringPrintf("{%" PRIuS "} ", result.size())); 41 for (size_t i = 0; i < result.size(); ++i) { 42 AutocompleteMatch match = result.match_at(i); 43 std::string provider_name = match.provider->name(); 44 output.append(base::StringPrintf("[\"%s\" by \"%s\"] ", 45 UTF16ToUTF8(match.contents).c_str(), 46 provider_name.c_str())); 47 } 48 return UTF8ToUTF16(output); 49} 50 51} // namespace 52 53class OmniboxApiTest : public ExtensionApiTest { 54 protected: 55 LocationBar* GetLocationBar() const { 56 return browser()->window()->GetLocationBar(); 57 } 58 59 AutocompleteController* GetAutocompleteController() const { 60 return GetLocationBar()->location_entry()->model()->popup_model()-> 61 autocomplete_controller(); 62 } 63 64 void WaitForTemplateURLModelToLoad() { 65 TemplateURLModel* model = 66 browser()->profile()->GetTemplateURLModel(); 67 model->Load(); 68 if (!model->loaded()) { 69 ui_test_utils::WaitForNotification( 70 NotificationType::TEMPLATE_URL_MODEL_LOADED); 71 } 72 } 73 74 void WaitForAutocompleteDone(AutocompleteController* controller) { 75 while (!controller->done()) { 76 ui_test_utils::WaitForNotification( 77 NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_READY); 78 } 79 } 80}; 81 82IN_PROC_BROWSER_TEST_F(OmniboxApiTest, MAYBE_Basic) { 83#if defined(TOOLKIT_GTK) 84 // Disable the timer because, on Lucid at least, it triggers resize/move 85 // behavior in the browser window, which dismisses the autocomplete popup 86 // before the results can be read. 87 static_cast<BrowserWindowGtk*>( 88 browser()->window())->DisableDebounceTimerForTests(true); 89#endif 90 91 ASSERT_TRUE(test_server()->Start()); 92 ASSERT_TRUE(RunExtensionTest("omnibox")) << message_; 93 94 // The results depend on the TemplateURLModel being loaded. Make sure it is 95 // loaded so that the autocomplete results are consistent. 96 WaitForTemplateURLModelToLoad(); 97 98 LocationBar* location_bar = GetLocationBar(); 99 AutocompleteController* autocomplete_controller = GetAutocompleteController(); 100 101 // Test that our extension's keyword is suggested to us when we partially type 102 // it. 103 { 104 autocomplete_controller->Start( 105 ASCIIToUTF16("keywor"), string16(), true, false, true, 106 AutocompleteInput::ALL_MATCHES); 107 108 WaitForAutocompleteDone(autocomplete_controller); 109 EXPECT_TRUE(autocomplete_controller->done()); 110 EXPECT_EQ(std::wstring(), location_bar->GetInputString()); 111 EXPECT_EQ(string16(), location_bar->location_entry()->GetText()); 112 EXPECT_TRUE(location_bar->location_entry()->IsSelectAll()); 113 114 // First result should be to search for what was typed, second should be to 115 // enter "extension keyword" mode. 116 const AutocompleteResult& result = autocomplete_controller->result(); 117 ASSERT_EQ(2U, result.size()) << AutocompleteResultAsString(result); 118 AutocompleteMatch match = result.match_at(0); 119 EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type); 120 EXPECT_FALSE(match.deletable); 121 122 match = result.match_at(1); 123 ASSERT_TRUE(match.template_url); 124 EXPECT_TRUE(match.template_url->IsExtensionKeyword()); 125 EXPECT_EQ(ASCIIToUTF16("keyword"), match.template_url->keyword()); 126 } 127 128 // Test that our extension can send suggestions back to us. 129 { 130 autocomplete_controller->Start( 131 ASCIIToUTF16("keyword suggestio"), string16(), true, false, true, 132 AutocompleteInput::ALL_MATCHES); 133 134 WaitForAutocompleteDone(autocomplete_controller); 135 EXPECT_TRUE(autocomplete_controller->done()); 136 137 // First result should be to invoke the keyword with what we typed, 2-4 138 // should be to invoke with suggestions from the extension, and the last 139 // should be to search for what we typed. 140 const AutocompleteResult& result = autocomplete_controller->result(); 141 ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result); 142 143 ASSERT_TRUE(result.match_at(0).template_url); 144 EXPECT_EQ(ASCIIToUTF16("keyword suggestio"), 145 result.match_at(0).fill_into_edit); 146 EXPECT_EQ(ASCIIToUTF16("keyword suggestion1"), 147 result.match_at(1).fill_into_edit); 148 EXPECT_EQ(ASCIIToUTF16("keyword suggestion2"), 149 result.match_at(2).fill_into_edit); 150 EXPECT_EQ(ASCIIToUTF16("keyword suggestion3"), 151 result.match_at(3).fill_into_edit); 152 153 string16 description = 154 ASCIIToUTF16("Description with style: <match>, [dim], (url till end)"); 155 EXPECT_EQ(description, result.match_at(1).contents); 156 ASSERT_EQ(6u, result.match_at(1).contents_class.size()); 157 158 EXPECT_EQ(0u, 159 result.match_at(1).contents_class[0].offset); 160 EXPECT_EQ(ACMatchClassification::NONE, 161 result.match_at(1).contents_class[0].style); 162 163 EXPECT_EQ(description.find('<'), 164 result.match_at(1).contents_class[1].offset); 165 EXPECT_EQ(ACMatchClassification::MATCH, 166 result.match_at(1).contents_class[1].style); 167 168 EXPECT_EQ(description.find('>') + 1u, 169 result.match_at(1).contents_class[2].offset); 170 EXPECT_EQ(ACMatchClassification::NONE, 171 result.match_at(1).contents_class[2].style); 172 173 EXPECT_EQ(description.find('['), 174 result.match_at(1).contents_class[3].offset); 175 EXPECT_EQ(ACMatchClassification::DIM, 176 result.match_at(1).contents_class[3].style); 177 178 EXPECT_EQ(description.find(']') + 1u, 179 result.match_at(1).contents_class[4].offset); 180 EXPECT_EQ(ACMatchClassification::NONE, 181 result.match_at(1).contents_class[4].style); 182 183 EXPECT_EQ(description.find('('), 184 result.match_at(1).contents_class[5].offset); 185 EXPECT_EQ(ACMatchClassification::URL, 186 result.match_at(1).contents_class[5].style); 187 188 AutocompleteMatch match = result.match_at(4); 189 EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type); 190 EXPECT_FALSE(match.deletable); 191 } 192 193 { 194 ResultCatcher catcher; 195 autocomplete_controller->Start( 196 ASCIIToUTF16("keyword command"), string16(), true, false, true, 197 AutocompleteInput::ALL_MATCHES); 198 location_bar->AcceptInput(); 199 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 200 } 201} 202