| // Copyright 2017 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "chrome/browser/android/favicon_helper.h" | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/task/single_thread_task_runner.h" | 
 | #include "base/test/task_environment.h" | 
 | #include "components/favicon/core/test/mock_favicon_service.h" | 
 | #include "components/favicon_base/favicon_callback.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/image/image_unittest_util.h" | 
 | #include "url/gurl.h" | 
 |  | 
 | using ::testing::_; | 
 | const int kDummyTaskId = 1; | 
 |  | 
 | favicon_base::FaviconRawBitmapResult | 
 | CreateTestBitmapResult(GURL url, int size, SkColor color = SK_ColorRED) { | 
 |   favicon_base::FaviconRawBitmapResult result; | 
 |   result.expired = false; | 
 |  | 
 |   // Create bitmap and fill with |color|. | 
 |   scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes()); | 
 |   gfx::PNGCodec::EncodeBGRASkBitmap(gfx::test::CreateBitmap(size, color), false, | 
 |                                     &data->data()); | 
 |  | 
 |   result.bitmap_data = data; | 
 |   result.pixel_size = gfx::Size(size, size); | 
 |   result.icon_url = url; | 
 |   result.icon_type = favicon_base::IconType::kFavicon; | 
 |   CHECK(result.is_valid()); | 
 |   return result; | 
 | } | 
 |  | 
 | class FaviconHelperTest : public testing::Test { | 
 |  public: | 
 |   FaviconHelperTest() { | 
 |     ON_CALL(mock_favicon_service_, GetRawFaviconForPageURL(_, _, _, _, _, _)) | 
 |         .WillByDefault([](const GURL& url, auto, int size, auto, | 
 |                           favicon_base::FaviconRawBitmapCallback callback, | 
 |                           auto) { | 
 |           std::move(callback).Run(CreateTestBitmapResult(url, size)); | 
 |           return kDummyTaskId; | 
 |         }); | 
 |  | 
 |     get_composed_favicon_raw_results_callback_ = base::BindOnce( | 
 |         &FaviconHelperTest::onNativeGetComposedFaviconImageFinished, | 
 |         base::Unretained(this)); | 
 |   } | 
 |  | 
 |   ~FaviconHelperTest() override { favicon_helper_->Destroy(nullptr); } | 
 |  | 
 |   void onNativeGetComposedFaviconImageFinished( | 
 |       const std::vector<favicon_base::FaviconRawBitmapResult>& result) { | 
 |     raw_bitmap_results_ = result; | 
 |   } | 
 |  | 
 |  protected: | 
 |   base::test::TaskEnvironment task_environment_; | 
 |   favicon::MockFaviconService mock_favicon_service_; | 
 |   raw_ptr<FaviconHelper> favicon_helper_ = new FaviconHelper(); | 
 |   std::vector<favicon_base::FaviconRawBitmapResult> raw_bitmap_results_; | 
 |   favicon_base::FaviconResultsCallback | 
 |       get_composed_favicon_raw_results_callback_; | 
 | }; | 
 |  | 
 | TEST_F(FaviconHelperTest, GetLargestSizeIndex) { | 
 |   std::vector<gfx::Size> sizes; | 
 |   gfx::Size size1 = gfx::Size(INT_MAX, INT_MAX); | 
 |   sizes.push_back(size1); | 
 |   gfx::Size size2 = gfx::Size(16, 16); | 
 |   sizes.push_back(size2); | 
 |   gfx::Size size3 = gfx::Size(32, 32); | 
 |   sizes.push_back(size3); | 
 |   EXPECT_EQ(2u, FaviconHelper::GetLargestSizeIndex(sizes)); | 
 |   sizes.clear(); | 
 |   sizes.push_back(size1); | 
 |   sizes.push_back(size1); | 
 |   EXPECT_EQ(0u, FaviconHelper::GetLargestSizeIndex(sizes)); | 
 | } | 
 |  | 
 | TEST_F(FaviconHelperTest, GetComposedFaviconImage) { | 
 |   raw_bitmap_results_.clear(); | 
 |   GURL url1 = GURL("http://www.tab1.com"); | 
 |   GURL url2 = GURL("http://www.tab2.com"); | 
 |   std::vector<GURL> urls = {url1, url2}; | 
 |  | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url1, _, _, 16, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url2, _, _, 16, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   favicon_helper_->GetComposedFaviconImageInternal( | 
 |       &mock_favicon_service_, urls, 16, | 
 |       std::move(get_composed_favicon_raw_results_callback_)); | 
 |  | 
 |   task_environment_.RunUntilIdle(); | 
 |  | 
 |   EXPECT_EQ(2, (int)raw_bitmap_results_.size()); | 
 | } | 
 |  | 
 | TEST_F(FaviconHelperTest, GetComposedFaviconImageWithOneFaviconFailed) { | 
 |   raw_bitmap_results_.clear(); | 
 |   GURL url1 = GURL("http://www.tab1.com"); | 
 |   GURL url2 = GURL("http://www.tab2.com"); | 
 |   GURL url3 = GURL("http://www.tab3.com"); | 
 |   std::vector<GURL> urls = {url1, url2, url3}; | 
 |  | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url1, _, _, 16, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url2, _, _, 16, _, _)) | 
 |       .Times(1); | 
 |   // With one favicon failed. | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url3, _, _, 16, _, _)) | 
 |       .WillOnce([](auto, auto, auto, auto, | 
 |                    favicon_base::FaviconRawBitmapCallback callback, auto) { | 
 |         std::move(callback).Run(favicon_base::FaviconRawBitmapResult()); | 
 |         return kDummyTaskId; | 
 |       }); | 
 |  | 
 |   favicon_helper_->GetComposedFaviconImageInternal( | 
 |       &mock_favicon_service_, urls, 16, | 
 |       std::move(get_composed_favicon_raw_results_callback_)); | 
 |  | 
 |   task_environment_.RunUntilIdle(); | 
 |  | 
 |   EXPECT_EQ(2, (int)raw_bitmap_results_.size()); | 
 | } | 
 |  | 
 | TEST_F(FaviconHelperTest, GetComposedFaviconImageOrderMatchesInput) { | 
 |   raw_bitmap_results_.clear(); | 
 |   GURL url1 = GURL("http://www.tab1.com"); | 
 |   GURL url2 = GURL("http://www.tab2.com"); | 
 |   GURL url3 = GURL("http://www.tab3.com"); | 
 |   std::vector<GURL> urls = {url1, url2, url3}; | 
 |  | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url1, _, _, 16, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url2, _, _, 16, _, _)) | 
 |       .WillOnce([](const GURL& url, auto, int size, auto, | 
 |                    favicon_base::FaviconRawBitmapCallback callback, | 
 |                    base::CancelableTaskTracker* tracker) { | 
 |         tracker->PostTask( | 
 |             base::SingleThreadTaskRunner::GetCurrentDefault().get(), FROM_HERE, | 
 |             base::BindOnce( | 
 |                 [](favicon_base::FaviconRawBitmapCallback callback, GURL url, | 
 |                    int size) { | 
 |                   sleep(5); | 
 |                   std::move(callback).Run(CreateTestBitmapResult(url, size)); | 
 |                 }, | 
 |                 std::move(callback), url, size)); | 
 |         return kDummyTaskId; | 
 |       }); | 
 |  | 
 |   EXPECT_CALL(mock_favicon_service_, | 
 |               GetRawFaviconForPageURL(url3, _, _, 16, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   favicon_helper_->GetComposedFaviconImageInternal( | 
 |       &mock_favicon_service_, urls, 16, | 
 |       std::move(get_composed_favicon_raw_results_callback_)); | 
 |  | 
 |   task_environment_.RunUntilIdle(); | 
 |  | 
 |   EXPECT_EQ(3, (int)raw_bitmap_results_.size()); | 
 |   EXPECT_EQ(url1, raw_bitmap_results_[0].icon_url); | 
 |   EXPECT_EQ(url2, raw_bitmap_results_[1].icon_url); | 
 |   EXPECT_EQ(url3, raw_bitmap_results_[2].icon_url); | 
 | } |