Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

bookmark_index_unittest.cc

// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>
#include <vector>

#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_index.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/history/in_memory_database.h"
#include "chrome/browser/history/query_parser.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"

class BookmarkIndexTest : public testing::Test {
 public:
  BookmarkIndexTest() : model_(new BookmarkModel(NULL)) {}

  void AddBookmarksWithTitles(const wchar_t** titles, size_t count) {
    std::vector<std::wstring> title_vector;
    for (size_t i = 0; i < count; ++i)
      title_vector.push_back(titles[i]);
    AddBookmarksWithTitles(title_vector);
  }

  void AddBookmarksWithTitles(const std::vector<std::wstring>& titles) {
    GURL url("about:blank");
    for (size_t i = 0; i < titles.size(); ++i)
      model_->AddURL(model_->other_node(), static_cast<int>(i), titles[i], url);
  }

  void ExpectMatches(const std::wstring& query,
                     const wchar_t** expected_titles,
                     size_t expected_count) {
    std::vector<std::wstring> title_vector;
    for (size_t i = 0; i < expected_count; ++i)
      title_vector.push_back(expected_titles[i]);
    ExpectMatches(query, title_vector);
  }

  void ExpectMatches(const std::wstring& query,
                     const std::vector<std::wstring> expected_titles) {
    std::vector<bookmark_utils::TitleMatch> matches;
    model_->GetBookmarksWithTitlesMatching(query, 1000, &matches);
    ASSERT_EQ(expected_titles.size(), matches.size());
    for (size_t i = 0; i < expected_titles.size(); ++i) {
      bool found = false;
      for (size_t j = 0; j < matches.size(); ++j) {
        if (std::wstring(expected_titles[i]) == matches[j].node->GetTitle()) {
          matches.erase(matches.begin() + j);
          found = true;
          break;
        }
      }
      ASSERT_TRUE(found);
    }
  }

  void ExtractMatchPositions(const std::string& string,
                             Snippet::MatchPositions* matches) {
    std::vector<std::string> match_strings;
    SplitString(string, L':', &match_strings);
    for (size_t i = 0; i < match_strings.size(); ++i) {
      std::vector<std::string> chunks;
      SplitString(match_strings[i], ',', &chunks);
      ASSERT_EQ(2U, chunks.size());
      matches->push_back(Snippet::MatchPosition());
      matches->back().first = StringToInt(chunks[0]);
      matches->back().second = StringToInt(chunks[1]);
    }
  }

  void ExpectMatchPositions(const std::wstring& query,
                            const Snippet::MatchPositions& expected_positions) {
    std::vector<bookmark_utils::TitleMatch> matches;
    model_->GetBookmarksWithTitlesMatching(query, 1000, &matches);
    ASSERT_EQ(1U, matches.size());
    const bookmark_utils::TitleMatch& match = matches[0];
    ASSERT_EQ(expected_positions.size(), match.match_positions.size());
    for (size_t i = 0; i < expected_positions.size(); ++i) {
      EXPECT_EQ(expected_positions[i].first, match.match_positions[i].first);
      EXPECT_EQ(expected_positions[i].second, match.match_positions[i].second);
    }
  }

 protected:
  scoped_ptr<BookmarkModel> model_;

 private:
  DISALLOW_COPY_AND_ASSIGN(BookmarkIndexTest);
};

// Various permutations with differing input, queries and output that exercises
// all query paths.
TEST_F(BookmarkIndexTest, Tests) {
  struct TestData {
    const std::wstring input;
    const std::wstring query;
    const std::wstring expected;
  } data[] = {
    // Trivial test case of only one term, exact match.
    { L"a;b",                       L"A",       L"a" },

    // Prefix match, one term.
    { L"abcd;abc;b",                L"abc",     L"abcd;abc" },

    // Prefix match, multiple terms.
    { L"abcd cdef;abcd;abcd cdefg", L"abc cde", L"abcd cdef;abcd cdefg"},

    // Exact and prefix match.
    { L"ab cdef;abcd;abcd cdefg",   L"ab cdef", L"ab cdef"},

    // Exact and prefix match.
    { L"ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
      L"ab cde ghi",
      L"ab cdef ghij"},

    // Title with term multiple times.
    { L"ab ab",                     L"ab",      L"ab ab"},

    // Make sure quotes don't do a prefix match.
    { L"think",                     L"\"thi\"", L""},
  };
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
    std::vector<std::wstring> titles;
    SplitString(data[i].input, L';', &titles);
    AddBookmarksWithTitles(titles);

    std::vector<std::wstring> expected;
    if (!data[i].expected.empty())
      SplitString(data[i].expected, L';', &expected);

    ExpectMatches(data[i].query, expected);

    model_.reset(new BookmarkModel(NULL));
  }
}

// Makes sure match positions are updated appropriately.
TEST_F(BookmarkIndexTest, MatchPositions) {
  struct TestData {
    const std::wstring title;
    const std::wstring query;
    const std::string expected;
  } data[] = {
    // Trivial test case of only one term, exact match.
    { L"a",                         L"A",       "0,1" },
    { L"foo bar",                   L"bar",     "4,7" },
    { L"fooey bark",                L"bar foo", "0,3:6,9"},
  };
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
    std::vector<std::wstring> titles;
    titles.push_back(data[i].title);
    AddBookmarksWithTitles(titles);

    Snippet::MatchPositions expected_matches;
    ExtractMatchPositions(data[i].expected, &expected_matches);
    ExpectMatchPositions(data[i].query, expected_matches);

    model_.reset(new BookmarkModel(NULL));
  }
}

