blob: cb1fba5360a9ceb655bc7c91cf2cf5b63556be4d [file] [log] [blame]
// Copyright 2022 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/supervised_user/android/favicon_fetcher.h"
#include <cstddef>
#include <string>
#include <utility>
#include "base/android/scoped_java_ref.h"
#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/test/gmock_callback_support.h"
#include "components/favicon/core/large_icon_service.h"
#include "components/favicon_base/favicon_callback.h"
#include "components/favicon_base/favicon_types.h"
#include "favicon_fetcher.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "url/gurl.h"
namespace {
const GURL& StringToGURL(std::string uri) {
static const base::NoDestructor<GURL> url(uri);
return *url;
}
const base::CancelableTaskTracker::TaskId kTaskId = 1;
favicon_base::LargeIconImageResult CreateEmptyTestImageResult() {
SkBitmap bitmap_result = SkBitmap();
return favicon_base::LargeIconImageResult(
gfx::Image::CreateFrom1xBitmap(bitmap_result), StringToGURL("icon.com"));
}
favicon_base::LargeIconImageResult CreateTestImageResult() {
return favicon_base::LargeIconImageResult(gfx::test::CreateImage(/*size=*/10),
StringToGURL("icon.com"));
}
class MockLargeIconService : public favicon::LargeIconService {
public:
MockLargeIconService() = default;
MockLargeIconService(const MockLargeIconService&) = delete;
MockLargeIconService& operator=(const MockLargeIconService&) = delete;
~MockLargeIconService() override = default;
// LargeIconService overrides.
MOCK_METHOD(void,
GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache,
(const GURL& page_url,
bool should_trim_page_url_path,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
favicon_base::GoogleFaviconServerCallback callback),
(override));
MOCK_METHOD(base::CancelableTaskTracker::TaskId,
GetLargeIconRawBitmapOrFallbackStyleForPageUrl,
(const GURL& page_url,
int min_source_size_in_pixel,
int desired_size_in_pixel,
favicon_base::LargeIconCallback callback,
base::CancelableTaskTracker* tracker),
(override));
MOCK_METHOD(base::CancelableTaskTracker::TaskId,
GetLargeIconImageOrFallbackStyleForPageUrl,
(const GURL& page_url,
int min_source_size_in_pixel,
int desired_size_in_pixel,
favicon_base::LargeIconImageCallback callback,
base::CancelableTaskTracker* tracker),
(override));
MOCK_METHOD(
base::CancelableTaskTracker::TaskId,
GetLargeIconRawBitmapForPageUrl,
(const GURL& page_url,
int min_source_size_in_pixel,
std::optional<int> size_in_pixel_to_resize_to,
LargeIconService::NoBigEnoughIconBehavior no_big_enough_icon_behavior,
favicon_base::LargeIconCallback callback,
base::CancelableTaskTracker* tracker),
(override));
MOCK_METHOD(base::CancelableTaskTracker::TaskId,
GetLargeIconRawBitmapOrFallbackStyleForIconUrl,
(const GURL& icon_url,
int min_source_size_in_pixel,
int desired_size_in_pixel,
favicon_base::LargeIconCallback callback,
base::CancelableTaskTracker* tracker),
(override));
MOCK_METHOD(base::CancelableTaskTracker::TaskId,
GetIconRawBitmapOrFallbackStyleForPageUrl,
(const GURL& page_url,
int desired_size_in_pixel,
favicon_base::LargeIconCallback callback,
base::CancelableTaskTracker* tracker),
(override));
MOCK_METHOD(void,
GetLargeIconFromCacheFallbackToGoogleServer,
(const GURL& page_url,
StandardIconSize min_source_size_in_pixel,
std::optional<StandardIconSize> size_in_pixel_to_resize_to,
NoBigEnoughIconBehavior no_big_enough_icon_behavior,
bool should_trim_page_url_path,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
favicon_base::LargeIconCallback callback,
base::CancelableTaskTracker* tracker),
(override));
MOCK_METHOD(void,
TouchIconFromGoogleServer,
(const GURL& icon_url),
(override));
};
// FaviconFetcher is the class under test, however we need to mock some of its
// methods.
class MockFaviconFetcher : public ::FaviconFetcher {
public:
explicit MockFaviconFetcher(
raw_ptr<favicon::LargeIconService> large_icon_service)
: FaviconFetcher(large_icon_service) {}
MOCK_METHOD(void,
ExecuteFaviconCallback,
(const base::android::ScopedJavaGlobalRef<jobject>& callback,
SkBitmap bitmap),
(override));
};
class FaviconFetcherTest : public ::testing::Test {
public:
FaviconFetcherTest() = default;
FaviconFetcherTest(const FaviconFetcherTest&) = delete;
FaviconFetcherTest& operator=(const FaviconFetcherTest&) = delete;
protected:
MockLargeIconService mock_large_icon_service_;
raw_ptr<MockFaviconFetcher> favicon_fetcher_ =
new MockFaviconFetcher(&mock_large_icon_service_);
};
// Checks that an image was successfully returned from the server
// after an image fetch request. Checks that the image is returned to the
// caller and the fetcher object is successfully destroyed.
TEST_F(FaviconFetcherTest, SucessfullImageRequestSuccessfulImageFetch) {
// Successful image request from server.
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce(base::test::RunOnceCallback<3>(
favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
// Returns an empty image at first, then a valid image (after requesting it
// from server).
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconImageOrFallbackStyleForPageUrl(
testing::_, testing::_, testing::_, testing::_, testing::_))
.Times(2)
.WillOnce([=](auto, auto, auto,
favicon_base::LargeIconImageCallback image_callback, auto) {
std::move(image_callback).Run(CreateEmptyTestImageResult());
return kTaskId;
})
.WillOnce([=](auto, auto, auto,
favicon_base::LargeIconImageCallback image_callback, auto) {
std::move(image_callback).Run(CreateTestImageResult());
return kTaskId;
});
// Tests that favicon is returned to the caller (Android callback execution).
EXPECT_CALL(*favicon_fetcher_, ExecuteFaviconCallback(testing::_, testing::_))
.Times(1);
base::WeakPtr<FaviconFetcher> faviconFetcherWeakPtr =
favicon_fetcher_->GetWeakPtr();
favicon_fetcher_->FetchFavicon(StringToGURL("page.com"), true, 16, 32,
base::android::ScopedJavaGlobalRef<jobject>());
// Tests that the favicon_fetcher_ instance test is destroyed.
EXPECT_TRUE(faviconFetcherWeakPtr.WasInvalidated());
}
// Checks that an image that does not meet our specs is returned from the server
// after an image fetch request. Checks that no image is returned to the
// caller and the fetcher object is successfully destroyed.
TEST_F(FaviconFetcherTest, SucessfullImageRequestUnsuccessfulImageFetch) {
// Successful image request from server.
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce(base::test::RunOnceCallback<3>(
favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
// Returns an empty image twice (when image does not comply to our specs).
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconImageOrFallbackStyleForPageUrl(
testing::_, testing::_, testing::_, testing::_, testing::_))
.Times(2)
.WillRepeatedly([=](auto, auto, auto,
favicon_base::LargeIconImageCallback image_callback,
auto) {
std::move(image_callback).Run(CreateEmptyTestImageResult());
return kTaskId;
});
// No favicon is returned to the caller.
EXPECT_CALL(*favicon_fetcher_, ExecuteFaviconCallback(testing::_, testing::_))
.Times(0);
base::WeakPtr<FaviconFetcher> faviconFetcherWeakPtr =
favicon_fetcher_->GetWeakPtr();
favicon_fetcher_->FetchFavicon(StringToGURL("page.com"), true, 16, 32,
base::android::ScopedJavaGlobalRef<jobject>());
// Tests that the favicon_fetcher_ instance test is destroyed.
EXPECT_TRUE(faviconFetcherWeakPtr.WasInvalidated());
}
// Checks that an image is successfully returned from the cache without
// making a request to retrieve it from the server. Checks that the image is
// returned to the caller and the fetcher object is successfully destroyed.
TEST_F(FaviconFetcherTest, SuccessfullImageFetchFromCache) {
// Returns a valid image (already cached).
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconImageOrFallbackStyleForPageUrl(
testing::_, testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce([=](auto, auto, auto,
favicon_base::LargeIconImageCallback image_callback, auto) {
std::move(image_callback).Run(CreateTestImageResult());
return kTaskId;
});
// Tests that favicon is returned to the caller (Android callback execution).
EXPECT_CALL(*favicon_fetcher_, ExecuteFaviconCallback(testing::_, testing::_))
.Times(1);
// No server request is done when image exists in cache.
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
testing::_, testing::_, testing::_, testing::_))
.Times(0);
base::WeakPtr<FaviconFetcher> faviconFetcherWeakPtr =
favicon_fetcher_->GetWeakPtr();
favicon_fetcher_->FetchFavicon(StringToGURL("page.com"), true, 16, 32,
base::android::ScopedJavaGlobalRef<jobject>());
// Tests that the favicon_fetcher_ instance test is destroyed.
EXPECT_TRUE(faviconFetcherWeakPtr.WasInvalidated());
}
// Checks that no image is successfuly returned from the server after requesting
// it. Checks that no image is returned to the caller and the fetcher object is
// successfully destroyed.
TEST_F(FaviconFetcherTest, UnuccessfullImageRequest) {
// Unsuccessful image request from server.
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce(base::test::RunOnceCallback<3>(
favicon_base::GoogleFaviconServerRequestStatus::FAILURE_HTTP_ERROR));
// Returns an empty image.
EXPECT_CALL(mock_large_icon_service_,
GetLargeIconImageOrFallbackStyleForPageUrl(
testing::_, testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce([=](auto, auto, auto,
favicon_base::LargeIconImageCallback image_callback, auto) {
std::move(image_callback).Run(CreateEmptyTestImageResult());
return kTaskId;
});
// Nothing is returned to the caller.
EXPECT_CALL(*favicon_fetcher_, ExecuteFaviconCallback(testing::_, testing::_))
.Times(0);
base::WeakPtr<FaviconFetcher> faviconFetcherWeakPtr =
favicon_fetcher_->GetWeakPtr();
favicon_fetcher_->FetchFavicon(StringToGURL("page.com"), true, 16, 32,
base::android::ScopedJavaGlobalRef<jobject>());
// Tests that the favicon_fetcher_ instance test is destroyed.
EXPECT_TRUE(faviconFetcherWeakPtr.WasInvalidated());
}
} // namespace