• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_factory.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "components/search_engines/template_url_service.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 
26 class 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 
shortcuts_map() const44   const ShortcutsBackend::ShortcutMap& shortcuts_map() const {
45     return backend_->shortcuts_map();
46   }
changed_notified() const47   bool changed_notified() const { return changed_notified_; }
set_changed_notified(bool 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 
ShortcutsBackendTest()74 ShortcutsBackendTest::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 
81 history::ShortcutsDatabase::Shortcut::MatchCore
MatchCoreForTesting(const std::string & url,const std::string & contents_class,const std::string & description_class,AutocompleteMatch::Type type)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 
SetSearchProvider()99 void 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 
SetUp()112 void 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 
TearDown()127 void ShortcutsBackendTest::TearDown() {
128   backend_->RemoveObserver(this);
129   db_thread_.Stop();
130 }
131 
OnShortcutsLoaded()132 void ShortcutsBackendTest::OnShortcutsLoaded() {
133   load_notified_ = true;
134   base::MessageLoop::current()->Quit();
135 }
136 
OnShortcutsChanged()137 void ShortcutsBackendTest::OnShortcutsChanged() {
138   changed_notified_ = true;
139 }
140 
InitBackend()141 void 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 
AddShortcut(const history::ShortcutsDatabase::Shortcut & shortcut)152 bool ShortcutsBackendTest::AddShortcut(
153     const history::ShortcutsDatabase::Shortcut& shortcut) {
154   return backend_->AddShortcut(shortcut);
155 }
156 
UpdateShortcut(const history::ShortcutsDatabase::Shortcut & shortcut)157 bool ShortcutsBackendTest::UpdateShortcut(
158     const history::ShortcutsDatabase::Shortcut& shortcut) {
159   return backend_->UpdateShortcut(shortcut);
160 }
161 
DeleteShortcutsWithURL(const GURL & url)162 bool ShortcutsBackendTest::DeleteShortcutsWithURL(const GURL& url) {
163   return backend_->DeleteShortcutsWithURL(url);
164 }
165 
DeleteShortcutsWithIDs(const history::ShortcutsDatabase::ShortcutIDs & deleted_ids)166 bool 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.
TEST_F(ShortcutsBackendTest,SanitizeMatchCore)176 TEST_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 
TEST_F(ShortcutsBackendTest,EntitySuggestionTest)220 TEST_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 
TEST_F(ShortcutsBackendTest,AddAndUpdateShortcut)247 TEST_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 
TEST_F(ShortcutsBackendTest,DeleteShortcuts)274 TEST_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