// Makes sure index is updated when a node is removed.
TEST_F(BookmarkIndexTest, Remove) {
  const wchar_t* input[] = { L"a", L"b" };
  AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));

  // Remove the node and make sure we don't get back any results.
  model_->Remove(model_->other_node(), 0);
  ExpectMatches(L"A", NULL, 0U);
}

// Makes sure index is updated when a node's title is changed.
TEST_F(BookmarkIndexTest, ChangeTitle) {
  const wchar_t* input[] = { L"a", L"b" };
  AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));

  // Remove the node and make sure we don't get back any results.
  const wchar_t* expected[] = { L"blah" };
  model_->SetTitle(model_->other_node()->GetChild(0), L"blah");
  ExpectMatches(L"BlAh", expected, ARRAYSIZE_UNSAFE(expected));
}

// Makes sure no more than max queries is returned.
TEST_F(BookmarkIndexTest, HonorMax) {
  const wchar_t* input[] = { L"abcd", L"abcde" };
  AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));

  std::vector<bookmark_utils::TitleMatch> matches;
  model_->GetBookmarksWithTitlesMatching(L"ABc", 1, &matches);
  EXPECT_EQ(1U, matches.size());
}

// Makes sure if the lower case string of a bookmark title is more characters
// than the upper case string no match positions are returned.
TEST_F(BookmarkIndexTest, EmptyMatchOnMultiwideLowercaseString) {
  const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0, L"\u0130 i",
                                          GURL("http://www.google.com"));

  std::vector<bookmark_utils::TitleMatch> matches;
  model_->GetBookmarksWithTitlesMatching(L"i", 100, &matches);
  ASSERT_EQ(1U, matches.size());
  EXPECT_TRUE(matches[0].node == n1);
  EXPECT_TRUE(matches[0].match_positions.empty());
}

TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
  // This ensures MessageLoop::current() will exist, which is needed by
  // TestingProfile::BlockUntilHistoryProcessesPendingRequests().
  MessageLoop loop(MessageLoop::TYPE_DEFAULT);
  ChromeThread ui_thread(ChromeThread::UI, &loop);
  ChromeThread file_thread(ChromeThread::FILE, &loop);

  TestingProfile profile;
  profile.CreateHistoryService(true, false);
  profile.BlockUntilHistoryProcessesPendingRequests();
  profile.CreateBookmarkModel(true);
  profile.BlockUntilBookmarkModelLoaded();

  BookmarkModel* model = profile.GetBookmarkModel();

  HistoryService* const history_service =
      profile.GetHistoryService(Profile::EXPLICIT_ACCESS);

  history::URLDatabase* url_db = history_service->InMemoryDatabase();

  struct TestData {
    const GURL url;
    const std::wstring title;
    const int typed_count;
  } data[] = {
    { GURL("http://www.google.com/"),      L"Google",           100 },
    { GURL("http://maps.google.com/"),     L"Google Maps",       40 },
    { GURL("http://docs.google.com/"),     L"Google Docs",       50 },
    { GURL("http://reader.google.com/"),   L"Google Reader",     80 },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
    history::URLRow info(data[i].url);
    info.set_title(data[i].title);
    info.set_typed_count(data[i].typed_count);
    // Populate the InMemoryDatabase....
    url_db->AddURL(info);
    // Populate the BookmarkIndex.
    model->AddURL(model->other_node(), i, data[i].title, data[i].url);
  }

  // Check that the InMemoryDatabase stored the URLs properly.
  history::URLRow result1;
  url_db->GetRowForURL(data[0].url, &result1);
  EXPECT_EQ(data[0].title, result1.title());

  history::URLRow result2;
  url_db->GetRowForURL(data[1].url, &result2);
  EXPECT_EQ(data[1].title, result2.title());

  history::URLRow result3;
  url_db->GetRowForURL(data[2].url, &result3);
  EXPECT_EQ(data[2].title, result3.title());

  history::URLRow result4;
  url_db->GetRowForURL(data[3].url, &result4);
  EXPECT_EQ(data[3].title, result4.title());

  // Populate match nodes.
  std::vector<bookmark_utils::TitleMatch> matches;
  model->GetBookmarksWithTitlesMatching(L"google", 4, &matches);

  // The resulting order should be:
  // 1. Google (google.com) 100
  // 2. Google Reader (google.com/reader) 80
  // 3. Google Docs (docs.google.com) 50
  // 4. Google Maps (maps.google.com) 40
  EXPECT_EQ(4, static_cast<int>(matches.size()));
  EXPECT_EQ(data[0].url, matches[0].node->GetURL());
  EXPECT_EQ(data[3].url, matches[1].node->GetURL());
  EXPECT_EQ(data[2].url, matches[2].node->GetURL());
  EXPECT_EQ(data[1].url, matches[3].node->GetURL());

  matches.clear();
  // Select top two matches.
  model->GetBookmarksWithTitlesMatching(L"google", 2, &matches);

  EXPECT_EQ(2, static_cast<int>(matches.size()));
  EXPECT_EQ(data[0].url, matches[0].node->GetURL());
  EXPECT_EQ(data[3].url, matches[1].node->GetURL());
}


Generated by  Doxygen 1.6.0   Back to index