shortcuts_backend_unittest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 "chrome/browser/autocomplete/shortcuts_backend.h" 6 7#include "base/files/scoped_temp_dir.h" 8#include "base/message_loop/message_loop.h" 9#include "base/path_service.h" 10#include "base/strings/stringprintf.h" 11#include "base/strings/utf_string_conversions.h" 12#include "chrome/browser/autocomplete/shortcuts_backend_factory.h" 13#include "chrome/browser/history/shortcuts_database.h" 14#include "chrome/browser/search_engines/template_url_service.h" 15#include "chrome/browser/search_engines/template_url_service_factory.h" 16#include "chrome/test/base/testing_profile.h" 17#include "chrome/test/base/ui_test_utils.h" 18#include "content/public/test/test_browser_thread.h" 19#include "sql/statement.h" 20 21#include "testing/gtest/include/gtest/gtest.h" 22 23 24// ShortcutsBackendTest ------------------------------------------------------- 25 26class ShortcutsBackendTest : public testing::Test, 27 public ShortcutsBackend::ShortcutsBackendObserver { 28 public: 29 ShortcutsBackendTest(); 30 31 history::ShortcutsDatabase::Shortcut::MatchCore MatchCoreForTesting( 32 const std::string& url, 33 const std::string& contents_class = std::string(), 34 const std::string& description_class = std::string(), 35 AutocompleteMatch::Type type = AutocompleteMatchType::URL_WHAT_YOU_TYPED); 36 void SetSearchProvider(); 37 38 virtual void SetUp(); 39 virtual void TearDown(); 40 41 virtual void OnShortcutsLoaded() OVERRIDE; 42 virtual void OnShortcutsChanged() OVERRIDE; 43 44 const ShortcutsBackend::ShortcutMap& shortcuts_map() const { 45 return backend_->shortcuts_map(); 46 } 47 bool changed_notified() const { return changed_notified_; } 48 void set_changed_notified(bool changed_notified) { 49 changed_notified_ = changed_notified; 50 } 51 52 void InitBackend(); 53 bool AddShortcut(const history::ShortcutsDatabase::Shortcut& shortcut); 54 bool UpdateShortcut(const history::ShortcutsDatabase::Shortcut& shortcut); 55 bool DeleteShortcutsWithURL(const GURL& url); 56 bool DeleteShortcutsWithIDs( 57 const history::ShortcutsDatabase::ShortcutIDs& deleted_ids); 58 59 protected: 60 TestingProfile profile_; 61 62 private: 63 scoped_refptr<ShortcutsBackend> backend_; 64 base::MessageLoopForUI ui_message_loop_; 65 content::TestBrowserThread ui_thread_; 66 content::TestBrowserThread db_thread_; 67 68 bool load_notified_; 69 bool changed_notified_; 70 71 DISALLOW_COPY_AND_ASSIGN(ShortcutsBackendTest); 72}; 73 74ShortcutsBackendTest::ShortcutsBackendTest() 75 : ui_thread_(content::BrowserThread::UI, &ui_message_loop_), 76 db_thread_(content::BrowserThread::DB), 77 load_notified_(false), 78 changed_notified_(false) { 79} 80 81history::ShortcutsDatabase::Shortcut::MatchCore 82 ShortcutsBackendTest::MatchCoreForTesting( 83 const std::string& url, 84 const std::string& contents_class, 85 const std::string& description_class, 86 AutocompleteMatch::Type type) { 87 AutocompleteMatch match(NULL, 0, 0, type); 88 match.destination_url = GURL(url); 89 match.contents = base::ASCIIToUTF16("test"); 90 match.contents_class = 91 AutocompleteMatch::ClassificationsFromString(contents_class); 92 match.description_class = 93 AutocompleteMatch::ClassificationsFromString(description_class); 94 match.search_terms_args.reset( 95 new TemplateURLRef::SearchTermsArgs(match.contents)); 96 return ShortcutsBackend::MatchToMatchCore(match, &profile_); 97} 98 99void ShortcutsBackendTest::SetSearchProvider() { 100 TemplateURLService* template_url_service = 101 TemplateURLServiceFactory::GetForProfile(&profile_); 102 TemplateURLData data; 103 data.SetURL("http://foo.com/search?bar={searchTerms}"); 104 data.SetKeyword(base::UTF8ToUTF16("foo")); 105 106 TemplateURL* template_url = new TemplateURL(data); 107 // Takes ownership of |template_url|. 108 template_url_service->Add(template_url); 109 template_url_service->SetUserSelectedDefaultSearchProvider(template_url); 110} 111 112void ShortcutsBackendTest::SetUp() { 113 db_thread_.Start(); 114 ShortcutsBackendFactory::GetInstance()->SetTestingFactoryAndUse( 115 &profile_, &ShortcutsBackendFactory::BuildProfileForTesting); 116 backend_ = ShortcutsBackendFactory::GetForProfile(&profile_); 117 ASSERT_TRUE(backend_.get()); 118 backend_->AddObserver(this); 119 120 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( 121 &profile_, &TemplateURLServiceFactory::BuildInstanceFor); 122 TemplateURLService* template_url_service = 123 TemplateURLServiceFactory::GetForProfile(&profile_); 124 ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service); 125} 126 127void ShortcutsBackendTest::TearDown() { 128 backend_->RemoveObserver(this); 129 db_thread_.Stop(); 130} 131 132void ShortcutsBackendTest::OnShortcutsLoaded() { 133 load_notified_ = true; 134 base::MessageLoop::current()->Quit(); 135} 136 137void ShortcutsBackendTest::OnShortcutsChanged() { 138 changed_notified_ = true; 139} 140 141void ShortcutsBackendTest::InitBackend() { 142 ShortcutsBackend* backend = 143 ShortcutsBackendFactory::GetForProfile(&profile_).get(); 144 ASSERT_TRUE(backend); 145 ASSERT_FALSE(load_notified_); 146 ASSERT_FALSE(backend_->initialized()); 147 base::MessageLoop::current()->Run(); 148 EXPECT_TRUE(load_notified_); 149 EXPECT_TRUE(backend_->initialized()); 150} 151 152bool ShortcutsBackendTest::AddShortcut( 153 const history::ShortcutsDatabase::Shortcut& shortcut) { 154 return backend_->AddShortcut(shortcut); 155} 156 157bool ShortcutsBackendTest::UpdateShortcut( 158 const history::ShortcutsDatabase::Shortcut& shortcut) { 159 return backend_->UpdateShortcut(shortcut); 160} 161 162bool ShortcutsBackendTest::DeleteShortcutsWithURL(const GURL& url) { 163 return backend_->DeleteShortcutsWithURL(url); 164} 165 166bool ShortcutsBackendTest::DeleteShortcutsWithIDs( 167 const history::ShortcutsDatabase::ShortcutIDs& deleted_ids) { 168 return backend_->DeleteShortcutsWithIDs(deleted_ids); 169} 170 171 172// Actual tests --------------------------------------------------------------- 173 174// Verifies that creating MatchCores strips classifications and sanitizes match 175// types. 176TEST_F(ShortcutsBackendTest, SanitizeMatchCore) { 177 struct { 178 std::string input_contents_class; 179 std::string input_description_class; 180 AutocompleteMatch::Type input_type; 181 std::string output_contents_class; 182 std::string output_description_class; 183 AutocompleteMatch::Type output_type; 184 } cases[] = { 185 { "0,1,4,0", "0,3,4,1", AutocompleteMatchType::URL_WHAT_YOU_TYPED, 186 "0,1,4,0", "0,1", AutocompleteMatchType::HISTORY_URL }, 187 { "0,3,5,1", "0,2,5,0", AutocompleteMatchType::NAVSUGGEST, 188 "0,1", "0,0", AutocompleteMatchType::HISTORY_URL }, 189 { "0,1", "0,0,11,2,15,0", 190 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, 191 "0,1", "0,0", AutocompleteMatchType::SEARCH_HISTORY }, 192 { "0,1", "0,0", AutocompleteMatchType::SEARCH_SUGGEST, 193 "0,1", "0,0", AutocompleteMatchType::SEARCH_HISTORY }, 194 { "0,1", "0,0", AutocompleteMatchType::SEARCH_SUGGEST_ENTITY, 195 "", "", AutocompleteMatchType::SEARCH_HISTORY }, 196 { "0,1", "0,0", AutocompleteMatchType::SEARCH_SUGGEST_INFINITE, 197 "", "", AutocompleteMatchType::SEARCH_HISTORY }, 198 { "0,1", "0,0", AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED, 199 "", "", AutocompleteMatchType::SEARCH_HISTORY }, 200 { "0,1", "0,0", AutocompleteMatchType::SEARCH_SUGGEST_PROFILE, 201 "", "", AutocompleteMatchType::SEARCH_HISTORY }, 202 { "0,1", "0,0", AutocompleteMatchType::SEARCH_SUGGEST_ANSWER, 203 "", "", AutocompleteMatchType::SEARCH_HISTORY }, 204 }; 205 206 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 207 history::ShortcutsDatabase::Shortcut::MatchCore match_core( 208 MatchCoreForTesting(std::string(), cases[i].input_contents_class, 209 cases[i].input_description_class, 210 cases[i].input_type)); 211 EXPECT_EQ(cases[i].output_contents_class, match_core.contents_class) 212 << ":i:" << i << ":type:" << cases[i].input_type; 213 EXPECT_EQ(cases[i].output_description_class, match_core.description_class) 214 << ":i:" << i << ":type:" << cases[i].input_type; 215 EXPECT_EQ(cases[i].output_type, match_core.type) 216 << ":i:" << i << ":type:" << cases[i].input_type; 217 } 218} 219 220TEST_F(ShortcutsBackendTest, EntitySuggestionTest) { 221 SetSearchProvider(); 222 AutocompleteMatch match; 223 match.fill_into_edit = base::UTF8ToUTF16("franklin d roosevelt"); 224 match.type = AutocompleteMatchType::SEARCH_SUGGEST_ENTITY; 225 match.contents = base::UTF8ToUTF16("roosevelt"); 226 match.contents_class = 227 AutocompleteMatch::ClassificationsFromString("0,0,5,2"); 228 match.description = base::UTF8ToUTF16("Franklin D. Roosevelt"); 229 match.description_class = AutocompleteMatch::ClassificationsFromString("0,4"); 230 match.destination_url = GURL( 231 "http://www.foo.com/search?bar=franklin+d+roosevelt&gs_ssp=1234"); 232 match.keyword = base::UTF8ToUTF16("foo"); 233 match.search_terms_args.reset( 234 new TemplateURLRef::SearchTermsArgs(match.fill_into_edit)); 235 236 history::ShortcutsDatabase::Shortcut::MatchCore match_core = 237 ShortcutsBackend::MatchToMatchCore(match, &profile_); 238 239 EXPECT_EQ("http://foo.com/search?bar=franklin+d+roosevelt", 240 match_core.destination_url.spec()); 241 EXPECT_EQ(match.fill_into_edit, match_core.contents); 242 EXPECT_EQ("0,0", match_core.contents_class); 243 EXPECT_EQ(base::string16(), match_core.description); 244 EXPECT_TRUE(match_core.description_class.empty()); 245} 246 247TEST_F(ShortcutsBackendTest, AddAndUpdateShortcut) { 248 InitBackend(); 249 EXPECT_FALSE(changed_notified()); 250 251 history::ShortcutsDatabase::Shortcut shortcut( 252 "BD85DBA2-8C29-49F9-84AE-48E1E90880DF", base::ASCIIToUTF16("goog"), 253 MatchCoreForTesting("http://www.google.com"), base::Time::Now(), 100); 254 EXPECT_TRUE(AddShortcut(shortcut)); 255 EXPECT_TRUE(changed_notified()); 256 ShortcutsBackend::ShortcutMap::const_iterator shortcut_iter( 257 shortcuts_map().find(shortcut.text)); 258 ASSERT_TRUE(shortcut_iter != shortcuts_map().end()); 259 EXPECT_EQ(shortcut.id, shortcut_iter->second.id); 260 EXPECT_EQ(shortcut.match_core.contents, 261 shortcut_iter->second.match_core.contents); 262 263 set_changed_notified(false); 264 shortcut.match_core.contents = base::ASCIIToUTF16("Google Web Search"); 265 EXPECT_TRUE(UpdateShortcut(shortcut)); 266 EXPECT_TRUE(changed_notified()); 267 shortcut_iter = shortcuts_map().find(shortcut.text); 268 ASSERT_TRUE(shortcut_iter != shortcuts_map().end()); 269 EXPECT_EQ(shortcut.id, shortcut_iter->second.id); 270 EXPECT_EQ(shortcut.match_core.contents, 271 shortcut_iter->second.match_core.contents); 272} 273 274TEST_F(ShortcutsBackendTest, DeleteShortcuts) { 275 InitBackend(); 276 history::ShortcutsDatabase::Shortcut shortcut1( 277 "BD85DBA2-8C29-49F9-84AE-48E1E90880DF", base::ASCIIToUTF16("goog"), 278 MatchCoreForTesting("http://www.google.com"), base::Time::Now(), 100); 279 EXPECT_TRUE(AddShortcut(shortcut1)); 280 281 history::ShortcutsDatabase::Shortcut shortcut2( 282 "BD85DBA2-8C29-49F9-84AE-48E1E90880E0", base::ASCIIToUTF16("gle"), 283 MatchCoreForTesting("http://www.google.com"), base::Time::Now(), 100); 284 EXPECT_TRUE(AddShortcut(shortcut2)); 285 286 history::ShortcutsDatabase::Shortcut shortcut3( 287 "BD85DBA2-8C29-49F9-84AE-48E1E90880E1", base::ASCIIToUTF16("sp"), 288 MatchCoreForTesting("http://www.sport.com"), base::Time::Now(), 10); 289 EXPECT_TRUE(AddShortcut(shortcut3)); 290 291 history::ShortcutsDatabase::Shortcut shortcut4( 292 "BD85DBA2-8C29-49F9-84AE-48E1E90880E2", base::ASCIIToUTF16("mov"), 293 MatchCoreForTesting("http://www.film.com"), base::Time::Now(), 10); 294 EXPECT_TRUE(AddShortcut(shortcut4)); 295 296 ASSERT_EQ(4U, shortcuts_map().size()); 297 EXPECT_EQ(shortcut1.id, shortcuts_map().find(shortcut1.text)->second.id); 298 EXPECT_EQ(shortcut2.id, shortcuts_map().find(shortcut2.text)->second.id); 299 EXPECT_EQ(shortcut3.id, shortcuts_map().find(shortcut3.text)->second.id); 300 EXPECT_EQ(shortcut4.id, shortcuts_map().find(shortcut4.text)->second.id); 301 302 EXPECT_TRUE(DeleteShortcutsWithURL(shortcut1.match_core.destination_url)); 303 304 ASSERT_EQ(2U, shortcuts_map().size()); 305 EXPECT_EQ(0U, shortcuts_map().count(shortcut1.text)); 306 EXPECT_EQ(0U, shortcuts_map().count(shortcut2.text)); 307 const ShortcutsBackend::ShortcutMap::const_iterator shortcut3_iter( 308 shortcuts_map().find(shortcut3.text)); 309 ASSERT_TRUE(shortcut3_iter != shortcuts_map().end()); 310 EXPECT_EQ(shortcut3.id, shortcut3_iter->second.id); 311 const ShortcutsBackend::ShortcutMap::const_iterator shortcut4_iter( 312 shortcuts_map().find(shortcut4.text)); 313 ASSERT_TRUE(shortcut4_iter != shortcuts_map().end()); 314 EXPECT_EQ(shortcut4.id, shortcut4_iter->second.id); 315 316 history::ShortcutsDatabase::ShortcutIDs deleted_ids; 317 deleted_ids.push_back(shortcut3.id); 318 deleted_ids.push_back(shortcut4.id); 319 EXPECT_TRUE(DeleteShortcutsWithIDs(deleted_ids)); 320 321 ASSERT_EQ(0U, shortcuts_map().size()); 322} 323