| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/favicon/core/favicon_backend.h" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/containers/lru_cache.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/test/task_environment.h" |
| #include "components/favicon/core/favicon_backend_delegate.h" |
| #include "components/favicon/core/favicon_database.h" |
| #include "components/favicon/core/favicon_types.h" |
| #include "components/favicon_base/favicon_types.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/gfx/codec/png_codec.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "url/gurl.h" |
| |
| namespace favicon { |
| |
| namespace { |
| |
| using favicon::FaviconBitmap; |
| using favicon::FaviconBitmapType; |
| using favicon::IconMapping; |
| using favicon_base::IconType; |
| using favicon_base::IconTypeSet; |
| using ::testing::ElementsAre; |
| using ::testing::UnorderedElementsAre; |
| using RedirectCache = base::LRUCache<GURL, std::vector<GURL>>; |
| |
| const int kTinyEdgeSize = 10; |
| const int kSmallEdgeSize = 16; |
| const int kLargeEdgeSize = 32; |
| |
| const gfx::Size kTinySize = gfx::Size(kTinyEdgeSize, kTinyEdgeSize); |
| const gfx::Size kSmallSize = gfx::Size(kSmallEdgeSize, kSmallEdgeSize); |
| const gfx::Size kLargeSize = gfx::Size(kLargeEdgeSize, kLargeEdgeSize); |
| |
| } // namespace |
| |
| class FaviconBackendTest : public testing::Test, public FaviconBackendDelegate { |
| public: |
| FaviconBackendTest() = default; |
| ~FaviconBackendTest() override = default; |
| |
| // testing::Test |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| backend_ = FaviconBackend::Create( |
| temp_dir_.GetPath().AppendASCII("favicons"), this); |
| ASSERT_TRUE(backend_); |
| } |
| |
| void TearDown() override { backend_.reset(); } |
| |
| // FaviconBackendDelegate: |
| std::vector<GURL> GetCachedRecentRedirectsForPage( |
| const GURL& page_url) override { |
| auto iter = recent_redirects_.Get(page_url); |
| if (iter != recent_redirects_.end()) |
| return iter->second; |
| return {page_url}; |
| } |
| |
| protected: |
| void SetFavicons(const base::flat_set<GURL>& page_urls, |
| favicon_base::IconType icon_type, |
| const GURL& icon_url, |
| const std::vector<SkBitmap>& bitmaps) { |
| backend_->SetFavicons(page_urls, icon_type, icon_url, bitmaps, |
| FaviconBitmapType::ON_VISIT); |
| } |
| |
| // Returns a vector with the small and large edge sizes. |
| const std::vector<int> GetEdgeSizesSmallAndLarge() { |
| std::vector<int> sizes_small_and_large; |
| sizes_small_and_large.push_back(kSmallEdgeSize); |
| sizes_small_and_large.push_back(kLargeEdgeSize); |
| return sizes_small_and_large; |
| } |
| |
| // Returns the number of icon mappings of |icon_type| to |page_url|. |
| size_t NumIconMappingsForPageURL(const GURL& page_url, IconType icon_type) { |
| std::vector<IconMapping> icon_mappings; |
| backend_->db()->GetIconMappingsForPageURL(page_url, {icon_type}, |
| &icon_mappings); |
| return icon_mappings.size(); |
| } |
| |
| // Returns the icon mappings for |page_url|. |
| std::vector<IconMapping> GetIconMappingsForPageURL(const GURL& page_url) { |
| std::vector<IconMapping> icon_mappings; |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings); |
| return icon_mappings; |
| } |
| |
| // Returns the favicon bitmaps for |icon_id| sorted by pixel size in |
| // ascending order. Returns true if there is at least one favicon bitmap. |
| bool GetSortedFaviconBitmaps(favicon_base::FaviconID icon_id, |
| std::vector<FaviconBitmap>* favicon_bitmaps) { |
| if (!backend_->db()->GetFaviconBitmaps(icon_id, favicon_bitmaps)) |
| return false; |
| std::sort(favicon_bitmaps->begin(), favicon_bitmaps->end(), |
| [](const FaviconBitmap& a, const FaviconBitmap& b) { |
| return a.pixel_size.GetArea() < b.pixel_size.GetArea(); |
| }); |
| return true; |
| } |
| |
| // Returns true if there is exactly one favicon bitmap associated to |
| // |favicon_id|. If true, returns favicon bitmap in output parameter. |
| bool GetOnlyFaviconBitmap(const favicon_base::FaviconID icon_id, |
| FaviconBitmap* favicon_bitmap) { |
| std::vector<FaviconBitmap> favicon_bitmaps; |
| if (!backend_->db()->GetFaviconBitmaps(icon_id, &favicon_bitmaps)) |
| return false; |
| if (favicon_bitmaps.size() != 1) |
| return false; |
| *favicon_bitmap = favicon_bitmaps[0]; |
| return true; |
| } |
| |
| // Creates an |edge_size|x|edge_size| bitmap of |color|. |
| SkBitmap CreateBitmap(SkColor color, int edge_size) { |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(edge_size, edge_size); |
| bitmap.eraseColor(color); |
| return bitmap; |
| } |
| |
| // Returns true if |bitmap_data| is equal to |expected_data|. |
| bool BitmapDataEqual(char expected_data, |
| scoped_refptr<base::RefCountedMemory> bitmap_data) { |
| return bitmap_data.get() && |
| bitmap_data->size() == 1u && |
| *bitmap_data->front() == expected_data; |
| } |
| |
| // Returns true if |bitmap_data| is of |color|. |
| bool BitmapColorEqual(SkColor expected_color, |
| scoped_refptr<base::RefCountedMemory> bitmap_data) { |
| SkBitmap bitmap; |
| if (!gfx::PNGCodec::Decode(bitmap_data->front(), bitmap_data->size(), |
| &bitmap)) |
| return false; |
| return expected_color == bitmap.getColor(0, 0); |
| } |
| |
| base::test::TaskEnvironment task_environment_; |
| std::unique_ptr<FaviconBackend> backend_; |
| // Used in GetCachedRecentRedirectsForPage(). |
| RedirectCache recent_redirects_{8}; |
| |
| private: |
| base::ScopedTempDir temp_dir_; |
| }; |
| |
| // Test that SetFaviconMappingsForPageAndRedirects correctly updates icon |
| // mappings based on redirects, icon URLs and icon types. |
| TEST_F(FaviconBackendTest, SetFaviconMappingsForPageAndRedirects) { |
| // Init recent_redirects_ |
| const GURL url1("http://www.google.com"); |
| const GURL url2("http://www.google.com/m"); |
| recent_redirects_.Put(url1, std::vector<GURL>{url2, url1}); |
| |
| const GURL icon_url1("http://www.google.com/icon"); |
| const GURL icon_url2("http://www.google.com/icon2"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| // Add a favicon. |
| SetFavicons({url1}, IconType::kFavicon, icon_url1, bitmaps); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kFavicon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, IconType::kFavicon)); |
| |
| // Add one touch_icon |
| SetFavicons({url1}, IconType::kTouchIcon, icon_url1, bitmaps); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kTouchIcon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, IconType::kTouchIcon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kFavicon)); |
| |
| // Add one kTouchPrecomposedIcon |
| SetFavicons({url1}, IconType::kTouchPrecomposedIcon, icon_url1, bitmaps); |
| // The touch_icon was replaced. |
| EXPECT_EQ(0u, NumIconMappingsForPageURL(url1, IconType::kTouchIcon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kFavicon)); |
| EXPECT_EQ(1u, |
| NumIconMappingsForPageURL(url1, IconType::kTouchPrecomposedIcon)); |
| EXPECT_EQ(1u, |
| NumIconMappingsForPageURL(url2, IconType::kTouchPrecomposedIcon)); |
| |
| // Add a touch_icon. |
| SetFavicons({url1}, IconType::kTouchIcon, icon_url1, bitmaps); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kTouchIcon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kFavicon)); |
| // The kTouchPrecomposedIcon was replaced. |
| EXPECT_EQ(0u, |
| NumIconMappingsForPageURL(url1, IconType::kTouchPrecomposedIcon)); |
| |
| // Add a web manifest_icon. |
| SetFavicons({url1}, IconType::kWebManifestIcon, icon_url2, bitmaps); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kWebManifestIcon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kFavicon)); |
| // The kTouchIcon was replaced. |
| EXPECT_EQ(0u, NumIconMappingsForPageURL(url1, IconType::kTouchIcon)); |
| |
| // The kTouchPrecomposedIcon was replaced. |
| EXPECT_EQ(0u, |
| NumIconMappingsForPageURL(url1, IconType::kTouchPrecomposedIcon)); |
| |
| // Add a different favicon. |
| SetFavicons({url1}, IconType::kFavicon, icon_url2, bitmaps); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kWebManifestIcon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url1, IconType::kFavicon)); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url2, IconType::kFavicon)); |
| } |
| |
| TEST_F(FaviconBackendTest, |
| SetFaviconMappingsForPageAndRedirectsWithFragmentWithoutStripping) { |
| const GURL url("http://www.google.com#abc"); |
| const GURL url_without_ref("http://www.google.com"); |
| const GURL icon_url("http://www.google.com/icon"); |
| SetFavicons( |
| {url}, IconType::kFavicon, icon_url, |
| std::vector<SkBitmap>{CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)}); |
| |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(url, IconType::kFavicon)); |
| EXPECT_EQ(0u, NumIconMappingsForPageURL(url_without_ref, IconType::kFavicon)); |
| } |
| |
| // Test that there is no churn in icon mappings from calling |
| // SetFavicons() twice with the same |bitmaps| parameter. |
| TEST_F(FaviconBackendTest, SetFaviconMappingsForPageDuplicates) { |
| const GURL url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon"); |
| |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| SetFavicons({url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE(backend_->db()->GetIconMappingsForPageURL( |
| url, {IconType::kFavicon}, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| favicon::IconMappingID mapping_id = icon_mappings[0].mapping_id; |
| |
| SetFavicons({url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| icon_mappings.clear(); |
| EXPECT_TRUE(backend_->db()->GetIconMappingsForPageURL( |
| url, {IconType::kFavicon}, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| |
| // The same row in the icon_mapping table should be used for the mapping as |
| // before. |
| EXPECT_EQ(mapping_id, icon_mappings[0].mapping_id); |
| } |
| |
| // Test that calling SetFavicons() with FaviconBitmapData of different pixel |
| // sizes than the initially passed in FaviconBitmapData deletes the no longer |
| // used favicon bitmaps. |
| TEST_F(FaviconBackendTest, SetFaviconsDeleteBitmaps) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon"); |
| |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| // Test initial state. |
| std::vector<IconMapping> icon_mappings = GetIconMappingsForPageURL(page_url); |
| ASSERT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url, icon_mappings[0].icon_url); |
| EXPECT_EQ(IconType::kFavicon, icon_mappings[0].icon_type); |
| favicon_base::FaviconID favicon_id = icon_mappings[0].icon_id; |
| |
| std::vector<FaviconBitmap> favicon_bitmaps; |
| EXPECT_TRUE(GetSortedFaviconBitmaps(favicon_id, &favicon_bitmaps)); |
| EXPECT_EQ(2u, favicon_bitmaps.size()); |
| favicon::FaviconBitmapID small_bitmap_id = favicon_bitmaps[0].bitmap_id; |
| EXPECT_NE(0, small_bitmap_id); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmaps[0].bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmaps[0].pixel_size); |
| favicon::FaviconBitmapID large_bitmap_id = favicon_bitmaps[1].bitmap_id; |
| EXPECT_NE(0, large_bitmap_id); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorRED, favicon_bitmaps[1].bitmap_data)); |
| EXPECT_EQ(kLargeSize, favicon_bitmaps[1].pixel_size); |
| |
| // Call SetFavicons() with bitmap data for only the large bitmap. Check that |
| // the small bitmap is in fact deleted. |
| bitmaps.clear(); |
| bitmaps.push_back(CreateBitmap(SK_ColorWHITE, kLargeEdgeSize)); |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| scoped_refptr<base::RefCountedMemory> bitmap_data_out; |
| gfx::Size pixel_size_out; |
| EXPECT_FALSE(backend_->db()->GetFaviconBitmap( |
| small_bitmap_id, nullptr, nullptr, &bitmap_data_out, &pixel_size_out)); |
| EXPECT_TRUE(backend_->db()->GetFaviconBitmap( |
| large_bitmap_id, nullptr, nullptr, &bitmap_data_out, &pixel_size_out)); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorWHITE, bitmap_data_out)); |
| EXPECT_EQ(kLargeSize, pixel_size_out); |
| |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| } |
| |
| // Test updating a single favicon bitmap's data via SetFavicons. |
| TEST_F(FaviconBackendTest, SetFaviconsReplaceBitmapData) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| |
| // Add bitmap to the database. |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| favicon_base::FaviconID original_favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, original_favicon_id); |
| FaviconBitmap original_favicon_bitmap; |
| EXPECT_TRUE( |
| GetOnlyFaviconBitmap(original_favicon_id, &original_favicon_bitmap)); |
| EXPECT_TRUE( |
| BitmapColorEqual(SK_ColorBLUE, original_favicon_bitmap.bitmap_data)); |
| EXPECT_NE(base::Time(), original_favicon_bitmap.last_updated); |
| |
| // Call SetFavicons() with completely identical data. |
| bitmaps[0] = CreateBitmap(SK_ColorBLUE, kSmallEdgeSize); |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| favicon_base::FaviconID updated_favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, updated_favicon_id); |
| FaviconBitmap updated_favicon_bitmap; |
| EXPECT_TRUE( |
| GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap)); |
| EXPECT_TRUE( |
| BitmapColorEqual(SK_ColorBLUE, updated_favicon_bitmap.bitmap_data)); |
| EXPECT_NE(base::Time(), updated_favicon_bitmap.last_updated); |
| |
| // Call SetFavicons() with a different bitmap of the same size. |
| bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize); |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| updated_favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, updated_favicon_id); |
| EXPECT_TRUE( |
| GetOnlyFaviconBitmap(updated_favicon_id, &updated_favicon_bitmap)); |
| EXPECT_TRUE( |
| BitmapColorEqual(SK_ColorWHITE, updated_favicon_bitmap.bitmap_data)); |
| |
| // There should be no churn in FaviconIDs or FaviconBitmapIds even though |
| // the bitmap data changed. |
| EXPECT_EQ(original_favicon_bitmap.icon_id, updated_favicon_bitmap.icon_id); |
| EXPECT_EQ(original_favicon_bitmap.bitmap_id, |
| updated_favicon_bitmap.bitmap_id); |
| } |
| |
| // Test that if two pages share the same FaviconID, changing the favicon for |
| // one page does not affect the other. |
| TEST_F(FaviconBackendTest, SetFaviconsSameFaviconURLForTwoPages) { |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| GURL icon_url_new("http://www.google.com/favicon2.ico"); |
| GURL page_url1("http://www.google.com"); |
| GURL page_url2("http://www.google.ca"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| SetFavicons({page_url1}, IconType::kFavicon, icon_url, bitmaps); |
| |
| backend_->UpdateFaviconMappingsAndFetch( |
| {page_url2}, icon_url, IconType::kFavicon, GetEdgeSizesSmallAndLarge()); |
| |
| // Check that the same FaviconID is mapped to both page URLs. |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url1, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| favicon_base::FaviconID favicon_id = icon_mappings[0].icon_id; |
| EXPECT_NE(0, favicon_id); |
| |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url2, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| |
| // Change the icon URL that |page_url1| is mapped to. |
| bitmaps.clear(); |
| bitmaps.push_back(CreateBitmap(SK_ColorWHITE, kSmallEdgeSize)); |
| SetFavicons({page_url1}, IconType::kFavicon, icon_url_new, bitmaps); |
| |
| // |page_url1| should map to a new FaviconID and have valid bitmap data. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url1, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url_new, icon_mappings[0].icon_url); |
| EXPECT_NE(favicon_id, icon_mappings[0].icon_id); |
| |
| std::vector<FaviconBitmap> favicon_bitmaps; |
| EXPECT_TRUE(backend_->db()->GetFaviconBitmaps(icon_mappings[0].icon_id, |
| &favicon_bitmaps)); |
| EXPECT_EQ(1u, favicon_bitmaps.size()); |
| |
| // |page_url2| should still map to the same FaviconID and have valid bitmap |
| // data. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url2, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| |
| favicon_bitmaps.clear(); |
| EXPECT_TRUE(backend_->db()->GetFaviconBitmaps(favicon_id, &favicon_bitmaps)); |
| EXPECT_EQ(2u, favicon_bitmaps.size()); |
| } |
| |
| // Test that if two pages share the same favicon, reported via a single call to |
| // SetFavicons(), it gets associated to both page URLs. |
| TEST_F(FaviconBackendTest, SetFaviconsWithTwoPageURLs) { |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| GURL page_url1("http://www.google.com"); |
| GURL page_url2("http://www.google.ca"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| SetFavicons({page_url1, page_url2}, IconType::kFavicon, icon_url, bitmaps); |
| |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url1, &icon_mappings)); |
| ASSERT_EQ(1u, icon_mappings.size()); |
| favicon_base::FaviconID favicon_id = icon_mappings[0].icon_id; |
| EXPECT_NE(0, favicon_id); |
| |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url2, &icon_mappings)); |
| ASSERT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| } |
| |
| // Test that favicon mappings can be deleted using DeleteFaviconMappings(). |
| TEST_F(FaviconBackendTest, DeleteFaviconMappings) { |
| GURL icon_url1("http://www.google.com/favicon.ico"); |
| GURL icon_url2("http://www.google.com/favicon2.ico"); |
| GURL page_url("http://www.google.com"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| // Setup |
| SetFavicons({page_url}, IconType::kFavicon, icon_url1, bitmaps); |
| SetFavicons({page_url}, IconType::kTouchIcon, icon_url2, bitmaps); |
| |
| // Delete one of the two mappings. |
| backend_->DeleteFaviconMappings({page_url}, IconType::kTouchIcon); |
| EXPECT_EQ(1u, NumIconMappingsForPageURL(page_url, IconType::kFavicon)); |
| EXPECT_EQ(0u, NumIconMappingsForPageURL(page_url, IconType::kTouchIcon)); |
| |
| // Delete the second mapping. |
| backend_->DeleteFaviconMappings({page_url}, IconType::kFavicon); |
| EXPECT_EQ(0u, NumIconMappingsForPageURL(page_url, IconType::kFavicon)); |
| } |
| |
| // Tests calling SetOnDemandFavicons(). Neither |page_url| nor |icon_url| are |
| // known to the database. |
| TEST_F(FaviconBackendTest, SetOnDemandFaviconsForEmptyDB) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http:/www.google.com/favicon.ico"); |
| |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kSmallEdgeSize)); |
| |
| EXPECT_TRUE( |
| backend_ |
| ->SetOnDemandFavicons(page_url, IconType::kFavicon, icon_url, bitmaps) |
| .did_update_bitmap); |
| |
| favicon_base::FaviconID favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, favicon_id); |
| |
| FaviconBitmap favicon_bitmap; |
| ASSERT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap)); |
| // The newly set bitmap should have been retrieved. |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorRED, favicon_bitmap.bitmap_data)); |
| // The favicon should be marked as expired. |
| EXPECT_EQ(base::Time(), favicon_bitmap.last_updated); |
| |
| // The raw bitmap result is marked as fetched on-demand. |
| favicon_base::FaviconRawBitmapResult result = |
| backend_->GetLargestFaviconForUrl( |
| page_url, std::vector<IconTypeSet>({{IconType::kFavicon}}), |
| kSmallEdgeSize); |
| EXPECT_FALSE(result.fetched_because_of_page_visit); |
| } |
| |
| // Tests calling SetOnDemandFavicons(). |page_url| is known to the database |
| // but |icon_url| is not (the second should be irrelevant though). |
| TEST_F(FaviconBackendTest, SetOnDemandFaviconsForPageInDB) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url1("http:/www.google.com/favicon1.ico"); |
| GURL icon_url2("http:/www.google.com/favicon2.ico"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| |
| // Add bitmap to the database. |
| SetFavicons({page_url}, IconType::kFavicon, icon_url1, bitmaps); |
| favicon_base::FaviconID original_favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url1, IconType::kFavicon); |
| ASSERT_NE(0, original_favicon_id); |
| |
| // Call SetOnDemandFavicons() with a different icon URL and bitmap data. |
| bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize); |
| EXPECT_FALSE(backend_ |
| ->SetOnDemandFavicons(page_url, IconType::kFavicon, |
| icon_url2, bitmaps) |
| .did_update_bitmap); |
| EXPECT_EQ(0, backend_->db()->GetFaviconIDForFaviconURL(icon_url2, |
| IconType::kFavicon)); |
| |
| FaviconBitmap favicon_bitmap; |
| ASSERT_TRUE(GetOnlyFaviconBitmap(original_favicon_id, &favicon_bitmap)); |
| // The original bitmap should have been retrieved. |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data)); |
| // The favicon should not be marked as expired. |
| EXPECT_NE(base::Time(), favicon_bitmap.last_updated); |
| |
| // The raw bitmap result is not marked as fetched on-demand. |
| favicon_base::FaviconRawBitmapResult result = |
| backend_->GetLargestFaviconForUrl( |
| page_url, std::vector<IconTypeSet>({{IconType::kFavicon}}), |
| kSmallEdgeSize); |
| EXPECT_TRUE(result.fetched_because_of_page_visit); |
| } |
| |
| // Tests calling SetOnDemandFavicons(). |page_url| is not known to the |
| // database but |icon_url| is. |
| TEST_F(FaviconBackendTest, SetOnDemandFaviconsForIconInDB) { |
| const GURL old_page_url("http://www.google.com/old"); |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| |
| // Add bitmap to the database. |
| SetFavicons({old_page_url}, IconType::kFavicon, icon_url, bitmaps); |
| favicon_base::FaviconID original_favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| ASSERT_NE(0, original_favicon_id); |
| |
| // Call SetOnDemandFavicons() with a different bitmap. |
| bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize); |
| EXPECT_FALSE( |
| backend_ |
| ->SetOnDemandFavicons(page_url, IconType::kFavicon, icon_url, bitmaps) |
| .did_update_bitmap); |
| |
| EXPECT_EQ(original_favicon_id, backend_->db()->GetFaviconIDForFaviconURL( |
| icon_url, IconType::kFavicon)); |
| |
| FaviconBitmap favicon_bitmap; |
| ASSERT_TRUE(GetOnlyFaviconBitmap(original_favicon_id, &favicon_bitmap)); |
| // The original bitmap should have been retrieved. |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data)); |
| // The favicon should not be marked as expired. |
| EXPECT_NE(base::Time(), favicon_bitmap.last_updated); |
| |
| // The raw bitmap result is not marked as fetched on-demand. |
| favicon_base::FaviconRawBitmapResult result = |
| backend_->GetLargestFaviconForUrl( |
| page_url, std::vector<IconTypeSet>({{IconType::kFavicon}}), |
| kSmallEdgeSize); |
| EXPECT_TRUE(result.fetched_because_of_page_visit); |
| } |
| |
| // Test repeatedly calling MergeFavicon(). |page_url| is initially not known |
| // to the database. |
| TEST_F(FaviconBackendTest, MergeFaviconPageURLNotInDB) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http:/www.google.com/favicon.ico"); |
| |
| std::vector<unsigned char> data; |
| data.push_back('a'); |
| scoped_refptr<base::RefCountedBytes> bitmap_data( |
| new base::RefCountedBytes(data)); |
| |
| backend_->MergeFavicon(page_url, icon_url, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // |page_url| should now be mapped to |icon_url| and the favicon bitmap should |
| // be expired. |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url, icon_mappings[0].icon_url); |
| |
| FaviconBitmap favicon_bitmap; |
| EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); |
| EXPECT_EQ(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapDataEqual('a', favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| data[0] = 'b'; |
| bitmap_data = new base::RefCountedBytes(data); |
| backend_->MergeFavicon(page_url, icon_url, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // |page_url| should still have a single favicon bitmap. The bitmap data |
| // should be updated. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url, icon_mappings[0].icon_url); |
| |
| EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); |
| EXPECT_EQ(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| } |
| |
| // Test calling MergeFavicon() when |page_url| is known to the database. |
| TEST_F(FaviconBackendTest, MergeFaviconPageURLInDB) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url1("http:/www.google.com/favicon.ico"); |
| GURL icon_url2("http://www.google.com/favicon2.ico"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| |
| SetFavicons({page_url}, IconType::kFavicon, icon_url1, bitmaps); |
| |
| // Test initial state. |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); |
| |
| FaviconBitmap favicon_bitmap; |
| EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); |
| EXPECT_NE(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| // 1) Merge identical favicon bitmap. |
| std::vector<unsigned char> data; |
| gfx::PNGCodec::EncodeBGRASkBitmap(bitmaps[0], false, &data); |
| scoped_refptr<base::RefCountedBytes> bitmap_data( |
| new base::RefCountedBytes(data)); |
| backend_->MergeFavicon(page_url, icon_url1, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // All the data should stay the same and no notifications should have been |
| // sent. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); |
| |
| EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); |
| EXPECT_NE(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| // 2) Merge favicon bitmap of the same size. |
| data.clear(); |
| data.push_back('b'); |
| bitmap_data = new base::RefCountedBytes(data); |
| backend_->MergeFavicon(page_url, icon_url1, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // The small favicon bitmap at |icon_url1| should be overwritten. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); |
| |
| EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); |
| EXPECT_EQ(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| // 3) Merge favicon for the same icon URL, but a pixel size for which there is |
| // no favicon bitmap. |
| data[0] = 'c'; |
| bitmap_data = new base::RefCountedBytes(data); |
| backend_->MergeFavicon(page_url, icon_url1, IconType::kFavicon, bitmap_data, |
| kTinySize); |
| |
| // A new favicon bitmap should be created and the preexisting favicon bitmap |
| // ('b') should be expired. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url1, icon_mappings[0].icon_url); |
| |
| std::vector<FaviconBitmap> favicon_bitmaps; |
| EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id, |
| &favicon_bitmaps)); |
| EXPECT_EQ(base::Time(), favicon_bitmaps[0].last_updated); |
| EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data)); |
| EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size); |
| EXPECT_EQ(base::Time(), favicon_bitmaps[1].last_updated); |
| EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmaps[1].bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size); |
| |
| // 4) Merge favicon for an icon URL different from the icon URLs already |
| // mapped to page URL. |
| data[0] = 'd'; |
| bitmap_data = new base::RefCountedBytes(data); |
| backend_->MergeFavicon(page_url, icon_url2, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // The existing favicon bitmaps should be copied over to the newly created |
| // favicon at |icon_url2|. |page_url| should solely be mapped to |icon_url2|. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url2, icon_mappings[0].icon_url); |
| |
| favicon_bitmaps.clear(); |
| EXPECT_TRUE(GetSortedFaviconBitmaps(icon_mappings[0].icon_id, |
| &favicon_bitmaps)); |
| EXPECT_EQ(base::Time(), favicon_bitmaps[0].last_updated); |
| EXPECT_TRUE(BitmapDataEqual('c', favicon_bitmaps[0].bitmap_data)); |
| EXPECT_EQ(kTinySize, favicon_bitmaps[0].pixel_size); |
| // The favicon being merged should take precedence over the preexisting |
| // favicon bitmaps. |
| EXPECT_EQ(base::Time(), favicon_bitmaps[1].last_updated); |
| EXPECT_TRUE(BitmapDataEqual('d', favicon_bitmaps[1].bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmaps[1].pixel_size); |
| } |
| |
| // Test calling MergeFavicon() when |icon_url| is known to the database but not |
| // mapped to |page_url|. |
| TEST_F(FaviconBackendTest, MergeFaviconIconURLMappedToDifferentPageURL) { |
| GURL page_url1("http://www.google.com"); |
| GURL page_url2("http://news.google.com"); |
| GURL page_url3("http://maps.google.com"); |
| GURL icon_url("http:/www.google.com/favicon.ico"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| |
| SetFavicons({page_url1}, IconType::kFavicon, icon_url, bitmaps); |
| |
| // Test initial state. |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url1, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(icon_url, icon_mappings[0].icon_url); |
| |
| FaviconBitmap favicon_bitmap; |
| EXPECT_TRUE(GetOnlyFaviconBitmap(icon_mappings[0].icon_id, &favicon_bitmap)); |
| EXPECT_NE(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| // 1) Merge in an identical favicon bitmap data but for a different page URL. |
| std::vector<unsigned char> data; |
| gfx::PNGCodec::EncodeBGRASkBitmap(bitmaps[0], false, &data); |
| scoped_refptr<base::RefCountedBytes> bitmap_data( |
| new base::RefCountedBytes(data)); |
| |
| backend_->MergeFavicon(page_url2, icon_url, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| favicon_base::FaviconID favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, favicon_id); |
| |
| EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap)); |
| EXPECT_NE(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorBLUE, favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| // 2) Merging a favicon bitmap with different bitmap data for the same icon |
| // URL should overwrite the small favicon bitmap at |icon_url|. |
| data.clear(); |
| data.push_back('b'); |
| bitmap_data = new base::RefCountedBytes(data); |
| backend_->MergeFavicon(page_url3, icon_url, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| favicon_id = |
| backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, favicon_id); |
| |
| EXPECT_TRUE(GetOnlyFaviconBitmap(favicon_id, &favicon_bitmap)); |
| EXPECT_EQ(base::Time(), favicon_bitmap.last_updated); |
| EXPECT_TRUE(BitmapDataEqual('b', favicon_bitmap.bitmap_data)); |
| EXPECT_EQ(kSmallSize, favicon_bitmap.pixel_size); |
| |
| // |icon_url| should be mapped to all three page URLs. |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url1, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url2, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| |
| icon_mappings.clear(); |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url3, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| EXPECT_EQ(favicon_id, icon_mappings[0].icon_id); |
| } |
| |
| // Test that MergeFavicon() does not add more than |
| // |kMaxFaviconBitmapsPerIconURL| to a favicon. |
| TEST_F(FaviconBackendTest, MergeFaviconMaxFaviconBitmapsPerIconURL) { |
| GURL page_url("http://www.google.com"); |
| std::string icon_url_string("http://www.google.com/favicon.ico"); |
| size_t replace_index = icon_url_string.size() - 1; |
| |
| std::vector<unsigned char> data; |
| data.push_back('a'); |
| scoped_refptr<base::RefCountedMemory> bitmap_data = |
| base::RefCountedBytes::TakeVector(&data); |
| |
| int pixel_size = 1; |
| for (size_t i = 0; i < kMaxFaviconBitmapsPerIconURL + 1; ++i) { |
| icon_url_string[replace_index] = '0' + i; |
| GURL icon_url(icon_url_string); |
| |
| backend_->MergeFavicon(page_url, icon_url, IconType::kFavicon, bitmap_data, |
| gfx::Size(pixel_size, pixel_size)); |
| ++pixel_size; |
| } |
| |
| // There should be a single favicon mapped to |page_url| with exactly |
| // kMaxFaviconBitmapsPerIconURL favicon bitmaps. |
| std::vector<IconMapping> icon_mappings; |
| EXPECT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| EXPECT_EQ(1u, icon_mappings.size()); |
| std::vector<FaviconBitmap> favicon_bitmaps; |
| EXPECT_TRUE(backend_->db()->GetFaviconBitmaps(icon_mappings[0].icon_id, |
| &favicon_bitmaps)); |
| EXPECT_EQ(kMaxFaviconBitmapsPerIconURL, favicon_bitmaps.size()); |
| } |
| |
| // Tests that the favicon set by MergeFavicon() shows up in the result of |
| // GetFaviconsForURL(). |
| TEST_F(FaviconBackendTest, MergeFaviconShowsUpInGetFaviconsForURLResult) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| GURL merged_icon_url("http://wwww.google.com/favicon2.ico"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| // Set some preexisting favicons for |page_url|. |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| // Merge small favicon. |
| std::vector<unsigned char> data; |
| data.push_back('c'); |
| scoped_refptr<base::RefCountedBytes> bitmap_data( |
| new base::RefCountedBytes(data)); |
| backend_->MergeFavicon(page_url, merged_icon_url, IconType::kFavicon, |
| bitmap_data, kSmallSize); |
| |
| // Request favicon bitmaps for both 1x and 2x to simulate request done by |
| // BookmarkModel::GetFavicon(). |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results = |
| backend_->GetFaviconsForUrl(page_url, {IconType::kFavicon}, |
| GetEdgeSizesSmallAndLarge(), false); |
| |
| EXPECT_EQ(2u, bitmap_results.size()); |
| const favicon_base::FaviconRawBitmapResult& first_result = bitmap_results[0]; |
| const favicon_base::FaviconRawBitmapResult& result = |
| (first_result.pixel_size == kSmallSize) ? first_result |
| : bitmap_results[1]; |
| EXPECT_TRUE(BitmapDataEqual('c', result.bitmap_data)); |
| } |
| |
| // Tests that calling MergeFavicon() with identical favicon data does not affect |
| // the favicon bitmap's "last updated" time. This is important because sync |
| // calls MergeFavicon() for all of the favicons that it manages at startup. |
| TEST_F(FaviconBackendTest, MergeIdenticalFaviconDoesNotChangeLastUpdatedTime) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| std::vector<unsigned char> data; |
| data.push_back('a'); |
| |
| scoped_refptr<base::RefCountedBytes> bitmap_data( |
| new base::RefCountedBytes(data)); |
| backend_->MergeFavicon(page_url, icon_url, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // Find the ID of the add favicon bitmap. |
| std::vector<IconMapping> icon_mappings; |
| ASSERT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| ASSERT_EQ(1u, icon_mappings.size()); |
| std::vector<FaviconBitmap> favicon_bitmaps; |
| ASSERT_TRUE(backend_->db()->GetFaviconBitmaps(icon_mappings[0].icon_id, |
| &favicon_bitmaps)); |
| |
| // Change the last updated time of the just added favicon bitmap. |
| const base::Time kLastUpdateTime = base::Time::Now() - base::Days(314); |
| backend_->db()->SetFaviconBitmapLastUpdateTime(favicon_bitmaps[0].bitmap_id, |
| kLastUpdateTime); |
| |
| // Call MergeFavicon() with identical data. |
| backend_->MergeFavicon(page_url, icon_url, IconType::kFavicon, bitmap_data, |
| kSmallSize); |
| |
| // Check that the "last updated" time did not change. |
| icon_mappings.clear(); |
| ASSERT_TRUE( |
| backend_->db()->GetIconMappingsForPageURL(page_url, &icon_mappings)); |
| ASSERT_EQ(1u, icon_mappings.size()); |
| favicon_bitmaps.clear(); |
| ASSERT_TRUE(backend_->db()->GetFaviconBitmaps(icon_mappings[0].icon_id, |
| &favicon_bitmaps)); |
| EXPECT_EQ(kLastUpdateTime, favicon_bitmaps[0].last_updated); |
| } |
| |
| // Tests GetFaviconsForURL with icon_types priority, |
| TEST_F(FaviconBackendTest, TestGetFaviconsForURLWithIconTypesPriority) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| GURL touch_icon_url("http://wwww.google.com/touch_icon.ico"); |
| |
| std::vector<SkBitmap> favicon_bitmaps; |
| favicon_bitmaps.push_back(CreateBitmap(SK_ColorBLUE, 16)); |
| favicon_bitmaps.push_back(CreateBitmap(SK_ColorRED, 32)); |
| |
| std::vector<SkBitmap> touch_bitmaps; |
| touch_bitmaps.push_back(CreateBitmap(SK_ColorWHITE, 64)); |
| |
| // Set some preexisting favicons for |page_url|. |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, favicon_bitmaps); |
| SetFavicons({page_url}, IconType::kTouchIcon, touch_icon_url, touch_bitmaps); |
| |
| std::vector<IconTypeSet> icon_types; |
| icon_types.push_back({IconType::kFavicon}); |
| icon_types.push_back({IconType::kTouchIcon}); |
| |
| favicon_base::FaviconRawBitmapResult result = |
| backend_->GetLargestFaviconForUrl(page_url, icon_types, 16); |
| |
| // Verify the result icon is 32x32 favicon. |
| EXPECT_EQ(gfx::Size(32, 32), result.pixel_size); |
| EXPECT_EQ(IconType::kFavicon, result.icon_type); |
| |
| // Change Minimal size to 32x32 and verify the 64x64 touch icon returned. |
| result = backend_->GetLargestFaviconForUrl(page_url, icon_types, 32); |
| EXPECT_EQ(gfx::Size(64, 64), result.pixel_size); |
| EXPECT_EQ(IconType::kTouchIcon, result.icon_type); |
| } |
| |
| // Test the the first types of icon is returned if its size equal to the |
| // second types icon. |
| TEST_F(FaviconBackendTest, TestGetFaviconsForURLReturnFavicon) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| GURL touch_icon_url("http://wwww.google.com/touch_icon.ico"); |
| |
| std::vector<SkBitmap> favicon_bitmaps; |
| favicon_bitmaps.push_back(CreateBitmap(SK_ColorBLUE, 16)); |
| favicon_bitmaps.push_back(CreateBitmap(SK_ColorRED, 32)); |
| |
| std::vector<SkBitmap> touch_bitmaps; |
| touch_bitmaps.push_back(CreateBitmap(SK_ColorWHITE, 32)); |
| |
| // Set some preexisting favicons for |page_url|. |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, favicon_bitmaps); |
| SetFavicons({page_url}, IconType::kTouchIcon, touch_icon_url, touch_bitmaps); |
| |
| std::vector<IconTypeSet> icon_types; |
| icon_types.push_back({IconType::kFavicon}); |
| icon_types.push_back({IconType::kTouchIcon}); |
| |
| favicon_base::FaviconRawBitmapResult result = |
| backend_->GetLargestFaviconForUrl(page_url, icon_types, 16); |
| |
| // Verify the result icon is 32x32 favicon. |
| EXPECT_EQ(gfx::Size(32, 32), result.pixel_size); |
| EXPECT_EQ(IconType::kFavicon, result.icon_type); |
| |
| // Change minimal size to 32x32 and verify the 32x32 favicon returned. |
| favicon_base::FaviconRawBitmapResult result1 = |
| backend_->GetLargestFaviconForUrl(page_url, icon_types, 32); |
| EXPECT_EQ(gfx::Size(32, 32), result1.pixel_size); |
| EXPECT_EQ(IconType::kFavicon, result1.icon_type); |
| } |
| |
| // Test the favicon is returned if its size is smaller than minimal size, |
| // because it is only one available. |
| TEST_F(FaviconBackendTest, TestGetFaviconsForURLReturnFaviconEvenItSmaller) { |
| GURL page_url("http://www.google.com"); |
| GURL icon_url("http://www.google.com/favicon.ico"); |
| |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, 16)); |
| |
| // Set preexisting favicons for |page_url|. |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| std::vector<IconTypeSet> icon_types; |
| icon_types.push_back({IconType::kFavicon}); |
| icon_types.push_back({IconType::kTouchIcon}); |
| |
| favicon_base::FaviconRawBitmapResult result = |
| backend_->GetLargestFaviconForUrl(page_url, icon_types, 32); |
| |
| // Verify 16x16 icon is returned, even it small than minimal_size. |
| EXPECT_EQ(gfx::Size(16, 16), result.pixel_size); |
| EXPECT_EQ(IconType::kFavicon, result.icon_type); |
| } |
| |
| // Test the results of GetFaviconsForUrl() when there are no found favicons. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlEmpty) { |
| const GURL page_url("http://www.google.com/"); |
| |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results = |
| backend_->GetFaviconsForUrl(page_url, {IconType::kFavicon}, |
| GetEdgeSizesSmallAndLarge(), false); |
| EXPECT_TRUE(bitmap_results.empty()); |
| } |
| |
| // Test the results of GetFaviconsForUrl() when there are matching favicons |
| // but there are no associated favicon bitmaps. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlNoFaviconBitmaps) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon1"); |
| |
| favicon_base::FaviconID icon_id = |
| backend_->db()->AddFavicon(icon_url, IconType::kFavicon); |
| EXPECT_NE(0, icon_id); |
| EXPECT_NE(0, backend_->db()->AddIconMapping(page_url, icon_id)); |
| |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url, {IconType::kFavicon}, |
| GetEdgeSizesSmallAndLarge(), false); |
| EXPECT_TRUE(bitmap_results_out.empty()); |
| } |
| |
| // Test that GetFaviconsForUrl() returns results for the bitmaps which most |
| // closely match the passed in the desired pixel sizes. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlSelectClosestMatch) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon1"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorWHITE, kTinyEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| bitmaps.push_back(CreateBitmap(SK_ColorRED, kLargeEdgeSize)); |
| |
| SetFavicons({page_url}, IconType::kFavicon, icon_url, bitmaps); |
| |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url, {IconType::kFavicon}, |
| GetEdgeSizesSmallAndLarge(), false); |
| |
| // The bitmap data for the small and large bitmaps should be returned as their |
| // sizes match exactly. |
| EXPECT_EQ(2u, bitmap_results_out.size()); |
| // No required order for results. |
| if (bitmap_results_out[0].pixel_size == kLargeSize) { |
| favicon_base::FaviconRawBitmapResult tmp_result = bitmap_results_out[0]; |
| bitmap_results_out[0] = bitmap_results_out[1]; |
| bitmap_results_out[1] = tmp_result; |
| } |
| |
| EXPECT_FALSE(bitmap_results_out[0].expired); |
| EXPECT_TRUE( |
| BitmapColorEqual(SK_ColorBLUE, bitmap_results_out[0].bitmap_data)); |
| EXPECT_EQ(kSmallSize, bitmap_results_out[0].pixel_size); |
| EXPECT_EQ(icon_url, bitmap_results_out[0].icon_url); |
| EXPECT_EQ(IconType::kFavicon, bitmap_results_out[0].icon_type); |
| |
| EXPECT_FALSE(bitmap_results_out[1].expired); |
| EXPECT_TRUE(BitmapColorEqual(SK_ColorRED, bitmap_results_out[1].bitmap_data)); |
| EXPECT_EQ(kLargeSize, bitmap_results_out[1].pixel_size); |
| EXPECT_EQ(icon_url, bitmap_results_out[1].icon_url); |
| EXPECT_EQ(IconType::kFavicon, bitmap_results_out[1].icon_type); |
| } |
| |
| // Test the results of GetFaviconsForUrl() when called with different |
| // |icon_types|. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlIconType) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url1("http://www.google.com/icon1.png"); |
| const GURL icon_url2("http://www.google.com/icon2.png"); |
| std::vector<SkBitmap> bitmaps; |
| bitmaps.push_back(CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)); |
| |
| std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data; |
| SetFavicons({page_url}, IconType::kFavicon, icon_url1, bitmaps); |
| SetFavicons({page_url}, IconType::kTouchIcon, icon_url2, bitmaps); |
| |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url, {IconType::kFavicon}, |
| GetEdgeSizesSmallAndLarge(), false); |
| |
| EXPECT_EQ(1u, bitmap_results_out.size()); |
| EXPECT_EQ(IconType::kFavicon, bitmap_results_out[0].icon_type); |
| EXPECT_EQ(icon_url1, bitmap_results_out[0].icon_url); |
| |
| bitmap_results_out = backend_->GetFaviconsForUrl( |
| page_url, {IconType::kTouchIcon}, GetEdgeSizesSmallAndLarge(), false); |
| |
| EXPECT_EQ(1u, bitmap_results_out.size()); |
| EXPECT_EQ(IconType::kTouchIcon, bitmap_results_out[0].icon_type); |
| EXPECT_EQ(icon_url2, bitmap_results_out[0].icon_url); |
| } |
| |
| // Test that GetFaviconsForUrl() behaves correctly for different values of |
| // |fallback_to_host|. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlFallbackToHost) { |
| const GURL page_url_http("http://www.google.com/"); |
| const GURL page_url_https("https://www.google.com/"); |
| const GURL page_url_http_same_prefix("http://www.google.com.au/"); |
| const GURL page_url_http_same_suffix("http://m.www.google.com/"); |
| const GURL page_url_different_scheme("file://www.google.com/"); |
| const GURL icon_url1("http://www.google.com.au/icon.png"); |
| const GURL icon_url2("http://maps.google.com.au/icon.png"); |
| const GURL icon_url3("https://www.google.com/icon.png"); |
| |
| std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data; |
| SetFavicons({page_url_http_same_prefix}, IconType::kFavicon, icon_url1, |
| {CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)}); |
| SetFavicons({page_url_http_same_suffix}, IconType::kFavicon, icon_url2, |
| {CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)}); |
| |
| { |
| // Querying for the http URL with |fallback_to_host|=false returns nothing. |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url_http, |
| {IconType::kFavicon, IconType::kTouchIcon}, |
| {kSmallEdgeSize}, false); |
| |
| EXPECT_TRUE(bitmap_results_out.empty()); |
| |
| // Querying for the http URL with |fallback_to_host|=true should not return |
| // the favicon associated with a different host, even when that host has the |
| // same prefix or suffix. |
| bitmap_results_out = backend_->GetFaviconsForUrl( |
| page_url_http, {IconType::kFavicon, IconType::kTouchIcon}, |
| {kSmallEdgeSize}, true); |
| |
| EXPECT_TRUE(bitmap_results_out.empty()); |
| } |
| |
| SetFavicons({page_url_https}, IconType::kFavicon, icon_url3, |
| {CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)}); |
| |
| { |
| // Querying for the http URL with |fallback_to_host|=false returns nothing. |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url_http, |
| {IconType::kFavicon, IconType::kTouchIcon}, |
| {kSmallEdgeSize}, false); |
| |
| EXPECT_TRUE(bitmap_results_out.empty()); |
| |
| // Querying for the http URL with |fallback_to_host|=true returns the |
| // favicon associated with the https URL. |
| bitmap_results_out = backend_->GetFaviconsForUrl( |
| page_url_http, {IconType::kFavicon, IconType::kTouchIcon}, |
| {kSmallEdgeSize}, true); |
| |
| ASSERT_EQ(1u, bitmap_results_out.size()); |
| EXPECT_EQ(icon_url3, bitmap_results_out[0].icon_url); |
| } |
| |
| { |
| // Querying for a URL with non HTTP/HTTPS scheme returns nothing even if |
| // |fallback_to_host| is true. |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url_different_scheme, |
| {IconType::kFavicon, IconType::kTouchIcon}, |
| {kSmallEdgeSize}, false); |
| |
| EXPECT_TRUE(bitmap_results_out.empty()); |
| |
| bitmap_results_out = backend_->GetFaviconsForUrl( |
| page_url_different_scheme, {IconType::kFavicon, IconType::kTouchIcon}, |
| {kSmallEdgeSize}, true); |
| |
| EXPECT_TRUE(bitmap_results_out.empty()); |
| } |
| } |
| |
| // Test that when GetFaviconsForUrl() is called with multiple icon types that |
| // the best favicon bitmap is selected from among all of the icon types. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlMultipleIconTypes) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url1("http://www.google.com/icon1.png"); |
| const GURL icon_url2("http://www.google.com/icon2.png"); |
| |
| std::vector<favicon_base::FaviconRawBitmapData> favicon_bitmap_data; |
| SetFavicons({page_url}, IconType::kFavicon, icon_url1, |
| {CreateBitmap(SK_ColorBLUE, kSmallEdgeSize)}); |
| SetFavicons({page_url}, IconType::kTouchIcon, icon_url2, |
| {CreateBitmap(SK_ColorBLUE, kLargeEdgeSize)}); |
| |
| struct TestCase { |
| int desired_edge_size; |
| GURL expected_icon_url; |
| } kTestCases[]{{kSmallEdgeSize, icon_url1}, {kLargeEdgeSize, icon_url2}}; |
| |
| for (const TestCase& test_case : kTestCases) { |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results = |
| backend_->GetFaviconsForUrl(page_url, |
| {IconType::kFavicon, IconType::kTouchIcon}, |
| {test_case.desired_edge_size}, false); |
| |
| ASSERT_EQ(1u, bitmap_results.size()); |
| EXPECT_EQ(test_case.expected_icon_url, bitmap_results[0].icon_url); |
| } |
| } |
| |
| // Test that GetFaviconsForUrl() correctly sets the expired flag for bitmap |
| // reults. |
| TEST_F(FaviconBackendTest, GetFaviconsForUrlExpired) { |
| const GURL page_url("http://www.google.com/"); |
| const GURL icon_url("http://www.google.com/icon.png"); |
| |
| std::vector<unsigned char> data; |
| data.push_back('a'); |
| scoped_refptr<base::RefCountedBytes> bitmap_data( |
| base::RefCountedBytes::TakeVector(&data)); |
| base::Time last_updated = base::Time::FromTimeT(0); |
| favicon_base::FaviconID icon_id = backend_->db()->AddFavicon( |
| icon_url, IconType::kFavicon, bitmap_data, FaviconBitmapType::ON_VISIT, |
| last_updated, kSmallSize); |
| EXPECT_NE(0, icon_id); |
| EXPECT_NE(0, backend_->db()->AddIconMapping(page_url, icon_id)); |
| |
| std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results_out = |
| backend_->GetFaviconsForUrl(page_url, {IconType::kFavicon}, |
| GetEdgeSizesSmallAndLarge(), false); |
| |
| EXPECT_EQ(1u, bitmap_results_out.size()); |
| EXPECT_TRUE(bitmap_results_out[0].expired); |
| } |
| |
| } // namespace favicon |