• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/file_util.h"
6 #include "base/path_service.h"
7 #include "base/string_util.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/autocomplete/autocomplete.h"
10 #include "chrome/browser/autocomplete/autocomplete_match.h"
11 #include "chrome/browser/autocomplete/history_contents_provider.h"
12 #include "chrome/browser/bookmarks/bookmark_model.h"
13 #include "chrome/browser/history/history.h"
14 #include "chrome/test/testing_browser_process.h"
15 #include "chrome/test/testing_browser_process_test.h"
16 #include "chrome/test/testing_profile.h"
17 #include "content/browser/browser_thread.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 
20 using base::Time;
21 using base::TimeDelta;
22 
23 namespace {
24 
25 struct TestEntry {
26   const char* url;
27   const char* title;
28   const char* body;
29 } test_entries[] = {
30   {"http://www.google.com/1", "PAGEONE 1",   "FOO some body text"},
31   {"http://www.google.com/2", "PAGEONE 2",   "FOO some more blah blah"},
32   {"http://www.google.com/3", "PAGETHREE 3", "BAR some hello world for you"},
33 };
34 
35 class HistoryContentsProviderTest : public TestingBrowserProcessTest,
36                                     public ACProviderListener {
37  public:
HistoryContentsProviderTest()38   HistoryContentsProviderTest()
39       : ui_thread_(BrowserThread::UI, &message_loop_),
40         file_thread_(BrowserThread::FILE, &message_loop_) {}
41 
RunQuery(const AutocompleteInput & input,bool minimal_changes)42   void RunQuery(const AutocompleteInput& input,
43                 bool minimal_changes) {
44     provider_->Start(input, minimal_changes);
45 
46     // When we're waiting for asynchronous messages, we have to spin the message
47     // loop. This will be exited in the OnProviderUpdate function when complete.
48     if (input.matches_requested() == AutocompleteInput::ALL_MATCHES)
49       MessageLoop::current()->Run();
50   }
51 
matches() const52   const ACMatches& matches() const { return provider_->matches(); }
53 
profile() const54   TestingProfile* profile() const { return profile_.get(); }
55 
provider() const56   HistoryContentsProvider* provider() const { return provider_.get(); }
57 
58  private:
59   // testing::Test
SetUp()60   virtual void SetUp() {
61     profile_.reset(new TestingProfile());
62     profile_->CreateHistoryService(false, false);
63 
64     HistoryService* history_service =
65         profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
66 
67     // Populate history.
68     for (size_t i = 0; i < arraysize(test_entries); i++) {
69       // We need the ID scope and page ID so that the visit tracker can find it.
70       // We just use the index for the page ID below.
71       const void* id_scope = reinterpret_cast<void*>(1);
72       GURL url(test_entries[i].url);
73 
74       // Add everything in order of time. We don't want to have a time that
75       // is "right now" or it will nondeterministically appear in the results.
76       Time t = Time::Now() - TimeDelta::FromDays(arraysize(test_entries) + i);
77 
78       history_service->AddPage(url, t, id_scope, i, GURL(),
79                                PageTransition::LINK, history::RedirectList(),
80                                history::SOURCE_BROWSED, false);
81       history_service->SetPageTitle(url, UTF8ToUTF16(test_entries[i].title));
82       history_service->SetPageContents(url, UTF8ToUTF16(test_entries[i].body));
83     }
84 
85     provider_ = new HistoryContentsProvider(this, profile_.get());
86   }
87 
TearDown()88   virtual void TearDown() {
89     provider_ = NULL;
90     profile_.reset(NULL);
91   }
92 
93   // ACProviderListener
OnProviderUpdate(bool updated_matches)94   virtual void OnProviderUpdate(bool updated_matches) {
95     // We must quit the message loop (if running) to return control to the test.
96     // Note, calling Quit() directly will checkfail if the loop isn't running,
97     // so we post a task, which is safe for either case.
98     MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
99   }
100 
101   MessageLoopForUI message_loop_;
102   BrowserThread ui_thread_;
103   BrowserThread file_thread_;
104 
105   scoped_ptr<TestingProfile> profile_;
106   scoped_refptr<HistoryContentsProvider> provider_;
107 };
108 
TEST_F(HistoryContentsProviderTest,Body)109 TEST_F(HistoryContentsProviderTest, Body) {
110   AutocompleteInput input(ASCIIToUTF16("FOO"), string16(), true, false, true,
111                           AutocompleteInput::ALL_MATCHES);
112   RunQuery(input, false);
113 
114   // The results should be the first two pages, in decreasing order.
115   const ACMatches& m = matches();
116   ASSERT_EQ(2U, m.size());
117   EXPECT_EQ(test_entries[0].url, m[0].destination_url.spec());
118   EXPECT_STREQ(test_entries[0].title, UTF16ToUTF8(m[0].description).c_str());
119   EXPECT_EQ(test_entries[1].url, m[1].destination_url.spec());
120   EXPECT_STREQ(test_entries[1].title, UTF16ToUTF8(m[1].description).c_str());
121 }
122 
TEST_F(HistoryContentsProviderTest,Title)123 TEST_F(HistoryContentsProviderTest, Title) {
124   AutocompleteInput input(ASCIIToUTF16("PAGEONE"), string16(), true, false,
125                           true, AutocompleteInput::ALL_MATCHES);
126   RunQuery(input, false);
127 
128   // The results should be the first two pages.
129   const ACMatches& m = matches();
130   ASSERT_EQ(2U, m.size());
131   EXPECT_EQ(test_entries[0].url, m[0].destination_url.spec());
132   EXPECT_STREQ(test_entries[0].title, UTF16ToUTF8(m[0].description).c_str());
133   EXPECT_EQ(test_entries[1].url, m[1].destination_url.spec());
134   EXPECT_STREQ(test_entries[1].title, UTF16ToUTF8(m[1].description).c_str());
135 }
136 
137 // The "minimal changes" flag should mean that we don't re-query the DB.
TEST_F(HistoryContentsProviderTest,MinimalChanges)138 TEST_F(HistoryContentsProviderTest, MinimalChanges) {
139   // A minimal changes request when there have been no real queries should
140   // give us no results.
141   AutocompleteInput sync_input(ASCIIToUTF16("PAGEONE"), string16(), true, false,
142                                true, AutocompleteInput::SYNCHRONOUS_MATCHES);
143   RunQuery(sync_input, true);
144   const ACMatches& m1 = matches();
145   EXPECT_EQ(0U, m1.size());
146 
147   // Now do a "regular" query to get the results.
148   AutocompleteInput async_input(ASCIIToUTF16("PAGEONE"), string16(), true,
149                                 false, true, AutocompleteInput::ALL_MATCHES);
150   RunQuery(async_input, false);
151   const ACMatches& m2 = matches();
152   EXPECT_EQ(2U, m2.size());
153 
154   // Now do a minimal one where we want synchronous results, and the results
155   // should still be there.
156   RunQuery(sync_input, true);
157   const ACMatches& m3 = matches();
158   EXPECT_EQ(2U, m3.size());
159 }
160 
161 // Tests that the BookmarkModel is queried correctly.
TEST_F(HistoryContentsProviderTest,Bookmarks)162 TEST_F(HistoryContentsProviderTest, Bookmarks) {
163   profile()->CreateBookmarkModel(false);
164   profile()->BlockUntilBookmarkModelLoaded();
165 
166   // Add a bookmark.
167   GURL bookmark_url("http://www.google.com/4");
168   profile()->GetBookmarkModel()->SetURLStarred(bookmark_url,
169                                                ASCIIToUTF16("bar"), true);
170 
171   // Ask for synchronous. This should only get the bookmark.
172   AutocompleteInput sync_input(ASCIIToUTF16("bar"), string16(), true, false,
173                                true, AutocompleteInput::SYNCHRONOUS_MATCHES);
174   RunQuery(sync_input, false);
175   const ACMatches& m1 = matches();
176   ASSERT_EQ(1U, m1.size());
177   EXPECT_EQ(bookmark_url, m1[0].destination_url);
178   EXPECT_EQ(ASCIIToUTF16("bar"), m1[0].description);
179   EXPECT_TRUE(m1[0].starred);
180 
181   // Ask for async. We should get the bookmark immediately.
182   AutocompleteInput async_input(ASCIIToUTF16("bar"), string16(), true, false,
183                                 true, AutocompleteInput::ALL_MATCHES);
184   provider()->Start(async_input, false);
185   const ACMatches& m2 = matches();
186   ASSERT_EQ(1U, m2.size());
187   EXPECT_EQ(bookmark_url, m2[0].destination_url);
188 
189   // Run the message loop (needed for async history results).
190   MessageLoop::current()->Run();
191 
192   // We should have two urls now, bookmark_url and http://www.google.com/3.
193   const ACMatches& m3 = matches();
194   ASSERT_EQ(2U, m3.size());
195   if (bookmark_url == m3[0].destination_url) {
196     EXPECT_EQ("http://www.google.com/3", m3[1].destination_url.spec());
197   } else {
198     EXPECT_EQ(bookmark_url, m3[1].destination_url);
199     EXPECT_EQ("http://www.google.com/3", m3[0].destination_url.spec());
200   }
201 }
202 
203 // Tests that history is deleted properly.
TEST_F(HistoryContentsProviderTest,DeleteMatch)204 TEST_F(HistoryContentsProviderTest, DeleteMatch) {
205   AutocompleteInput input(ASCIIToUTF16("bar"), string16(), true, false, true,
206                           AutocompleteInput::ALL_MATCHES);
207   RunQuery(input, false);
208 
209   // Query; the result should be the third page.
210   const ACMatches& m = matches();
211   ASSERT_EQ(1U, m.size());
212   EXPECT_EQ(test_entries[2].url, m[0].destination_url.spec());
213 
214   // Now delete the match and ensure it was removed.
215   provider()->DeleteMatch(m[0]);
216   EXPECT_EQ(0U, matches().size());
217 }
218 
219 // Tests deleting starred results from history, not affecting bookmarks/matches.
TEST_F(HistoryContentsProviderTest,DeleteStarredMatch)220 TEST_F(HistoryContentsProviderTest, DeleteStarredMatch) {
221   profile()->CreateBookmarkModel(false);
222   profile()->BlockUntilBookmarkModelLoaded();
223 
224   // Bookmark a history item.
225   GURL bookmark_url(test_entries[2].url);
226   profile()->GetBookmarkModel()->SetURLStarred(bookmark_url,
227                                                ASCIIToUTF16("bar"), true);
228 
229   // Get the match to delete its history
230   AutocompleteInput input(ASCIIToUTF16("bar"), string16(), true, false, true,
231                           AutocompleteInput::ALL_MATCHES);
232   RunQuery(input, false);
233   const ACMatches& m = matches();
234   ASSERT_EQ(1U, m.size());
235 
236   // Now delete the match and ensure it was *not* removed.
237   provider()->DeleteMatch(m[0]);
238   EXPECT_EQ(1U, matches().size());
239 
240   // Run a query that would only match history (but the history is deleted)
241   AutocompleteInput you_input(ASCIIToUTF16("you"), string16(), true, false,
242                               true, AutocompleteInput::ALL_MATCHES);
243   RunQuery(you_input, false);
244   EXPECT_EQ(0U, matches().size());
245 
246   // Run a query that matches the bookmark
247   RunQuery(input, false);
248   EXPECT_EQ(1U, matches().size());
249 }
250 
251 }  // namespace
252