1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_index.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/macros.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_match.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/test/bookmark_test_helpers.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/test/test_bookmark_client.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::ASCIIToUTF16;
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using base::UTF8ToUTF16;
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace bookmarks {
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace {
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kAboutBlankURL[] = "about:blank";
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass BookmarkClientMock : public TestBookmarkClient {
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  BookmarkClientMock(const std::map<GURL, int>& typed_count_map)
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      : typed_count_map_(typed_count_map) {}
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual bool SupportsTypedCountForNodes() OVERRIDE { return true; }
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void GetTypedCountForNodes(
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      const NodeSet& nodes,
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      NodeTypedCountPairs* node_typed_count_pairs) OVERRIDE {
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    for (NodeSet::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      const BookmarkNode* node = *it;
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      std::map<GURL, int>::const_iterator found =
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          typed_count_map_.find(node->url());
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (found == typed_count_map_.end())
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        continue;
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      node_typed_count_pairs->push_back(std::make_pair(node, found->second));
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private:
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const std::map<GURL, int> typed_count_map_;
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BookmarkClientMock);
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BookmarkIndexTest : public testing::Test {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  BookmarkIndexTest() : model_(client_.CreateModel()) {}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  typedef std::pair<std::string, std::string> TitleAndURL;
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  void AddBookmarks(const char** titles, const char** urls, size_t count) {
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // The pair is (title, url).
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<TitleAndURL> bookmarks;
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (size_t i = 0; i < count; ++i) {
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      TitleAndURL bookmark(titles[i], urls[i]);
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      bookmarks.push_back(bookmark);
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    AddBookmarks(bookmarks);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void AddBookmarks(const std::vector<TitleAndURL>& bookmarks) {
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (size_t i = 0; i < bookmarks.size(); ++i) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_->AddURL(model_->other_node(), static_cast<int>(i),
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     ASCIIToUTF16(bookmarks[i].first),
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     GURL(bookmarks[i].second));
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ExpectMatches(const std::string& query,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const char** expected_titles,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     size_t expected_count) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> title_vector;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < expected_count; ++i)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title_vector.push_back(expected_titles[i]);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExpectMatches(query, title_vector);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ExpectMatches(const std::string& query,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::vector<std::string>& expected_titles) {
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<BookmarkMatch> matches;
920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    model_->GetBookmarksMatching(ASCIIToUTF16(query), 1000, &matches);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_EQ(expected_titles.size(), matches.size());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < expected_titles.size(); ++i) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool found = false;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t j = 0; j < matches.size(); ++j) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ASCIIToUTF16(expected_titles[i]) == matches[j].node->GetTitle()) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          matches.erase(matches.begin() + j);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          found = true;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT_TRUE(found);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ExtractMatchPositions(const std::string& string,
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             BookmarkMatch::MatchPositions* matches) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> match_strings;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitString(string, ':', &match_strings);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < match_strings.size(); ++i) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<std::string> chunks;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::SplitString(match_strings[i], ',', &chunks);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASSERT_EQ(2U, chunks.size());
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      matches->push_back(BookmarkMatch::MatchPosition());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int chunks0, chunks1;
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      EXPECT_TRUE(base::StringToInt(chunks[0], &chunks0));
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      EXPECT_TRUE(base::StringToInt(chunks[1], &chunks1));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      matches->back().first = chunks0;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      matches->back().second = chunks1;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void ExpectMatchPositions(
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      const BookmarkMatch::MatchPositions& actual_positions,
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      const BookmarkMatch::MatchPositions& expected_positions) {
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ASSERT_EQ(expected_positions.size(), actual_positions.size());
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < expected_positions.size(); ++i) {
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      EXPECT_EQ(expected_positions[i].first, actual_positions[i].first);
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      EXPECT_EQ(expected_positions[i].second, actual_positions[i].second);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  TestBookmarkClient client_;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<BookmarkModel> model_;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BookmarkIndexTest);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Various permutations with differing input, queries and output that exercises
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all query paths.
1440529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochTEST_F(BookmarkIndexTest, GetBookmarksMatching) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct TestData {
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string titles;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string query;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string expected;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } data[] = {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Trivial test case of only one term, exact match.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "a;b",                        "A",        "a" },
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prefix match, one term.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "abcd;abc;b",                 "abc",      "abcd;abc" },
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prefix match, multiple terms.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "abcd cdef;abcd;abcd cdefg",  "abc cde",  "abcd cdef;abcd cdefg"},
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Exact and prefix match.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "ab cdef;abcd;abcd cdefg",    "ab cdef",  "ab cdef"},
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Exact and prefix match.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ab cde ghi",
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ab cdef ghij"},
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Title with term multiple times.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "ab ab",                      "ab",       "ab ab"},
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure quotes don't do a prefix match.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "think",                      "\"thi\"",  ""},
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Prefix matches against multiple candidates.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4"},
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> titles;
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::SplitString(data[i].titles, ';', &titles);
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<TitleAndURL> bookmarks;
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (size_t j = 0; j < titles.size(); ++j) {
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      TitleAndURL bookmark(titles[j], kAboutBlankURL);
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      bookmarks.push_back(bookmark);
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    AddBookmarks(bookmarks);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> expected;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!data[i].expected.empty())
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::SplitString(data[i].expected, ';', &expected);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExpectMatches(data[i].query, expected);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_ = client_.CreateModel();
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Analogous to GetBookmarksMatching, this test tests various permutations
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// of title, URL, and input to see if the title/URL matches the input as
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// expected.
1990529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochTEST_F(BookmarkIndexTest, GetBookmarksMatchingWithURLs) {
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  struct TestData {
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string query;
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string title;
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string url;
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const bool should_be_retrieved;
2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } data[] = {
2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Test single-word inputs.  Include both exact matches and prefix matches.
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Foo",    "http://www.bar.com/",    true  },
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Foodie", "http://www.bar.com/",    true  },
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.foo.com/",    true  },
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.foodie.com/", true  },
2110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Foo",    "http://www.foo.com/",    true  },
2120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.bar.com/",    false },
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.bar.com/blah/foo/blah-again/ ",    true  },
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.bar.com/blah/foodie/blah-again/ ", true  },
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.bar.com/blah-foo/blah-again/ ",    true  },
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.bar.com/blah-foodie/blah-again/ ", true  },
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo", "Bar",    "http://www.bar.com/blahafoo/blah-again/ ",    false },
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Test multi-word inputs.
2200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Foo Bar",      "http://baz.com/",   true  },
2210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Foodie Bar",   "http://baz.com/",   true  },
2220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "bar foo", "Foo Bar",      "http://baz.com/",   true  },
2230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "bar foo", "Foodie Barly", "http://baz.com/",   true  },
2240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Foo Baz",      "http://baz.com/",   false },
2250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Foo Baz",      "http://bar.com/",   true  },
2260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Foo Baz",      "http://barly.com/", true  },
2270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Foodie Baz",   "http://barly.com/", true  },
2280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "bar foo", "Foo Baz",      "http://bar.com/",   true  },
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "bar foo", "Foo Baz",      "http://barly.com/", true  },
2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bar",      "http://blah.com/foo",         true  },
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Barly",    "http://blah.com/foodie",      true  },
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bur",      "http://blah.com/foo/bar",     true  },
2330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bur",      "http://blah.com/food/barly",  true  },
2340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bur",      "http://bar.com/blah/foo",     true  },
2350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bur",      "http://barly.com/blah/food",  true  },
2360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bur",      "http://bar.com/blah/flub",    false },
2370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "foo bar", "Baz Bur",      "http://foo.com/blah/flub",    false }
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  };
2390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_ = client_.CreateModel();
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<TitleAndURL> bookmarks;
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    bookmarks.push_back(TitleAndURL(data[i].title, data[i].url));
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    AddBookmarks(bookmarks);
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<std::string> expected;
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (data[i].should_be_retrieved)
2480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      expected.push_back(data[i].title);
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ExpectMatches(data[i].query, expected);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2540529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochTEST_F(BookmarkIndexTest, Normalization) {
255e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  struct TestData {
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const char* const title;
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const char* const query;
258e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  } data[] = {
259e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "fooa\xcc\x88-test", "foo\xc3\xa4-test" },
260e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "fooa\xcc\x88-test", "fooa\xcc\x88-test" },
261e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "fooa\xcc\x88-test", "foo\xc3\xa4" },
262e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "fooa\xcc\x88-test", "fooa\xcc\x88" },
263e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "fooa\xcc\x88-test", "foo" },
264e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "foo\xc3\xa4-test", "foo\xc3\xa4-test" },
265e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "foo\xc3\xa4-test", "fooa\xcc\x88-test" },
266e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "foo\xc3\xa4-test", "foo\xc3\xa4" },
267e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "foo\xc3\xa4-test", "fooa\xcc\x88" },
268e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "foo\xc3\xa4-test", "foo" },
269e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    { "foo", "foo" }
270e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  };
271e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  GURL url(kAboutBlankURL);
273e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    model_->AddURL(model_->other_node(), 0, UTF8ToUTF16(data[i].title), url);
2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<BookmarkMatch> matches;
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    model_->GetBookmarksMatching(UTF8ToUTF16(data[i].query), 10, &matches);
277e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    EXPECT_EQ(1u, matches.size());
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_ = client_.CreateModel();
279e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
280e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
281e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
2820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Makes sure match positions are updated appropriately for title matches.
2830529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochTEST_F(BookmarkIndexTest, MatchPositionsTitles) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct TestData {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string title;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string query;
2870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string expected_title_match_positions;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } data[] = {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Trivial test case of only one term, exact match.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "a",                        "A",        "0,1" },
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "foo bar",                  "bar",      "4,7" },
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    { "fooey bark",               "bar foo",  "0,3:6,9" },
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Non-trivial tests.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "foobar foo",               "foobar foo",   "0,6:7,10" },
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "foobar foo",               "foo foobar",   "0,6:7,10" },
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "foobar foobar",            "foobar foo",   "0,6:7,13" },
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "foobar foobar",            "foo foobar",   "0,6:7,13" },
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
3000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<TitleAndURL> bookmarks;
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    TitleAndURL bookmark(data[i].title, kAboutBlankURL);
3020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    bookmarks.push_back(bookmark);
3030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    AddBookmarks(bookmarks);
3040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<BookmarkMatch> matches;
3060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    model_->GetBookmarksMatching(ASCIIToUTF16(data[i].query), 1000, &matches);
3070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ASSERT_EQ(1U, matches.size());
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    BookmarkMatch::MatchPositions expected_title_matches;
3100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ExtractMatchPositions(data[i].expected_title_match_positions,
3110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          &expected_title_matches);
3120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ExpectMatchPositions(matches[0].title_match_positions,
3130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                         expected_title_matches);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_ = client_.CreateModel();
3160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Makes sure match positions are updated appropriately for URL matches.
3200529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochTEST_F(BookmarkIndexTest, MatchPositionsURLs) {
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The encoded stuff between /wiki/ and the # is 第二次世界大戦
3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const std::string ja_wiki_url = "http://ja.wikipedia.org/wiki/%E7%AC%AC%E4"
3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      "%BA%8C%E6%AC%A1%E4%B8%96%E7%95%8C%E5%A4%A7%E6%88%A6#.E3.83.B4.E3.82.A7"
3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ".E3.83.AB.E3.82.B5.E3.82.A4.E3.83.A6.E4.BD.93.E5.88.B6";
3250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  struct TestData {
3260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string query;
3270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string url;
3280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string expected_url_match_positions;
3290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } data[] = {
3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "foo",        "http://www.foo.com/",    "11,14" },
3315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "foo",        "http://www.foodie.com/", "11,14" },
3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "foo",        "http://www.foofoo.com/", "11,14" },
3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "www",        "http://www.foo.com/",    "7,10"  },
3345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "foo",        "http://www.foodie.com/blah/foo/fi", "11,14:27,30"      },
3355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "foo",        "http://www.blah.com/blah/foo/fi",   "25,28"            },
3365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "foo www",    "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30" },
3375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "www foo",    "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30" },
3385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "www bla",    "http://www.foodie.com/blah/foo/fi", "7,10:22,25"       },
3395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "http",       "http://www.foo.com/",               "0,4"              },
3405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "http www",   "http://www.foo.com/",               "0,4:7,10"         },
3415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "http foo",   "http://www.foo.com/",               "0,4:11,14"        },
3425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "http foo",   "http://www.bar.com/baz/foodie/hi",  "0,4:23,26"        },
3435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "第二次",      ja_wiki_url,                         "29,56"            },
3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "ja 第二次",   ja_wiki_url,                         "7,9:29,56"        },
3455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    { "第二次 E3.8", ja_wiki_url,                         "29,56:94,98:103,107:"
3465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                         "112,116:121,125:"
3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                         "130,134:139,143"  }
3480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  };
3490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    model_ = client_.CreateModel();
3520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<TitleAndURL> bookmarks;
3530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    TitleAndURL bookmark("123456", data[i].url);
3540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    bookmarks.push_back(bookmark);
3550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    AddBookmarks(bookmarks);
3560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<BookmarkMatch> matches;
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    model_->GetBookmarksMatching(UTF8ToUTF16(data[i].query), 1000, &matches);
3590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ASSERT_EQ(1U, matches.size()) << data[i].url << data[i].query;
3600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    BookmarkMatch::MatchPositions expected_url_matches;
3620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ExtractMatchPositions(data[i].expected_url_match_positions,
3630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          &expected_url_matches);
3640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ExpectMatchPositions(matches[0].url_match_positions, expected_url_matches);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Makes sure index is updated when a node is removed.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(BookmarkIndexTest, Remove) {
3700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const char* titles[] = { "a", "b" };
371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char* urls[] = {kAboutBlankURL, kAboutBlankURL};
3720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  AddBookmarks(titles, urls, ARRAYSIZE_UNSAFE(titles));
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the node and make sure we don't get back any results.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->Remove(model_->other_node(), 0);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExpectMatches("A", NULL, 0U);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Makes sure index is updated when a node's title is changed.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(BookmarkIndexTest, ChangeTitle) {
3810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const char* titles[] = { "a", "b" };
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char* urls[] = {kAboutBlankURL, kAboutBlankURL};
3830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  AddBookmarks(titles, urls, ARRAYSIZE_UNSAFE(titles));
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the node and make sure we don't get back any results.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* expected[] = { "blah" };
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetTitle(model_->other_node()->GetChild(0), ASCIIToUTF16("blah"));
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExpectMatches("BlAh", expected, ARRAYSIZE_UNSAFE(expected));
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Makes sure no more than max queries is returned.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(BookmarkIndexTest, HonorMax) {
3930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const char* titles[] = { "abcd", "abcde" };
394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char* urls[] = {kAboutBlankURL, kAboutBlankURL};
3950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  AddBookmarks(titles, urls, ARRAYSIZE_UNSAFE(titles));
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<BookmarkMatch> matches;
3980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  model_->GetBookmarksMatching(ASCIIToUTF16("ABc"), 1, &matches);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1U, matches.size());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Makes sure if the lower case string of a bookmark title is more characters
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// than the upper case string no match positions are returned.
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(BookmarkIndexTest, EmptyMatchOnMultiwideLowercaseString) {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0,
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          base::WideToUTF16(L"\u0130 i"),
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GURL("http://www.google.com"));
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<BookmarkMatch> matches;
4100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  model_->GetBookmarksMatching(ASCIIToUTF16("i"), 100, &matches);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(1U, matches.size());
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(n1, matches[0].node);
4130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EXPECT_TRUE(matches[0].title_match_positions.empty());
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct TestData {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL url;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* title;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int typed_count;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } data[] = {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { GURL("http://www.google.com/"),      "Google",           100 },
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { GURL("http://maps.google.com/"),     "Google Maps",       40 },
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { GURL("http://docs.google.com/"),     "Google Docs",       50 },
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { GURL("http://reader.google.com/"),   "Google Reader",     80 },
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::map<GURL, int> typed_count_map;
429010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i)
430010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    typed_count_map.insert(std::make_pair(data[i].url, data[i].typed_count));
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
432010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  BookmarkClientMock client(typed_count_map);
4331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<BookmarkModel> model = client.CreateModel();
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i)
436010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Populate the BookmarkIndex.
437010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    model->AddURL(
438cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        model->other_node(), i, UTF8ToUTF16(data[i].title), data[i].url);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate match nodes.
4410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<BookmarkMatch> matches;
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  model->GetBookmarksMatching(ASCIIToUTF16("google"), 4, &matches);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The resulting order should be:
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1. Google (google.com) 100
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2. Google Reader (google.com/reader) 80
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3. Google Docs (docs.google.com) 50
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 4. Google Maps (maps.google.com) 40
449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_EQ(4, static_cast<int>(matches.size()));
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data[0].url, matches[0].node->url());
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data[3].url, matches[1].node->url());
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data[2].url, matches[2].node->url());
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data[1].url, matches[3].node->url());
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  matches.clear();
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Select top two matches.
4570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  model->GetBookmarksMatching(ASCIIToUTF16("google"), 2, &matches);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
459cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_EQ(2, static_cast<int>(matches.size()));
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data[0].url, matches[0].node->url());
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data[3].url, matches[1].node->url());
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
463cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
46546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace bookmarks
466