blob: 009e6785a070bc3b25b8f0cc8b79e924453c70fa [file] [log] [blame]
// Copyright 2016 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.
#import "ios/chrome/browser/ui/history/favicon_view_provider.h"
#include <memory>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/sys_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/large_icon_service.h"
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
#include "ios/chrome/browser/chrome_paths.h"
#include "ios/web/public/test/test_web_thread.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
#include "skia/ext/skia_utils_ios.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#include "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/gtest_support.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface FaviconViewProvider (Testing)
@property(nonatomic, retain) UIImage* favicon;
@property(nonatomic, copy) NSString* fallbackText;
@property(nonatomic, retain) UIColor* fallbackBackgroundColor;
@property(nonatomic, retain) UIColor* fallbackTextColor;
@end
namespace {
using favicon::PostReply;
using testing::_;
// Dummy URL for the favicon case.
const char kTestFaviconURL[] = "http://test/favicon";
// Dummy URL for the fallback case.
const char kTestFallbackURL[] = "http://test/fallback";
// Dummy icon URL.
const char kTestFaviconIconURL[] = "http://test/icons/favicon";
// Size of dummy favicon image.
const CGFloat kTestFaviconSize = 57;
favicon_base::FaviconRawBitmapResult CreateTestBitmap() {
favicon_base::FaviconRawBitmapResult result;
result.expired = false;
base::FilePath favicon_path;
PathService::Get(ios::DIR_TEST_DATA, &favicon_path);
favicon_path =
favicon_path.Append(FILE_PATH_LITERAL("favicon/test_favicon.png"));
NSData* favicon_data = [NSData
dataWithContentsOfFile:base::SysUTF8ToNSString(favicon_path.value())];
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes(
static_cast<const unsigned char*>([favicon_data bytes]),
[favicon_data length]));
result.bitmap_data = data;
CGFloat scaled_size = [UIScreen mainScreen].scale * kTestFaviconSize;
result.pixel_size = gfx::Size(scaled_size, scaled_size);
result.icon_url = GURL(kTestFaviconIconURL);
result.icon_type = favicon_base::TOUCH_ICON;
CHECK(result.is_valid());
return result;
}
class FaviconViewProviderTest : public PlatformTest {
protected:
void SetUp() override {
DCHECK_CURRENTLY_ON(web::WebThread::UI);
PlatformTest::SetUp();
large_icon_service_.reset(new favicon::LargeIconService(
&mock_favicon_service_, base::ThreadTaskRunnerHandle::Get(),
/*image_fetcher=*/nullptr));
EXPECT_CALL(mock_favicon_service_, GetLargestRawFaviconForPageURL(
GURL(kTestFaviconURL), _, _, _, _))
.WillRepeatedly(PostReply<5>(CreateTestBitmap()));
}
web::TestWebThreadBundle thread_bundle_;
testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_;
std::unique_ptr<favicon::LargeIconService> large_icon_service_;
base::CancelableTaskTracker cancelable_task_tracker_;
};
// Tests that image is set when a favicon is returned from LargeIconService.
TEST_F(FaviconViewProviderTest, Favicon) {
id mock_delegate =
[OCMockObject mockForProtocol:@protocol(FaviconViewProviderDelegate)];
FaviconViewProvider* viewProvider =
[[FaviconViewProvider alloc] initWithURL:GURL(kTestFaviconURL)
faviconSize:kTestFaviconSize
minFaviconSize:kTestFaviconSize
largeIconService:large_icon_service_.get()
delegate:mock_delegate];
void (^confirmationBlock)(NSInvocation*) = ^(NSInvocation* invocation) {
__unsafe_unretained FaviconViewProvider* viewProvider;
[invocation getArgument:&viewProvider atIndex:2];
EXPECT_NSNE(nil, viewProvider.favicon);
};
[[[mock_delegate stub] andDo:confirmationBlock]
faviconViewProviderFaviconDidLoad:viewProvider];
EXPECT_OCMOCK_VERIFY(mock_delegate);
}
// Tests that fallback data is set when no favicon is returned from
// LargeIconService.
TEST_F(FaviconViewProviderTest, FallbackIcon) {
EXPECT_CALL(mock_favicon_service_, GetLargestRawFaviconForPageURL(
GURL(kTestFallbackURL), _, _, _, _))
.WillRepeatedly(PostReply<5>(favicon_base::FaviconRawBitmapResult()));
id mock_delegate =
[OCMockObject mockForProtocol:@protocol(FaviconViewProviderDelegate)];
FaviconViewProvider* item =
[[FaviconViewProvider alloc] initWithURL:GURL(kTestFallbackURL)
faviconSize:kTestFaviconSize
minFaviconSize:kTestFaviconSize
largeIconService:large_icon_service_.get()
delegate:mock_delegate];
// Confirm that fallback text and color have been set before delegate call.
void (^confirmationBlock)(NSInvocation*) = ^(NSInvocation* invocation) {
__unsafe_unretained FaviconViewProvider* viewProvider;
[invocation getArgument:&viewProvider atIndex:2];
// Fallback text is the first letter of the URL.
NSString* defaultText = @"T";
// Default colors are defined in
// components/favicon_base/fallback_icon_style.h.
UIColor* defaultTextColor = skia::UIColorFromSkColor(SK_ColorWHITE);
UIColor* defaultBackgroundColor =
skia::UIColorFromSkColor(SkColorSetRGB(0x78, 0x78, 0x78));
EXPECT_NSEQ(defaultText, viewProvider.fallbackText);
EXPECT_NSEQ(defaultTextColor, viewProvider.fallbackTextColor);
EXPECT_NSEQ(defaultBackgroundColor, viewProvider.fallbackBackgroundColor);
};
[[[mock_delegate stub] andDo:confirmationBlock]
faviconViewProviderFaviconDidLoad:item];
EXPECT_OCMOCK_VERIFY(mock_delegate);
}
} // namespace