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 <algorithm>
6#include <vector>
7
8#include "base/basictypes.h"
9#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/memory/ref_counted_memory.h"
13#include "base/path_service.h"
14#include "chrome/browser/history/history_database.h"
15#include "chrome/browser/history/history_unittest_base.h"
16#include "chrome/browser/history/thumbnail_database.h"
17#include "chrome/common/chrome_constants.h"
18#include "chrome/common/chrome_paths.h"
19#include "chrome/common/thumbnail_score.h"
20#include "chrome/test/base/testing_profile.h"
21#include "chrome/tools/profiles/thumbnail-inl.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "third_party/skia/include/core/SkBitmap.h"
24#include "ui/gfx/codec/jpeg_codec.h"
25#include "url/gurl.h"
26
27using base::Time;
28using base::TimeDelta;
29
30namespace history {
31
32namespace {
33
34// data we'll put into the thumbnail database
35static const unsigned char blob1[] =
36    "12346102356120394751634516591348710478123649165419234519234512349134";
37static const unsigned char blob2[] =
38    "goiwuegrqrcomizqyzkjalitbahxfjytrqvpqeroicxmnlkhlzunacxaneviawrtxcywhgef";
39static const unsigned char blob3[] =
40    "3716871354098370776510470746794707624107647054607467847164027";
41const double kBoringness = 0.25;
42const double kWorseBoringness = 0.50;
43const double kBetterBoringness = 0.10;
44const double kTotallyBoring = 1.0;
45
46const int64 kPage1 = 1234;
47
48const gfx::Size kSmallSize = gfx::Size(16, 16);
49const gfx::Size kLargeSize = gfx::Size(32, 32);
50
51}  // namespace
52
53class ThumbnailDatabaseTest : public testing::Test {
54 public:
55  ThumbnailDatabaseTest() {
56  }
57  virtual ~ThumbnailDatabaseTest() {
58  }
59
60 protected:
61  virtual void SetUp() {
62    // Get a temporary directory for the test DB files.
63    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
64
65    file_name_ = temp_dir_.path().AppendASCII("TestThumbnails.db");
66    new_file_name_ = temp_dir_.path().AppendASCII("TestFavicons.db");
67    history_db_name_ = temp_dir_.path().AppendASCII("TestHistory.db");
68    google_bitmap_.reset(
69        gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));
70  }
71
72  scoped_ptr<SkBitmap> google_bitmap_;
73
74  base::ScopedTempDir temp_dir_;
75  base::FilePath file_name_;
76  base::FilePath new_file_name_;
77  base::FilePath history_db_name_;
78};
79
80class IconMappingMigrationTest : public HistoryUnitTestBase {
81 public:
82  IconMappingMigrationTest() {
83  }
84  virtual ~IconMappingMigrationTest() {
85  }
86
87 protected:
88  virtual void SetUp() {
89    profile_.reset(new TestingProfile);
90
91    base::FilePath data_path;
92    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
93    data_path = data_path.AppendASCII("History");
94
95    history_db_name_ = profile_->GetPath().Append(chrome::kHistoryFilename);
96    // Set up history and thumbnails as they would be before migration.
97    ASSERT_NO_FATAL_FAILURE(
98        ExecuteSQLScript(data_path.AppendASCII("history.20.sql"),
99                         history_db_name_));
100    thumbnail_db_name_ =
101        profile_->GetPath().Append(chrome::kThumbnailsFilename);
102    ASSERT_NO_FATAL_FAILURE(
103        ExecuteSQLScript(data_path.AppendASCII("thumbnails.3.sql"),
104                         thumbnail_db_name_));
105  }
106
107 protected:
108  base::FilePath history_db_name_;
109  base::FilePath thumbnail_db_name_;
110
111 private:
112  scoped_ptr<TestingProfile> profile_;
113};
114
115TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) {
116  ThumbnailDatabase db;
117  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
118  db.BeginTransaction();
119
120  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
121  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
122
123  GURL url("http://google.com");
124  chrome::FaviconID icon_id = db.AddFavicon(url, chrome::FAVICON);
125  base::Time time = base::Time::Now();
126  FaviconBitmapID bitmap1_id = db.AddFaviconBitmap(icon_id, favicon, time,
127                                                   kSmallSize);
128  FaviconBitmapID bitmap2_id = db.AddFaviconBitmap(icon_id, favicon, time,
129                                                   kLargeSize);
130  EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_));
131  EXPECT_TRUE(db.IsLatestVersion());
132
133  GURL url_out;
134  chrome::IconType icon_type_out;
135  EXPECT_TRUE(db.GetFaviconHeader(icon_id, &url_out, &icon_type_out));
136
137  EXPECT_EQ(url, url_out);
138  EXPECT_EQ(chrome::FAVICON, icon_type_out);
139
140  std::vector<FaviconBitmap> favicon_bitmaps_out;
141  EXPECT_TRUE(db.GetFaviconBitmaps(icon_id, &favicon_bitmaps_out));
142  EXPECT_EQ(2u, favicon_bitmaps_out.size());
143
144  FaviconBitmap favicon_bitmap1 = favicon_bitmaps_out[0];
145  FaviconBitmap favicon_bitmap2 = favicon_bitmaps_out[1];
146
147  // Favicon bitmaps do not need to be in particular order.
148  if (favicon_bitmap1.bitmap_id == bitmap2_id) {
149    FaviconBitmap tmp_favicon_bitmap = favicon_bitmap1;
150    favicon_bitmap1 = favicon_bitmap2;
151    favicon_bitmap2 = tmp_favicon_bitmap;
152  }
153
154  EXPECT_EQ(bitmap1_id, favicon_bitmap1.bitmap_id);
155  EXPECT_EQ(icon_id, favicon_bitmap1.icon_id);
156  EXPECT_EQ(time.ToInternalValue(),
157            favicon_bitmap1.last_updated.ToInternalValue());
158  EXPECT_EQ(data.size(), favicon_bitmap1.bitmap_data->size());
159  EXPECT_TRUE(std::equal(data.begin(),
160                         data.end(),
161                         favicon_bitmap1.bitmap_data->front()));
162  EXPECT_EQ(kSmallSize, favicon_bitmap1.pixel_size);
163
164  EXPECT_EQ(bitmap2_id, favicon_bitmap2.bitmap_id);
165  EXPECT_EQ(icon_id, favicon_bitmap2.icon_id);
166  EXPECT_EQ(time.ToInternalValue(),
167            favicon_bitmap2.last_updated.ToInternalValue());
168  EXPECT_EQ(data.size(), favicon_bitmap2.bitmap_data->size());
169  EXPECT_TRUE(std::equal(data.begin(),
170                         data.end(),
171                         favicon_bitmap2.bitmap_data->front()));
172  EXPECT_EQ(kLargeSize, favicon_bitmap2.pixel_size);
173}
174
175TEST_F(ThumbnailDatabaseTest, AddIconMapping) {
176  ThumbnailDatabase db;
177  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
178  db.BeginTransaction();
179
180  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
181  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
182
183  GURL url("http://google.com");
184  base::Time time = base::Time::Now();
185  chrome::FaviconID id = db.AddFavicon(url,
186                                       chrome::TOUCH_ICON,
187                                       favicon,
188                                       time,
189                                       gfx::Size());
190  EXPECT_NE(0, id);
191
192  EXPECT_NE(0, db.AddIconMapping(url, id));
193  std::vector<IconMapping> icon_mappings;
194  EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mappings));
195  EXPECT_EQ(1u, icon_mappings.size());
196  EXPECT_EQ(url, icon_mappings.front().page_url);
197  EXPECT_EQ(id, icon_mappings.front().icon_id);
198}
199
200TEST_F(ThumbnailDatabaseTest, UpdateIconMapping) {
201  ThumbnailDatabase db;
202  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
203  db.BeginTransaction();
204
205  GURL url("http://google.com");
206  chrome::FaviconID id =
207      db.AddFavicon(url, chrome::TOUCH_ICON);
208
209  EXPECT_LT(0, db.AddIconMapping(url, id));
210  std::vector<IconMapping> icon_mapping;
211  EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
212  ASSERT_EQ(1u, icon_mapping.size());
213  EXPECT_EQ(url, icon_mapping.front().page_url);
214  EXPECT_EQ(id, icon_mapping.front().icon_id);
215
216  GURL url1("http://www.google.com/");
217  chrome::FaviconID new_id =
218      db.AddFavicon(url1, chrome::TOUCH_ICON);
219  EXPECT_TRUE(db.UpdateIconMapping(icon_mapping.front().mapping_id, new_id));
220
221  icon_mapping.clear();
222  EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
223  ASSERT_EQ(1u, icon_mapping.size());
224  EXPECT_EQ(url, icon_mapping.front().page_url);
225  EXPECT_EQ(new_id, icon_mapping.front().icon_id);
226  EXPECT_NE(id, icon_mapping.front().icon_id);
227}
228
229TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) {
230  ThumbnailDatabase db;
231  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
232  db.BeginTransaction();
233
234  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
235  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
236
237  GURL url("http://google.com");
238  chrome::FaviconID id =
239      db.AddFavicon(url, chrome::TOUCH_ICON);
240  base::Time time = base::Time::Now();
241  db.AddFaviconBitmap(id, favicon, time, gfx::Size());
242  EXPECT_LT(0, db.AddIconMapping(url, id));
243
244  chrome::FaviconID id2 =
245      db.AddFavicon(url, chrome::FAVICON);
246  EXPECT_LT(0, db.AddIconMapping(url, id2));
247  ASSERT_NE(id, id2);
248
249  std::vector<IconMapping> icon_mapping;
250  EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
251  ASSERT_EQ(2u, icon_mapping.size());
252  EXPECT_EQ(icon_mapping.front().icon_type, chrome::TOUCH_ICON);
253  EXPECT_TRUE(db.GetIconMappingsForPageURL(url, chrome::FAVICON, NULL));
254
255  db.DeleteIconMappings(url);
256
257  EXPECT_FALSE(db.GetIconMappingsForPageURL(url, NULL));
258  EXPECT_FALSE(db.GetIconMappingsForPageURL(url, chrome::FAVICON, NULL));
259}
260
261TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURL) {
262  ThumbnailDatabase db;
263  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
264  db.BeginTransaction();
265
266  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
267  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
268
269  GURL url("http://google.com");
270
271  chrome::FaviconID id1 = db.AddFavicon(url, chrome::TOUCH_ICON);
272  base::Time time = base::Time::Now();
273  db.AddFaviconBitmap(id1, favicon, time, kSmallSize);
274  db.AddFaviconBitmap(id1, favicon, time, kLargeSize);
275  EXPECT_LT(0, db.AddIconMapping(url, id1));
276
277  chrome::FaviconID id2 = db.AddFavicon(url, chrome::FAVICON);
278  EXPECT_NE(id1, id2);
279  db.AddFaviconBitmap(id2, favicon, time, kSmallSize);
280  EXPECT_LT(0, db.AddIconMapping(url, id2));
281
282  std::vector<IconMapping> icon_mappings;
283  EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mappings));
284  ASSERT_EQ(2u, icon_mappings.size());
285  EXPECT_EQ(id1, icon_mappings[0].icon_id);
286  EXPECT_EQ(id2, icon_mappings[1].icon_id);
287}
288
289// Test upgrading database to version 4.
290TEST_F(ThumbnailDatabaseTest, UpgradeToVersion4) {
291  ThumbnailDatabase db;
292  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
293  db.BeginTransaction();
294
295  const char* name = "favicons";
296  std::string sql;
297  sql.append("DROP TABLE IF EXISTS ");
298  sql.append(name);
299  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
300
301  sql.resize(0);
302  sql.append("CREATE TABLE ");
303  sql.append(name);
304  sql.append("("
305             "id INTEGER PRIMARY KEY,"
306             "url LONGVARCHAR NOT NULL,"
307             "last_updated INTEGER DEFAULT 0,"
308             "image_data BLOB)");
309  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
310
311  EXPECT_TRUE(db.UpgradeToVersion4());
312
313  GURL url("http://google.com");
314
315  sql::Statement statement;
316  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
317      "INSERT INTO favicons (url, icon_type) VALUES (?, ?)"));
318  statement.BindString(0, URLDatabase::GURLToDatabaseURL(url));
319  statement.BindInt(1, chrome::TOUCH_ICON);
320  EXPECT_TRUE(statement.Run());
321
322  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
323      "SELECT icon_type FROM favicons"));
324  EXPECT_TRUE(statement.Step());
325
326  EXPECT_EQ(chrome::TOUCH_ICON,
327            static_cast<chrome::IconType>(statement.ColumnInt(0)));
328}
329
330// Test upgrading database to version 5.
331TEST_F(ThumbnailDatabaseTest, UpgradeToVersion5) {
332  ThumbnailDatabase db;
333  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
334  db.BeginTransaction();
335
336  const char* name = "favicons";
337  std::string sql;
338  sql.append("DROP TABLE IF EXISTS ");
339  sql.append(name);
340  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
341
342  sql.resize(0);
343  sql.append("CREATE TABLE ");
344  sql.append(name);
345  sql.append("("
346             "id INTEGER PRIMARY KEY,"
347             "url LONGVARCHAR NOT NULL,"
348             "last_updated INTEGER DEFAULT 0,"
349             "image_data BLOB,"
350             "icon_type INTEGER DEFAULT 1)");
351  ASSERT_TRUE(db.db_.Execute(sql.c_str()));
352
353  ASSERT_TRUE(db.UpgradeToVersion5());
354
355  sql = "SELECT sizes FROM favicons";
356  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
357}
358
359// Test upgrading database to version 6.
360TEST_F(ThumbnailDatabaseTest, UpgradeToVersion6) {
361  ThumbnailDatabase db;
362  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
363  db.BeginTransaction();
364
365  const char* name = "favicons";
366  std::string sql;
367  sql.append("DROP TABLE IF EXISTS ");
368  sql.append(name);
369  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
370
371  sql.clear();
372  sql.append("CREATE TABLE ");
373  sql.append(name);
374  sql.append("("
375             "id INTEGER PRIMARY KEY,"
376             "url LONGVARCHAR NOT NULL,"
377             "last_updated INTEGER DEFAULT 0,"
378             "image_data BLOB,"
379             "icon_type INTEGER DEFAULT 1,"
380             "sizes LONGVARCHAR)");
381  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
382
383  int favicon_id = 1;
384  GURL url("http://google.com");
385  int64 last_updated = Time::Now().ToInternalValue();
386  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
387  scoped_refptr<base::RefCountedBytes> bitmap_data(
388      new base::RefCountedBytes(data));
389
390  sql::Statement statement;
391  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
392      "INSERT INTO favicons (id, url, last_updated, image_data, icon_type, "
393      "sizes) VALUES (?, ?, ?, ?, ?, ?)"));
394  statement.BindInt(0, favicon_id);
395  statement.BindString(1, URLDatabase::GURLToDatabaseURL(url));
396  statement.BindInt64(2, last_updated);
397  statement.BindBlob(3, bitmap_data->front(),
398                     static_cast<int>(bitmap_data->size()));
399  statement.BindInt(4, chrome::TOUCH_ICON);
400  statement.BindCString(5, "Data which happened to be there");
401  EXPECT_TRUE(statement.Run());
402
403  EXPECT_TRUE(db.UpgradeToVersion6());
404
405  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
406      "SELECT id, url, icon_type, sizes FROM favicons"));
407  EXPECT_TRUE(statement.Step());
408  EXPECT_EQ(favicon_id, statement.ColumnInt(0));
409  EXPECT_EQ(url, GURL(statement.ColumnString(1)));
410  EXPECT_EQ(chrome::TOUCH_ICON, statement.ColumnInt(2));
411  // Any previous data in sizes should be cleared.
412  EXPECT_EQ(std::string(), statement.ColumnString(3));
413
414  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
415      "SELECT icon_id, last_updated, image_data, width, height "
416      "FROM favicon_bitmaps"));
417  EXPECT_TRUE(statement.Step());
418  EXPECT_EQ(favicon_id, statement.ColumnInt(0));
419  EXPECT_EQ(last_updated, statement.ColumnInt64(1));
420  EXPECT_EQ(static_cast<int>(bitmap_data->size()),
421            statement.ColumnByteLength(2));
422  EXPECT_EQ(0, statement.ColumnInt(3));
423  EXPECT_EQ(0, statement.ColumnInt(4));
424}
425
426// Test upgrading database to version 7.
427TEST_F(ThumbnailDatabaseTest, UpgradeToVersion7) {
428  ThumbnailDatabase db;
429  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
430  db.BeginTransaction();
431
432  const char* name = "favicons";
433  std::string sql;
434  sql.append("DROP TABLE IF EXISTS ");
435  sql.append(name);
436  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
437
438  sql.clear();
439  sql.append("CREATE TABLE ");
440  sql.append(name);
441  sql.append("("
442             "id INTEGER PRIMARY KEY,"
443             "url LONGVARCHAR NOT NULL,"
444             "icon_type INTEGER DEFAULT 1,"
445             "sizes LONGVARCHAR)");
446  EXPECT_TRUE(db.db_.Execute(sql.c_str()));
447
448  int favicon_id = 1;
449  GURL url("http://google.com");
450
451  sql::Statement statement;
452  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
453      "INSERT INTO favicons (id, url, icon_type, sizes) "
454      "VALUES (?, ?, ?, ?)"));
455  statement.BindInt(0, favicon_id);
456  statement.BindString(1, URLDatabase::GURLToDatabaseURL(url));
457  statement.BindInt(2, chrome::TOUCH_ICON);
458  statement.BindCString(3, "Data which happened to be there");
459  EXPECT_TRUE(statement.Run());
460
461  EXPECT_TRUE(db.UpgradeToVersion7());
462
463  EXPECT_FALSE(db.db_.DoesColumnExist("favicons", "sizes"));
464
465  statement.Assign(db.db_.GetCachedStatement(SQL_FROM_HERE,
466      "SELECT id, url, icon_type FROM favicons"));
467  EXPECT_TRUE(statement.Step());
468  EXPECT_EQ(favicon_id, statement.ColumnInt(0));
469  EXPECT_EQ(url, GURL(statement.ColumnString(1)));
470  EXPECT_EQ(chrome::TOUCH_ICON, statement.ColumnInt(2));
471}
472
473// Test that only data moved to a temporary table is left in the main table
474// once the temporary table is committed.
475TEST_F(ThumbnailDatabaseTest, TemporaryTables) {
476  ThumbnailDatabase db;
477
478  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
479
480  db.BeginTransaction();
481
482  EXPECT_TRUE(db.InitTemporaryTables());
483
484  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
485  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
486
487  GURL unkept_url("http://google.com/favicon2.ico");
488  chrome::FaviconID unkept_id = db.AddFavicon(unkept_url, chrome::FAVICON);
489  db.AddFaviconBitmap(unkept_id, favicon, base::Time::Now(), kSmallSize);
490
491  GURL kept_url("http://google.com/favicon.ico");
492  chrome::FaviconID kept_id = db.AddFavicon(kept_url, chrome::FAVICON);
493  db.AddFaviconBitmap(kept_id, favicon, base::Time::Now(), kLargeSize);
494
495  GURL page_url("http://google.com");
496  db.AddIconMapping(page_url, unkept_id);
497  db.AddIconMapping(page_url, kept_id);
498
499  chrome::FaviconID new_favicon_id =
500      db.CopyFaviconAndFaviconBitmapsToTemporaryTables(kept_id);
501  EXPECT_NE(0, new_favicon_id);
502  EXPECT_TRUE(db.AddToTemporaryIconMappingTable(page_url, new_favicon_id));
503
504  EXPECT_TRUE(db.CommitTemporaryTables());
505
506  // Only copied data should be left.
507  std::vector<IconMapping> icon_mappings;
508  EXPECT_TRUE(
509      db.GetIconMappingsForPageURL(page_url, chrome::FAVICON, &icon_mappings));
510  EXPECT_EQ(1u, icon_mappings.size());
511  EXPECT_EQ(new_favicon_id, icon_mappings[0].icon_id);
512  EXPECT_EQ(page_url, icon_mappings[0].page_url);
513
514  std::vector<FaviconBitmap> favicon_bitmaps;
515  EXPECT_TRUE(db.GetFaviconBitmaps(icon_mappings[0].icon_id, &favicon_bitmaps));
516  EXPECT_EQ(1u, favicon_bitmaps.size());
517  EXPECT_EQ(kLargeSize, favicon_bitmaps[0].pixel_size);
518
519  EXPECT_FALSE(db.GetFaviconIDForFaviconURL(unkept_url, false, NULL));
520}
521
522// Tests that deleting a favicon deletes the favicon row and favicon bitmap
523// rows from the database.
524TEST_F(ThumbnailDatabaseTest, DeleteFavicon) {
525  ThumbnailDatabase db;
526  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
527  db.BeginTransaction();
528
529  std::vector<unsigned char> data1(blob1, blob1 + sizeof(blob1));
530  scoped_refptr<base::RefCountedBytes> favicon1(
531      new base::RefCountedBytes(data1));
532  std::vector<unsigned char> data2(blob2, blob2 + sizeof(blob2));
533  scoped_refptr<base::RefCountedBytes> favicon2(
534      new base::RefCountedBytes(data2));
535
536  GURL url("http://google.com");
537  chrome::FaviconID id = db.AddFavicon(url, chrome::FAVICON);
538  base::Time last_updated = base::Time::Now();
539  db.AddFaviconBitmap(id, favicon1, last_updated, kSmallSize);
540  db.AddFaviconBitmap(id, favicon2, last_updated, kLargeSize);
541
542  EXPECT_TRUE(db.GetFaviconBitmaps(id, NULL));
543
544  EXPECT_TRUE(db.DeleteFavicon(id));
545  EXPECT_FALSE(db.GetFaviconBitmaps(id, NULL));
546}
547
548TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURLForReturnOrder) {
549  ThumbnailDatabase db;
550  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
551  db.BeginTransaction();
552
553  // Add a favicon
554  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
555  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
556
557  GURL page_url("http://google.com");
558  GURL icon_url("http://google.com/favicon.ico");
559  base::Time time = base::Time::Now();
560
561  chrome::FaviconID id = db.AddFavicon(icon_url,
562                                       chrome::FAVICON,
563                                       favicon,
564                                       time,
565                                       gfx::Size());
566  EXPECT_NE(0, db.AddIconMapping(page_url, id));
567  std::vector<IconMapping> icon_mappings;
568  EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url, &icon_mappings));
569
570  EXPECT_EQ(page_url, icon_mappings.front().page_url);
571  EXPECT_EQ(id, icon_mappings.front().icon_id);
572  EXPECT_EQ(chrome::FAVICON, icon_mappings.front().icon_type);
573  EXPECT_EQ(icon_url, icon_mappings.front().icon_url);
574
575  // Add a touch icon
576  std::vector<unsigned char> data2(blob2, blob2 + sizeof(blob2));
577  scoped_refptr<base::RefCountedBytes> favicon2 =
578      new base::RefCountedBytes(data);
579
580  chrome::FaviconID id2 = db.AddFavicon(icon_url,
581                                        chrome::TOUCH_ICON,
582                                        favicon2,
583                                        time,
584                                        gfx::Size());
585  EXPECT_NE(0, db.AddIconMapping(page_url, id2));
586
587  icon_mappings.clear();
588  EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url, &icon_mappings));
589
590  EXPECT_EQ(page_url, icon_mappings.front().page_url);
591  EXPECT_EQ(id2, icon_mappings.front().icon_id);
592  EXPECT_EQ(chrome::TOUCH_ICON, icon_mappings.front().icon_type);
593  EXPECT_EQ(icon_url, icon_mappings.front().icon_url);
594
595  // Add a touch precomposed icon
596  scoped_refptr<base::RefCountedBytes> favicon3 =
597      new base::RefCountedBytes(data2);
598
599  chrome::FaviconID id3 = db.AddFavicon(icon_url,
600                                        chrome::TOUCH_PRECOMPOSED_ICON,
601                                        favicon3,
602                                        time,
603                                        gfx::Size());
604  EXPECT_NE(0, db.AddIconMapping(page_url, id3));
605
606  icon_mappings.clear();
607  EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url, &icon_mappings));
608
609  EXPECT_EQ(page_url, icon_mappings.front().page_url);
610  EXPECT_EQ(id3, icon_mappings.front().icon_id);
611  EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON, icon_mappings.front().icon_type);
612  EXPECT_EQ(icon_url, icon_mappings.front().icon_url);
613}
614
615// Test result of GetIconMappingsForPageURL when an icon type is passed in.
616TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURLWithIconType) {
617  ThumbnailDatabase db;
618  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
619  db.BeginTransaction();
620
621  GURL url("http://google.com");
622  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
623  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
624  base::Time time = base::Time::Now();
625
626  chrome::FaviconID id1 = db.AddFavicon(url,
627                                        chrome::FAVICON,
628                                        favicon,
629                                        time,
630                                        gfx::Size());
631  EXPECT_NE(0, db.AddIconMapping(url, id1));
632
633  chrome::FaviconID id2 = db.AddFavicon(url,
634                                        chrome::TOUCH_ICON,
635                                        favicon,
636                                        time,
637                                        gfx::Size());
638  EXPECT_NE(0, db.AddIconMapping(url, id2));
639
640  chrome::FaviconID id3 = db.AddFavicon(url,
641                                        chrome::TOUCH_ICON,
642                                        favicon,
643                                        time,
644                                        gfx::Size());
645  EXPECT_NE(0, db.AddIconMapping(url, id3));
646
647  // Only the mappings for favicons of type TOUCH_ICON should be returned as
648  // TOUCH_ICON is a larger icon type than FAVICON.
649  std::vector<IconMapping> icon_mappings;
650  EXPECT_TRUE(db.GetIconMappingsForPageURL(
651      url,
652      chrome::FAVICON | chrome::TOUCH_ICON | chrome::TOUCH_PRECOMPOSED_ICON,
653      &icon_mappings));
654
655  EXPECT_EQ(2u, icon_mappings.size());
656  if (id2 == icon_mappings[0].icon_id) {
657    EXPECT_EQ(id3, icon_mappings[1].icon_id);
658  } else {
659    EXPECT_EQ(id3, icon_mappings[0].icon_id);
660    EXPECT_EQ(id2, icon_mappings[1].icon_id);
661  }
662
663  icon_mappings.clear();
664  EXPECT_TRUE(
665      db.GetIconMappingsForPageURL(url, chrome::TOUCH_ICON, &icon_mappings));
666  if (id2 == icon_mappings[0].icon_id) {
667    EXPECT_EQ(id3, icon_mappings[1].icon_id);
668  } else {
669    EXPECT_EQ(id3, icon_mappings[0].icon_id);
670    EXPECT_EQ(id2, icon_mappings[1].icon_id);
671  }
672
673  icon_mappings.clear();
674  EXPECT_TRUE(
675      db.GetIconMappingsForPageURL(url, chrome::FAVICON, &icon_mappings));
676  EXPECT_EQ(1u, icon_mappings.size());
677  EXPECT_EQ(id1, icon_mappings[0].icon_id);
678}
679
680TEST_F(ThumbnailDatabaseTest, HasMappingFor) {
681  ThumbnailDatabase db;
682  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
683  db.BeginTransaction();
684
685  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
686  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
687
688  // Add a favicon which will have icon_mappings
689  base::Time time = base::Time::Now();
690  chrome::FaviconID id1 = db.AddFavicon(GURL("http://google.com"),
691                                        chrome::FAVICON,
692                                        favicon,
693                                        time,
694                                        gfx::Size());
695  EXPECT_NE(id1, 0);
696
697  // Add another type of favicon
698  time = base::Time::Now();
699  chrome::FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"),
700                                        chrome::TOUCH_ICON,
701                                        favicon,
702                                        time,
703                                        gfx::Size());
704  EXPECT_NE(id2, 0);
705
706  // Add 3rd favicon
707  time = base::Time::Now();
708  chrome::FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"),
709                                        chrome::TOUCH_ICON,
710                                        favicon,
711                                        time,
712                                        gfx::Size());
713  EXPECT_NE(id3, 0);
714
715  // Add 2 icon mapping
716  GURL page_url("http://www.google.com");
717  EXPECT_TRUE(db.AddIconMapping(page_url, id1));
718  EXPECT_TRUE(db.AddIconMapping(page_url, id2));
719
720  EXPECT_TRUE(db.HasMappingFor(id1));
721  EXPECT_TRUE(db.HasMappingFor(id2));
722  EXPECT_FALSE(db.HasMappingFor(id3));
723
724  // Remove all mappings
725  db.DeleteIconMappings(page_url);
726  EXPECT_FALSE(db.HasMappingFor(id1));
727  EXPECT_FALSE(db.HasMappingFor(id2));
728  EXPECT_FALSE(db.HasMappingFor(id3));
729}
730
731TEST_F(ThumbnailDatabaseTest, CloneIconMappings) {
732  ThumbnailDatabase db;
733  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
734  db.BeginTransaction();
735
736  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
737  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
738
739  // Add a favicon which will have icon_mappings
740  chrome::FaviconID id1 = db.AddFavicon(
741      GURL("http://google.com"), chrome::FAVICON);
742  EXPECT_NE(0, id1);
743  base::Time time = base::Time::Now();
744  db.AddFaviconBitmap(id1, favicon, time, gfx::Size());
745
746  // Add another type of favicon
747  chrome::FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"),
748                                        chrome::TOUCH_ICON);
749  EXPECT_NE(0, id2);
750  time = base::Time::Now();
751  db.AddFaviconBitmap(id2, favicon, time, gfx::Size());
752
753  // Add 3rd favicon
754  chrome::FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"),
755                                        chrome::TOUCH_ICON);
756  EXPECT_NE(0, id3);
757  time = base::Time::Now();
758  db.AddFaviconBitmap(id3, favicon, time, gfx::Size());
759
760  GURL page1_url("http://page1.com");
761  EXPECT_TRUE(db.AddIconMapping(page1_url, id1));
762  EXPECT_TRUE(db.AddIconMapping(page1_url, id2));
763
764  GURL page2_url("http://page2.com");
765  EXPECT_TRUE(db.AddIconMapping(page2_url, id3));
766
767  // Test we do nothing with existing mappings.
768  std::vector<IconMapping> icon_mapping;
769  EXPECT_TRUE(db.GetIconMappingsForPageURL(page2_url, &icon_mapping));
770  ASSERT_EQ(1U, icon_mapping.size());
771
772  EXPECT_TRUE(db.CloneIconMappings(page1_url, page2_url));
773
774  icon_mapping.clear();
775  EXPECT_TRUE(db.GetIconMappingsForPageURL(page2_url, &icon_mapping));
776  ASSERT_EQ(1U, icon_mapping.size());
777  EXPECT_EQ(page2_url, icon_mapping[0].page_url);
778  EXPECT_EQ(id3, icon_mapping[0].icon_id);
779
780  // Test we clone if the new page has no mappings.
781  GURL page3_url("http://page3.com");
782  EXPECT_TRUE(db.CloneIconMappings(page1_url, page3_url));
783
784  icon_mapping.clear();
785  EXPECT_TRUE(db.GetIconMappingsForPageURL(page3_url, &icon_mapping));
786
787  ASSERT_EQ(2U, icon_mapping.size());
788  if (icon_mapping[0].icon_id == id2)
789    std::swap(icon_mapping[0], icon_mapping[1]);
790  EXPECT_EQ(page3_url, icon_mapping[0].page_url);
791  EXPECT_EQ(id1, icon_mapping[0].icon_id);
792  EXPECT_EQ(page3_url, icon_mapping[1].page_url);
793  EXPECT_EQ(id2, icon_mapping[1].icon_id);
794}
795
796TEST_F(IconMappingMigrationTest, TestIconMappingMigration) {
797  HistoryDatabase history_db;
798  ASSERT_TRUE(history_db.db_.Open(history_db_name_));
799  history_db.BeginTransaction();
800
801  const GURL icon1 = GURL("http://www.google.com/favicon.ico");
802  const GURL icon2 = GURL("http://www.yahoo.com/favicon.ico");
803
804  ThumbnailDatabase db;
805  ASSERT_EQ(sql::INIT_OK, db.Init(thumbnail_db_name_, NULL, &history_db));
806  db.BeginTransaction();
807
808  // Migration should be done.
809  // Test one icon_mapping.
810  GURL page_url1 = GURL("http://google.com/");
811  std::vector<IconMapping> icon_mappings;
812  EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url1, &icon_mappings));
813  ASSERT_EQ(1u, icon_mappings.size());
814  EXPECT_EQ(chrome::FAVICON, icon_mappings[0].icon_type);
815  EXPECT_EQ(page_url1, icon_mappings[0].page_url);
816  EXPECT_EQ(1, icon_mappings[0].icon_id);
817  EXPECT_EQ(icon1, icon_mappings[0].icon_url);
818
819  // Test a page which has the same icon.
820  GURL page_url3 = GURL("http://www.google.com/");
821  icon_mappings.clear();
822  EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url3, &icon_mappings));
823  ASSERT_EQ(1u, icon_mappings.size());
824  EXPECT_EQ(chrome::FAVICON, icon_mappings[0].icon_type);
825  EXPECT_EQ(page_url3, icon_mappings[0].page_url);
826  EXPECT_EQ(1, icon_mappings[0].icon_id);
827  EXPECT_EQ(icon1, icon_mappings[0].icon_url);
828
829  // Test a icon_mapping with different IconID.
830  GURL page_url2 = GURL("http://yahoo.com/");
831  icon_mappings.clear();
832  EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url2, &icon_mappings));
833  ASSERT_EQ(1u, icon_mappings.size());
834  EXPECT_EQ(chrome::FAVICON, icon_mappings[0].icon_type);
835  EXPECT_EQ(page_url2, icon_mappings[0].page_url);
836  EXPECT_EQ(2, icon_mappings[0].icon_id);
837  EXPECT_EQ(icon2, icon_mappings[0].icon_url);
838
839  // Test a page without icon
840  GURL page_url4 = GURL("http://www.google.com/blank.html");
841  EXPECT_FALSE(db.GetIconMappingsForPageURL(page_url4, NULL));
842}
843
844TEST_F(ThumbnailDatabaseTest, IconMappingEnumerator) {
845  ThumbnailDatabase db;
846  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
847  db.BeginTransaction();
848
849  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
850  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
851
852  GURL url("http://google.com");
853  GURL icon_url1("http://google.com/favicon.ico");
854  chrome::FaviconID touch_icon_id1 = db.AddFavicon(icon_url1,
855                                                   chrome::TOUCH_ICON,
856                                                   favicon,
857                                                   base::Time::Now(),
858                                                   gfx::Size());
859  ASSERT_NE(0, touch_icon_id1);
860  IconMappingID touch_mapping_id1 = db.AddIconMapping(url, touch_icon_id1);
861  ASSERT_NE(0, touch_mapping_id1);
862
863  chrome::FaviconID favicon_id1 = db.AddFavicon(icon_url1,
864                                                chrome::FAVICON,
865                                                favicon,
866                                                base::Time::Now(),
867                                                gfx::Size());
868  ASSERT_NE(0, favicon_id1);
869  IconMappingID favicon_mapping_id1 = db.AddIconMapping(url, favicon_id1);
870  ASSERT_NE(0, favicon_mapping_id1);
871
872  GURL url2("http://chromium.org");
873  GURL icon_url2("http://chromium.org/favicon.ico");
874  chrome::FaviconID favicon_id2 = db.AddFavicon(icon_url2,
875                                                chrome::FAVICON,
876                                                favicon,
877                                                base::Time::Now(),
878                                                gfx::Size());
879  ASSERT_NE(0, favicon_id2);
880  IconMappingID favicon_mapping_id2 = db.AddIconMapping(url2, favicon_id2);
881  ASSERT_NE(0, favicon_mapping_id2);
882
883  IconMapping icon_mapping;
884  ThumbnailDatabase::IconMappingEnumerator enumerator1;
885  ASSERT_TRUE(db.InitIconMappingEnumerator(chrome::FAVICON, &enumerator1));
886  // There are 2 favicon mappings.
887  bool has_favicon_mapping1 = false;
888  bool has_favicon_mapping2 = false;
889  int mapping_count = 0;
890  while (enumerator1.GetNextIconMapping(&icon_mapping)) {
891    mapping_count++;
892    if (favicon_mapping_id1 == icon_mapping.mapping_id) {
893      has_favicon_mapping1 = true;
894      EXPECT_EQ(url, icon_mapping.page_url);
895      EXPECT_EQ(favicon_id1, icon_mapping.icon_id);
896      EXPECT_EQ(icon_url1, icon_mapping.icon_url);
897      EXPECT_EQ(chrome::FAVICON, icon_mapping.icon_type);
898    } else if (favicon_mapping_id2 == icon_mapping.mapping_id) {
899      has_favicon_mapping2 = true;
900      EXPECT_EQ(url2, icon_mapping.page_url);
901      EXPECT_EQ(favicon_id2, icon_mapping.icon_id);
902      EXPECT_EQ(icon_url2, icon_mapping.icon_url);
903      EXPECT_EQ(chrome::FAVICON, icon_mapping.icon_type);
904    }
905  }
906  EXPECT_EQ(2, mapping_count);
907  EXPECT_TRUE(has_favicon_mapping1);
908  EXPECT_TRUE(has_favicon_mapping2);
909
910  ThumbnailDatabase::IconMappingEnumerator enumerator2;
911  ASSERT_TRUE(db.InitIconMappingEnumerator(chrome::TOUCH_ICON, &enumerator2));
912  ASSERT_TRUE(enumerator2.GetNextIconMapping(&icon_mapping));
913  EXPECT_EQ(touch_mapping_id1, icon_mapping.mapping_id);
914  EXPECT_EQ(url, icon_mapping.page_url);
915  EXPECT_EQ(touch_icon_id1, icon_mapping.icon_id);
916  EXPECT_EQ(icon_url1, icon_mapping.icon_url);
917  EXPECT_EQ(chrome::TOUCH_ICON, icon_mapping.icon_type);
918
919  EXPECT_FALSE(enumerator2.GetNextIconMapping(&icon_mapping));
920}
921
922}  // namespace history
923