Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(506)

Side by Side Diff: components/bookmarks/core/browser/bookmark_index_unittest.cc

Issue 284893003: Move bookmarks/core/... to bookmarks/... (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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 "components/bookmarks/core/browser/bookmark_index.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/macros.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 "components/bookmarks/core/browser/bookmark_match.h"
16 #include "components/bookmarks/core/browser/bookmark_model.h"
17 #include "components/bookmarks/core/test/bookmark_test_helpers.h"
18 #include "components/bookmarks/core/test/test_bookmark_client.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 using base::ASCIIToUTF16;
22
23 namespace {
24
25 class BookmarkClientMock : public test::TestBookmarkClient {
26 public:
27 BookmarkClientMock(const std::map<GURL, int>& typed_count_map)
28 : typed_count_map_(typed_count_map) {}
29
30 virtual bool SupportsTypedCountForNodes() OVERRIDE { return true; }
31
32 virtual void GetTypedCountForNodes(
33 const NodeSet& nodes,
34 NodeTypedCountPairs* node_typed_count_pairs) OVERRIDE {
35 for (NodeSet::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
36 const BookmarkNode* node = *it;
37 std::map<GURL, int>::const_iterator found =
38 typed_count_map_.find(node->url());
39 if (found == typed_count_map_.end())
40 continue;
41
42 node_typed_count_pairs->push_back(std::make_pair(node, found->second));
43 }
44 }
45
46 private:
47 const std::map<GURL, int> typed_count_map_;
48
49 DISALLOW_COPY_AND_ASSIGN(BookmarkClientMock);
50 };
51
52 }
53
54 class BookmarkIndexTest : public testing::Test {
55 public:
56 BookmarkIndexTest() : model_(client_.CreateModel(false)) {}
57
58 typedef std::pair<std::string, std::string> TitleAndURL;
59
60 void AddBookmarks(const char** titles, const char** urls, size_t count) {
61 // The pair is (title, url).
62 std::vector<TitleAndURL> bookmarks;
63 for (size_t i = 0; i < count; ++i) {
64 TitleAndURL bookmark(titles[i], urls[i]);
65 bookmarks.push_back(bookmark);
66 }
67 AddBookmarks(bookmarks);
68 }
69
70 void AddBookmarks(const std::vector<TitleAndURL> bookmarks) {
71 for (size_t i = 0; i < bookmarks.size(); ++i) {
72 model_->AddURL(model_->other_node(), static_cast<int>(i),
73 ASCIIToUTF16(bookmarks[i].first),
74 GURL(bookmarks[i].second));
75 }
76 }
77
78 void ExpectMatches(const std::string& query,
79 const char** expected_titles,
80 size_t expected_count) {
81 std::vector<std::string> title_vector;
82 for (size_t i = 0; i < expected_count; ++i)
83 title_vector.push_back(expected_titles[i]);
84 ExpectMatches(query, title_vector);
85 }
86
87 void ExpectMatches(const std::string& query,
88 const std::vector<std::string>& expected_titles) {
89 std::vector<BookmarkMatch> matches;
90 model_->GetBookmarksMatching(ASCIIToUTF16(query), 1000, &matches);
91 ASSERT_EQ(expected_titles.size(), matches.size());
92 for (size_t i = 0; i < expected_titles.size(); ++i) {
93 bool found = false;
94 for (size_t j = 0; j < matches.size(); ++j) {
95 if (ASCIIToUTF16(expected_titles[i]) == matches[j].node->GetTitle()) {
96 matches.erase(matches.begin() + j);
97 found = true;
98 break;
99 }
100 }
101 ASSERT_TRUE(found);
102 }
103 }
104
105 void ExtractMatchPositions(const std::string& string,
106 BookmarkMatch::MatchPositions* matches) {
107 std::vector<std::string> match_strings;
108 base::SplitString(string, ':', &match_strings);
109 for (size_t i = 0; i < match_strings.size(); ++i) {
110 std::vector<std::string> chunks;
111 base::SplitString(match_strings[i], ',', &chunks);
112 ASSERT_EQ(2U, chunks.size());
113 matches->push_back(BookmarkMatch::MatchPosition());
114 int chunks0, chunks1;
115 base::StringToInt(chunks[0], &chunks0);
116 base::StringToInt(chunks[1], &chunks1);
117 matches->back().first = chunks0;
118 matches->back().second = chunks1;
119 }
120 }
121
122 void ExpectMatchPositions(
123 const BookmarkMatch::MatchPositions& actual_positions,
124 const BookmarkMatch::MatchPositions& expected_positions) {
125 ASSERT_EQ(expected_positions.size(), actual_positions.size());
126 for (size_t i = 0; i < expected_positions.size(); ++i) {
127 EXPECT_EQ(expected_positions[i].first, actual_positions[i].first);
128 EXPECT_EQ(expected_positions[i].second, actual_positions[i].second);
129 }
130 }
131
132 protected:
133 test::TestBookmarkClient client_;
134 scoped_ptr<BookmarkModel> model_;
135
136 private:
137 DISALLOW_COPY_AND_ASSIGN(BookmarkIndexTest);
138 };
139
140 // Various permutations with differing input, queries and output that exercises
141 // all query paths.
142 TEST_F(BookmarkIndexTest, GetBookmarksMatching) {
143 struct TestData {
144 const std::string titles;
145 const std::string query;
146 const std::string expected;
147 } data[] = {
148 // Trivial test case of only one term, exact match.
149 { "a;b", "A", "a" },
150
151 // Prefix match, one term.
152 { "abcd;abc;b", "abc", "abcd;abc" },
153
154 // Prefix match, multiple terms.
155 { "abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg"},
156
157 // Exact and prefix match.
158 { "ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef"},
159
160 // Exact and prefix match.
161 { "ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
162 "ab cde ghi",
163 "ab cdef ghij"},
164
165 // Title with term multiple times.
166 { "ab ab", "ab", "ab ab"},
167
168 // Make sure quotes don't do a prefix match.
169 { "think", "\"thi\"", ""},
170
171 // Prefix matches against multiple candidates.
172 { "abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4"},
173 };
174 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
175 std::vector<std::string> titles;
176 base::SplitString(data[i].titles, ';', &titles);
177 std::vector<TitleAndURL> bookmarks;
178 for (size_t j = 0; j < titles.size(); ++j) {
179 TitleAndURL bookmark(titles[j], "about:blank");
180 bookmarks.push_back(bookmark);
181 }
182 AddBookmarks(bookmarks);
183
184 std::vector<std::string> expected;
185 if (!data[i].expected.empty())
186 base::SplitString(data[i].expected, ';', &expected);
187
188 ExpectMatches(data[i].query, expected);
189
190 model_ = client_.CreateModel(false);
191 }
192 }
193
194 // Analogous to GetBookmarksMatching, this test tests various permutations
195 // of title, URL, and input to see if the title/URL matches the input as
196 // expected.
197 TEST_F(BookmarkIndexTest, GetBookmarksMatchingWithURLs) {
198 struct TestData {
199 const std::string query;
200 const std::string title;
201 const std::string url;
202 const bool should_be_retrieved;
203 } data[] = {
204 // Test single-word inputs. Include both exact matches and prefix matches.
205 { "foo", "Foo", "http://www.bar.com/", true },
206 { "foo", "Foodie", "http://www.bar.com/", true },
207 { "foo", "Bar", "http://www.foo.com/", true },
208 { "foo", "Bar", "http://www.foodie.com/", true },
209 { "foo", "Foo", "http://www.foo.com/", true },
210 { "foo", "Bar", "http://www.bar.com/", false },
211 { "foo", "Bar", "http://www.bar.com/blah/foo/blah-again/ ", true },
212 { "foo", "Bar", "http://www.bar.com/blah/foodie/blah-again/ ", true },
213 { "foo", "Bar", "http://www.bar.com/blah-foo/blah-again/ ", true },
214 { "foo", "Bar", "http://www.bar.com/blah-foodie/blah-again/ ", true },
215 { "foo", "Bar", "http://www.bar.com/blahafoo/blah-again/ ", false },
216
217 // Test multi-word inputs.
218 { "foo bar", "Foo Bar", "http://baz.com/", true },
219 { "foo bar", "Foodie Bar", "http://baz.com/", true },
220 { "bar foo", "Foo Bar", "http://baz.com/", true },
221 { "bar foo", "Foodie Barly", "http://baz.com/", true },
222 { "foo bar", "Foo Baz", "http://baz.com/", false },
223 { "foo bar", "Foo Baz", "http://bar.com/", true },
224 { "foo bar", "Foo Baz", "http://barly.com/", true },
225 { "foo bar", "Foodie Baz", "http://barly.com/", true },
226 { "bar foo", "Foo Baz", "http://bar.com/", true },
227 { "bar foo", "Foo Baz", "http://barly.com/", true },
228 { "foo bar", "Baz Bar", "http://blah.com/foo", true },
229 { "foo bar", "Baz Barly", "http://blah.com/foodie", true },
230 { "foo bar", "Baz Bur", "http://blah.com/foo/bar", true },
231 { "foo bar", "Baz Bur", "http://blah.com/food/barly", true },
232 { "foo bar", "Baz Bur", "http://bar.com/blah/foo", true },
233 { "foo bar", "Baz Bur", "http://barly.com/blah/food", true },
234 { "foo bar", "Baz Bur", "http://bar.com/blah/flub", false },
235 { "foo bar", "Baz Bur", "http://foo.com/blah/flub", false }
236 };
237
238 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
239 model_ = client_.CreateModel(true);
240 std::vector<TitleAndURL> bookmarks;
241 bookmarks.push_back(TitleAndURL(data[i].title, data[i].url));
242 AddBookmarks(bookmarks);
243
244 std::vector<std::string> expected;
245 if (data[i].should_be_retrieved)
246 expected.push_back(data[i].title);
247
248 ExpectMatches(data[i].query, expected);
249 }
250 }
251
252 TEST_F(BookmarkIndexTest, Normalization) {
253 struct TestData {
254 const char* title;
255 const char* query;
256 } data[] = {
257 { "fooa\xcc\x88-test", "foo\xc3\xa4-test" },
258 { "fooa\xcc\x88-test", "fooa\xcc\x88-test" },
259 { "fooa\xcc\x88-test", "foo\xc3\xa4" },
260 { "fooa\xcc\x88-test", "fooa\xcc\x88" },
261 { "fooa\xcc\x88-test", "foo" },
262 { "foo\xc3\xa4-test", "foo\xc3\xa4-test" },
263 { "foo\xc3\xa4-test", "fooa\xcc\x88-test" },
264 { "foo\xc3\xa4-test", "foo\xc3\xa4" },
265 { "foo\xc3\xa4-test", "fooa\xcc\x88" },
266 { "foo\xc3\xa4-test", "foo" },
267 { "foo", "foo" }
268 };
269
270 GURL url("about:blank");
271 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
272 model_->AddURL(model_->other_node(), 0, base::UTF8ToUTF16(data[i].title),
273 url);
274 std::vector<BookmarkMatch> matches;
275 model_->GetBookmarksMatching(
276 base::UTF8ToUTF16(data[i].query), 10, &matches);
277 EXPECT_EQ(1u, matches.size());
278 model_ = client_.CreateModel(false);
279 }
280 }
281
282 // Makes sure match positions are updated appropriately for title matches.
283 TEST_F(BookmarkIndexTest, MatchPositionsTitles) {
284 struct TestData {
285 const std::string title;
286 const std::string query;
287 const std::string expected_title_match_positions;
288 } data[] = {
289 // Trivial test case of only one term, exact match.
290 { "a", "A", "0,1" },
291 { "foo bar", "bar", "4,7" },
292 { "fooey bark", "bar foo", "0,3:6,9" },
293 // Non-trivial tests.
294 { "foobar foo", "foobar foo", "0,6:7,10" },
295 { "foobar foo", "foo foobar", "0,6:7,10" },
296 { "foobar foobar", "foobar foo", "0,6:7,13" },
297 { "foobar foobar", "foo foobar", "0,6:7,13" },
298 };
299 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
300 std::vector<TitleAndURL> bookmarks;
301 TitleAndURL bookmark(data[i].title, "about:blank");
302 bookmarks.push_back(bookmark);
303 AddBookmarks(bookmarks);
304
305 std::vector<BookmarkMatch> matches;
306 model_->GetBookmarksMatching(ASCIIToUTF16(data[i].query), 1000, &matches);
307 ASSERT_EQ(1U, matches.size());
308
309 BookmarkMatch::MatchPositions expected_title_matches;
310 ExtractMatchPositions(data[i].expected_title_match_positions,
311 &expected_title_matches);
312 ExpectMatchPositions(matches[0].title_match_positions,
313 expected_title_matches);
314
315 model_ = client_.CreateModel(false);
316 }
317 }
318
319 // Makes sure match positions are updated appropriately for URL matches.
320 TEST_F(BookmarkIndexTest, MatchPositionsURLs) {
321 // The encoded stuff between /wiki/ and the # is 第二次世界大戦
322 const std::string ja_wiki_url = "http://ja.wikipedia.org/wiki/%E7%AC%AC%E4"
323 "%BA%8C%E6%AC%A1%E4%B8%96%E7%95%8C%E5%A4%A7%E6%88%A6#.E3.83.B4.E3.82.A7"
324 ".E3.83.AB.E3.82.B5.E3.82.A4.E3.83.A6.E4.BD.93.E5.88.B6";
325 struct TestData {
326 const std::string query;
327 const std::string url;
328 const std::string expected_url_match_positions;
329 } data[] = {
330 { "foo", "http://www.foo.com/", "11,14" },
331 { "foo", "http://www.foodie.com/", "11,14" },
332 { "foo", "http://www.foofoo.com/", "11,14" },
333 { "www", "http://www.foo.com/", "7,10" },
334 { "foo", "http://www.foodie.com/blah/foo/fi", "11,14:27,30" },
335 { "foo", "http://www.blah.com/blah/foo/fi", "25,28" },
336 { "foo www", "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30" },
337 { "www foo", "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30" },
338 { "www bla", "http://www.foodie.com/blah/foo/fi", "7,10:22,25" },
339 { "http", "http://www.foo.com/", "0,4" },
340 { "http www", "http://www.foo.com/", "0,4:7,10" },
341 { "http foo", "http://www.foo.com/", "0,4:11,14" },
342 { "http foo", "http://www.bar.com/baz/foodie/hi", "0,4:23,26" },
343 { "第二次", ja_wiki_url, "29,56" },
344 { "ja 第二次", ja_wiki_url, "7,9:29,56" },
345 { "第二次 E3.8", ja_wiki_url, "29,56:94,98:103,107:"
346 "112,116:121,125:"
347 "130,134:139,143" }
348 };
349
350 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
351 model_ = client_.CreateModel(true);
352 std::vector<TitleAndURL> bookmarks;
353 TitleAndURL bookmark("123456", data[i].url);
354 bookmarks.push_back(bookmark);
355 AddBookmarks(bookmarks);
356
357 std::vector<BookmarkMatch> matches;
358 model_->GetBookmarksMatching(
359 base::UTF8ToUTF16(data[i].query), 1000, &matches);
360 ASSERT_EQ(1U, matches.size()) << data[i].url << data[i].query;
361
362 BookmarkMatch::MatchPositions expected_url_matches;
363 ExtractMatchPositions(data[i].expected_url_match_positions,
364 &expected_url_matches);
365 ExpectMatchPositions(matches[0].url_match_positions, expected_url_matches);
366 }
367 }
368
369 // Makes sure index is updated when a node is removed.
370 TEST_F(BookmarkIndexTest, Remove) {
371 const char* titles[] = { "a", "b" };
372 const char* urls[] = { "about:blank", "about:blank" };
373 AddBookmarks(titles, urls, ARRAYSIZE_UNSAFE(titles));
374
375 // Remove the node and make sure we don't get back any results.
376 model_->Remove(model_->other_node(), 0);
377 ExpectMatches("A", NULL, 0U);
378 }
379
380 // Makes sure index is updated when a node's title is changed.
381 TEST_F(BookmarkIndexTest, ChangeTitle) {
382 const char* titles[] = { "a", "b" };
383 const char* urls[] = { "about:blank", "about:blank" };
384 AddBookmarks(titles, urls, ARRAYSIZE_UNSAFE(titles));
385
386 // Remove the node and make sure we don't get back any results.
387 const char* expected[] = { "blah" };
388 model_->SetTitle(model_->other_node()->GetChild(0), ASCIIToUTF16("blah"));
389 ExpectMatches("BlAh", expected, ARRAYSIZE_UNSAFE(expected));
390 }
391
392 // Makes sure no more than max queries is returned.
393 TEST_F(BookmarkIndexTest, HonorMax) {
394 const char* titles[] = { "abcd", "abcde" };
395 const char* urls[] = { "about:blank", "about:blank" };
396 AddBookmarks(titles, urls, ARRAYSIZE_UNSAFE(titles));
397
398 std::vector<BookmarkMatch> matches;
399 model_->GetBookmarksMatching(ASCIIToUTF16("ABc"), 1, &matches);
400 EXPECT_EQ(1U, matches.size());
401 }
402
403 // Makes sure if the lower case string of a bookmark title is more characters
404 // than the upper case string no match positions are returned.
405 TEST_F(BookmarkIndexTest, EmptyMatchOnMultiwideLowercaseString) {
406 const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0,
407 base::WideToUTF16(L"\u0130 i"),
408 GURL("http://www.google.com"));
409
410 std::vector<BookmarkMatch> matches;
411 model_->GetBookmarksMatching(ASCIIToUTF16("i"), 100, &matches);
412 ASSERT_EQ(1U, matches.size());
413 EXPECT_TRUE(matches[0].node == n1);
414 EXPECT_TRUE(matches[0].title_match_positions.empty());
415 }
416
417 TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
418 struct TestData {
419 const GURL url;
420 const char* title;
421 const int typed_count;
422 } data[] = {
423 { GURL("http://www.google.com/"), "Google", 100 },
424 { GURL("http://maps.google.com/"), "Google Maps", 40 },
425 { GURL("http://docs.google.com/"), "Google Docs", 50 },
426 { GURL("http://reader.google.com/"), "Google Reader", 80 },
427 };
428
429 std::map<GURL, int> typed_count_map;
430 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i)
431 typed_count_map.insert(std::make_pair(data[i].url, data[i].typed_count));
432
433 BookmarkClientMock client(typed_count_map);
434 scoped_ptr<BookmarkModel> model = client.CreateModel(false);
435
436 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i)
437 // Populate the BookmarkIndex.
438 model->AddURL(
439 model->other_node(), i, base::UTF8ToUTF16(data[i].title), data[i].url);
440
441 // Populate match nodes.
442 std::vector<BookmarkMatch> matches;
443 model->GetBookmarksMatching(ASCIIToUTF16("google"), 4, &matches);
444
445 // The resulting order should be:
446 // 1. Google (google.com) 100
447 // 2. Google Reader (google.com/reader) 80
448 // 3. Google Docs (docs.google.com) 50
449 // 4. Google Maps (maps.google.com) 40
450 EXPECT_EQ(4, static_cast<int>(matches.size()));
451 EXPECT_EQ(data[0].url, matches[0].node->url());
452 EXPECT_EQ(data[3].url, matches[1].node->url());
453 EXPECT_EQ(data[2].url, matches[2].node->url());
454 EXPECT_EQ(data[1].url, matches[3].node->url());
455
456 matches.clear();
457 // Select top two matches.
458 model->GetBookmarksMatching(ASCIIToUTF16("google"), 2, &matches);
459
460 EXPECT_EQ(2, static_cast<int>(matches.size()));
461 EXPECT_EQ(data[0].url, matches[0].node->url());
462 EXPECT_EQ(data[3].url, matches[1].node->url());
463 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698