Home | History | Annotate | Download | only in history
      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.
      4 
      5 #include "chrome/browser/history/history_backend.h"
      6 
      7 #include <algorithm>
      8 #include <set>
      9 #include <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/file_util.h"
     15 #include "base/files/file_path.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/memory/scoped_ptr.h"
     18 #include "base/path_service.h"
     19 #include "base/run_loop.h"
     20 #include "base/strings/string16.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "base/strings/utf_string_conversions.h"
     23 #include "chrome/browser/chrome_notification_types.h"
     24 #include "chrome/browser/history/history_notifications.h"
     25 #include "chrome/browser/history/history_service.h"
     26 #include "chrome/browser/history/history_service_factory.h"
     27 #include "chrome/browser/history/in_memory_database.h"
     28 #include "chrome/browser/history/in_memory_history_backend.h"
     29 #include "chrome/browser/history/visit_filter.h"
     30 #include "chrome/common/chrome_constants.h"
     31 #include "chrome/common/chrome_paths.h"
     32 #include "chrome/common/importer/imported_favicon_usage.h"
     33 #include "chrome/test/base/testing_profile.h"
     34 #include "components/history/core/test/history_client_fake_bookmarks.h"
     35 #include "content/public/browser/notification_details.h"
     36 #include "content/public/browser/notification_source.h"
     37 #include "content/public/test/test_browser_thread.h"
     38 #include "testing/gmock/include/gmock/gmock.h"
     39 #include "testing/gtest/include/gtest/gtest.h"
     40 #include "url/gurl.h"
     41 
     42 using base::Time;
     43 
     44 // This file only tests functionality where it is most convenient to call the
     45 // backend directly. Most of the history backend functions are tested by the
     46 // history unit test. Because of the elaborate callbacks involved, this is no
     47 // harder than calling it directly for many things.
     48 
     49 namespace {
     50 
     51 const int kTinyEdgeSize = 10;
     52 const int kSmallEdgeSize = 16;
     53 const int kLargeEdgeSize = 32;
     54 
     55 const gfx::Size kTinySize = gfx::Size(kTinyEdgeSize, kTinyEdgeSize);
     56 const gfx::Size kSmallSize = gfx::Size(kSmallEdgeSize, kSmallEdgeSize);
     57 const gfx::Size kLargeSize = gfx::Size(kLargeEdgeSize, kLargeEdgeSize);
     58 
     59 // Comparison functions as to make it easier to check results of
     60 // GetFaviconBitmaps() and GetIconMappingsForPageURL().
     61 bool IconMappingLessThan(const history::IconMapping& a,
     62                          const history::IconMapping& b) {
     63   return a.icon_url < b.icon_url;
     64 }
     65 
     66 bool FaviconBitmapLessThan(const history::FaviconBitmap& a,
     67                            const history::FaviconBitmap& b) {
     68   return a.pixel_size.GetArea() < b.pixel_size.GetArea();
     69 }
     70 
     71 class HistoryClientMock : public history::HistoryClientFakeBookmarks {
     72  public:
     73   MOCK_METHOD0(BlockUntilBookmarksLoaded, void());
     74 };
     75 
     76 }  // namespace
     77 
     78 namespace history {
     79 
     80 class HistoryBackendTestBase;
     81 
     82 // This must be a separate object since HistoryBackend manages its lifetime.
     83 // This just forwards the messages we're interested in to the test object.
     84 class HistoryBackendTestDelegate : public HistoryBackend::Delegate {
     85  public:
     86   explicit HistoryBackendTestDelegate(HistoryBackendTestBase* test)
     87       : test_(test) {}
     88 
     89   virtual void NotifyProfileError(sql::InitStatus init_status) OVERRIDE {}
     90   virtual void SetInMemoryBackend(
     91       scoped_ptr<InMemoryHistoryBackend> backend) OVERRIDE;
     92   virtual void BroadcastNotifications(
     93       int type,
     94       scoped_ptr<HistoryDetails> details) OVERRIDE;
     95   virtual void DBLoaded() OVERRIDE;
     96   virtual void NotifyVisitDBObserversOnAddVisit(
     97       const BriefVisitInfo& info) OVERRIDE {}
     98 
     99  private:
    100   // Not owned by us.
    101   HistoryBackendTestBase* test_;
    102 
    103   DISALLOW_COPY_AND_ASSIGN(HistoryBackendTestDelegate);
    104 };
    105 
    106 class HistoryBackendCancelableRequest
    107     : public CancelableRequestProvider,
    108       public CancelableRequestConsumerTSimple<int> {
    109  public:
    110   HistoryBackendCancelableRequest() {}
    111 
    112   template<class RequestType>
    113   CancelableRequestProvider::Handle MockScheduleOfRequest(
    114       RequestType* request) {
    115     AddRequest(request, this);
    116     return request->handle();
    117   }
    118 };
    119 
    120 class HistoryBackendTestBase : public testing::Test {
    121  public:
    122   typedef std::vector<std::pair<int, HistoryDetails*> > NotificationList;
    123 
    124   HistoryBackendTestBase()
    125       : loaded_(false),
    126         ui_thread_(content::BrowserThread::UI, &message_loop_) {}
    127 
    128   virtual ~HistoryBackendTestBase() {
    129     STLDeleteValues(&broadcasted_notifications_);
    130   }
    131 
    132  protected:
    133   int num_broadcasted_notifications() const {
    134     return broadcasted_notifications_.size();
    135   }
    136 
    137   const NotificationList& broadcasted_notifications() const {
    138     return broadcasted_notifications_;
    139   }
    140 
    141   void ClearBroadcastedNotifications() {
    142     STLDeleteValues(&broadcasted_notifications_);
    143   }
    144 
    145   base::FilePath test_dir() {
    146     return test_dir_;
    147   }
    148 
    149   void BroadcastNotifications(int type, scoped_ptr<HistoryDetails> details) {
    150     // Send the notifications directly to the in-memory database.
    151     content::Details<HistoryDetails> det(details.get());
    152     mem_backend_->Observe(
    153         type, content::Source<HistoryBackendTestBase>(NULL), det);
    154 
    155     // The backend passes ownership of the details pointer to us.
    156     broadcasted_notifications_.push_back(
    157         std::make_pair(type, details.release()));
    158   }
    159 
    160   history::HistoryClientFakeBookmarks history_client_;
    161   scoped_refptr<HistoryBackend> backend_;  // Will be NULL on init failure.
    162   scoped_ptr<InMemoryHistoryBackend> mem_backend_;
    163   bool loaded_;
    164 
    165  private:
    166   friend class HistoryBackendTestDelegate;
    167 
    168   // testing::Test
    169   virtual void SetUp() {
    170     if (!base::CreateNewTempDirectory(FILE_PATH_LITERAL("BackendTest"),
    171                                       &test_dir_))
    172       return;
    173     backend_ = new HistoryBackend(
    174         test_dir_, new HistoryBackendTestDelegate(this), &history_client_);
    175     backend_->Init(std::string(), false);
    176   }
    177 
    178   virtual void TearDown() {
    179     if (backend_.get())
    180       backend_->Closing();
    181     backend_ = NULL;
    182     mem_backend_.reset();
    183     base::DeleteFile(test_dir_, true);
    184     base::RunLoop().RunUntilIdle();
    185     history_client_.ClearAllBookmarks();
    186   }
    187 
    188   void SetInMemoryBackend(scoped_ptr<InMemoryHistoryBackend> backend) {
    189     mem_backend_.swap(backend);
    190   }
    191 
    192   // The types and details of notifications which were broadcasted.
    193   NotificationList broadcasted_notifications_;
    194 
    195   base::MessageLoop message_loop_;
    196   base::FilePath test_dir_;
    197   content::TestBrowserThread ui_thread_;
    198 
    199   DISALLOW_COPY_AND_ASSIGN(HistoryBackendTestBase);
    200 };
    201 
    202 void HistoryBackendTestDelegate::SetInMemoryBackend(
    203     scoped_ptr<InMemoryHistoryBackend> backend) {
    204   test_->SetInMemoryBackend(backend.Pass());
    205 }
    206 
    207 void HistoryBackendTestDelegate::BroadcastNotifications(
    208     int type,
    209     scoped_ptr<HistoryDetails> details) {
    210   test_->BroadcastNotifications(type, details.Pass());
    211 }
    212 
    213 void HistoryBackendTestDelegate::DBLoaded() {
    214   test_->loaded_ = true;
    215 }
    216 
    217 class HistoryBackendTest : public HistoryBackendTestBase {
    218  public:
    219   HistoryBackendTest() {}
    220   virtual ~HistoryBackendTest() {}
    221 
    222   // Callback for QueryMostVisited.
    223   void OnQueryMostVisited(CancelableRequestProvider::Handle handle,
    224                           history::MostVisitedURLList data) {
    225     most_visited_list_.swap(data);
    226   }
    227 
    228   // Callback for QueryFiltered.
    229   void OnQueryFiltered(CancelableRequestProvider::Handle handle,
    230                        const history::FilteredURLList& data) {
    231     filtered_list_ = data;
    232   }
    233 
    234  protected:
    235   const history::MostVisitedURLList& get_most_visited_list() const {
    236     return most_visited_list_;
    237   }
    238 
    239   const history::FilteredURLList& get_filtered_list() const {
    240     return filtered_list_;
    241   }
    242 
    243   void AddRedirectChain(const char* sequence[], int page_id) {
    244     AddRedirectChainWithTransitionAndTime(sequence, page_id,
    245                                           content::PAGE_TRANSITION_LINK,
    246                                           Time::Now());
    247   }
    248 
    249   void AddRedirectChainWithTransitionAndTime(
    250       const char* sequence[],
    251       int page_id,
    252       content::PageTransition transition,
    253       base::Time time) {
    254     history::RedirectList redirects;
    255     for (int i = 0; sequence[i] != NULL; ++i)
    256       redirects.push_back(GURL(sequence[i]));
    257 
    258     ContextID context_id = reinterpret_cast<ContextID>(1);
    259     history::HistoryAddPageArgs request(
    260         redirects.back(), time, context_id, page_id, GURL(),
    261         redirects, transition, history::SOURCE_BROWSED,
    262         true);
    263     backend_->AddPage(request);
    264   }
    265 
    266   // Adds CLIENT_REDIRECT page transition.
    267   // |url1| is the source URL and |url2| is the destination.
    268   // |did_replace| is true if the transition is non-user initiated and the
    269   // navigation entry for |url2| has replaced that for |url1|. The possibly
    270   // updated transition code of the visit records for |url1| and |url2| is
    271   // returned by filling in |*transition1| and |*transition2|, respectively.
    272   // |time| is a time of the redirect.
    273   void AddClientRedirect(const GURL& url1, const GURL& url2, bool did_replace,
    274                          base::Time time,
    275                          int* transition1, int* transition2) {
    276     ContextID dummy_context_id = reinterpret_cast<ContextID>(0x87654321);
    277     history::RedirectList redirects;
    278     if (url1.is_valid())
    279       redirects.push_back(url1);
    280     if (url2.is_valid())
    281       redirects.push_back(url2);
    282     HistoryAddPageArgs request(
    283         url2, time, dummy_context_id, 0, url1,
    284         redirects, content::PAGE_TRANSITION_CLIENT_REDIRECT,
    285         history::SOURCE_BROWSED, did_replace);
    286     backend_->AddPage(request);
    287 
    288     *transition1 = GetTransition(url1);
    289     *transition2 = GetTransition(url2);
    290   }
    291 
    292   int GetTransition(const GURL& url) {
    293     if (!url.is_valid())
    294       return 0;
    295     URLRow row;
    296     URLID id = backend_->db()->GetRowForURL(url, &row);
    297     VisitVector visits;
    298     EXPECT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
    299     return visits[0].transition;
    300   }
    301 
    302   // Returns a vector with the small edge size.
    303   const std::vector<int> GetEdgeSizesSmall() {
    304     std::vector<int> sizes_small;
    305     sizes_small.push_back(kSmallEdgeSize);
    306     return sizes_small;
    307   }
    308 
    309   // Returns a vector with the large edge size.
    310   const std::vector<int> GetEdgeSizesLarge() {
    311     std::vector<int> sizes_large;
    312     sizes_large.push_back(kLargeEdgeSize);
    313     return sizes_large;
    314   }
    315 
    316   // Returns a vector with the small and large edge sizes.
    317   const std::vector<int> GetEdgeSizesSmallAndLarge() {
    318     std::vector<int> sizes_small_and_large;
    319     sizes_small_and_large.push_back(kSmallEdgeSize);
    320     sizes_small_and_large.push_back(kLargeEdgeSize);
    321     return sizes_small_and_large;
    322   }
    323 
    324   // Returns a vector with the tiny, small, and large edge sizes.
    325   const std::vector<int> GetEdgeSizesTinySmallAndLarge() {
    326     std::vector<int> sizes_tiny_small_and_large;
    327     sizes_tiny_small_and_large.push_back(kTinyEdgeSize);
    328     sizes_tiny_small_and_large.push_back(kSmallEdgeSize);
    329     sizes_tiny_small_and_large.push_back(kLargeEdgeSize);
    330     return sizes_tiny_small_and_large;
    331   }
    332 
    333   // Returns the number of icon mappings of |icon_type| to |page_url|.
    334   size_t NumIconMappingsForPageURL(const GURL& page_url,
    335                                    favicon_base::IconType icon_type) {
    336     std::vector<IconMapping> icon_mappings;
    337     backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_type,
    338                                                        &icon_mappings);
    339     return icon_mappings.size();
    340   }
    341 
    342   // Returns the icon mappings for |page_url| sorted alphabetically by icon
    343   // URL in ascending order. Returns true if there is at least one icon
    344   // mapping.
    345   bool GetSortedIconMappingsForPageURL(
    346       const GURL& page_url,
    347       std::vector<IconMapping>* icon_mappings) {
    348     if (!backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
    349         icon_mappings)) {
    350       return false;
    351     }
    352     std::sort(icon_mappings->begin(), icon_mappings->end(),
    353               IconMappingLessThan);
    354     return true;
    355   }
    356 
    357   // Returns the favicon bitmaps for |icon_id| sorted by pixel size in
    358   // ascending order. Returns true if there is at least one favicon bitmap.
    359   bool GetSortedFaviconBitmaps(favicon_base::FaviconID icon_id,
    360                                std::vector<FaviconBitmap>* favicon_bitmaps) {
    361     if (!backend_->thumbnail_db_->GetFaviconBitmaps(icon_id, favicon_bitmaps))
    362       return false;
    363     std::sort(favicon_bitmaps->begin(), favicon_bitmaps->end(),
    364               FaviconBitmapLessThan);
    365     return true;
    366   }
    367 
    368   // Returns true if there is exactly one favicon bitmap associated to
    369   // |favicon_id|. If true, returns favicon bitmap in output parameter.
    370   bool GetOnlyFaviconBitmap(const favicon_base::FaviconID icon_id,
    371                             FaviconBitmap* favicon_bitmap) {
    372     std::vector<FaviconBitmap> favicon_bitmaps;
    373     if (!backend_->thumbnail_db_->GetFaviconBitmaps(icon_id, &favicon_bitmaps))
    374       return false;
    375     if (favicon_bitmaps.size() != 1)
    376       return false;
    377     *favicon_bitmap = favicon_bitmaps[0];
    378     return true;
    379   }
    380 
    381   // Generates |favicon_bitmap_data| with entries for the icon_urls and sizes
    382   // specified. The bitmap_data for entries are lowercase letters of the
    383   // alphabet starting at 'a' for the entry at index 0.
    384   void GenerateFaviconBitmapData(
    385       const GURL& icon_url1,
    386       const std::vector<int>& icon_url1_sizes,
    387       std::vector<favicon_base::FaviconRawBitmapData>* favicon_bitmap_data) {
    388     GenerateFaviconBitmapData(icon_url1, icon_url1_sizes, GURL(),
    389                               std::vector<int>(), favicon_bitmap_data);
    390   }
    391 
    392   void GenerateFaviconBitmapData(
    393       const GURL& icon_url1,
    394       const std::vector<int>& icon_url1_sizes,
    395       const GURL& icon_url2,
    396       const std::vector<int>& icon_url2_sizes,
    397       std::vector<favicon_base::FaviconRawBitmapData>* favicon_bitmap_data) {
    398     favicon_bitmap_data->clear();
    399 
    400     char bitmap_char = 'a';
    401     for (size_t i = 0; i < icon_url1_sizes.size(); ++i) {
    402       std::vector<unsigned char> data;
    403       data.push_back(bitmap_char);
    404       favicon_base::FaviconRawBitmapData bitmap_data_element;
    405       bitmap_data_element.bitmap_data =
    406           base::RefCountedBytes::TakeVector(&data);
    407       bitmap_data_element.pixel_size =
    408           gfx::Size(icon_url1_sizes[i], icon_url1_sizes[i]);
    409       bitmap_data_element.icon_url = icon_url1;
    410       favicon_bitmap_data->push_back(bitmap_data_element);
    411 
    412       ++bitmap_char;
    413     }
    414 
    415     for (size_t i = 0; i < icon_url2_sizes.size(); ++i) {
    416       std::vector<unsigned char> data;
    417       data.push_back(bitmap_char);
    418       favicon_base::FaviconRawBitmapData bitmap_data_element;
    419       bitmap_data_element.bitmap_data =
    420           base::RefCountedBytes::TakeVector(&data);
    421       bitmap_data_element.pixel_size =
    422           gfx::Size(icon_url2_sizes[i], icon_url2_sizes[i]);
    423       bitmap_data_element.icon_url = icon_url2;
    424       favicon_bitmap_data->push_back(bitmap_data_element);
    425 
    426       ++bitmap_char;
    427     }
    428   }
    429 
    430   // Returns true if |bitmap_data| is equal to |expected_data|.
    431   bool BitmapDataEqual(char expected_data,
    432                        scoped_refptr<base::RefCountedMemory> bitmap_data) {
    433     return bitmap_data.get() &&
    434            bitmap_data->size() == 1u &&
    435            *bitmap_data->front() == expected_data;
    436   }
    437 
    438  private:
    439   history::MostVisitedURLList most_visited_list_;
    440   history::FilteredURLList filtered_list_;
    441 
    442   DISALLOW_COPY_AND_ASSIGN(HistoryBackendTest);
    443 };
    444 
    445 class InMemoryHistoryBackendTest : public HistoryBackendTestBase {
    446  public:
    447   InMemoryHistoryBackendTest() {}
    448   virtual ~InMemoryHistoryBackendTest() {}
    449 
    450  protected:
    451   void SimulateNotification(int type,
    452                             const URLRow* row1,
    453                             const URLRow* row2 = NULL,
    454                             const URLRow* row3 = NULL) {
    455     URLRows rows;
    456     rows.push_back(*row1);
    457     if (row2) rows.push_back(*row2);
    458     if (row3) rows.push_back(*row3);
    459 
    460     if (type == chrome::NOTIFICATION_HISTORY_URLS_MODIFIED) {
    461       scoped_ptr<URLsModifiedDetails> details(new URLsModifiedDetails());
    462       details->changed_urls.swap(rows);
    463       BroadcastNotifications(type, details.PassAs<HistoryDetails>());
    464     } else if (type == chrome::NOTIFICATION_HISTORY_URL_VISITED) {
    465       for (URLRows::const_iterator it = rows.begin(); it != rows.end(); ++it) {
    466         scoped_ptr<URLVisitedDetails> details(new URLVisitedDetails());
    467         details->row = *it;
    468         BroadcastNotifications(type, details.PassAs<HistoryDetails>());
    469       }
    470     } else if (type == chrome::NOTIFICATION_HISTORY_URLS_DELETED) {
    471       scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails());
    472       details->rows = rows;
    473       BroadcastNotifications(type, details.PassAs<HistoryDetails>());
    474     } else {
    475       NOTREACHED();
    476     }
    477   }
    478 
    479   size_t GetNumberOfMatchingSearchTerms(const int keyword_id,
    480                                         const base::string16& prefix) {
    481     std::vector<KeywordSearchTermVisit> matching_terms;
    482     mem_backend_->db()->GetMostRecentKeywordSearchTerms(
    483         keyword_id, prefix, 1, &matching_terms);
    484     return matching_terms.size();
    485   }
    486 
    487   static URLRow CreateTestTypedURL() {
    488     URLRow url_row(GURL("https://www.google.com/"));
    489     url_row.set_id(10);
    490     url_row.set_title(base::UTF8ToUTF16("Google Search"));
    491     url_row.set_typed_count(1);
    492     url_row.set_visit_count(1);
    493     url_row.set_last_visit(Time::Now() - base::TimeDelta::FromHours(1));
    494     return url_row;
    495   }
    496 
    497   static URLRow CreateAnotherTestTypedURL() {
    498     URLRow url_row(GURL("https://maps.google.com/"));
    499     url_row.set_id(20);
    500     url_row.set_title(base::UTF8ToUTF16("Google Maps"));
    501     url_row.set_typed_count(2);
    502     url_row.set_visit_count(3);
    503     url_row.set_last_visit(Time::Now() - base::TimeDelta::FromHours(2));
    504     return url_row;
    505   }
    506 
    507   static URLRow CreateTestNonTypedURL() {
    508     URLRow url_row(GURL("https://news.google.com/"));
    509     url_row.set_id(30);
    510     url_row.set_title(base::UTF8ToUTF16("Google News"));
    511     url_row.set_visit_count(5);
    512     url_row.set_last_visit(Time::Now() - base::TimeDelta::FromHours(3));
    513     return url_row;
    514   }
    515 
    516   void PopulateTestURLsAndSearchTerms(URLRow* row1,
    517                                       URLRow* row2,
    518                                       const base::string16& term1,
    519                                       const base::string16& term2);
    520 
    521   void TestAddingAndChangingURLRows(int notification_type);
    522 
    523   static const TemplateURLID kTestKeywordId;
    524   static const char kTestSearchTerm1[];
    525   static const char kTestSearchTerm2[];
    526 
    527  private:
    528   DISALLOW_COPY_AND_ASSIGN(InMemoryHistoryBackendTest);
    529 };
    530 
    531 const TemplateURLID InMemoryHistoryBackendTest::kTestKeywordId = 42;
    532 const char InMemoryHistoryBackendTest::kTestSearchTerm1[] = "banana";
    533 const char InMemoryHistoryBackendTest::kTestSearchTerm2[] = "orange";
    534 
    535 // http://crbug.com/114287
    536 #if defined(OS_WIN)
    537 #define MAYBE_Loaded DISABLED_Loaded
    538 #else
    539 #define MAYBE_Loaded Loaded
    540 #endif // defined(OS_WIN)
    541 TEST_F(HistoryBackendTest, MAYBE_Loaded) {
    542   ASSERT_TRUE(backend_.get());
    543   ASSERT_TRUE(loaded_);
    544 }
    545 
    546 TEST_F(HistoryBackendTest, DeleteAll) {
    547   ASSERT_TRUE(backend_.get());
    548 
    549   // Add two favicons, each with two bitmaps. Note that we add favicon2 before
    550   // adding favicon1. This is so that favicon1 one gets ID 2 autoassigned to
    551   // the database, which will change when the other one is deleted. This way
    552   // we can test that updating works properly.
    553   GURL favicon_url1("http://www.google.com/favicon.ico");
    554   GURL favicon_url2("http://news.google.com/favicon.ico");
    555   favicon_base::FaviconID favicon2 =
    556       backend_->thumbnail_db_->AddFavicon(favicon_url2, favicon_base::FAVICON);
    557   favicon_base::FaviconID favicon1 =
    558       backend_->thumbnail_db_->AddFavicon(favicon_url1, favicon_base::FAVICON);
    559 
    560   std::vector<unsigned char> data;
    561   data.push_back('a');
    562   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1,
    563       new base::RefCountedBytes(data), Time::Now(), kSmallSize));
    564   data[0] = 'b';
    565   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon1,
    566      new base::RefCountedBytes(data), Time::Now(), kLargeSize));
    567 
    568   data[0] = 'c';
    569   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2,
    570       new base::RefCountedBytes(data), Time::Now(), kSmallSize));
    571   data[0] = 'd';
    572   EXPECT_TRUE(backend_->thumbnail_db_->AddFaviconBitmap(favicon2,
    573      new base::RefCountedBytes(data), Time::Now(), kLargeSize));
    574 
    575   // First visit two URLs.
    576   URLRow row1(GURL("http://www.google.com/"));
    577   row1.set_visit_count(2);
    578   row1.set_typed_count(1);
    579   row1.set_last_visit(Time::Now());
    580   backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1);
    581 
    582   URLRow row2(GURL("http://news.google.com/"));
    583   row2.set_visit_count(1);
    584   row2.set_last_visit(Time::Now());
    585   backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2);
    586 
    587   URLRows rows;
    588   rows.push_back(row2);  // Reversed order for the same reason as favicons.
    589   rows.push_back(row1);
    590   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    591 
    592   URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
    593   URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
    594 
    595   // Get the two visits for the URLs we just added.
    596   VisitVector visits;
    597   backend_->db_->GetVisitsForURL(row1_id, &visits);
    598   ASSERT_EQ(1U, visits.size());
    599 
    600   visits.clear();
    601   backend_->db_->GetVisitsForURL(row2_id, &visits);
    602   ASSERT_EQ(1U, visits.size());
    603 
    604   // The in-memory backend should have been set and it should have gotten the
    605   // typed URL.
    606   ASSERT_TRUE(mem_backend_.get());
    607   URLRow outrow1;
    608   EXPECT_TRUE(mem_backend_->db_->GetRowForURL(row1.url(), NULL));
    609 
    610   // Star row1.
    611   history_client_.AddBookmark(row1.url());
    612 
    613   // Now finally clear all history.
    614   ClearBroadcastedNotifications();
    615   backend_->DeleteAllHistory();
    616 
    617   // The first URL should be preserved but the time should be cleared.
    618   EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1));
    619   EXPECT_EQ(row1.url(), outrow1.url());
    620   EXPECT_EQ(0, outrow1.visit_count());
    621   EXPECT_EQ(0, outrow1.typed_count());
    622   EXPECT_TRUE(Time() == outrow1.last_visit());
    623 
    624   // The second row should be deleted.
    625   URLRow outrow2;
    626   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &outrow2));
    627 
    628   // All visits should be deleted for both URLs.
    629   VisitVector all_visits;
    630   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    631   ASSERT_EQ(0U, all_visits.size());
    632 
    633   // We should have a favicon and favicon bitmaps for the first URL only. We
    634   // look them up by favicon URL since the IDs may have changed.
    635   favicon_base::FaviconID out_favicon1 =
    636       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
    637           favicon_url1, favicon_base::FAVICON, NULL);
    638   EXPECT_TRUE(out_favicon1);
    639 
    640   std::vector<FaviconBitmap> favicon_bitmaps;
    641   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
    642       out_favicon1, &favicon_bitmaps));
    643   ASSERT_EQ(2u, favicon_bitmaps.size());
    644 
    645   FaviconBitmap favicon_bitmap1 = favicon_bitmaps[0];
    646   FaviconBitmap favicon_bitmap2 = favicon_bitmaps[1];
    647 
    648   // Favicon bitmaps do not need to be in particular order.
    649   if (favicon_bitmap1.pixel_size == kLargeSize) {
    650     FaviconBitmap tmp_favicon_bitmap = favicon_bitmap1;
    651     favicon_bitmap1 = favicon_bitmap2;
    652     favicon_bitmap2 = tmp_favicon_bitmap;
    653   }
    654 
    655   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap1.bitmap_data));
    656   EXPECT_EQ(kSmallSize, favicon_bitmap1.pixel_size);
    657 
    658   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap2.bitmap_data));
    659   EXPECT_EQ(kLargeSize, favicon_bitmap2.pixel_size);
    660 
    661   favicon_base::FaviconID out_favicon2 =
    662       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
    663           favicon_url2, favicon_base::FAVICON, NULL);
    664   EXPECT_FALSE(out_favicon2) << "Favicon not deleted";
    665 
    666   // The remaining URL should still reference the same favicon, even if its
    667   // ID has changed.
    668   std::vector<IconMapping> mappings;
    669   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
    670       outrow1.url(), favicon_base::FAVICON, &mappings));
    671   EXPECT_EQ(1u, mappings.size());
    672   EXPECT_EQ(out_favicon1, mappings[0].icon_id);
    673 
    674   // The first URL should still be bookmarked.
    675   EXPECT_TRUE(history_client_.IsBookmarked(row1.url()));
    676 
    677   // Check that we fire the notification about all history having been deleted.
    678   ASSERT_EQ(1u, broadcasted_notifications().size());
    679   ASSERT_EQ(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
    680             broadcasted_notifications()[0].first);
    681   const URLsDeletedDetails* details = static_cast<const URLsDeletedDetails*>(
    682       broadcasted_notifications()[0].second);
    683   EXPECT_TRUE(details->all_history);
    684   EXPECT_FALSE(details->expired);
    685 }
    686 
    687 // Checks that adding a visit, then calling DeleteAll, and then trying to add
    688 // data for the visited page works.  This can happen when clearing the history
    689 // immediately after visiting a page.
    690 TEST_F(HistoryBackendTest, DeleteAllThenAddData) {
    691   ASSERT_TRUE(backend_.get());
    692 
    693   Time visit_time = Time::Now();
    694   GURL url("http://www.google.com/");
    695   HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
    696                              history::RedirectList(),
    697                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
    698                              history::SOURCE_BROWSED, false);
    699   backend_->AddPage(request);
    700 
    701   // Check that a row was added.
    702   URLRow outrow;
    703   EXPECT_TRUE(backend_->db_->GetRowForURL(url, &outrow));
    704 
    705   // Check that the visit was added.
    706   VisitVector all_visits;
    707   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    708   ASSERT_EQ(1U, all_visits.size());
    709 
    710   // Clear all history.
    711   backend_->DeleteAllHistory();
    712 
    713   // The row should be deleted.
    714   EXPECT_FALSE(backend_->db_->GetRowForURL(url, &outrow));
    715 
    716   // The visit should be deleted.
    717   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    718   ASSERT_EQ(0U, all_visits.size());
    719 
    720   // Try and set the title.
    721   backend_->SetPageTitle(url, base::UTF8ToUTF16("Title"));
    722 
    723   // The row should still be deleted.
    724   EXPECT_FALSE(backend_->db_->GetRowForURL(url, &outrow));
    725 
    726   // The visit should still be deleted.
    727   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
    728   ASSERT_EQ(0U, all_visits.size());
    729 }
    730 
    731 TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
    732   GURL favicon_url1("http://www.google.com/favicon.ico");
    733   GURL favicon_url2("http://news.google.com/favicon.ico");
    734 
    735   std::vector<unsigned char> data;
    736   data.push_back('1');
    737   favicon_base::FaviconID favicon1 =
    738       backend_->thumbnail_db_->AddFavicon(favicon_url1,
    739                                           favicon_base::FAVICON,
    740                                           new base::RefCountedBytes(data),
    741                                           Time::Now(),
    742                                           gfx::Size());
    743 
    744   data[0] = '2';
    745   favicon_base::FaviconID favicon2 =
    746       backend_->thumbnail_db_->AddFavicon(favicon_url2,
    747                                           favicon_base::FAVICON,
    748                                           new base::RefCountedBytes(data),
    749                                           Time::Now(),
    750                                           gfx::Size());
    751 
    752   // First visit two URLs.
    753   URLRow row1(GURL("http://www.google.com/"));
    754   row1.set_visit_count(2);
    755   row1.set_typed_count(1);
    756   row1.set_last_visit(Time::Now());
    757   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
    758 
    759   URLRow row2(GURL("http://news.google.com/"));
    760   row2.set_visit_count(1);
    761   row2.set_last_visit(Time::Now());
    762   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2));
    763 
    764   URLRows rows;
    765   rows.push_back(row2);  // Reversed order for the same reason as favicons.
    766   rows.push_back(row1);
    767   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    768 
    769   URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
    770   URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
    771 
    772   // Star the two URLs.
    773   history_client_.AddBookmark(row1.url());
    774   history_client_.AddBookmark(row2.url());
    775 
    776   // Delete url 2. Because url 2 is starred this won't delete the URL, only
    777   // the visits.
    778   backend_->expirer_.DeleteURL(row2.url());
    779 
    780   // Make sure url 2 is still valid, but has no visits.
    781   URLRow tmp_url_row;
    782   EXPECT_EQ(row2_id, backend_->db_->GetRowForURL(row2.url(), NULL));
    783   VisitVector visits;
    784   backend_->db_->GetVisitsForURL(row2_id, &visits);
    785   EXPECT_EQ(0U, visits.size());
    786   // The favicon should still be valid.
    787   EXPECT_EQ(favicon2,
    788             backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
    789                 favicon_url2, favicon_base::FAVICON, NULL));
    790 
    791   // Unstar row2.
    792   history_client_.DelBookmark(row2.url());
    793 
    794   // Tell the backend it was unstarred. We have to explicitly do this as
    795   // BookmarkModel isn't wired up to the backend during testing.
    796   std::set<GURL> unstarred_urls;
    797   unstarred_urls.insert(row2.url());
    798   backend_->URLsNoLongerBookmarked(unstarred_urls);
    799 
    800   // The URL should no longer exist.
    801   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row));
    802   // And the favicon should be deleted.
    803   EXPECT_EQ(0,
    804             backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
    805                 favicon_url2, favicon_base::FAVICON, NULL));
    806 
    807   // Unstar row 1.
    808   history_client_.DelBookmark(row1.url());
    809 
    810   // Tell the backend it was unstarred. We have to explicitly do this as
    811   // BookmarkModel isn't wired up to the backend during testing.
    812   unstarred_urls.clear();
    813   unstarred_urls.insert(row1.url());
    814   backend_->URLsNoLongerBookmarked(unstarred_urls);
    815 
    816   // The URL should still exist (because there were visits).
    817   EXPECT_EQ(row1_id, backend_->db_->GetRowForURL(row1.url(), NULL));
    818 
    819   // There should still be visits.
    820   visits.clear();
    821   backend_->db_->GetVisitsForURL(row1_id, &visits);
    822   EXPECT_EQ(1U, visits.size());
    823 
    824   // The favicon should still be valid.
    825   EXPECT_EQ(favicon1,
    826             backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
    827                 favicon_url1, favicon_base::FAVICON, NULL));
    828 }
    829 
    830 // Tests a handful of assertions for a navigation with a type of
    831 // KEYWORD_GENERATED.
    832 TEST_F(HistoryBackendTest, KeywordGenerated) {
    833   ASSERT_TRUE(backend_.get());
    834 
    835   GURL url("http://google.com");
    836 
    837   Time visit_time = Time::Now() - base::TimeDelta::FromDays(1);
    838   HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
    839                              history::RedirectList(),
    840                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
    841                              history::SOURCE_BROWSED, false);
    842   backend_->AddPage(request);
    843 
    844   // A row should have been added for the url.
    845   URLRow row;
    846   URLID url_id = backend_->db()->GetRowForURL(url, &row);
    847   ASSERT_NE(0, url_id);
    848 
    849   // The typed count should be 1.
    850   ASSERT_EQ(1, row.typed_count());
    851 
    852   // KEYWORD_GENERATED urls should not be added to the segment db.
    853   std::string segment_name = VisitSegmentDatabase::ComputeSegmentName(url);
    854   EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment_name));
    855 
    856   // One visit should be added.
    857   VisitVector visits;
    858   EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
    859   EXPECT_EQ(1U, visits.size());
    860 
    861   // But no visible visits.
    862   visits.clear();
    863   QueryOptions query_options;
    864   query_options.max_count = 1;
    865   backend_->db()->GetVisibleVisitsInRange(query_options, &visits);
    866   EXPECT_TRUE(visits.empty());
    867 
    868   // Expire the visits.
    869   std::set<GURL> restrict_urls;
    870   backend_->expire_backend()->ExpireHistoryBetween(restrict_urls,
    871                                                    visit_time, Time::Now());
    872 
    873   // The visit should have been nuked.
    874   visits.clear();
    875   EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
    876   EXPECT_TRUE(visits.empty());
    877 
    878   // As well as the url.
    879   ASSERT_EQ(0, backend_->db()->GetRowForURL(url, &row));
    880 }
    881 
    882 TEST_F(HistoryBackendTest, ClientRedirect) {
    883   ASSERT_TRUE(backend_.get());
    884 
    885   int transition1;
    886   int transition2;
    887 
    888   // Initial transition to page A.
    889   GURL url_a("http://google.com/a");
    890   AddClientRedirect(GURL(), url_a, false, base::Time(),
    891                     &transition1, &transition2);
    892   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
    893 
    894   // User initiated redirect to page B.
    895   GURL url_b("http://google.com/b");
    896   AddClientRedirect(url_a, url_b, false, base::Time(),
    897                     &transition1, &transition2);
    898   EXPECT_TRUE(transition1 & content::PAGE_TRANSITION_CHAIN_END);
    899   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
    900 
    901   // Non-user initiated redirect to page C.
    902   GURL url_c("http://google.com/c");
    903   AddClientRedirect(url_b, url_c, true, base::Time(),
    904                     &transition1, &transition2);
    905   EXPECT_FALSE(transition1 & content::PAGE_TRANSITION_CHAIN_END);
    906   EXPECT_TRUE(transition2 & content::PAGE_TRANSITION_CHAIN_END);
    907 }
    908 
    909 TEST_F(HistoryBackendTest, AddPagesWithDetails) {
    910   ASSERT_TRUE(backend_.get());
    911 
    912   // Import one non-typed URL, and two recent and one expired typed URLs.
    913   URLRow row1(GURL("https://news.google.com/"));
    914   row1.set_visit_count(1);
    915   row1.set_last_visit(Time::Now());
    916   URLRow row2(GURL("https://www.google.com/"));
    917   row2.set_typed_count(1);
    918   row2.set_last_visit(Time::Now());
    919   URLRow row3(GURL("https://mail.google.com/"));
    920   row3.set_visit_count(1);
    921   row3.set_typed_count(1);
    922   row3.set_last_visit(Time::Now() - base::TimeDelta::FromDays(7 - 1));
    923   URLRow row4(GURL("https://maps.google.com/"));
    924   row4.set_visit_count(1);
    925   row4.set_typed_count(1);
    926   row4.set_last_visit(Time::Now() - base::TimeDelta::FromDays(365 + 2));
    927 
    928   URLRows rows;
    929   rows.push_back(row1);
    930   rows.push_back(row2);
    931   rows.push_back(row3);
    932   rows.push_back(row4);
    933   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    934 
    935   // Verify that recent URLs have ended up in the main |db_|, while the already
    936   // expired URL has been ignored.
    937   URLRow stored_row1, stored_row2, stored_row3, stored_row4;
    938   EXPECT_NE(0, backend_->db_->GetRowForURL(row1.url(), &stored_row1));
    939   EXPECT_NE(0, backend_->db_->GetRowForURL(row2.url(), &stored_row2));
    940   EXPECT_NE(0, backend_->db_->GetRowForURL(row3.url(), &stored_row3));
    941   EXPECT_EQ(0, backend_->db_->GetRowForURL(row4.url(), &stored_row4));
    942 
    943   // Ensure that a notification was fired for both typed and non-typed URLs.
    944   // Further verify that the IDs in the notification are set to those that are
    945   // in effect in the main database. The InMemoryHistoryBackend relies on this
    946   // for caching.
    947   ASSERT_EQ(1u, broadcasted_notifications().size());
    948   ASSERT_EQ(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
    949             broadcasted_notifications()[0].first);
    950   const URLsModifiedDetails* details = static_cast<const URLsModifiedDetails*>(
    951       broadcasted_notifications()[0].second);
    952   EXPECT_EQ(3u, details->changed_urls.size());
    953 
    954   URLRows::const_iterator it_row1 = std::find_if(
    955       details->changed_urls.begin(),
    956       details->changed_urls.end(),
    957       history::URLRow::URLRowHasURL(row1.url()));
    958   ASSERT_NE(details->changed_urls.end(), it_row1);
    959   EXPECT_EQ(stored_row1.id(), it_row1->id());
    960 
    961   URLRows::const_iterator it_row2 = std::find_if(
    962         details->changed_urls.begin(),
    963         details->changed_urls.end(),
    964         history::URLRow::URLRowHasURL(row2.url()));
    965   ASSERT_NE(details->changed_urls.end(), it_row2);
    966   EXPECT_EQ(stored_row2.id(), it_row2->id());
    967 
    968   URLRows::const_iterator it_row3 = std::find_if(
    969         details->changed_urls.begin(),
    970         details->changed_urls.end(),
    971         history::URLRow::URLRowHasURL(row3.url()));
    972   ASSERT_NE(details->changed_urls.end(), it_row3);
    973   EXPECT_EQ(stored_row3.id(), it_row3->id());
    974 }
    975 
    976 // This verifies that a notification is fired. In-depth testing of logic should
    977 // be done in HistoryTest.SetTitle.
    978 TEST_F(HistoryBackendTest, SetPageTitleFiresNotificationWithCorrectDetails) {
    979   const char kTestUrlTitle[] = "Google Search";
    980 
    981   ASSERT_TRUE(backend_.get());
    982 
    983   // Add two pages, then change the title of the second one.
    984   URLRow row1(GURL("https://news.google.com/"));
    985   row1.set_typed_count(1);
    986   row1.set_last_visit(Time::Now());
    987   URLRow row2(GURL("https://www.google.com/"));
    988   row2.set_visit_count(2);
    989   row2.set_last_visit(Time::Now());
    990 
    991   URLRows rows;
    992   rows.push_back(row1);
    993   rows.push_back(row2);
    994   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
    995 
    996   ClearBroadcastedNotifications();
    997   backend_->SetPageTitle(row2.url(), base::UTF8ToUTF16(kTestUrlTitle));
    998 
    999   // Ensure that a notification was fired, and further verify that the IDs in
   1000   // the notification are set to those that are in effect in the main database.
   1001   // The InMemoryHistoryBackend relies on this for caching.
   1002   URLRow stored_row2;
   1003   EXPECT_TRUE(backend_->GetURL(row2.url(), &stored_row2));
   1004   ASSERT_EQ(1u, broadcasted_notifications().size());
   1005   ASSERT_EQ(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
   1006             broadcasted_notifications()[0].first);
   1007   const URLsModifiedDetails* details = static_cast<const URLsModifiedDetails*>(
   1008       broadcasted_notifications()[0].second);
   1009   ASSERT_EQ(1u, details->changed_urls.size());
   1010   EXPECT_EQ(base::UTF8ToUTF16(kTestUrlTitle), details->changed_urls[0].title());
   1011   EXPECT_EQ(stored_row2.id(), details->changed_urls[0].id());
   1012 }
   1013 
   1014 TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
   1015   // Setup test data - two Urls in the history, one with favicon assigned and
   1016   // one without.
   1017   GURL favicon_url1("http://www.google.com/favicon.ico");
   1018   std::vector<unsigned char> data;
   1019   data.push_back('1');
   1020   favicon_base::FaviconID favicon1 = backend_->thumbnail_db_->AddFavicon(
   1021       favicon_url1,
   1022       favicon_base::FAVICON,
   1023       base::RefCountedBytes::TakeVector(&data),
   1024       Time::Now(),
   1025       gfx::Size());
   1026   URLRow row1(GURL("http://www.google.com/"));
   1027   row1.set_visit_count(1);
   1028   row1.set_last_visit(Time::Now());
   1029   EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
   1030 
   1031   URLRow row2(GURL("http://news.google.com/"));
   1032   row2.set_visit_count(1);
   1033   row2.set_last_visit(Time::Now());
   1034   URLRows rows;
   1035   rows.push_back(row1);
   1036   rows.push_back(row2);
   1037   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
   1038   URLRow url_row1, url_row2;
   1039   EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
   1040   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
   1041   EXPECT_EQ(1u, NumIconMappingsForPageURL(row1.url(), favicon_base::FAVICON));
   1042   EXPECT_EQ(0u, NumIconMappingsForPageURL(row2.url(), favicon_base::FAVICON));
   1043 
   1044   // Now provide one imported favicon for both URLs already in the registry.
   1045   // The new favicon should only be used with the URL that doesn't already have
   1046   // a favicon.
   1047   std::vector<ImportedFaviconUsage> favicons;
   1048   ImportedFaviconUsage favicon;
   1049   favicon.favicon_url = GURL("http://news.google.com/favicon.ico");
   1050   favicon.png_data.push_back('2');
   1051   favicon.urls.insert(row1.url());
   1052   favicon.urls.insert(row2.url());
   1053   favicons.push_back(favicon);
   1054   backend_->SetImportedFavicons(favicons);
   1055   EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
   1056   EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
   1057 
   1058   std::vector<IconMapping> mappings;
   1059   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1060       row1.url(), favicon_base::FAVICON, &mappings));
   1061   EXPECT_EQ(1u, mappings.size());
   1062   EXPECT_EQ(favicon1, mappings[0].icon_id);
   1063   EXPECT_EQ(favicon_url1, mappings[0].icon_url);
   1064 
   1065   mappings.clear();
   1066   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1067       row2.url(), favicon_base::FAVICON, &mappings));
   1068   EXPECT_EQ(1u, mappings.size());
   1069   EXPECT_EQ(favicon.favicon_url, mappings[0].icon_url);
   1070 
   1071   // A URL should not be added to history (to store favicon), if
   1072   // the URL is not bookmarked.
   1073   GURL url3("http://mail.google.com");
   1074   favicons.clear();
   1075   favicon.favicon_url = GURL("http://mail.google.com/favicon.ico");
   1076   favicon.png_data.push_back('3');
   1077   favicon.urls.insert(url3);
   1078   favicons.push_back(favicon);
   1079   backend_->SetImportedFavicons(favicons);
   1080   URLRow url_row3;
   1081   EXPECT_TRUE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
   1082 
   1083   // If the URL is bookmarked, it should get added to history with 0 visits.
   1084   history_client_.AddBookmark(url3);
   1085   backend_->SetImportedFavicons(favicons);
   1086   EXPECT_FALSE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
   1087   EXPECT_TRUE(url_row3.visit_count() == 0);
   1088 }
   1089 
   1090 TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
   1091   ASSERT_TRUE(backend_.get());
   1092 
   1093   GURL url("http://anyuser:anypass@www.google.com");
   1094   GURL stripped_url("http://www.google.com");
   1095 
   1096   // Clear all history.
   1097   backend_->DeleteAllHistory();
   1098 
   1099   // Visit the url with username, password.
   1100   backend_->AddPageVisit(url, base::Time::Now(), 0,
   1101       content::PageTransitionFromInt(
   1102           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
   1103       history::SOURCE_BROWSED);
   1104 
   1105   // Fetch the row information about stripped url from history db.
   1106   VisitVector visits;
   1107   URLID row_id = backend_->db_->GetRowForURL(stripped_url, NULL);
   1108   backend_->db_->GetVisitsForURL(row_id, &visits);
   1109 
   1110   // Check if stripped url is stored in database.
   1111   ASSERT_EQ(1U, visits.size());
   1112 }
   1113 
   1114 TEST_F(HistoryBackendTest, AddPageVisitSource) {
   1115   ASSERT_TRUE(backend_.get());
   1116 
   1117   GURL url("http://www.google.com");
   1118 
   1119   // Clear all history.
   1120   backend_->DeleteAllHistory();
   1121 
   1122   // Assume visiting the url from an externsion.
   1123   backend_->AddPageVisit(
   1124       url, base::Time::Now(), 0, content::PAGE_TRANSITION_TYPED,
   1125       history::SOURCE_EXTENSION);
   1126   // Assume the url is imported from Firefox.
   1127   backend_->AddPageVisit(url, base::Time::Now(), 0,
   1128                          content::PAGE_TRANSITION_TYPED,
   1129                          history::SOURCE_FIREFOX_IMPORTED);
   1130   // Assume this url is also synced.
   1131   backend_->AddPageVisit(url, base::Time::Now(), 0,
   1132                          content::PAGE_TRANSITION_TYPED,
   1133                          history::SOURCE_SYNCED);
   1134 
   1135   // Fetch the row information about the url from history db.
   1136   VisitVector visits;
   1137   URLID row_id = backend_->db_->GetRowForURL(url, NULL);
   1138   backend_->db_->GetVisitsForURL(row_id, &visits);
   1139 
   1140   // Check if all the visits to the url are stored in database.
   1141   ASSERT_EQ(3U, visits.size());
   1142   VisitSourceMap visit_sources;
   1143   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1144   ASSERT_EQ(3U, visit_sources.size());
   1145   int sources = 0;
   1146   for (int i = 0; i < 3; i++) {
   1147     switch (visit_sources[visits[i].visit_id]) {
   1148       case history::SOURCE_EXTENSION:
   1149         sources |= 0x1;
   1150         break;
   1151       case history::SOURCE_FIREFOX_IMPORTED:
   1152         sources |= 0x2;
   1153         break;
   1154       case history::SOURCE_SYNCED:
   1155         sources |= 0x4;
   1156       default:
   1157         break;
   1158     }
   1159   }
   1160   EXPECT_EQ(0x7, sources);
   1161 }
   1162 
   1163 TEST_F(HistoryBackendTest, AddPageVisitNotLastVisit) {
   1164   ASSERT_TRUE(backend_.get());
   1165 
   1166   GURL url("http://www.google.com");
   1167 
   1168   // Clear all history.
   1169   backend_->DeleteAllHistory();
   1170 
   1171   // Create visit times
   1172   base::Time recent_time = base::Time::Now();
   1173   base::TimeDelta visit_age = base::TimeDelta::FromDays(3);
   1174   base::Time older_time = recent_time - visit_age;
   1175 
   1176   // Visit the url with recent time.
   1177   backend_->AddPageVisit(url, recent_time, 0,
   1178       content::PageTransitionFromInt(
   1179           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
   1180       history::SOURCE_BROWSED);
   1181 
   1182   // Add to the url a visit with older time (could be syncing from another
   1183   // client, etc.).
   1184   backend_->AddPageVisit(url, older_time, 0,
   1185       content::PageTransitionFromInt(
   1186           content::PageTransitionGetQualifier(content::PAGE_TRANSITION_TYPED)),
   1187       history::SOURCE_SYNCED);
   1188 
   1189   // Fetch the row information about url from history db.
   1190   VisitVector visits;
   1191   URLRow row;
   1192   URLID row_id = backend_->db_->GetRowForURL(url, &row);
   1193   backend_->db_->GetVisitsForURL(row_id, &visits);
   1194 
   1195   // Last visit time should be the most recent time, not the most recently added
   1196   // visit.
   1197   ASSERT_EQ(2U, visits.size());
   1198   ASSERT_EQ(recent_time, row.last_visit());
   1199 }
   1200 
   1201 TEST_F(HistoryBackendTest, AddPageVisitFiresNotificationWithCorrectDetails) {
   1202   ASSERT_TRUE(backend_.get());
   1203 
   1204   GURL url1("http://www.google.com");
   1205   GURL url2("http://maps.google.com");
   1206 
   1207   // Clear all history.
   1208   backend_->DeleteAllHistory();
   1209   ClearBroadcastedNotifications();
   1210 
   1211   // Visit two distinct URLs, the second one twice.
   1212   backend_->AddPageVisit(url1, base::Time::Now(), 0,
   1213                          content::PAGE_TRANSITION_LINK,
   1214                          history::SOURCE_BROWSED);
   1215   for (int i = 0; i < 2; ++i) {
   1216     backend_->AddPageVisit(url2, base::Time::Now(), 0,
   1217                            content::PAGE_TRANSITION_TYPED,
   1218                            history::SOURCE_BROWSED);
   1219   }
   1220 
   1221   URLRow stored_row1, stored_row2;
   1222   EXPECT_NE(0, backend_->db_->GetRowForURL(url1, &stored_row1));
   1223   EXPECT_NE(0, backend_->db_->GetRowForURL(url2, &stored_row2));
   1224 
   1225   // Expect that NOTIFICATION_HISTORY_URLS_VISITED has been fired 3x, and that
   1226   // each time, the URLRows have the correct URLs and IDs set.
   1227   ASSERT_EQ(3, num_broadcasted_notifications());
   1228   ASSERT_EQ(chrome::NOTIFICATION_HISTORY_URL_VISITED,
   1229             broadcasted_notifications()[0].first);
   1230   const URLVisitedDetails* details = static_cast<const URLVisitedDetails*>(
   1231       broadcasted_notifications()[0].second);
   1232   EXPECT_EQ(content::PAGE_TRANSITION_LINK,
   1233             content::PageTransitionStripQualifier(details->transition));
   1234   EXPECT_EQ(stored_row1.id(), details->row.id());
   1235   EXPECT_EQ(stored_row1.url(), details->row.url());
   1236 
   1237   // No further checking, this case analogous to the first one.
   1238   ASSERT_EQ(chrome::NOTIFICATION_HISTORY_URL_VISITED,
   1239             broadcasted_notifications()[1].first);
   1240 
   1241   ASSERT_EQ(chrome::NOTIFICATION_HISTORY_URL_VISITED,
   1242             broadcasted_notifications()[2].first);
   1243   details = static_cast<const URLVisitedDetails*>(
   1244       broadcasted_notifications()[2].second);
   1245   EXPECT_EQ(content::PAGE_TRANSITION_TYPED,
   1246             content::PageTransitionStripQualifier(details->transition));
   1247   EXPECT_EQ(stored_row2.id(), details->row.id());
   1248   EXPECT_EQ(stored_row2.url(), details->row.url());
   1249 }
   1250 
   1251 TEST_F(HistoryBackendTest, AddPageArgsSource) {
   1252   ASSERT_TRUE(backend_.get());
   1253 
   1254   GURL url("http://testpageargs.com");
   1255 
   1256   // Assume this page is browsed by user.
   1257   HistoryAddPageArgs request1(url, base::Time::Now(), NULL, 0, GURL(),
   1258                              history::RedirectList(),
   1259                              content::PAGE_TRANSITION_KEYWORD_GENERATED,
   1260                              history::SOURCE_BROWSED, false);
   1261   backend_->AddPage(request1);
   1262   // Assume this page is synced.
   1263   HistoryAddPageArgs request2(url, base::Time::Now(), NULL, 0, GURL(),
   1264                              history::RedirectList(),
   1265                              content::PAGE_TRANSITION_LINK,
   1266                              history::SOURCE_SYNCED, false);
   1267   backend_->AddPage(request2);
   1268   // Assume this page is browsed again.
   1269   HistoryAddPageArgs request3(url, base::Time::Now(), NULL, 0, GURL(),
   1270                              history::RedirectList(),
   1271                              content::PAGE_TRANSITION_TYPED,
   1272                              history::SOURCE_BROWSED, false);
   1273   backend_->AddPage(request3);
   1274 
   1275   // Three visits should be added with proper sources.
   1276   VisitVector visits;
   1277   URLRow row;
   1278   URLID id = backend_->db()->GetRowForURL(url, &row);
   1279   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1280   ASSERT_EQ(3U, visits.size());
   1281   VisitSourceMap visit_sources;
   1282   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1283   ASSERT_EQ(1U, visit_sources.size());
   1284   EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second);
   1285 }
   1286 
   1287 TEST_F(HistoryBackendTest, AddVisitsSource) {
   1288   ASSERT_TRUE(backend_.get());
   1289 
   1290   GURL url1("http://www.cnn.com");
   1291   std::vector<VisitInfo> visits1, visits2;
   1292   visits1.push_back(VisitInfo(
   1293       Time::Now() - base::TimeDelta::FromDays(5),
   1294       content::PAGE_TRANSITION_LINK));
   1295   visits1.push_back(VisitInfo(
   1296       Time::Now() - base::TimeDelta::FromDays(1),
   1297       content::PAGE_TRANSITION_LINK));
   1298   visits1.push_back(VisitInfo(
   1299       Time::Now(), content::PAGE_TRANSITION_LINK));
   1300 
   1301   GURL url2("http://www.example.com");
   1302   visits2.push_back(VisitInfo(
   1303       Time::Now() - base::TimeDelta::FromDays(10),
   1304       content::PAGE_TRANSITION_LINK));
   1305   visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK));
   1306 
   1307   // Clear all history.
   1308   backend_->DeleteAllHistory();
   1309 
   1310   // Add the visits.
   1311   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
   1312   backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
   1313 
   1314   // Verify the visits were added with their sources.
   1315   VisitVector visits;
   1316   URLRow row;
   1317   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1318   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1319   ASSERT_EQ(3U, visits.size());
   1320   VisitSourceMap visit_sources;
   1321   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1322   ASSERT_EQ(3U, visit_sources.size());
   1323   for (int i = 0; i < 3; i++)
   1324     EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]);
   1325   id = backend_->db()->GetRowForURL(url2, &row);
   1326   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1327   ASSERT_EQ(2U, visits.size());
   1328   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1329   ASSERT_EQ(2U, visit_sources.size());
   1330   for (int i = 0; i < 2; i++)
   1331     EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
   1332 }
   1333 
   1334 TEST_F(HistoryBackendTest, GetMostRecentVisits) {
   1335   ASSERT_TRUE(backend_.get());
   1336 
   1337   GURL url1("http://www.cnn.com");
   1338   std::vector<VisitInfo> visits1;
   1339   visits1.push_back(VisitInfo(
   1340       Time::Now() - base::TimeDelta::FromDays(5),
   1341       content::PAGE_TRANSITION_LINK));
   1342   visits1.push_back(VisitInfo(
   1343       Time::Now() - base::TimeDelta::FromDays(1),
   1344       content::PAGE_TRANSITION_LINK));
   1345   visits1.push_back(VisitInfo(
   1346       Time::Now(), content::PAGE_TRANSITION_LINK));
   1347 
   1348   // Clear all history.
   1349   backend_->DeleteAllHistory();
   1350 
   1351   // Add the visits.
   1352   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
   1353 
   1354   // Verify the visits were added with their sources.
   1355   VisitVector visits;
   1356   URLRow row;
   1357   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1358   ASSERT_TRUE(backend_->db()->GetMostRecentVisitsForURL(id, 1, &visits));
   1359   ASSERT_EQ(1U, visits.size());
   1360   EXPECT_EQ(visits1[2].first, visits[0].visit_time);
   1361 }
   1362 
   1363 TEST_F(HistoryBackendTest, RemoveVisitsTransitions) {
   1364   ASSERT_TRUE(backend_.get());
   1365 
   1366   // Clear all history.
   1367   backend_->DeleteAllHistory();
   1368 
   1369   GURL url1("http://www.cnn.com");
   1370   VisitInfo typed_visit(
   1371       Time::Now() - base::TimeDelta::FromDays(6),
   1372       content::PAGE_TRANSITION_TYPED);
   1373   VisitInfo reload_visit(
   1374       Time::Now() - base::TimeDelta::FromDays(5),
   1375       content::PAGE_TRANSITION_RELOAD);
   1376   VisitInfo link_visit(
   1377       Time::Now() - base::TimeDelta::FromDays(4),
   1378       content::PAGE_TRANSITION_LINK);
   1379   std::vector<VisitInfo> visits_to_add;
   1380   visits_to_add.push_back(typed_visit);
   1381   visits_to_add.push_back(reload_visit);
   1382   visits_to_add.push_back(link_visit);
   1383 
   1384   // Add the visits.
   1385   backend_->AddVisits(url1, visits_to_add, history::SOURCE_SYNCED);
   1386 
   1387   // Verify that the various counts are what we expect.
   1388   VisitVector visits;
   1389   URLRow row;
   1390   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1391   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1392   ASSERT_EQ(3U, visits.size());
   1393   ASSERT_EQ(1, row.typed_count());
   1394   ASSERT_EQ(2, row.visit_count());
   1395 
   1396   // Now, delete the typed visit and verify that typed_count is updated.
   1397   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
   1398   id = backend_->db()->GetRowForURL(url1, &row);
   1399   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1400   ASSERT_EQ(2U, visits.size());
   1401   ASSERT_EQ(0, row.typed_count());
   1402   ASSERT_EQ(1, row.visit_count());
   1403 
   1404   // Delete the reload visit now and verify that none of the counts have
   1405   // changed.
   1406   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
   1407   id = backend_->db()->GetRowForURL(url1, &row);
   1408   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1409   ASSERT_EQ(1U, visits.size());
   1410   ASSERT_EQ(0, row.typed_count());
   1411   ASSERT_EQ(1, row.visit_count());
   1412 
   1413   // Delete the last visit and verify that we delete the URL.
   1414   ASSERT_TRUE(backend_->RemoveVisits(VisitVector(1, visits[0])));
   1415   ASSERT_EQ(0, backend_->db()->GetRowForURL(url1, &row));
   1416 }
   1417 
   1418 TEST_F(HistoryBackendTest, RemoveVisitsSource) {
   1419   ASSERT_TRUE(backend_.get());
   1420 
   1421   GURL url1("http://www.cnn.com");
   1422   std::vector<VisitInfo> visits1, visits2;
   1423   visits1.push_back(VisitInfo(
   1424       Time::Now() - base::TimeDelta::FromDays(5),
   1425       content::PAGE_TRANSITION_LINK));
   1426   visits1.push_back(VisitInfo(Time::Now(),
   1427     content::PAGE_TRANSITION_LINK));
   1428 
   1429   GURL url2("http://www.example.com");
   1430   visits2.push_back(VisitInfo(
   1431       Time::Now() - base::TimeDelta::FromDays(10),
   1432       content::PAGE_TRANSITION_LINK));
   1433   visits2.push_back(VisitInfo(Time::Now(), content::PAGE_TRANSITION_LINK));
   1434 
   1435   // Clear all history.
   1436   backend_->DeleteAllHistory();
   1437 
   1438   // Add the visits.
   1439   backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
   1440   backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
   1441 
   1442   // Verify the visits of url1 were added.
   1443   VisitVector visits;
   1444   URLRow row;
   1445   URLID id = backend_->db()->GetRowForURL(url1, &row);
   1446   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1447   ASSERT_EQ(2U, visits.size());
   1448   // Remove these visits.
   1449   ASSERT_TRUE(backend_->RemoveVisits(visits));
   1450 
   1451   // Now check only url2's source in visit_source table.
   1452   VisitSourceMap visit_sources;
   1453   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1454   ASSERT_EQ(0U, visit_sources.size());
   1455   id = backend_->db()->GetRowForURL(url2, &row);
   1456   ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
   1457   ASSERT_EQ(2U, visits.size());
   1458   ASSERT_TRUE(backend_->GetVisitsSource(visits, &visit_sources));
   1459   ASSERT_EQ(2U, visit_sources.size());
   1460   for (int i = 0; i < 2; i++)
   1461     EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
   1462 }
   1463 
   1464 // Test for migration of adding visit_source table.
   1465 TEST_F(HistoryBackendTest, MigrationVisitSource) {
   1466   ASSERT_TRUE(backend_.get());
   1467   backend_->Closing();
   1468   backend_ = NULL;
   1469 
   1470   base::FilePath old_history_path;
   1471   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
   1472   old_history_path = old_history_path.AppendASCII("History");
   1473   old_history_path = old_history_path.AppendASCII("HistoryNoSource");
   1474 
   1475   // Copy history database file to current directory so that it will be deleted
   1476   // in Teardown.
   1477   base::FilePath new_history_path(test_dir());
   1478   base::DeleteFile(new_history_path, true);
   1479   base::CreateDirectory(new_history_path);
   1480   base::FilePath new_history_file =
   1481       new_history_path.Append(chrome::kHistoryFilename);
   1482   ASSERT_TRUE(base::CopyFile(old_history_path, new_history_file));
   1483 
   1484   backend_ = new HistoryBackend(
   1485       new_history_path, new HistoryBackendTestDelegate(this), &history_client_);
   1486   backend_->Init(std::string(), false);
   1487   backend_->Closing();
   1488   backend_ = NULL;
   1489 
   1490   // Now the database should already be migrated.
   1491   // Check version first.
   1492   int cur_version = HistoryDatabase::GetCurrentVersion();
   1493   sql::Connection db;
   1494   ASSERT_TRUE(db.Open(new_history_file));
   1495   sql::Statement s(db.GetUniqueStatement(
   1496       "SELECT value FROM meta WHERE key = 'version'"));
   1497   ASSERT_TRUE(s.Step());
   1498   int file_version = s.ColumnInt(0);
   1499   EXPECT_EQ(cur_version, file_version);
   1500 
   1501   // Check visit_source table is created and empty.
   1502   s.Assign(db.GetUniqueStatement(
   1503       "SELECT name FROM sqlite_master WHERE name=\"visit_source\""));
   1504   ASSERT_TRUE(s.Step());
   1505   s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10"));
   1506   EXPECT_FALSE(s.Step());
   1507 }
   1508 
   1509 // Test that SetFaviconMappingsForPageAndRedirects correctly updates icon
   1510 // mappings based on redirects, icon URLs and icon types.
   1511 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageAndRedirects) {
   1512   // Init recent_redirects_
   1513   const GURL url1("http://www.google.com");
   1514   const GURL url2("http://www.google.com/m");
   1515   URLRow url_info1(url1);
   1516   url_info1.set_visit_count(0);
   1517   url_info1.set_typed_count(0);
   1518   url_info1.set_last_visit(base::Time());
   1519   url_info1.set_hidden(false);
   1520   backend_->db_->AddURL(url_info1);
   1521 
   1522   URLRow url_info2(url2);
   1523   url_info2.set_visit_count(0);
   1524   url_info2.set_typed_count(0);
   1525   url_info2.set_last_visit(base::Time());
   1526   url_info2.set_hidden(false);
   1527   backend_->db_->AddURL(url_info2);
   1528 
   1529   history::RedirectList redirects;
   1530   redirects.push_back(url2);
   1531   redirects.push_back(url1);
   1532   backend_->recent_redirects_.Put(url1, redirects);
   1533 
   1534   const GURL icon_url1("http://www.google.com/icon");
   1535   const GURL icon_url2("http://www.google.com/icon2");
   1536 
   1537   // Generate bitmap data for a page with two favicons.
   1538   std::vector<favicon_base::FaviconRawBitmapData> two_favicon_bitmap_data;
   1539   GenerateFaviconBitmapData(icon_url1, GetEdgeSizesSmallAndLarge(),
   1540       icon_url2, GetEdgeSizesSmallAndLarge(), &two_favicon_bitmap_data);
   1541 
   1542   // Generate bitmap data for a page with a single favicon.
   1543   std::vector<favicon_base::FaviconRawBitmapData> one_favicon_bitmap_data;
   1544   GenerateFaviconBitmapData(icon_url1, GetEdgeSizesSmallAndLarge(),
   1545                             &one_favicon_bitmap_data);
   1546 
   1547   // Add two favicons
   1548   backend_->SetFavicons(url1, favicon_base::FAVICON, two_favicon_bitmap_data);
   1549   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, favicon_base::FAVICON));
   1550   EXPECT_EQ(2u, NumIconMappingsForPageURL(url2, favicon_base::FAVICON));
   1551 
   1552   // Add one touch_icon
   1553   backend_->SetFavicons(
   1554       url1, favicon_base::TOUCH_ICON, one_favicon_bitmap_data);
   1555   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, favicon_base::TOUCH_ICON));
   1556   EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, favicon_base::TOUCH_ICON));
   1557   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, favicon_base::FAVICON));
   1558 
   1559   // Add one TOUCH_PRECOMPOSED_ICON
   1560   backend_->SetFavicons(
   1561       url1, favicon_base::TOUCH_PRECOMPOSED_ICON, one_favicon_bitmap_data);
   1562   // The touch_icon was replaced.
   1563   EXPECT_EQ(0u, NumIconMappingsForPageURL(url1, favicon_base::TOUCH_ICON));
   1564   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, favicon_base::FAVICON));
   1565   EXPECT_EQ(
   1566       1u,
   1567       NumIconMappingsForPageURL(url1, favicon_base::TOUCH_PRECOMPOSED_ICON));
   1568   EXPECT_EQ(
   1569       1u,
   1570       NumIconMappingsForPageURL(url2, favicon_base::TOUCH_PRECOMPOSED_ICON));
   1571 
   1572   // Add a touch_icon.
   1573   backend_->SetFavicons(
   1574       url1, favicon_base::TOUCH_ICON, one_favicon_bitmap_data);
   1575   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, favicon_base::TOUCH_ICON));
   1576   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, favicon_base::FAVICON));
   1577   // The TOUCH_PRECOMPOSED_ICON was replaced.
   1578   EXPECT_EQ(
   1579       0u,
   1580       NumIconMappingsForPageURL(url1, favicon_base::TOUCH_PRECOMPOSED_ICON));
   1581 
   1582   // Add a single favicon.
   1583   backend_->SetFavicons(url1, favicon_base::FAVICON, one_favicon_bitmap_data);
   1584   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, favicon_base::TOUCH_ICON));
   1585   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, favicon_base::FAVICON));
   1586   EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, favicon_base::FAVICON));
   1587 
   1588   // Add two favicons.
   1589   backend_->SetFavicons(url1, favicon_base::FAVICON, two_favicon_bitmap_data);
   1590   EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, favicon_base::TOUCH_ICON));
   1591   EXPECT_EQ(2u, NumIconMappingsForPageURL(url1, favicon_base::FAVICON));
   1592 }
   1593 
   1594 // Test that there is no churn in icon mappings from calling
   1595 // SetFavicons() twice with the same |favicon_bitmap_data| parameter.
   1596 TEST_F(HistoryBackendTest, SetFaviconMappingsForPageDuplicates) {
   1597   const GURL url("http://www.google.com/");
   1598   const GURL icon_url("http://www.google.com/icon");
   1599 
   1600   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   1601   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmallAndLarge(),
   1602                             &favicon_bitmap_data);
   1603 
   1604   backend_->SetFavicons(url, favicon_base::FAVICON, favicon_bitmap_data);
   1605 
   1606   std::vector<IconMapping> icon_mappings;
   1607   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1608       url, favicon_base::FAVICON, &icon_mappings));
   1609   EXPECT_EQ(1u, icon_mappings.size());
   1610   IconMappingID mapping_id = icon_mappings[0].mapping_id;
   1611 
   1612   backend_->SetFavicons(url, favicon_base::FAVICON, favicon_bitmap_data);
   1613 
   1614   icon_mappings.clear();
   1615   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1616       url, favicon_base::FAVICON, &icon_mappings));
   1617   EXPECT_EQ(1u, icon_mappings.size());
   1618 
   1619   // The same row in the icon_mapping table should be used for the mapping as
   1620   // before.
   1621   EXPECT_EQ(mapping_id, icon_mappings[0].mapping_id);
   1622 }
   1623 
   1624 // Test that calling SetFavicons() with FaviconBitmapData of different pixel
   1625 // sizes than the initially passed in FaviconBitmapData deletes the no longer
   1626 // used favicon bitmaps.
   1627 TEST_F(HistoryBackendTest, SetFaviconsDeleteBitmaps) {
   1628   const GURL page_url("http://www.google.com/");
   1629   const GURL icon_url("http://www.google.com/icon");
   1630 
   1631   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   1632   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmallAndLarge(),
   1633                             &favicon_bitmap_data);
   1634   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1635 
   1636   // Test initial state.
   1637   std::vector<IconMapping> icon_mappings;
   1638   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url, &icon_mappings));
   1639   EXPECT_EQ(1u, icon_mappings.size());
   1640   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1641   EXPECT_EQ(favicon_base::FAVICON, icon_mappings[0].icon_type);
   1642   favicon_base::FaviconID favicon_id = icon_mappings[0].icon_id;
   1643 
   1644   std::vector<FaviconBitmap> favicon_bitmaps;
   1645   EXPECT_TRUE(GetSortedFaviconBitmaps(favicon_id, &favicon_bitmaps));
   1646   EXPECT_EQ(2u, favicon_bitmaps.size());
   1647   FaviconBitmapID small_bitmap_id = favicon_bitmaps[0].bitmap_id;
   1648   EXPECT_NE(0, small_bitmap_id);
   1649   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmaps[0].bitmap_data));
   1650   EXPECT_EQ(kSmallSize, favicon_bitmaps[0].pixel_size);
   1651   FaviconBitmapID large_bitmap_id = favicon_bitmaps[1].bitmap_id;
   1652   EXPECT_NE(0, large_bitmap_id);
   1653   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data));
   1654   EXPECT_EQ(kLargeSize, favicon_bitmaps[1].pixel_size);
   1655 
   1656   // Call SetFavicons() with bitmap data for only the large bitmap. Check that
   1657   // the small bitmap is in fact deleted.
   1658   GenerateFaviconBitmapData(icon_url, GetEdgeSizesLarge(),
   1659       &favicon_bitmap_data);
   1660   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1661 
   1662   scoped_refptr<base::RefCountedMemory> bitmap_data_out;
   1663   gfx::Size pixel_size_out;
   1664   EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(small_bitmap_id,
   1665       NULL, &bitmap_data_out, &pixel_size_out));
   1666   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id,
   1667       NULL, &bitmap_data_out, &pixel_size_out));
   1668   EXPECT_TRUE(BitmapDataEqual('a', bitmap_data_out));
   1669   EXPECT_EQ(kLargeSize, pixel_size_out);
   1670 
   1671   icon_mappings.clear();
   1672   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1673       &icon_mappings));
   1674   EXPECT_EQ(1u, icon_mappings.size());
   1675   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1676 
   1677   // Call SetFavicons() with no bitmap data. Check that the bitmaps and icon
   1678   // mappings are deleted.
   1679   favicon_bitmap_data.clear();
   1680   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1681 
   1682   EXPECT_FALSE(backend_->thumbnail_db_->GetFaviconBitmap(large_bitmap_id, NULL,
   1683       NULL, NULL));
   1684   icon_mappings.clear();
   1685   EXPECT_FALSE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1686       &icon_mappings));
   1687 
   1688   // Notifications should have been broadcast for each call to SetFavicons().
   1689   EXPECT_EQ(3, num_broadcasted_notifications());
   1690 }
   1691 
   1692 // Test updating a single favicon bitmap's data via SetFavicons.
   1693 TEST_F(HistoryBackendTest, SetFaviconsReplaceBitmapData) {
   1694   const GURL page_url("http://www.google.com/");
   1695   const GURL icon_url("http://www.google.com/icon");
   1696 
   1697   std::vector<unsigned char> data_initial;
   1698   data_initial.push_back('a');
   1699 
   1700   favicon_base::FaviconRawBitmapData bitmap_data_element;
   1701   bitmap_data_element.bitmap_data =
   1702       base::RefCountedBytes::TakeVector(&data_initial);
   1703   bitmap_data_element.pixel_size = kSmallSize;
   1704   bitmap_data_element.icon_url = icon_url;
   1705   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   1706   favicon_bitmap_data.push_back(bitmap_data_element);
   1707 
   1708   // Add bitmap to the database.
   1709   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1710 
   1711   favicon_base::FaviconID original_favicon_id =
   1712       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1713           icon_url, favicon_base::FAVICON, NULL);
   1714   EXPECT_NE(0, original_favicon_id);
   1715   FaviconBitmap original_favicon_bitmap;
   1716   EXPECT_TRUE(
   1717       GetOnlyFaviconBitmap(original_favicon_id, &original_favicon_bitmap));
   1718   EXPECT_TRUE(BitmapDataEqual('a', original_favicon_bitmap.bitmap_data));
   1719 
   1720   EXPECT_EQ(1, num_broadcasted_notifications());
   1721 
   1722   // Call SetFavicons() with completely identical data.
   1723   std::vector<unsigned char> updated_data;
   1724   updated_data.push_back('a');
   1725   favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data);
   1726   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1727 
   1728   favicon_base::FaviconID updated_favicon_id =
   1729       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1730           icon_url, favicon_base::FAVICON, NULL);
   1731   EXPECT_NE(0, updated_favicon_id);
   1732   FaviconBitmap updated_favicon_bitmap;
   1733   EXPECT_TRUE(
   1734       GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
   1735   EXPECT_TRUE(BitmapDataEqual('a', updated_favicon_bitmap.bitmap_data));
   1736 
   1737   // Because the bitmap data is byte equivalent, no notifications should have
   1738   // been broadcasted.
   1739   EXPECT_EQ(1, num_broadcasted_notifications());
   1740 
   1741   // Call SetFavicons() with identical data but a different bitmap.
   1742   updated_data[0] = 'b';
   1743   favicon_bitmap_data[0].bitmap_data = new base::RefCountedBytes(updated_data);
   1744   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1745 
   1746   updated_favicon_id = backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1747       icon_url, favicon_base::FAVICON, NULL);
   1748   EXPECT_NE(0, updated_favicon_id);
   1749   EXPECT_TRUE(
   1750       GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap));
   1751   EXPECT_TRUE(BitmapDataEqual('b', updated_favicon_bitmap.bitmap_data));
   1752 
   1753   // There should be no churn in FaviconIDs or FaviconBitmapIds even though
   1754   // the bitmap data changed.
   1755   EXPECT_EQ(original_favicon_bitmap.icon_id, updated_favicon_bitmap.icon_id);
   1756   EXPECT_EQ(original_favicon_bitmap.bitmap_id,
   1757             updated_favicon_bitmap.bitmap_id);
   1758 
   1759   // A notification should have been broadcasted as the favicon bitmap data has
   1760   // changed.
   1761   EXPECT_EQ(2, num_broadcasted_notifications());
   1762 }
   1763 
   1764 // Test that if two pages share the same FaviconID, changing the favicon for
   1765 // one page does not affect the other.
   1766 TEST_F(HistoryBackendTest, SetFaviconsSameFaviconURLForTwoPages) {
   1767   GURL icon_url("http://www.google.com/favicon.ico");
   1768   GURL icon_url_new("http://www.google.com/favicon2.ico");
   1769   GURL page_url1("http://www.google.com");
   1770   GURL page_url2("http://www.google.ca");
   1771 
   1772   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   1773   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmallAndLarge(),
   1774                             &favicon_bitmap_data);
   1775 
   1776   backend_->SetFavicons(page_url1, favicon_base::FAVICON, favicon_bitmap_data);
   1777 
   1778   std::vector<GURL> icon_urls;
   1779   icon_urls.push_back(icon_url);
   1780 
   1781   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
   1782   backend_->UpdateFaviconMappingsAndFetch(page_url2,
   1783                                           icon_urls,
   1784                                           favicon_base::FAVICON,
   1785                                           GetEdgeSizesSmallAndLarge(),
   1786                                           &bitmap_results);
   1787 
   1788   // Check that the same FaviconID is mapped to both page URLs.
   1789   std::vector<IconMapping> icon_mappings;
   1790   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1791       page_url1, &icon_mappings));
   1792   EXPECT_EQ(1u, icon_mappings.size());
   1793   favicon_base::FaviconID favicon_id = icon_mappings[0].icon_id;
   1794   EXPECT_NE(0, favicon_id);
   1795 
   1796   icon_mappings.clear();
   1797   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1798       page_url2, &icon_mappings));
   1799   EXPECT_EQ(1u, icon_mappings.size());
   1800   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1801 
   1802   // Change the icon URL that |page_url1| is mapped to.
   1803   GenerateFaviconBitmapData(icon_url_new, GetEdgeSizesSmall(),
   1804                             &favicon_bitmap_data);
   1805   backend_->SetFavicons(page_url1, favicon_base::FAVICON, favicon_bitmap_data);
   1806 
   1807   // |page_url1| should map to a new FaviconID and have valid bitmap data.
   1808   icon_mappings.clear();
   1809   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1810       page_url1, &icon_mappings));
   1811   EXPECT_EQ(1u, icon_mappings.size());
   1812   EXPECT_EQ(icon_url_new, icon_mappings[0].icon_url);
   1813   EXPECT_NE(favicon_id, icon_mappings[0].icon_id);
   1814 
   1815   std::vector<FaviconBitmap> favicon_bitmaps;
   1816   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
   1817       icon_mappings[0].icon_id, &favicon_bitmaps));
   1818   EXPECT_EQ(1u, favicon_bitmaps.size());
   1819 
   1820   // |page_url2| should still map to the same FaviconID and have valid bitmap
   1821   // data.
   1822   icon_mappings.clear();
   1823   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   1824       page_url2, &icon_mappings));
   1825   EXPECT_EQ(1u, icon_mappings.size());
   1826   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   1827 
   1828   favicon_bitmaps.clear();
   1829   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(favicon_id,
   1830                                                          &favicon_bitmaps));
   1831   EXPECT_EQ(2u, favicon_bitmaps.size());
   1832 
   1833   // A notification should have been broadcast for each call to SetFavicons()
   1834   // and each call to UpdateFaviconMappingsAndFetch().
   1835   EXPECT_EQ(3, num_broadcasted_notifications());
   1836 }
   1837 
   1838 // Test that no notifications are broadcast as a result of calling
   1839 // UpdateFaviconMappingsAndFetch() for an icon URL which is already
   1840 // mapped to the passed in page URL.
   1841 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoChange) {
   1842   GURL page_url("http://www.google.com");
   1843   GURL icon_url("http://www.google.com/favicon.ico");
   1844   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   1845   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmall(),
   1846       &favicon_bitmap_data);
   1847 
   1848   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1849 
   1850   favicon_base::FaviconID icon_id =
   1851       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1852           icon_url, favicon_base::FAVICON, NULL);
   1853   EXPECT_NE(0, icon_id);
   1854   EXPECT_EQ(1, num_broadcasted_notifications());
   1855 
   1856   std::vector<GURL> icon_urls;
   1857   icon_urls.push_back(icon_url);
   1858 
   1859   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
   1860   backend_->UpdateFaviconMappingsAndFetch(page_url,
   1861                                           icon_urls,
   1862                                           favicon_base::FAVICON,
   1863                                           GetEdgeSizesSmallAndLarge(),
   1864                                           &bitmap_results);
   1865 
   1866   EXPECT_EQ(icon_id,
   1867             backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   1868                 icon_url, favicon_base::FAVICON, NULL));
   1869 
   1870   // No notification should have been broadcast as no icon mapping, favicon,
   1871   // or favicon bitmap was updated, added or removed.
   1872   EXPECT_EQ(1, num_broadcasted_notifications());
   1873 }
   1874 
   1875 // Test repeatedly calling MergeFavicon(). |page_url| is initially not known
   1876 // to the database.
   1877 TEST_F(HistoryBackendTest, MergeFaviconPageURLNotInDB) {
   1878   GURL page_url("http://www.google.com");
   1879   GURL icon_url("http:/www.google.com/favicon.ico");
   1880 
   1881   std::vector<unsigned char> data;
   1882   data.push_back('a');
   1883   scoped_refptr<base::RefCountedBytes> bitmap_data(
   1884       new base::RefCountedBytes(data));
   1885 
   1886   backend_->MergeFavicon(
   1887       page_url, icon_url, favicon_base::FAVICON, bitmap_data, kSmallSize);
   1888 
   1889   // |page_url| should now be mapped to |icon_url| and the favicon bitmap should
   1890   // not be expired.
   1891   std::vector<IconMapping> icon_mappings;
   1892   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1893       &icon_mappings));
   1894   EXPECT_EQ(1u, icon_mappings.size());
   1895   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1896 
   1897   FaviconBitmap favicon_bitmap;
   1898   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1899   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1900   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1901   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1902 
   1903   data[0] = 'b';
   1904   bitmap_data = new base::RefCountedBytes(data);
   1905   backend_->MergeFavicon(
   1906       page_url, icon_url, favicon_base::FAVICON, bitmap_data, kSmallSize);
   1907 
   1908   // |page_url| should still have a single favicon bitmap. The bitmap data
   1909   // should be updated.
   1910   icon_mappings.clear();
   1911   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1912       &icon_mappings));
   1913   EXPECT_EQ(1u, icon_mappings.size());
   1914   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   1915 
   1916   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1917   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1918   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
   1919   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1920 }
   1921 
   1922 // Test calling MergeFavicon() when |page_url| is known to the database.
   1923 TEST_F(HistoryBackendTest, MergeFaviconPageURLInDB) {
   1924   GURL page_url("http://www.google.com");
   1925   GURL icon_url1("http:/www.google.com/favicon.ico");
   1926   GURL icon_url2("http://www.google.com/favicon2.ico");
   1927 
   1928   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   1929   GenerateFaviconBitmapData(icon_url1, GetEdgeSizesSmall(),
   1930                             &favicon_bitmap_data);
   1931 
   1932   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   1933 
   1934   // Test initial state.
   1935   std::vector<IconMapping> icon_mappings;
   1936   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1937       &icon_mappings));
   1938   EXPECT_EQ(1u, icon_mappings.size());
   1939   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1940 
   1941   FaviconBitmap favicon_bitmap;
   1942   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1943   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1944   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1945   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1946 
   1947   EXPECT_EQ(1, num_broadcasted_notifications());
   1948 
   1949   // 1) Merge identical favicon bitmap.
   1950   std::vector<unsigned char> data;
   1951   data.push_back('a');
   1952   scoped_refptr<base::RefCountedBytes> bitmap_data(
   1953       new base::RefCountedBytes(data));
   1954   backend_->MergeFavicon(
   1955       page_url, icon_url1, favicon_base::FAVICON, bitmap_data, kSmallSize);
   1956 
   1957   // All the data should stay the same and no notifications should have been
   1958   // sent.
   1959   icon_mappings.clear();
   1960   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1961       &icon_mappings));
   1962   EXPECT_EQ(1u, icon_mappings.size());
   1963   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1964 
   1965   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1966   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1967   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   1968   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1969 
   1970   EXPECT_EQ(1, num_broadcasted_notifications());
   1971 
   1972   // 2) Merge favicon bitmap of the same size.
   1973   data[0] = 'b';
   1974   bitmap_data = new base::RefCountedBytes(data);
   1975   backend_->MergeFavicon(
   1976       page_url, icon_url1, favicon_base::FAVICON, bitmap_data, kSmallSize);
   1977 
   1978   // The small favicon bitmap at |icon_url1| should be overwritten.
   1979   icon_mappings.clear();
   1980   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   1981       &icon_mappings));
   1982   EXPECT_EQ(1u, icon_mappings.size());
   1983   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   1984 
   1985   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   1986   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   1987   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
   1988   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   1989 
   1990   // 3) Merge favicon for the same icon URL, but a pixel size for which there is
   1991   // no favicon bitmap.
   1992   data[0] = 'c';
   1993   bitmap_data = new base::RefCountedBytes(data);
   1994   backend_->MergeFavicon(
   1995       page_url, icon_url1, favicon_base::FAVICON, bitmap_data, kTinySize);
   1996 
   1997   // A new favicon bitmap should be created and the preexisting favicon bitmap
   1998   // ('b') should be expired.
   1999   icon_mappings.clear();
   2000   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   2001       &icon_mappings));
   2002   EXPECT_EQ(1u, icon_mappings.size());
   2003   EXPECT_EQ(icon_url1, icon_mappings[0].icon_url);
   2004 
   2005   std::vector<FaviconBitmap> favicon_bitmaps;
   2006   EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id,
   2007                                       &favicon_bitmaps));
   2008   EXPECT_NE(base::Time(), favicon_bitmaps[0].last_updated);
   2009   EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data));
   2010   EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size);
   2011   EXPECT_EQ(base::Time(), favicon_bitmaps[1].last_updated);
   2012   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data));
   2013   EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size);
   2014 
   2015   // 4) Merge favicon for an icon URL different from the icon URLs already
   2016   // mapped to page URL.
   2017   data[0] = 'd';
   2018   bitmap_data = new base::RefCountedBytes(data);
   2019   backend_->MergeFavicon(
   2020       page_url, icon_url2, favicon_base::FAVICON, bitmap_data, kSmallSize);
   2021 
   2022   // The existing favicon bitmaps should be copied over to the newly created
   2023   // favicon at |icon_url2|. |page_url| should solely be mapped to |icon_url2|.
   2024   icon_mappings.clear();
   2025   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   2026       &icon_mappings));
   2027   EXPECT_EQ(1u, icon_mappings.size());
   2028   EXPECT_EQ(icon_url2, icon_mappings[0].icon_url);
   2029 
   2030   favicon_bitmaps.clear();
   2031   EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id,
   2032                                       &favicon_bitmaps));
   2033   EXPECT_EQ(base::Time(), favicon_bitmaps[0].last_updated);
   2034   EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data));
   2035   EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size);
   2036   // The favicon being merged should take precedence over the preexisting
   2037   // favicon bitmaps.
   2038   EXPECT_NE(base::Time(), favicon_bitmaps[1].last_updated);
   2039   EXPECT_TRUE(BitmapDataEqual('d', favicon_bitmaps[1].bitmap_data));
   2040   EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size);
   2041 
   2042   // A notification should have been broadcast for each call to SetFavicons()
   2043   // and MergeFavicon().
   2044   EXPECT_EQ(4, num_broadcasted_notifications());
   2045 }
   2046 
   2047 // Test calling MergeFavicon() when |icon_url| is known to the database but not
   2048 // mapped to |page_url|.
   2049 TEST_F(HistoryBackendTest, MergeFaviconIconURLMappedToDifferentPageURL) {
   2050   GURL page_url1("http://www.google.com");
   2051   GURL page_url2("http://news.google.com");
   2052   GURL page_url3("http://maps.google.com");
   2053   GURL icon_url("http:/www.google.com/favicon.ico");
   2054 
   2055   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2056   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmall(),
   2057                             &favicon_bitmap_data);
   2058 
   2059   backend_->SetFavicons(page_url1, favicon_base::FAVICON, favicon_bitmap_data);
   2060 
   2061   // Test initial state.
   2062   std::vector<IconMapping> icon_mappings;
   2063   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
   2064       &icon_mappings));
   2065   EXPECT_EQ(1u, icon_mappings.size());
   2066   EXPECT_EQ(icon_url, icon_mappings[0].icon_url);
   2067 
   2068   FaviconBitmap favicon_bitmap;
   2069   EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap));
   2070   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   2071   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   2072   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   2073 
   2074   // 1) Merge in an identical favicon bitmap data but for a different page URL.
   2075   std::vector<unsigned char> data;
   2076   data.push_back('a');
   2077   scoped_refptr<base::RefCountedBytes> bitmap_data(
   2078       new base::RefCountedBytes(data));
   2079 
   2080   backend_->MergeFavicon(
   2081       page_url2, icon_url, favicon_base::FAVICON, bitmap_data, kSmallSize);
   2082 
   2083   favicon_base::FaviconID favicon_id =
   2084       backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   2085           icon_url, favicon_base::FAVICON, NULL);
   2086   EXPECT_NE(0, favicon_id);
   2087 
   2088   EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
   2089   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   2090   EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data));
   2091   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   2092 
   2093   // 2) Merging a favicon bitmap with different bitmap data for the same icon
   2094   // URL should overwrite the small favicon bitmap at |icon_url|.
   2095   bitmap_data->data()[0] = 'b';
   2096   backend_->MergeFavicon(
   2097       page_url3, icon_url, favicon_base::FAVICON, bitmap_data, kSmallSize);
   2098 
   2099   favicon_id = backend_->thumbnail_db_->GetFaviconIDForFaviconURL(
   2100       icon_url, favicon_base::FAVICON, NULL);
   2101   EXPECT_NE(0, favicon_id);
   2102 
   2103   EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap));
   2104   EXPECT_NE(base::Time(), favicon_bitmap.last_updated);
   2105   EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data));
   2106   EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size);
   2107 
   2108   // |icon_url| should be mapped to all three page URLs.
   2109   icon_mappings.clear();
   2110   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
   2111       &icon_mappings));
   2112   EXPECT_EQ(1u, icon_mappings.size());
   2113   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   2114 
   2115   icon_mappings.clear();
   2116   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url2,
   2117       &icon_mappings));
   2118   EXPECT_EQ(1u, icon_mappings.size());
   2119   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   2120 
   2121   icon_mappings.clear();
   2122   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url3,
   2123       &icon_mappings));
   2124   EXPECT_EQ(1u, icon_mappings.size());
   2125   EXPECT_EQ(favicon_id, icon_mappings[0].icon_id);
   2126 
   2127   // A notification should have been broadcast for each call to SetFavicons()
   2128   // and MergeFavicon().
   2129   EXPECT_EQ(3, num_broadcasted_notifications());
   2130 }
   2131 
   2132 // Test that MergeFavicon() does not add more than
   2133 // |kMaxFaviconBitmapsPerIconURL| to a favicon.
   2134 TEST_F(HistoryBackendTest, MergeFaviconMaxFaviconBitmapsPerIconURL) {
   2135   GURL page_url("http://www.google.com");
   2136   std::string icon_url_string("http://www.google.com/favicon.ico");
   2137   size_t replace_index = icon_url_string.size() - 1;
   2138 
   2139   std::vector<unsigned char> data;
   2140   data.push_back('a');
   2141   scoped_refptr<base::RefCountedMemory> bitmap_data =
   2142       base::RefCountedBytes::TakeVector(&data);
   2143 
   2144   int pixel_size = 1;
   2145   for (size_t i = 0; i < kMaxFaviconBitmapsPerIconURL + 1; ++i) {
   2146     icon_url_string[replace_index] = '0' + i;
   2147     GURL icon_url(icon_url_string);
   2148 
   2149     backend_->MergeFavicon(page_url,
   2150                            icon_url,
   2151                            favicon_base::FAVICON,
   2152                            bitmap_data,
   2153                            gfx::Size(pixel_size, pixel_size));
   2154     ++pixel_size;
   2155   }
   2156 
   2157   // There should be a single favicon mapped to |page_url| with exactly
   2158   // kMaxFaviconBitmapsPerIconURL favicon bitmaps.
   2159   std::vector<IconMapping> icon_mappings;
   2160   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url,
   2161       &icon_mappings));
   2162   EXPECT_EQ(1u, icon_mappings.size());
   2163   std::vector<FaviconBitmap> favicon_bitmaps;
   2164   EXPECT_TRUE(backend_->thumbnail_db_->GetFaviconBitmaps(
   2165       icon_mappings[0].icon_id, &favicon_bitmaps));
   2166   EXPECT_EQ(kMaxFaviconBitmapsPerIconURL, favicon_bitmaps.size());
   2167 }
   2168 
   2169 // Tests that the favicon set by MergeFavicon() shows up in the result of
   2170 // GetFaviconsForURL().
   2171 TEST_F(HistoryBackendTest, MergeFaviconShowsUpInGetFaviconsForURLResult) {
   2172   GURL page_url("http://www.google.com");
   2173   GURL icon_url("http://www.google.com/favicon.ico");
   2174   GURL merged_icon_url("http://wwww.google.com/favicon2.ico");
   2175 
   2176   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2177   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmallAndLarge(),
   2178                             &favicon_bitmap_data);
   2179 
   2180   // Set some preexisting favicons for |page_url|.
   2181   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2182 
   2183   // Merge small favicon.
   2184   std::vector<unsigned char> data;
   2185   data.push_back('c');
   2186   scoped_refptr<base::RefCountedBytes> bitmap_data(
   2187       new base::RefCountedBytes(data));
   2188   backend_->MergeFavicon(page_url,
   2189                          merged_icon_url,
   2190                          favicon_base::FAVICON,
   2191                          bitmap_data,
   2192                          kSmallSize);
   2193 
   2194   // Request favicon bitmaps for both 1x and 2x to simulate request done by
   2195   // BookmarkModel::GetFavicon().
   2196   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
   2197   backend_->GetFaviconsForURL(page_url,
   2198                               favicon_base::FAVICON,
   2199                               GetEdgeSizesSmallAndLarge(),
   2200                               &bitmap_results);
   2201 
   2202   EXPECT_EQ(2u, bitmap_results.size());
   2203   const favicon_base::FaviconRawBitmapResult& first_result = bitmap_results[0];
   2204   const favicon_base::FaviconRawBitmapResult& result =
   2205       (first_result.pixel_size == kSmallSize) ? first_result
   2206                                               : bitmap_results[1];
   2207   EXPECT_TRUE(BitmapDataEqual('c', result.bitmap_data));
   2208 }
   2209 
   2210 // Tests GetFaviconsForURL with icon_types priority,
   2211 TEST_F(HistoryBackendTest, TestGetFaviconsForURLWithIconTypesPriority) {
   2212   GURL page_url("http://www.google.com");
   2213   GURL icon_url("http://www.google.com/favicon.ico");
   2214   GURL touch_icon_url("http://wwww.google.com/touch_icon.ico");
   2215 
   2216   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2217   std::vector<int> favicon_size;
   2218   favicon_size.push_back(16);
   2219   favicon_size.push_back(32);
   2220   GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
   2221   ASSERT_EQ(2u, favicon_bitmap_data.size());
   2222 
   2223   std::vector<favicon_base::FaviconRawBitmapData> touch_icon_bitmap_data;
   2224   std::vector<int> touch_icon_size;
   2225   touch_icon_size.push_back(64);
   2226   GenerateFaviconBitmapData(icon_url, touch_icon_size, &touch_icon_bitmap_data);
   2227   ASSERT_EQ(1u, touch_icon_bitmap_data.size());
   2228 
   2229   // Set some preexisting favicons for |page_url|.
   2230   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2231   backend_->SetFavicons(
   2232       page_url, favicon_base::TOUCH_ICON, touch_icon_bitmap_data);
   2233 
   2234   favicon_base::FaviconRawBitmapResult result;
   2235   std::vector<int> icon_types;
   2236   icon_types.push_back(favicon_base::FAVICON);
   2237   icon_types.push_back(favicon_base::TOUCH_ICON);
   2238 
   2239   backend_->GetLargestFaviconForURL(page_url, icon_types, 16, &result);
   2240 
   2241   // Verify the result icon is 32x32 favicon.
   2242   EXPECT_EQ(gfx::Size(32, 32), result.pixel_size);
   2243   EXPECT_EQ(favicon_base::FAVICON, result.icon_type);
   2244 
   2245   // Change Minimal size to 32x32 and verify the 64x64 touch icon returned.
   2246   backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result);
   2247   EXPECT_EQ(gfx::Size(64, 64), result.pixel_size);
   2248   EXPECT_EQ(favicon_base::TOUCH_ICON, result.icon_type);
   2249 }
   2250 
   2251 // Test the the first types of icon is returned if its size equal to the
   2252 // second types icon.
   2253 TEST_F(HistoryBackendTest, TestGetFaviconsForURLReturnFavicon) {
   2254   GURL page_url("http://www.google.com");
   2255   GURL icon_url("http://www.google.com/favicon.ico");
   2256   GURL touch_icon_url("http://wwww.google.com/touch_icon.ico");
   2257 
   2258   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2259   std::vector<int> favicon_size;
   2260   favicon_size.push_back(16);
   2261   favicon_size.push_back(32);
   2262   GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
   2263   ASSERT_EQ(2u, favicon_bitmap_data.size());
   2264 
   2265   std::vector<favicon_base::FaviconRawBitmapData> touch_icon_bitmap_data;
   2266   std::vector<int> touch_icon_size;
   2267   touch_icon_size.push_back(32);
   2268   GenerateFaviconBitmapData(icon_url, touch_icon_size, &touch_icon_bitmap_data);
   2269   ASSERT_EQ(1u, touch_icon_bitmap_data.size());
   2270 
   2271   // Set some preexisting favicons for |page_url|.
   2272   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2273   backend_->SetFavicons(
   2274       page_url, favicon_base::TOUCH_ICON, touch_icon_bitmap_data);
   2275 
   2276   favicon_base::FaviconRawBitmapResult result;
   2277   std::vector<int> icon_types;
   2278   icon_types.push_back(favicon_base::FAVICON);
   2279   icon_types.push_back(favicon_base::TOUCH_ICON);
   2280 
   2281   backend_->GetLargestFaviconForURL(page_url, icon_types, 16, &result);
   2282 
   2283   // Verify the result icon is 32x32 favicon.
   2284   EXPECT_EQ(gfx::Size(32, 32), result.pixel_size);
   2285   EXPECT_EQ(favicon_base::FAVICON, result.icon_type);
   2286 
   2287   // Change minimal size to 32x32 and verify the 32x32 favicon returned.
   2288   favicon_base::FaviconRawBitmapResult result1;
   2289   backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result1);
   2290   EXPECT_EQ(gfx::Size(32, 32), result1.pixel_size);
   2291   EXPECT_EQ(favicon_base::FAVICON, result1.icon_type);
   2292 }
   2293 
   2294 // Test the favicon is returned if its size is smaller than minimal size,
   2295 // because it is only one available.
   2296 TEST_F(HistoryBackendTest, TestGetFaviconsForURLReturnFaviconEvenItSmaller) {
   2297   GURL page_url("http://www.google.com");
   2298   GURL icon_url("http://www.google.com/favicon.ico");
   2299 
   2300   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2301   std::vector<int> favicon_size;
   2302   favicon_size.push_back(16);
   2303   GenerateFaviconBitmapData(icon_url, favicon_size, &favicon_bitmap_data);
   2304   ASSERT_EQ(1u, favicon_bitmap_data.size());
   2305 
   2306   // Set preexisting favicons for |page_url|.
   2307   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2308 
   2309   favicon_base::FaviconRawBitmapResult result;
   2310   std::vector<int> icon_types;
   2311   icon_types.push_back(favicon_base::FAVICON);
   2312   icon_types.push_back(favicon_base::TOUCH_ICON);
   2313 
   2314   backend_->GetLargestFaviconForURL(page_url, icon_types, 32, &result);
   2315 
   2316   // Verify 16x16 icon is returned, even it small than minimal_size.
   2317   EXPECT_EQ(gfx::Size(16, 16), result.pixel_size);
   2318   EXPECT_EQ(favicon_base::FAVICON, result.icon_type);
   2319 }
   2320 
   2321 // Test UpdateFaviconMapingsAndFetch() when multiple icon types are passed in.
   2322 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchMultipleIconTypes) {
   2323   GURL page_url1("http://www.google.com");
   2324   GURL page_url2("http://news.google.com");
   2325   GURL page_url3("http://mail.google.com");
   2326   GURL icon_urla("http://www.google.com/favicon1.ico");
   2327   GURL icon_urlb("http://www.google.com/favicon2.ico");
   2328   GURL icon_urlc("http://www.google.com/favicon3.ico");
   2329 
   2330   // |page_url1| is mapped to |icon_urla| which if of type TOUCH_ICON.
   2331   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2332   GenerateFaviconBitmapData(icon_urla, GetEdgeSizesSmall(),
   2333       &favicon_bitmap_data);
   2334   backend_->SetFavicons(
   2335       page_url1, favicon_base::TOUCH_ICON, favicon_bitmap_data);
   2336 
   2337   // |page_url2| is mapped to |icon_urlb| and |icon_urlc| which are of type
   2338   // TOUCH_PRECOMPOSED_ICON.
   2339   GenerateFaviconBitmapData(icon_urlb, GetEdgeSizesSmall(), icon_urlc,
   2340                             GetEdgeSizesSmall(), &favicon_bitmap_data);
   2341   backend_->SetFavicons(
   2342       page_url2, favicon_base::TOUCH_PRECOMPOSED_ICON, favicon_bitmap_data);
   2343 
   2344   std::vector<GURL> icon_urls;
   2345   icon_urls.push_back(icon_urla);
   2346   icon_urls.push_back(icon_urlb);
   2347   icon_urls.push_back(icon_urlc);
   2348 
   2349   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
   2350   backend_->UpdateFaviconMappingsAndFetch(
   2351       page_url3,
   2352       icon_urls,
   2353       (favicon_base::TOUCH_ICON | favicon_base::TOUCH_PRECOMPOSED_ICON),
   2354       GetEdgeSizesSmallAndLarge(),
   2355       &bitmap_results);
   2356 
   2357   // |page_url1| and |page_url2| should still be mapped to the same icon URLs.
   2358   std::vector<IconMapping> icon_mappings;
   2359   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(page_url1,
   2360       &icon_mappings));
   2361   EXPECT_EQ(1u, icon_mappings.size());
   2362   EXPECT_EQ(icon_urla, icon_mappings[0].icon_url);
   2363   EXPECT_EQ(favicon_base::TOUCH_ICON, icon_mappings[0].icon_type);
   2364 
   2365   icon_mappings.clear();
   2366   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url2, &icon_mappings));
   2367   EXPECT_EQ(2u, icon_mappings.size());
   2368   EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url);
   2369   EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type);
   2370   EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url);
   2371   EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type);
   2372 
   2373   // |page_url3| should be mapped only to |icon_urlb| and |icon_urlc| as
   2374   // TOUCH_PRECOMPOSED_ICON is the largest IconType.
   2375   icon_mappings.clear();
   2376   EXPECT_TRUE(GetSortedIconMappingsForPageURL(page_url3, &icon_mappings));
   2377   EXPECT_EQ(2u, icon_mappings.size());
   2378   EXPECT_EQ(icon_urlb, icon_mappings[0].icon_url);
   2379   EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON, icon_mappings[0].icon_type);
   2380   EXPECT_EQ(icon_urlc, icon_mappings[1].icon_url);
   2381   EXPECT_EQ(favicon_base::TOUCH_PRECOMPOSED_ICON, icon_mappings[1].icon_type);
   2382 }
   2383 
   2384 // Test the results of GetFaviconsFromDB() when there are no found
   2385 // favicons.
   2386 TEST_F(HistoryBackendTest, GetFaviconsFromDBEmpty) {
   2387   const GURL page_url("http://www.google.com/");
   2388 
   2389   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
   2390   EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url,
   2391                                            favicon_base::FAVICON,
   2392                                            GetEdgeSizesSmallAndLarge(),
   2393                                            &bitmap_results));
   2394   EXPECT_TRUE(bitmap_results.empty());
   2395 }
   2396 
   2397 // Test the results of GetFaviconsFromDB() when there are matching favicons
   2398 // but there are no associated favicon bitmaps.
   2399 TEST_F(HistoryBackendTest, GetFaviconsFromDBNoFaviconBitmaps) {
   2400   const GURL page_url("http://www.google.com/");
   2401   const GURL icon_url("http://www.google.com/icon1");
   2402 
   2403   favicon_base::FaviconID icon_id =
   2404       backend_->thumbnail_db_->AddFavicon(icon_url, favicon_base::FAVICON);
   2405   EXPECT_NE(0, icon_id);
   2406   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
   2407 
   2408   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out;
   2409   EXPECT_FALSE(backend_->GetFaviconsFromDB(page_url,
   2410                                            favicon_base::FAVICON,
   2411                                            GetEdgeSizesSmallAndLarge(),
   2412                                            &bitmap_results_out));
   2413   EXPECT_TRUE(bitmap_results_out.empty());
   2414 }
   2415 
   2416 // Test that GetFaviconsFromDB() returns results for the bitmaps which most
   2417 // closely match the passed in the desired pixel sizes.
   2418 TEST_F(HistoryBackendTest, GetFaviconsFromDBSelectClosestMatch) {
   2419   const GURL page_url("http://www.google.com/");
   2420   const GURL icon_url("http://www.google.com/icon1");
   2421 
   2422   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2423   GenerateFaviconBitmapData(icon_url, GetEdgeSizesTinySmallAndLarge(),
   2424                             &favicon_bitmap_data);
   2425 
   2426   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2427 
   2428   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out;
   2429   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2430                                           favicon_base::FAVICON,
   2431                                           GetEdgeSizesSmallAndLarge(),
   2432                                           &bitmap_results_out));
   2433 
   2434   // The bitmap data for the small and large bitmaps should be returned as their
   2435   // sizes match exactly.
   2436   EXPECT_EQ(2u, bitmap_results_out.size());
   2437   // No required order for results.
   2438   if (bitmap_results_out[0].pixel_size == kLargeSize) {
   2439     favicon_base::FaviconRawBitmapResult tmp_result = bitmap_results_out[0];
   2440     bitmap_results_out[0] = bitmap_results_out[1];
   2441     bitmap_results_out[1] = tmp_result;
   2442   }
   2443 
   2444   EXPECT_FALSE(bitmap_results_out[0].expired);
   2445   EXPECT_TRUE(BitmapDataEqual('b', bitmap_results_out[0].bitmap_data));
   2446   EXPECT_EQ(kSmallSize, bitmap_results_out[0].pixel_size);
   2447   EXPECT_EQ(icon_url, bitmap_results_out[0].icon_url);
   2448   EXPECT_EQ(favicon_base::FAVICON, bitmap_results_out[0].icon_type);
   2449 
   2450   EXPECT_FALSE(bitmap_results_out[1].expired);
   2451   EXPECT_TRUE(BitmapDataEqual('c', bitmap_results_out[1].bitmap_data));
   2452   EXPECT_EQ(kLargeSize, bitmap_results_out[1].pixel_size);
   2453   EXPECT_EQ(icon_url, bitmap_results_out[1].icon_url);
   2454   EXPECT_EQ(favicon_base::FAVICON, bitmap_results_out[1].icon_type);
   2455 }
   2456 
   2457 // Test that GetFaviconsFromDB() returns results from the icon URL whose
   2458 // bitmaps most closely match the passed in desired sizes.
   2459 TEST_F(HistoryBackendTest, GetFaviconsFromDBSingleIconURL) {
   2460   const GURL page_url("http://www.google.com/");
   2461 
   2462   const GURL icon_url1("http://www.google.com/icon1");
   2463   const GURL icon_url2("http://www.google.com/icon2");
   2464 
   2465   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2466   GenerateFaviconBitmapData(icon_url1, GetEdgeSizesSmall(), icon_url2,
   2467                             GetEdgeSizesLarge(), &favicon_bitmap_data);
   2468 
   2469   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2470 
   2471   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out;
   2472   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2473                                           favicon_base::FAVICON,
   2474                                           GetEdgeSizesSmallAndLarge(),
   2475                                           &bitmap_results_out));
   2476 
   2477   // The results should have results for the icon URL with the large bitmap as
   2478   // downscaling is preferred to upscaling.
   2479   EXPECT_EQ(1u, bitmap_results_out.size());
   2480   EXPECT_EQ(kLargeSize, bitmap_results_out[0].pixel_size);
   2481   EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url);
   2482 }
   2483 
   2484 // Test the results of GetFaviconsFromDB() when called with different
   2485 // |icon_types|.
   2486 TEST_F(HistoryBackendTest, GetFaviconsFromDBIconType) {
   2487   const GURL page_url("http://www.google.com/");
   2488   const GURL icon_url1("http://www.google.com/icon1.png");
   2489   const GURL icon_url2("http://www.google.com/icon2.png");
   2490 
   2491   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2492   GenerateFaviconBitmapData(icon_url1, GetEdgeSizesSmall(),
   2493       &favicon_bitmap_data);
   2494   backend_->SetFavicons(page_url, favicon_base::FAVICON, favicon_bitmap_data);
   2495 
   2496   GenerateFaviconBitmapData(
   2497       icon_url2, GetEdgeSizesSmall(), &favicon_bitmap_data);
   2498   backend_->SetFavicons(
   2499       page_url, favicon_base::TOUCH_ICON, favicon_bitmap_data);
   2500 
   2501   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out;
   2502   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2503                                           favicon_base::FAVICON,
   2504                                           GetEdgeSizesSmallAndLarge(),
   2505                                           &bitmap_results_out));
   2506 
   2507   EXPECT_EQ(1u, bitmap_results_out.size());
   2508   EXPECT_EQ(favicon_base::FAVICON, bitmap_results_out[0].icon_type);
   2509   EXPECT_EQ(icon_url1, bitmap_results_out[0].icon_url);
   2510 
   2511   bitmap_results_out.clear();
   2512   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2513                                           favicon_base::TOUCH_ICON,
   2514                                           GetEdgeSizesSmallAndLarge(),
   2515                                           &bitmap_results_out));
   2516 
   2517   EXPECT_EQ(1u, bitmap_results_out.size());
   2518   EXPECT_EQ(favicon_base::TOUCH_ICON, bitmap_results_out[0].icon_type);
   2519   EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url);
   2520 }
   2521 
   2522 // Test that GetFaviconsFromDB() correctly sets the expired flag for bitmap
   2523 // reults.
   2524 TEST_F(HistoryBackendTest, GetFaviconsFromDBExpired) {
   2525   const GURL page_url("http://www.google.com/");
   2526   const GURL icon_url("http://www.google.com/icon.png");
   2527 
   2528   std::vector<unsigned char> data;
   2529   data.push_back('a');
   2530   scoped_refptr<base::RefCountedBytes> bitmap_data(
   2531       base::RefCountedBytes::TakeVector(&data));
   2532   base::Time last_updated = base::Time::FromTimeT(0);
   2533   favicon_base::FaviconID icon_id = backend_->thumbnail_db_->AddFavicon(
   2534       icon_url, favicon_base::FAVICON, bitmap_data, last_updated, kSmallSize);
   2535   EXPECT_NE(0, icon_id);
   2536   EXPECT_NE(0, backend_->thumbnail_db_->AddIconMapping(page_url, icon_id));
   2537 
   2538   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out;
   2539   EXPECT_TRUE(backend_->GetFaviconsFromDB(page_url,
   2540                                           favicon_base::FAVICON,
   2541                                           GetEdgeSizesSmallAndLarge(),
   2542                                           &bitmap_results_out));
   2543 
   2544   EXPECT_EQ(1u, bitmap_results_out.size());
   2545   EXPECT_TRUE(bitmap_results_out[0].expired);
   2546 }
   2547 
   2548 // Check that UpdateFaviconMappingsAndFetch() call back to the UI when there is
   2549 // no valid thumbnail database.
   2550 TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoDB) {
   2551   // Make the thumbnail database invalid.
   2552   backend_->thumbnail_db_.reset();
   2553 
   2554   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results;
   2555 
   2556   backend_->UpdateFaviconMappingsAndFetch(GURL(),
   2557                                           std::vector<GURL>(),
   2558                                           favicon_base::FAVICON,
   2559                                           GetEdgeSizesSmallAndLarge(),
   2560                                           &bitmap_results);
   2561 
   2562   EXPECT_TRUE(bitmap_results.empty());
   2563 }
   2564 
   2565 TEST_F(HistoryBackendTest, CloneFaviconIsRestrictedToSameDomain) {
   2566   const GURL url("http://www.google.com/");
   2567   const GURL same_domain_url("http://www.google.com/subdir/index.html");
   2568   const GURL foreign_domain_url("http://www.not-google.com/");
   2569   const GURL icon_url("http://www.google.com/icon.png");
   2570 
   2571   // Add a favicon
   2572   std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data;
   2573   GenerateFaviconBitmapData(icon_url, GetEdgeSizesSmall(),
   2574       &favicon_bitmap_data);
   2575   backend_->SetFavicons(url, favicon_base::FAVICON, favicon_bitmap_data);
   2576   EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
   2577       url, favicon_base::FAVICON, NULL));
   2578 
   2579   // Validate starting state.
   2580   std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out;
   2581   EXPECT_TRUE(backend_->GetFaviconsFromDB(url,
   2582                                           favicon_base::FAVICON,
   2583                                           GetEdgeSizesSmallAndLarge(),
   2584                                           &bitmap_results_out));
   2585   EXPECT_FALSE(backend_->GetFaviconsFromDB(same_domain_url,
   2586                                            favicon_base::FAVICON,
   2587                                            GetEdgeSizesSmallAndLarge(),
   2588                                            &bitmap_results_out));
   2589   EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url,
   2590                                            favicon_base::FAVICON,
   2591                                            GetEdgeSizesSmallAndLarge(),
   2592                                            &bitmap_results_out));
   2593 
   2594   // Same-domain cloning should work.
   2595   backend_->CloneFavicons(url, same_domain_url);
   2596   EXPECT_TRUE(backend_->GetFaviconsFromDB(same_domain_url,
   2597                                           favicon_base::FAVICON,
   2598                                           GetEdgeSizesSmallAndLarge(),
   2599                                           &bitmap_results_out));
   2600 
   2601   // Foreign-domain cloning is forbidden.
   2602   backend_->CloneFavicons(url, foreign_domain_url);
   2603   EXPECT_FALSE(backend_->GetFaviconsFromDB(foreign_domain_url,
   2604                                            favicon_base::FAVICON,
   2605                                            GetEdgeSizesSmallAndLarge(),
   2606                                            &bitmap_results_out));
   2607 }
   2608 
   2609 TEST_F(HistoryBackendTest, QueryFilteredURLs) {
   2610   const char* google = "http://www.google.com/";
   2611   const char* yahoo = "http://www.yahoo.com/";
   2612   const char* yahoo_sports = "http://sports.yahoo.com/";
   2613   const char* yahoo_sports_with_article1 =
   2614       "http://sports.yahoo.com/article1.htm";
   2615   const char* yahoo_sports_with_article2 =
   2616       "http://sports.yahoo.com/article2.htm";
   2617   const char* yahoo_sports_soccer = "http://sports.yahoo.com/soccer";
   2618   const char* apple = "http://www.apple.com/";
   2619 
   2620   // Clear all history.
   2621   backend_->DeleteAllHistory();
   2622 
   2623   Time tested_time = Time::Now().LocalMidnight() +
   2624                      base::TimeDelta::FromHours(4);
   2625   base::TimeDelta half_an_hour = base::TimeDelta::FromMinutes(30);
   2626   base::TimeDelta one_hour = base::TimeDelta::FromHours(1);
   2627   base::TimeDelta one_day = base::TimeDelta::FromDays(1);
   2628 
   2629   const content::PageTransition kTypedTransition =
   2630       content::PAGE_TRANSITION_TYPED;
   2631   const content::PageTransition kKeywordGeneratedTransition =
   2632       content::PAGE_TRANSITION_KEYWORD_GENERATED;
   2633 
   2634   const char* redirect_sequence[2];
   2635   redirect_sequence[1] = NULL;
   2636 
   2637   redirect_sequence[0] = google;
   2638   AddRedirectChainWithTransitionAndTime(
   2639       redirect_sequence, 0, kTypedTransition,
   2640       tested_time - one_day - half_an_hour * 2);
   2641   AddRedirectChainWithTransitionAndTime(
   2642       redirect_sequence, 0,
   2643       kTypedTransition, tested_time - one_day);
   2644   AddRedirectChainWithTransitionAndTime(
   2645       redirect_sequence, 0,
   2646       kTypedTransition, tested_time - half_an_hour / 2);
   2647   AddRedirectChainWithTransitionAndTime(
   2648       redirect_sequence, 0,
   2649       kTypedTransition, tested_time);
   2650 
   2651   // Add a visit with a transition that will make sure that no segment gets
   2652   // created for this page (so the subsequent entries will have different URLIDs
   2653   // and SegmentIDs).
   2654   redirect_sequence[0] = apple;
   2655   AddRedirectChainWithTransitionAndTime(
   2656       redirect_sequence, 0, kKeywordGeneratedTransition,
   2657       tested_time - one_day + one_hour * 6);
   2658 
   2659   redirect_sequence[0] = yahoo;
   2660   AddRedirectChainWithTransitionAndTime(
   2661       redirect_sequence, 0, kTypedTransition,
   2662       tested_time - one_day + half_an_hour);
   2663   AddRedirectChainWithTransitionAndTime(
   2664       redirect_sequence, 0, kTypedTransition,
   2665       tested_time - one_day + half_an_hour * 2);
   2666 
   2667   redirect_sequence[0] = yahoo_sports;
   2668   AddRedirectChainWithTransitionAndTime(
   2669       redirect_sequence, 0, kTypedTransition,
   2670       tested_time - one_day - half_an_hour * 2);
   2671   AddRedirectChainWithTransitionAndTime(
   2672       redirect_sequence, 0, kTypedTransition,
   2673       tested_time - one_day);
   2674   int transition1, transition2;
   2675   AddClientRedirect(GURL(yahoo_sports), GURL(yahoo_sports_with_article1), false,
   2676                     tested_time - one_day + half_an_hour,
   2677                     &transition1, &transition2);
   2678   AddClientRedirect(GURL(yahoo_sports_with_article1),
   2679                     GURL(yahoo_sports_with_article2),
   2680                     false,
   2681                     tested_time - one_day + half_an_hour * 2,
   2682                     &transition1, &transition2);
   2683 
   2684   redirect_sequence[0] = yahoo_sports_soccer;
   2685   AddRedirectChainWithTransitionAndTime(redirect_sequence, 0,
   2686                                         kTypedTransition,
   2687                                         tested_time - half_an_hour);
   2688   backend_->Commit();
   2689 
   2690   scoped_refptr<QueryFilteredURLsRequest> request1 =
   2691       new history::QueryFilteredURLsRequest(
   2692           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2693                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2694   HistoryBackendCancelableRequest cancellable_request;
   2695   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2696       request1.get());
   2697 
   2698   VisitFilter filter;
   2699   // Time limit is |tested_time| +/- 45 min.
   2700   base::TimeDelta three_quarters_of_an_hour = base::TimeDelta::FromMinutes(45);
   2701   filter.SetFilterTime(tested_time);
   2702   filter.SetFilterWidth(three_quarters_of_an_hour);
   2703   backend_->QueryFilteredURLs(request1, 100, filter, false);
   2704 
   2705   ASSERT_EQ(4U, get_filtered_list().size());
   2706   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2707   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2708             get_filtered_list()[1].url.spec());
   2709   EXPECT_EQ(std::string(yahoo), get_filtered_list()[2].url.spec());
   2710   EXPECT_EQ(std::string(yahoo_sports),
   2711             get_filtered_list()[3].url.spec());
   2712 
   2713   // Time limit is between |tested_time| and |tested_time| + 2 hours.
   2714   scoped_refptr<QueryFilteredURLsRequest> request2 =
   2715       new history::QueryFilteredURLsRequest(
   2716           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2717                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2718   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2719       request2.get());
   2720   filter.SetFilterTime(tested_time + one_hour);
   2721   filter.SetFilterWidth(one_hour);
   2722   backend_->QueryFilteredURLs(request2, 100, filter, false);
   2723 
   2724   ASSERT_EQ(3U, get_filtered_list().size());
   2725   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2726   EXPECT_EQ(std::string(yahoo), get_filtered_list()[1].url.spec());
   2727   EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec());
   2728 
   2729   // Time limit is between |tested_time| - 2 hours and |tested_time|.
   2730   scoped_refptr<QueryFilteredURLsRequest> request3 =
   2731       new history::QueryFilteredURLsRequest(
   2732           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2733                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2734   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2735       request3.get());
   2736   filter.SetFilterTime(tested_time - one_hour);
   2737   filter.SetFilterWidth(one_hour);
   2738   backend_->QueryFilteredURLs(request3, 100, filter, false);
   2739 
   2740   ASSERT_EQ(3U, get_filtered_list().size());
   2741   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2742   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2743             get_filtered_list()[1].url.spec());
   2744   EXPECT_EQ(std::string(yahoo_sports), get_filtered_list()[2].url.spec());
   2745 
   2746   filter.ClearFilters();
   2747   base::Time::Exploded exploded_time;
   2748   tested_time.LocalExplode(&exploded_time);
   2749 
   2750   // Today.
   2751   scoped_refptr<QueryFilteredURLsRequest> request4 =
   2752       new history::QueryFilteredURLsRequest(
   2753           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2754                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2755   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2756       request4.get());
   2757   filter.SetFilterTime(tested_time);
   2758   filter.SetDayOfTheWeekFilter(static_cast<int>(exploded_time.day_of_week));
   2759   backend_->QueryFilteredURLs(request4, 100, filter, false);
   2760 
   2761   ASSERT_EQ(2U, get_filtered_list().size());
   2762   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2763   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2764             get_filtered_list()[1].url.spec());
   2765 
   2766   // Today + time limit - only yahoo_sports_soccer should fit.
   2767   scoped_refptr<QueryFilteredURLsRequest> request5 =
   2768       new history::QueryFilteredURLsRequest(
   2769           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2770                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2771   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2772       request5.get());
   2773   filter.SetFilterTime(tested_time - base::TimeDelta::FromMinutes(40));
   2774   filter.SetFilterWidth(base::TimeDelta::FromMinutes(20));
   2775   backend_->QueryFilteredURLs(request5, 100, filter, false);
   2776 
   2777   ASSERT_EQ(1U, get_filtered_list().size());
   2778   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2779             get_filtered_list()[0].url.spec());
   2780 
   2781   // Make sure we get debug data if we request it.
   2782   scoped_refptr<QueryFilteredURLsRequest> request6 =
   2783       new history::QueryFilteredURLsRequest(
   2784           base::Bind(&HistoryBackendTest::OnQueryFiltered,
   2785                      base::Unretained(static_cast<HistoryBackendTest*>(this))));
   2786   cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>(
   2787       request6.get());
   2788   filter.SetFilterTime(tested_time);
   2789   filter.SetFilterWidth(one_hour * 2);
   2790   backend_->QueryFilteredURLs(request6, 100, filter, true);
   2791 
   2792   // If the SegmentID is used by QueryFilteredURLs when generating the debug
   2793   // data instead of the URLID, the |total_visits| for the |yahoo_sports_soccer|
   2794   // entry will be zero instead of 1.
   2795   ASSERT_GE(get_filtered_list().size(), 2U);
   2796   EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec());
   2797   EXPECT_EQ(std::string(yahoo_sports_soccer),
   2798       get_filtered_list()[1].url.spec());
   2799   EXPECT_EQ(4U, get_filtered_list()[0].extended_info.total_visits);
   2800   EXPECT_EQ(1U, get_filtered_list()[1].extended_info.total_visits);
   2801 }
   2802 
   2803 TEST_F(HistoryBackendTest, UpdateVisitDuration) {
   2804   // This unit test will test adding and deleting visit details information.
   2805   ASSERT_TRUE(backend_.get());
   2806 
   2807   GURL url1("http://www.cnn.com");
   2808   std::vector<VisitInfo> visit_info1, visit_info2;
   2809   Time start_ts = Time::Now() - base::TimeDelta::FromDays(5);
   2810   Time end_ts = start_ts + base::TimeDelta::FromDays(2);
   2811   visit_info1.push_back(VisitInfo(start_ts, content::PAGE_TRANSITION_LINK));
   2812 
   2813   GURL url2("http://www.example.com");
   2814   visit_info2.push_back(VisitInfo(Time::Now() - base::TimeDelta::FromDays(10),
   2815                                   content::PAGE_TRANSITION_LINK));
   2816 
   2817   // Clear all history.
   2818   backend_->DeleteAllHistory();
   2819 
   2820   // Add the visits.
   2821   backend_->AddVisits(url1, visit_info1, history::SOURCE_BROWSED);
   2822   backend_->AddVisits(url2, visit_info2, history::SOURCE_BROWSED);
   2823 
   2824   // Verify the entries for both visits were added in visit_details.
   2825   VisitVector visits1, visits2;
   2826   URLRow row;
   2827   URLID url_id1 = backend_->db()->GetRowForURL(url1, &row);
   2828   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1));
   2829   ASSERT_EQ(1U, visits1.size());
   2830   EXPECT_EQ(0, visits1[0].visit_duration.ToInternalValue());
   2831 
   2832   URLID url_id2 = backend_->db()->GetRowForURL(url2, &row);
   2833   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id2, &visits2));
   2834   ASSERT_EQ(1U, visits2.size());
   2835   EXPECT_EQ(0, visits2[0].visit_duration.ToInternalValue());
   2836 
   2837   // Update the visit to cnn.com.
   2838   backend_->UpdateVisitDuration(visits1[0].visit_id, end_ts);
   2839 
   2840   // Check the duration for visiting cnn.com was correctly updated.
   2841   ASSERT_TRUE(backend_->db()->GetVisitsForURL(url_id1, &visits1));
   2842   ASSERT_EQ(1U, visits1.size());
   2843   base::TimeDelta expected_duration = end_ts - start_ts;
   2844   EXPECT_EQ(expected_duration.ToInternalValue(),
   2845             visits1[0].visit_duration.ToInternalValue());
   2846 
   2847   // Remove the visit to cnn.com.
   2848   ASSERT_TRUE(backend_->RemoveVisits(visits1));
   2849 }
   2850 
   2851 // Test for migration of adding visit_duration column.
   2852 TEST_F(HistoryBackendTest, MigrationVisitDuration) {
   2853   ASSERT_TRUE(backend_.get());
   2854   backend_->Closing();
   2855   backend_ = NULL;
   2856 
   2857   base::FilePath old_history_path, old_history;
   2858   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
   2859   old_history_path = old_history_path.AppendASCII("History");
   2860   old_history = old_history_path.AppendASCII("HistoryNoDuration");
   2861 
   2862   // Copy history database file to current directory so that it will be deleted
   2863   // in Teardown.
   2864   base::FilePath new_history_path(test_dir());
   2865   base::DeleteFile(new_history_path, true);
   2866   base::CreateDirectory(new_history_path);
   2867   base::FilePath new_history_file =
   2868       new_history_path.Append(chrome::kHistoryFilename);
   2869   ASSERT_TRUE(base::CopyFile(old_history, new_history_file));
   2870 
   2871   backend_ = new HistoryBackend(
   2872       new_history_path, new HistoryBackendTestDelegate(this), &history_client_);
   2873   backend_->Init(std::string(), false);
   2874   backend_->Closing();
   2875   backend_ = NULL;
   2876 
   2877   // Now the history database should already be migrated.
   2878 
   2879   // Check version in history database first.
   2880   int cur_version = HistoryDatabase::GetCurrentVersion();
   2881   sql::Connection db;
   2882   ASSERT_TRUE(db.Open(new_history_file));
   2883   sql::Statement s(db.GetUniqueStatement(
   2884       "SELECT value FROM meta WHERE key = 'version'"));
   2885   ASSERT_TRUE(s.Step());
   2886   int file_version = s.ColumnInt(0);
   2887   EXPECT_EQ(cur_version, file_version);
   2888 
   2889   // Check visit_duration column in visits table is created and set to 0.
   2890   s.Assign(db.GetUniqueStatement(
   2891       "SELECT visit_duration FROM visits LIMIT 1"));
   2892   ASSERT_TRUE(s.Step());
   2893   EXPECT_EQ(0, s.ColumnInt(0));
   2894 }
   2895 
   2896 TEST_F(HistoryBackendTest, AddPageNoVisitForBookmark) {
   2897   ASSERT_TRUE(backend_.get());
   2898 
   2899   GURL url("http://www.google.com");
   2900   base::string16 title(base::UTF8ToUTF16("Bookmark title"));
   2901   backend_->AddPageNoVisitForBookmark(url, title);
   2902 
   2903   URLRow row;
   2904   backend_->GetURL(url, &row);
   2905   EXPECT_EQ(url, row.url());
   2906   EXPECT_EQ(title, row.title());
   2907   EXPECT_EQ(0, row.visit_count());
   2908 
   2909   backend_->DeleteURL(url);
   2910   backend_->AddPageNoVisitForBookmark(url, base::string16());
   2911   backend_->GetURL(url, &row);
   2912   EXPECT_EQ(url, row.url());
   2913   EXPECT_EQ(base::UTF8ToUTF16(url.spec()), row.title());
   2914   EXPECT_EQ(0, row.visit_count());
   2915 }
   2916 
   2917 TEST_F(HistoryBackendTest, ExpireHistoryForTimes) {
   2918   ASSERT_TRUE(backend_.get());
   2919 
   2920   HistoryAddPageArgs args[10];
   2921   for (size_t i = 0; i < arraysize(args); ++i) {
   2922     args[i].url = GURL("http://example" +
   2923                        std::string((i % 2 == 0 ? ".com" : ".net")));
   2924     args[i].time = base::Time::FromInternalValue(i);
   2925     backend_->AddPage(args[i]);
   2926   }
   2927   EXPECT_EQ(base::Time(), backend_->GetFirstRecordedTimeForTest());
   2928 
   2929   URLRow row;
   2930   for (size_t i = 0; i < arraysize(args); ++i) {
   2931     EXPECT_TRUE(backend_->GetURL(args[i].url, &row));
   2932   }
   2933 
   2934   std::set<base::Time> times;
   2935   times.insert(args[5].time);
   2936   backend_->ExpireHistoryForTimes(times,
   2937                                   base::Time::FromInternalValue(2),
   2938                                   base::Time::FromInternalValue(8));
   2939 
   2940   EXPECT_EQ(base::Time::FromInternalValue(0),
   2941             backend_->GetFirstRecordedTimeForTest());
   2942 
   2943   // Visits to http://example.com are untouched.
   2944   VisitVector visit_vector;
   2945   EXPECT_TRUE(backend_->GetVisitsForURL(
   2946       backend_->db_->GetRowForURL(GURL("http://example.com"), NULL),
   2947       &visit_vector));
   2948   ASSERT_EQ(5u, visit_vector.size());
   2949   EXPECT_EQ(base::Time::FromInternalValue(0), visit_vector[0].visit_time);
   2950   EXPECT_EQ(base::Time::FromInternalValue(2), visit_vector[1].visit_time);
   2951   EXPECT_EQ(base::Time::FromInternalValue(4), visit_vector[2].visit_time);
   2952   EXPECT_EQ(base::Time::FromInternalValue(6), visit_vector[3].visit_time);
   2953   EXPECT_EQ(base::Time::FromInternalValue(8), visit_vector[4].visit_time);
   2954 
   2955   // Visits to http://example.net between [2,8] are removed.
   2956   visit_vector.clear();
   2957   EXPECT_TRUE(backend_->GetVisitsForURL(
   2958       backend_->db_->GetRowForURL(GURL("http://example.net"), NULL),
   2959       &visit_vector));
   2960   ASSERT_EQ(2u, visit_vector.size());
   2961   EXPECT_EQ(base::Time::FromInternalValue(1), visit_vector[0].visit_time);
   2962   EXPECT_EQ(base::Time::FromInternalValue(9), visit_vector[1].visit_time);
   2963 
   2964   EXPECT_EQ(base::Time::FromInternalValue(0),
   2965             backend_->GetFirstRecordedTimeForTest());
   2966 }
   2967 
   2968 TEST_F(HistoryBackendTest, ExpireHistory) {
   2969   ASSERT_TRUE(backend_.get());
   2970   // Since history operations are dependent on the local timezone, make all
   2971   // entries relative to a fixed, local reference time.
   2972   base::Time reference_time = base::Time::UnixEpoch().LocalMidnight() +
   2973                               base::TimeDelta::FromHours(12);
   2974 
   2975   // Insert 4 entries into the database.
   2976   HistoryAddPageArgs args[4];
   2977   for (size_t i = 0; i < arraysize(args); ++i) {
   2978     args[i].url = GURL("http://example" + base::IntToString(i) + ".com");
   2979     args[i].time = reference_time + base::TimeDelta::FromDays(i);
   2980     backend_->AddPage(args[i]);
   2981   }
   2982 
   2983   URLRow url_rows[4];
   2984   for (unsigned int i = 0; i < arraysize(args); ++i)
   2985     ASSERT_TRUE(backend_->GetURL(args[i].url, &url_rows[i]));
   2986 
   2987   std::vector<ExpireHistoryArgs> expire_list;
   2988   VisitVector visits;
   2989 
   2990   // Passing an empty map should be a no-op.
   2991   backend_->ExpireHistory(expire_list);
   2992   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   2993   EXPECT_EQ(4U, visits.size());
   2994 
   2995   // Trying to delete an unknown URL with the time of the first visit should
   2996   // also be a no-op.
   2997   expire_list.resize(expire_list.size() + 1);
   2998   expire_list[0].SetTimeRangeForOneDay(args[0].time);
   2999   expire_list[0].urls.insert(GURL("http://google.does-not-exist"));
   3000   backend_->ExpireHistory(expire_list);
   3001   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   3002   EXPECT_EQ(4U, visits.size());
   3003 
   3004   // Now add the first URL with the same time -- it should get deleted.
   3005   expire_list.back().urls.insert(url_rows[0].url());
   3006   backend_->ExpireHistory(expire_list);
   3007 
   3008   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   3009   ASSERT_EQ(3U, visits.size());
   3010   EXPECT_EQ(visits[0].url_id, url_rows[1].id());
   3011   EXPECT_EQ(visits[1].url_id, url_rows[2].id());
   3012   EXPECT_EQ(visits[2].url_id, url_rows[3].id());
   3013 
   3014   // The first recorded time should also get updated.
   3015   EXPECT_EQ(backend_->GetFirstRecordedTimeForTest(), args[1].time);
   3016 
   3017   // Now delete the rest of the visits in one call.
   3018   for (unsigned int i = 1; i < arraysize(args); ++i) {
   3019     expire_list.resize(expire_list.size() + 1);
   3020     expire_list[i].SetTimeRangeForOneDay(args[i].time);
   3021     expire_list[i].urls.insert(args[i].url);
   3022   }
   3023   backend_->ExpireHistory(expire_list);
   3024 
   3025   backend_->db()->GetAllVisitsInRange(base::Time(), base::Time(), 0, &visits);
   3026   ASSERT_EQ(0U, visits.size());
   3027 }
   3028 
   3029 TEST_F(HistoryBackendTest, DeleteMatchingUrlsForKeyword) {
   3030   // Set up urls and keyword_search_terms
   3031   GURL url1("https://www.bing.com/?q=bar");
   3032   URLRow url_info1(url1);
   3033   url_info1.set_visit_count(0);
   3034   url_info1.set_typed_count(0);
   3035   url_info1.set_last_visit(Time());
   3036   url_info1.set_hidden(false);
   3037   const URLID url1_id = backend_->db()->AddURL(url_info1);
   3038   EXPECT_NE(0, url1_id);
   3039 
   3040   TemplateURLID keyword_id = 1;
   3041   base::string16 keyword = base::UTF8ToUTF16("bar");
   3042   ASSERT_TRUE(backend_->db()->SetKeywordSearchTermsForURL(
   3043       url1_id, keyword_id, keyword));
   3044 
   3045   GURL url2("https://www.google.com/?q=bar");
   3046   URLRow url_info2(url2);
   3047   url_info2.set_visit_count(0);
   3048   url_info2.set_typed_count(0);
   3049   url_info2.set_last_visit(Time());
   3050   url_info2.set_hidden(false);
   3051   const URLID url2_id = backend_->db()->AddURL(url_info2);
   3052   EXPECT_NE(0, url2_id);
   3053 
   3054   TemplateURLID keyword_id2 = 2;
   3055   ASSERT_TRUE(backend_->db()->SetKeywordSearchTermsForURL(
   3056       url2_id, keyword_id2, keyword));
   3057 
   3058   // Add another visit to the same URL
   3059   URLRow url_info3(url2);
   3060   url_info3.set_visit_count(0);
   3061   url_info3.set_typed_count(0);
   3062   url_info3.set_last_visit(Time());
   3063   url_info3.set_hidden(false);
   3064   const URLID url3_id = backend_->db()->AddURL(url_info3);
   3065   EXPECT_NE(0, url3_id);
   3066   ASSERT_TRUE(backend_->db()->SetKeywordSearchTermsForURL(
   3067       url3_id, keyword_id2, keyword));
   3068 
   3069   // Test that deletion works correctly
   3070   backend_->DeleteMatchingURLsForKeyword(keyword_id2, keyword);
   3071 
   3072   // Test that rows 2 and 3 are deleted, while 1 is intact
   3073   URLRow row;
   3074   EXPECT_TRUE(backend_->db()->GetURLRow(url1_id, &row));
   3075   EXPECT_EQ(url1.spec(), row.url().spec());
   3076   EXPECT_FALSE(backend_->db()->GetURLRow(url2_id, &row));
   3077   EXPECT_FALSE(backend_->db()->GetURLRow(url3_id, &row));
   3078 
   3079   // Test that corresponding keyword search terms are deleted for rows 2 & 3,
   3080   // but not for row 1
   3081   EXPECT_TRUE(backend_->db()->GetKeywordSearchTermRow(url1_id, NULL));
   3082   EXPECT_FALSE(backend_->db()->GetKeywordSearchTermRow(url2_id, NULL));
   3083   EXPECT_FALSE(backend_->db()->GetKeywordSearchTermRow(url3_id, NULL));
   3084 }
   3085 
   3086 // Simple test that removes a bookmark. This test exercises the code paths in
   3087 // History that block till bookmark bar model is loaded.
   3088 TEST_F(HistoryBackendTest, RemoveNotification) {
   3089   scoped_ptr<TestingProfile> profile(new TestingProfile());
   3090 
   3091   // Add a URL.
   3092   GURL url("http://www.google.com");
   3093   HistoryClientMock history_client;
   3094   history_client.AddBookmark(url);
   3095   scoped_ptr<HistoryService> service(
   3096       new HistoryService(&history_client, profile.get()));
   3097   EXPECT_TRUE(service->Init(profile->GetPath()));
   3098 
   3099   service->AddPage(
   3100       url, base::Time::Now(), NULL, 1, GURL(), RedirectList(),
   3101       content::PAGE_TRANSITION_TYPED, SOURCE_BROWSED, false);
   3102 
   3103   // This won't actually delete the URL, rather it'll empty out the visits.
   3104   // This triggers blocking on the BookmarkModel.
   3105   EXPECT_CALL(history_client, BlockUntilBookmarksLoaded());
   3106   service->DeleteURL(url);
   3107 }
   3108 
   3109 // Test DeleteFTSIndexDatabases deletes expected files.
   3110 TEST_F(HistoryBackendTest, DeleteFTSIndexDatabases) {
   3111   ASSERT_TRUE(backend_.get());
   3112 
   3113   base::FilePath history_path(test_dir());
   3114   base::FilePath db1(history_path.AppendASCII("History Index 2013-05"));
   3115   base::FilePath db1_journal(db1.InsertBeforeExtensionASCII("-journal"));
   3116   base::FilePath db1_wal(db1.InsertBeforeExtensionASCII("-wal"));
   3117   base::FilePath db2_symlink(history_path.AppendASCII("History Index 2013-06"));
   3118   base::FilePath db2_actual(history_path.AppendASCII("Underlying DB"));
   3119 
   3120   // Setup dummy index database files.
   3121   const char* data = "Dummy";
   3122   const size_t data_len = 5;
   3123   ASSERT_TRUE(base::WriteFile(db1, data, data_len));
   3124   ASSERT_TRUE(base::WriteFile(db1_journal, data, data_len));
   3125   ASSERT_TRUE(base::WriteFile(db1_wal, data, data_len));
   3126   ASSERT_TRUE(base::WriteFile(db2_actual, data, data_len));
   3127 #if defined(OS_POSIX)
   3128   EXPECT_TRUE(base::CreateSymbolicLink(db2_actual, db2_symlink));
   3129 #endif
   3130 
   3131   // Delete all DTS index databases.
   3132   backend_->DeleteFTSIndexDatabases();
   3133   EXPECT_FALSE(base::PathExists(db1));
   3134   EXPECT_FALSE(base::PathExists(db1_wal));
   3135   EXPECT_FALSE(base::PathExists(db1_journal));
   3136   EXPECT_FALSE(base::PathExists(db2_symlink));
   3137   EXPECT_TRUE(base::PathExists(db2_actual));  // Symlinks shouldn't be followed.
   3138 }
   3139 
   3140 // Common implementation for the two tests below, given that the only difference
   3141 // between them is the type of the notification sent out.
   3142 void InMemoryHistoryBackendTest::TestAddingAndChangingURLRows(
   3143     int notification_type) {
   3144   const char kTestTypedURLAlternativeTitle[] = "Google Search Again";
   3145   const char kTestNonTypedURLAlternativeTitle[] = "Google News Again";
   3146 
   3147   // Notify the in-memory database that a typed and non-typed URLRow (which were
   3148   // never before seen by the cache) have been modified.
   3149   URLRow row1(CreateTestTypedURL());
   3150   URLRow row2(CreateTestNonTypedURL());
   3151   SimulateNotification(notification_type, &row1, &row2);
   3152 
   3153   // The in-memory database should only pick up the typed URL, and should ignore
   3154   // the non-typed one. The typed URL should retain the ID that was present in
   3155   // the notification.
   3156   URLRow cached_row1, cached_row2;
   3157   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3158   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row2.url(), &cached_row2));
   3159   EXPECT_EQ(row1.id(), cached_row1.id());
   3160 
   3161   // Try changing attributes (other than typed_count) for existing URLRows.
   3162   row1.set_title(base::UTF8ToUTF16(kTestTypedURLAlternativeTitle));
   3163   row2.set_title(base::UTF8ToUTF16(kTestNonTypedURLAlternativeTitle));
   3164   SimulateNotification(notification_type, &row1, &row2);
   3165 
   3166   // URLRows that are cached by the in-memory database should be updated.
   3167   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3168   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row2.url(), &cached_row2));
   3169   EXPECT_EQ(base::UTF8ToUTF16(kTestTypedURLAlternativeTitle),
   3170             cached_row1.title());
   3171 
   3172   // Now decrease the typed count for the typed URLRow, and increase it for the
   3173   // previously non-typed URLRow.
   3174   row1.set_typed_count(0);
   3175   row2.set_typed_count(2);
   3176   SimulateNotification(notification_type, &row1, &row2);
   3177 
   3178   // The in-memory database should stop caching the first URLRow, and start
   3179   // caching the second URLRow.
   3180   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3181   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row2.url(), &cached_row2));
   3182   EXPECT_EQ(row2.id(), cached_row2.id());
   3183   EXPECT_EQ(base::UTF8ToUTF16(kTestNonTypedURLAlternativeTitle),
   3184             cached_row2.title());
   3185 }
   3186 
   3187 TEST_F(InMemoryHistoryBackendTest, OnURLsModified) {
   3188   TestAddingAndChangingURLRows(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED);
   3189 }
   3190 
   3191 TEST_F(InMemoryHistoryBackendTest, OnURLsVisisted) {
   3192   TestAddingAndChangingURLRows(chrome::NOTIFICATION_HISTORY_URL_VISITED);
   3193 }
   3194 
   3195 TEST_F(InMemoryHistoryBackendTest, OnURLsDeletedPiecewise) {
   3196   // Add two typed and one non-typed URLRow to the in-memory database.
   3197   URLRow row1(CreateTestTypedURL());
   3198   URLRow row2(CreateAnotherTestTypedURL());
   3199   URLRow row3(CreateTestNonTypedURL());
   3200   SimulateNotification(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
   3201                        &row1, &row2, &row3);
   3202 
   3203   // Notify the in-memory database that the second typed URL and the non-typed
   3204   // URL has been deleted.
   3205   SimulateNotification(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
   3206                        &row2, &row3);
   3207 
   3208   // Expect that the first typed URL remains intact, the second typed URL is
   3209   // correctly removed, and the non-typed URL does not magically appear.
   3210   URLRow cached_row1;
   3211   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3212   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row2.url(), NULL));
   3213   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row3.url(), NULL));
   3214   EXPECT_EQ(row1.id(), cached_row1.id());
   3215 }
   3216 
   3217 TEST_F(InMemoryHistoryBackendTest, OnURLsDeletedEnMasse) {
   3218   // Add two typed and one non-typed URLRow to the in-memory database.
   3219   URLRow row1(CreateTestTypedURL());
   3220   URLRow row2(CreateAnotherTestTypedURL());
   3221   URLRow row3(CreateTestNonTypedURL());
   3222   SimulateNotification(chrome::NOTIFICATION_HISTORY_URLS_MODIFIED,
   3223                        &row1, &row2, &row3);
   3224 
   3225   // Now notify the in-memory database that all history has been deleted.
   3226   scoped_ptr<URLsDeletedDetails> details(new URLsDeletedDetails());
   3227   details->all_history = true;
   3228   BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED,
   3229                          details.PassAs<HistoryDetails>());
   3230 
   3231   // Expect that everything goes away.
   3232   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row1.url(), NULL));
   3233   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row2.url(), NULL));
   3234   EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row3.url(), NULL));
   3235 }
   3236 
   3237 void InMemoryHistoryBackendTest::PopulateTestURLsAndSearchTerms(
   3238     URLRow* row1,
   3239     URLRow* row2,
   3240     const base::string16& term1,
   3241     const base::string16& term2) {
   3242   // Add a typed and a non-typed URLRow to the in-memory database. This time,
   3243   // though, do it through the history backend...
   3244   URLRows rows;
   3245   rows.push_back(*row1);
   3246   rows.push_back(*row2);
   3247   backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
   3248   backend_->db()->GetRowForURL(row1->url(), row1);  // Get effective IDs from
   3249   backend_->db()->GetRowForURL(row2->url(), row2);  // the database.
   3250 
   3251   // ... so that we can also use that for adding the search terms. This way, we
   3252   // not only test that the notifications involved are handled correctly, but
   3253   // also that they are fired correctly (in the history backend).
   3254   backend_->SetKeywordSearchTermsForURL(row1->url(), kTestKeywordId, term1);
   3255   backend_->SetKeywordSearchTermsForURL(row2->url(), kTestKeywordId, term2);
   3256 }
   3257 
   3258 TEST_F(InMemoryHistoryBackendTest, SetKeywordSearchTerms) {
   3259   URLRow row1(CreateTestTypedURL());
   3260   URLRow row2(CreateTestNonTypedURL());
   3261   base::string16 term1(base::UTF8ToUTF16(kTestSearchTerm1));
   3262   base::string16 term2(base::UTF8ToUTF16(kTestSearchTerm2));
   3263   PopulateTestURLsAndSearchTerms(&row1, &row2, term1, term2);
   3264 
   3265   // Both URLs now have associated search terms, so the in-memory database
   3266   // should cache both of them, regardless whether they have been typed or not.
   3267   URLRow cached_row1, cached_row2;
   3268   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3269   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row2.url(), &cached_row2));
   3270   EXPECT_EQ(row1.id(), cached_row1.id());
   3271   EXPECT_EQ(row2.id(), cached_row2.id());
   3272 
   3273   // Verify that lookups will actually return both search terms; and also check
   3274   // at the low level that the rows are there.
   3275   EXPECT_EQ(1u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term1));
   3276   EXPECT_EQ(1u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term2));
   3277   EXPECT_TRUE(mem_backend_->db()->GetKeywordSearchTermRow(row1.id(), NULL));
   3278   EXPECT_TRUE(mem_backend_->db()->GetKeywordSearchTermRow(row2.id(), NULL));
   3279 }
   3280 
   3281 TEST_F(InMemoryHistoryBackendTest, DeleteKeywordSearchTerms) {
   3282   URLRow row1(CreateTestTypedURL());
   3283   URLRow row2(CreateTestNonTypedURL());
   3284   base::string16 term1(base::UTF8ToUTF16(kTestSearchTerm1));
   3285   base::string16 term2(base::UTF8ToUTF16(kTestSearchTerm2));
   3286   PopulateTestURLsAndSearchTerms(&row1, &row2, term1, term2);
   3287 
   3288   // Delete both search terms. This should be reflected in the in-memory DB.
   3289   backend_->DeleteKeywordSearchTermForURL(row1.url());
   3290   backend_->DeleteKeywordSearchTermForURL(row2.url());
   3291 
   3292   // The typed URL should remain intact.
   3293   // Note: we do not need to guarantee anything about the non-typed URL.
   3294   URLRow cached_row1;
   3295   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3296   EXPECT_EQ(row1.id(), cached_row1.id());
   3297 
   3298   // Verify that the search terms are no longer returned as results, and also
   3299   // check at the low level that they are gone for good.
   3300   EXPECT_EQ(0u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term1));
   3301   EXPECT_EQ(0u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term2));
   3302   EXPECT_FALSE(mem_backend_->db()->GetKeywordSearchTermRow(row1.id(), NULL));
   3303   EXPECT_FALSE(mem_backend_->db()->GetKeywordSearchTermRow(row2.id(), NULL));
   3304 }
   3305 
   3306 TEST_F(InMemoryHistoryBackendTest, DeleteAllSearchTermsForKeyword) {
   3307   URLRow row1(CreateTestTypedURL());
   3308   URLRow row2(CreateTestNonTypedURL());
   3309   base::string16 term1(base::UTF8ToUTF16(kTestSearchTerm1));
   3310   base::string16 term2(base::UTF8ToUTF16(kTestSearchTerm2));
   3311   PopulateTestURLsAndSearchTerms(&row1, &row2, term1, term2);
   3312 
   3313   // Removing a keyword should cause all corresponding search terms to be
   3314   // deleted from the in-memory database (and also the main database).
   3315   TemplateURLID id = kTestKeywordId;
   3316   mem_backend_->Observe(chrome::NOTIFICATION_TEMPLATE_URL_REMOVED,
   3317                         content::Source<HistoryBackendTestBase>(NULL),
   3318                         content::Details<TemplateURLID>(&id));
   3319 
   3320   // The typed URL should remain intact.
   3321   // Note: we do not need to guarantee anything about the non-typed URL.
   3322   URLRow cached_row1;
   3323   EXPECT_NE(0, mem_backend_->db()->GetRowForURL(row1.url(), &cached_row1));
   3324   EXPECT_EQ(row1.id(), cached_row1.id());
   3325 
   3326   // Verify that the search terms are no longer returned as results, and also
   3327   // check at the low level that they are gone for good.
   3328   EXPECT_EQ(0u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term1));
   3329   EXPECT_EQ(0u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term2));
   3330   EXPECT_FALSE(mem_backend_->db()->GetKeywordSearchTermRow(row1.id(), NULL));
   3331   EXPECT_FALSE(mem_backend_->db()->GetKeywordSearchTermRow(row2.id(), NULL));
   3332 }
   3333 
   3334 TEST_F(InMemoryHistoryBackendTest, OnURLsDeletedWithSearchTerms) {
   3335   URLRow row1(CreateTestTypedURL());
   3336   URLRow row2(CreateTestNonTypedURL());
   3337   base::string16 term1(base::UTF8ToUTF16(kTestSearchTerm1));
   3338   base::string16 term2(base::UTF8ToUTF16(kTestSearchTerm2));
   3339   PopulateTestURLsAndSearchTerms(&row1, &row2, term1, term2);
   3340 
   3341   // Notify the in-memory database that the second typed URL has been deleted.
   3342   SimulateNotification(chrome::NOTIFICATION_HISTORY_URLS_DELETED, &row2);
   3343 
   3344   // Verify that the second term is no longer returned as result, and also check
   3345   // at the low level that it is gone for good. The term corresponding to the
   3346   // first URLRow should not be affected.
   3347   EXPECT_EQ(1u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term1));
   3348   EXPECT_EQ(0u, GetNumberOfMatchingSearchTerms(kTestKeywordId, term2));
   3349   EXPECT_TRUE(mem_backend_->db()->GetKeywordSearchTermRow(row1.id(), NULL));
   3350   EXPECT_FALSE(mem_backend_->db()->GetKeywordSearchTermRow(row2.id(), NULL));
   3351 }
   3352 
   3353 }  // namespace history
   3354