NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / bookmarks / bookmark_index_unittest.cc
blobf80c294a59edfb4657989061ca03601d9fa0be36
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.
5 #include "chrome/browser/bookmarks/bookmark_index.h"
7 #include <string>
8 #include <vector>
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/bookmarks/bookmark_model.h"
16 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
17 #include "chrome/browser/bookmarks/bookmark_test_helpers.h"
18 #include "chrome/browser/bookmarks/bookmark_title_match.h"
19 #include "chrome/browser/history/history_service.h"
20 #include "chrome/browser/history/history_service_factory.h"
21 #include "chrome/browser/history/url_database.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using base::ASCIIToUTF16;
28 class BookmarkIndexTest : public testing::Test {
29 public:
30 BookmarkIndexTest() : model_(new BookmarkModel(NULL)) {}
32 void AddBookmarksWithTitles(const char** titles, size_t count) {
33 std::vector<std::string> title_vector;
34 for (size_t i = 0; i < count; ++i)
35 title_vector.push_back(titles[i]);
36 AddBookmarksWithTitles(title_vector);
39 void AddBookmarksWithTitles(const std::vector<std::string>& titles) {
40 GURL url("about:blank");
41 for (size_t i = 0; i < titles.size(); ++i)
42 model_->AddURL(model_->other_node(), static_cast<int>(i),
43 ASCIIToUTF16(titles[i]), url);
46 void ExpectMatches(const std::string& query,
47 const char** expected_titles,
48 size_t expected_count) {
49 std::vector<std::string> title_vector;
50 for (size_t i = 0; i < expected_count; ++i)
51 title_vector.push_back(expected_titles[i]);
52 ExpectMatches(query, title_vector);
55 void ExpectMatches(const std::string& query,
56 const std::vector<std::string>& expected_titles) {
57 std::vector<BookmarkTitleMatch> matches;
58 model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16(query), 1000, &matches);
59 ASSERT_EQ(expected_titles.size(), matches.size());
60 for (size_t i = 0; i < expected_titles.size(); ++i) {
61 bool found = false;
62 for (size_t j = 0; j < matches.size(); ++j) {
63 if (ASCIIToUTF16(expected_titles[i]) == matches[j].node->GetTitle()) {
64 matches.erase(matches.begin() + j);
65 found = true;
66 break;
69 ASSERT_TRUE(found);
73 void ExtractMatchPositions(const std::string& string,
74 BookmarkTitleMatch::MatchPositions* matches) {
75 std::vector<std::string> match_strings;
76 base::SplitString(string, ':', &match_strings);
77 for (size_t i = 0; i < match_strings.size(); ++i) {
78 std::vector<std::string> chunks;
79 base::SplitString(match_strings[i], ',', &chunks);
80 ASSERT_EQ(2U, chunks.size());
81 matches->push_back(BookmarkTitleMatch::MatchPosition());
82 int chunks0, chunks1;
83 base::StringToInt(chunks[0], &chunks0);
84 base::StringToInt(chunks[1], &chunks1);
85 matches->back().first = chunks0;
86 matches->back().second = chunks1;
90 void ExpectMatchPositions(
91 const std::string& query,
92 const BookmarkTitleMatch::MatchPositions& expected_positions) {
93 std::vector<BookmarkTitleMatch> matches;
94 model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16(query), 1000, &matches);
95 ASSERT_EQ(1U, matches.size());
96 const BookmarkTitleMatch& match = matches[0];
97 ASSERT_EQ(expected_positions.size(), match.match_positions.size());
98 for (size_t i = 0; i < expected_positions.size(); ++i) {
99 EXPECT_EQ(expected_positions[i].first, match.match_positions[i].first);
100 EXPECT_EQ(expected_positions[i].second, match.match_positions[i].second);
104 protected:
105 scoped_ptr<BookmarkModel> model_;
107 private:
108 DISALLOW_COPY_AND_ASSIGN(BookmarkIndexTest);
111 // Various permutations with differing input, queries and output that exercises
112 // all query paths.
113 TEST_F(BookmarkIndexTest, Tests) {
114 struct TestData {
115 const std::string input;
116 const std::string query;
117 const std::string expected;
118 } data[] = {
119 // Trivial test case of only one term, exact match.
120 { "a;b", "A", "a" },
122 // Prefix match, one term.
123 { "abcd;abc;b", "abc", "abcd;abc" },
125 // Prefix match, multiple terms.
126 { "abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg"},
128 // Exact and prefix match.
129 { "ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef"},
131 // Exact and prefix match.
132 { "ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
133 "ab cde ghi",
134 "ab cdef ghij"},
136 // Title with term multiple times.
137 { "ab ab", "ab", "ab ab"},
139 // Make sure quotes don't do a prefix match.
140 { "think", "\"thi\"", ""},
142 // Prefix matches against multiple candidates.
143 { "abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4"},
145 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
146 std::vector<std::string> titles;
147 base::SplitString(data[i].input, ';', &titles);
148 AddBookmarksWithTitles(titles);
150 std::vector<std::string> expected;
151 if (!data[i].expected.empty())
152 base::SplitString(data[i].expected, ';', &expected);
154 ExpectMatches(data[i].query, expected);
156 model_.reset(new BookmarkModel(NULL));
160 // Makes sure match positions are updated appropriately.
161 TEST_F(BookmarkIndexTest, MatchPositions) {
162 struct TestData {
163 const std::string title;
164 const std::string query;
165 const std::string expected;
166 } data[] = {
167 // Trivial test case of only one term, exact match.
168 { "a", "A", "0,1" },
169 { "foo bar", "bar", "4,7" },
170 { "fooey bark", "bar foo", "0,3:6,9"},
171 // Non-trivial tests.
172 { "foobar foo", "foobar foo", "0,6:7,10" },
173 { "foobar foo", "foo foobar", "0,6:7,10" },
174 { "foobar foobar", "foobar foo", "0,6:7,13" },
175 { "foobar foobar", "foo foobar", "0,6:7,13" },
177 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
178 std::vector<std::string> titles;
179 titles.push_back(data[i].title);
180 AddBookmarksWithTitles(titles);
182 BookmarkTitleMatch::MatchPositions expected_matches;
183 ExtractMatchPositions(data[i].expected, &expected_matches);
184 ExpectMatchPositions(data[i].query, expected_matches);
186 model_.reset(new BookmarkModel(NULL));
190 // Makes sure index is updated when a node is removed.
191 TEST_F(BookmarkIndexTest, Remove) {
192 const char* input[] = { "a", "b" };
193 AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));
195 // Remove the node and make sure we don't get back any results.
196 model_->Remove(model_->other_node(), 0);
197 ExpectMatches("A", NULL, 0U);
200 // Makes sure index is updated when a node's title is changed.
201 TEST_F(BookmarkIndexTest, ChangeTitle) {
202 const char* input[] = { "a", "b" };
203 AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));
205 // Remove the node and make sure we don't get back any results.
206 const char* expected[] = { "blah" };
207 model_->SetTitle(model_->other_node()->GetChild(0), ASCIIToUTF16("blah"));
208 ExpectMatches("BlAh", expected, ARRAYSIZE_UNSAFE(expected));
211 // Makes sure no more than max queries is returned.
212 TEST_F(BookmarkIndexTest, HonorMax) {
213 const char* input[] = { "abcd", "abcde" };
214 AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));
216 std::vector<BookmarkTitleMatch> matches;
217 model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16("ABc"), 1, &matches);
218 EXPECT_EQ(1U, matches.size());
221 // Makes sure if the lower case string of a bookmark title is more characters
222 // than the upper case string no match positions are returned.
223 TEST_F(BookmarkIndexTest, EmptyMatchOnMultiwideLowercaseString) {
224 const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0,
225 base::WideToUTF16(L"\u0130 i"),
226 GURL("http://www.google.com"));
228 std::vector<BookmarkTitleMatch> matches;
229 model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16("i"), 100, &matches);
230 ASSERT_EQ(1U, matches.size());
231 EXPECT_TRUE(matches[0].node == n1);
232 EXPECT_TRUE(matches[0].match_positions.empty());
235 TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
236 // This ensures MessageLoop::current() will exist, which is needed by
237 // TestingProfile::BlockUntilHistoryProcessesPendingRequests().
238 content::TestBrowserThreadBundle thread_bundle;
240 TestingProfile profile;
241 ASSERT_TRUE(profile.CreateHistoryService(true, false));
242 profile.BlockUntilHistoryProcessesPendingRequests();
243 profile.CreateBookmarkModel(true);
245 BookmarkModel* model = BookmarkModelFactory::GetForProfile(&profile);
246 test::WaitForBookmarkModelToLoad(model);
248 HistoryService* const history_service =
249 HistoryServiceFactory::GetForProfile(&profile, Profile::EXPLICIT_ACCESS);
251 history::URLDatabase* url_db = history_service->InMemoryDatabase();
253 struct TestData {
254 const GURL url;
255 const char* title;
256 const int typed_count;
257 } data[] = {
258 { GURL("http://www.google.com/"), "Google", 100 },
259 { GURL("http://maps.google.com/"), "Google Maps", 40 },
260 { GURL("http://docs.google.com/"), "Google Docs", 50 },
261 { GURL("http://reader.google.com/"), "Google Reader", 80 },
264 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
265 history::URLRow info(data[i].url);
266 info.set_title(base::UTF8ToUTF16(data[i].title));
267 info.set_typed_count(data[i].typed_count);
268 // Populate the InMemoryDatabase....
269 url_db->AddURL(info);
270 // Populate the BookmarkIndex.
271 model->AddURL(model->other_node(), i, base::UTF8ToUTF16(data[i].title),
272 data[i].url);
275 // Check that the InMemoryDatabase stored the URLs properly.
276 history::URLRow result1;
277 url_db->GetRowForURL(data[0].url, &result1);
278 EXPECT_EQ(data[0].title, base::UTF16ToUTF8(result1.title()));
280 history::URLRow result2;
281 url_db->GetRowForURL(data[1].url, &result2);
282 EXPECT_EQ(data[1].title, base::UTF16ToUTF8(result2.title()));
284 history::URLRow result3;
285 url_db->GetRowForURL(data[2].url, &result3);
286 EXPECT_EQ(data[2].title, base::UTF16ToUTF8(result3.title()));
288 history::URLRow result4;
289 url_db->GetRowForURL(data[3].url, &result4);
290 EXPECT_EQ(data[3].title, base::UTF16ToUTF8(result4.title()));
292 // Populate match nodes.
293 std::vector<BookmarkTitleMatch> matches;
294 model->GetBookmarksWithTitlesMatching(ASCIIToUTF16("google"), 4, &matches);
296 // The resulting order should be:
297 // 1. Google (google.com) 100
298 // 2. Google Reader (google.com/reader) 80
299 // 3. Google Docs (docs.google.com) 50
300 // 4. Google Maps (maps.google.com) 40
301 EXPECT_EQ(4, static_cast<int>(matches.size()));
302 EXPECT_EQ(data[0].url, matches[0].node->url());
303 EXPECT_EQ(data[3].url, matches[1].node->url());
304 EXPECT_EQ(data[2].url, matches[2].node->url());
305 EXPECT_EQ(data[1].url, matches[3].node->url());
307 matches.clear();
308 // Select top two matches.
309 model->GetBookmarksWithTitlesMatching(ASCIIToUTF16("google"), 2, &matches);
311 EXPECT_EQ(2, static_cast<int>(matches.size()));
312 EXPECT_EQ(data[0].url, matches[0].node->url());
313 EXPECT_EQ(data[3].url, matches[1].node->url());