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