Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / favicon / favicon_handler_unittest.cc
blob08cc59a34689953d36a0c1ce77999239acb04c59
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.
5 #include "base/memory/scoped_ptr.h"
6 #include "chrome/browser/favicon/favicon_handler.h"
7 #include "chrome/browser/favicon/favicon_service_factory.h"
8 #include "chrome/browser/history/history_service_factory.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
11 #include "content/public/browser/favicon_status.h"
12 #include "content/public/browser/invalidate_type.h"
13 #include "content/public/browser/navigation_entry.h"
14 #include "content/public/browser/web_contents.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "ui/gfx/codec/png_codec.h"
17 #include "ui/gfx/favicon_size.h"
18 #include "ui/gfx/image/image.h"
20 class TestFaviconHandler;
22 using content::FaviconURL;
23 using content::NavigationEntry;
24 using content::WebContents;
26 namespace {
28 // Fill the given bmp with valid png data.
29 void FillDataToBitmap(int w, int h, SkBitmap* bmp) {
30 bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
31 bmp->allocPixels();
33 unsigned char* src_data =
34 reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0));
35 for (int i = 0; i < w * h; i++) {
36 src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255);
37 src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255);
38 src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255);
39 src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255);
43 // Fill the given data buffer with valid png data.
44 void FillBitmap(int w, int h, std::vector<unsigned char>* output) {
45 SkBitmap bitmap;
46 FillDataToBitmap(w, h, &bitmap);
47 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, output);
50 void SetFaviconBitmapResult(
51 const GURL& icon_url,
52 chrome::IconType icon_type,
53 bool expired,
54 std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
55 scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
56 FillBitmap(gfx::kFaviconSize, gfx::kFaviconSize, &data->data());
57 chrome::FaviconBitmapResult bitmap_result;
58 bitmap_result.expired = expired;
59 bitmap_result.bitmap_data = data;
60 // Use a pixel size other than (0,0) as (0,0) has a special meaning.
61 bitmap_result.pixel_size = gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize);
62 bitmap_result.icon_type = icon_type;
63 bitmap_result.icon_url = icon_url;
65 favicon_bitmap_results->push_back(bitmap_result);
68 void SetFaviconBitmapResult(
69 const GURL& icon_url,
70 std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) {
71 SetFaviconBitmapResult(icon_url, chrome::FAVICON, false /* expired */,
72 favicon_bitmap_results);
75 // This class is used to save the download request for verifying with test case.
76 // It also will be used to invoke the onDidDownload callback.
77 class DownloadHandler {
78 public:
79 explicit DownloadHandler(TestFaviconHandler* favicon_helper)
80 : favicon_helper_(favicon_helper),
81 failed_(false) {
84 virtual ~DownloadHandler() {
87 void Reset() {
88 download_.reset(NULL);
89 failed_ = false;
92 void AddDownload(
93 int download_id,
94 const GURL& image_url,
95 int image_size,
96 int max_image_size) {
97 download_.reset(new Download(
98 download_id, image_url, image_size, max_image_size, false));
101 void InvokeCallback();
103 void set_failed(bool failed) { failed_ = failed; }
105 bool HasDownload() const { return download_.get() != NULL; }
106 const GURL& GetImageUrl() const { return download_->image_url; }
107 void SetImageSize(int size) { download_->image_size = size; }
109 private:
110 struct Download {
111 Download(int id, GURL url, int size, int max_size, bool failed)
112 : download_id(id),
113 image_url(url),
114 image_size(size),
115 max_image_size(max_size) {}
116 ~Download() {}
117 int download_id;
118 GURL image_url;
119 int image_size;
120 int max_image_size;
123 TestFaviconHandler* favicon_helper_;
124 scoped_ptr<Download> download_;
125 bool failed_;
127 DISALLOW_COPY_AND_ASSIGN(DownloadHandler);
130 // This class is used to save the history request for verifying with test case.
131 // It also will be used to simulate the history response.
132 class HistoryRequestHandler {
133 public:
134 HistoryRequestHandler(const GURL& page_url,
135 const GURL& icon_url,
136 int icon_type,
137 const FaviconService::FaviconResultsCallback& callback)
138 : page_url_(page_url),
139 icon_url_(icon_url),
140 icon_type_(icon_type),
141 callback_(callback) {
144 HistoryRequestHandler(const GURL& page_url,
145 const GURL& icon_url,
146 int icon_type,
147 const std::vector<unsigned char>& bitmap_data)
148 : page_url_(page_url),
149 icon_url_(icon_url),
150 icon_type_(icon_type),
151 bitmap_data_(bitmap_data) {
154 virtual ~HistoryRequestHandler() {}
155 void InvokeCallback();
157 const GURL page_url_;
158 const GURL icon_url_;
159 const int icon_type_;
160 const std::vector<unsigned char> bitmap_data_;
161 std::vector<chrome::FaviconBitmapResult> history_results_;
162 FaviconService::FaviconResultsCallback callback_;
164 private:
165 DISALLOW_COPY_AND_ASSIGN(HistoryRequestHandler);
168 } // namespace
171 class TestFaviconHandlerDelegate : public FaviconHandlerDelegate {
172 public:
173 TestFaviconHandlerDelegate() {
176 virtual ~TestFaviconHandlerDelegate() {
179 virtual NavigationEntry* GetActiveEntry() OVERRIDE {
180 ADD_FAILURE() << "TestFaviconHandlerDelegate::GetActiveEntry() "
181 << "should never be called in tests.";
182 return NULL;
185 virtual int StartDownload(const GURL& url,
186 int max_bitmap_size) OVERRIDE {
187 ADD_FAILURE() << "TestFaviconHandlerDelegate::StartDownload() "
188 << "should never be called in tests.";
189 return -1;
192 virtual void NotifyFaviconUpdated(bool icon_url_changed) OVERRIDE {
193 ADD_FAILURE() << "TestFaviconHandlerDelegate::NotifyFaviconUpdated() "
194 << "should never be called in tests.";
197 private:
198 DISALLOW_COPY_AND_ASSIGN(TestFaviconHandlerDelegate);
201 // This class is used to catch the FaviconHandler's download and history
202 // request, and also provide the methods to access the FaviconHandler
203 // internals.
204 class TestFaviconHandler : public FaviconHandler {
205 public:
206 TestFaviconHandler(const GURL& page_url,
207 Profile* profile,
208 FaviconHandlerDelegate* delegate,
209 Type type)
210 : FaviconHandler(profile, delegate, type),
211 entry_(NavigationEntry::Create()),
212 download_id_(0),
213 num_favicon_updates_(0) {
214 entry_->SetURL(page_url);
215 download_handler_.reset(new DownloadHandler(this));
218 virtual ~TestFaviconHandler() {
221 HistoryRequestHandler* history_handler() {
222 return history_handler_.get();
225 // This method will take the ownership of the given handler.
226 void set_history_handler(HistoryRequestHandler* handler) {
227 history_handler_.reset(handler);
230 DownloadHandler* download_handler() {
231 return download_handler_.get();
234 size_t num_favicon_update_notifications() const {
235 return num_favicon_updates_;
238 void ResetNumFaviconUpdateNotifications() {
239 num_favicon_updates_ = 0;
242 // Methods to access favicon internals.
243 virtual NavigationEntry* GetEntry() OVERRIDE {
244 return entry_.get();
247 const std::deque<FaviconURL>& urls() {
248 return image_urls_;
251 FaviconURL* current_candidate() {
252 return FaviconHandler::current_candidate();
255 protected:
256 virtual void UpdateFaviconMappingAndFetch(
257 const GURL& page_url,
258 const GURL& icon_url,
259 chrome::IconType icon_type,
260 const FaviconService::FaviconResultsCallback& callback,
261 CancelableTaskTracker* tracker) OVERRIDE {
262 history_handler_.reset(new HistoryRequestHandler(page_url, icon_url,
263 icon_type, callback));
266 virtual void GetFavicon(
267 const GURL& icon_url,
268 chrome::IconType icon_type,
269 const FaviconService::FaviconResultsCallback& callback,
270 CancelableTaskTracker* tracker) OVERRIDE {
271 history_handler_.reset(new HistoryRequestHandler(GURL(), icon_url,
272 icon_type, callback));
275 virtual void GetFaviconForURL(
276 const GURL& page_url,
277 int icon_types,
278 const FaviconService::FaviconResultsCallback& callback,
279 CancelableTaskTracker* tracker) OVERRIDE {
280 history_handler_.reset(new HistoryRequestHandler(page_url, GURL(),
281 icon_types, callback));
284 virtual int DownloadFavicon(const GURL& image_url,
285 int max_bitmap_size) OVERRIDE {
286 download_id_++;
287 download_handler_->AddDownload(
288 download_id_, image_url, 0, max_bitmap_size);
289 return download_id_;
292 virtual void SetHistoryFavicons(const GURL& page_url,
293 const GURL& icon_url,
294 chrome::IconType icon_type,
295 const gfx::Image& image) OVERRIDE {
296 scoped_refptr<base::RefCountedMemory> bytes = image.As1xPNGBytes();
297 std::vector<unsigned char> bitmap_data(bytes->front(),
298 bytes->front() + bytes->size());
299 history_handler_.reset(new HistoryRequestHandler(
300 page_url, icon_url, icon_type, bitmap_data));
303 virtual FaviconService* GetFaviconService() OVERRIDE {
304 // Just give none NULL value, so overridden methods can be hit.
305 return (FaviconService*)(1);
308 virtual bool ShouldSaveFavicon(const GURL& url) OVERRIDE {
309 return true;
312 virtual void NotifyFaviconUpdated(bool icon_url_changed) OVERRIDE {
313 ++num_favicon_updates_;
316 GURL page_url_;
318 private:
319 scoped_ptr<NavigationEntry> entry_;
321 // The unique id of a download request. It will be returned to a
322 // FaviconHandler.
323 int download_id_;
325 scoped_ptr<DownloadHandler> download_handler_;
326 scoped_ptr<HistoryRequestHandler> history_handler_;
328 // The number of times that NotifyFaviconUpdated() has been called.
329 size_t num_favicon_updates_;
331 DISALLOW_COPY_AND_ASSIGN(TestFaviconHandler);
334 namespace {
336 void HistoryRequestHandler::InvokeCallback() {
337 if (!callback_.is_null()) {
338 callback_.Run(history_results_);
342 void DownloadHandler::InvokeCallback() {
343 int original_size = (download_->image_size > 0) ?
344 download_->image_size : gfx::kFaviconSize;
345 int downloaded_size = original_size;
346 if (download_->max_image_size != 0 &&
347 downloaded_size > download_->max_image_size) {
348 downloaded_size = download_->max_image_size;
350 std::vector<SkBitmap> bitmaps;
351 std::vector<gfx::Size> original_bitmap_sizes;
352 if (!failed_) {
353 SkBitmap bitmap;
354 FillDataToBitmap(downloaded_size, downloaded_size, &bitmap);
355 bitmaps.push_back(bitmap);
356 original_bitmap_sizes.push_back(gfx::Size(original_size, original_size));
358 favicon_helper_->OnDidDownloadFavicon(download_->download_id,
359 download_->image_url,
360 bitmaps,
361 original_bitmap_sizes);
364 class FaviconHandlerTest : public ChromeRenderViewHostTestHarness {
365 public:
366 FaviconHandlerTest() {
369 virtual ~FaviconHandlerTest() {
372 // Simulates requesting a favicon for |page_url| given:
373 // - We have not previously cached anything in history for |page_url| or for
374 // any of |candidates|.
375 // - The page provides favicons at |candidate_icons|.
376 // - The favicons at |candidate_icons| have edge pixel sizes of
377 // |candidate_icon_sizes|.
378 void DownloadTillDoneIgnoringHistory(
379 TestFaviconHandler* favicon_handler,
380 const GURL& page_url,
381 const std::vector<FaviconURL>& candidate_icons,
382 const int* candidate_icon_sizes) {
383 favicon_handler->ResetNumFaviconUpdateNotifications();
385 favicon_handler->FetchFavicon(page_url);
386 favicon_handler->history_handler()->InvokeCallback();
388 favicon_handler->OnUpdateFaviconURL(0, candidate_icons);
389 EXPECT_EQ(candidate_icons.size(), favicon_handler->image_urls().size());
391 DownloadHandler* download_handler = favicon_handler->download_handler();
392 for (size_t i = 0; i < candidate_icons.size(); ++i) {
393 favicon_handler->history_handler()->history_results_.clear();
394 favicon_handler->history_handler()->InvokeCallback();
395 ASSERT_TRUE(download_handler->HasDownload());
396 EXPECT_EQ(download_handler->GetImageUrl(),
397 candidate_icons[i].icon_url);
398 download_handler->SetImageSize(candidate_icon_sizes[i]);
399 download_handler->InvokeCallback();
401 if (favicon_handler->num_favicon_update_notifications())
402 return;
406 virtual void SetUp() {
407 // The score computed by SelectFaviconFrames() is dependent on the supported
408 // scale factors of the platform. It is used for determining the goodness of
409 // a downloaded bitmap in FaviconHandler::OnDidDownloadFavicon().
410 // Force the values of the scale factors so that the tests produce the same
411 // results on all platforms.
412 std::vector<ui::ScaleFactor> scale_factors;
413 scale_factors.push_back(ui::SCALE_FACTOR_100P);
414 scoped_set_supported_scale_factors_.reset(
415 new ui::test::ScopedSetSupportedScaleFactors(scale_factors));
417 ChromeRenderViewHostTestHarness::SetUp();
420 virtual void TearDown() OVERRIDE {
421 Profile* profile = Profile::FromBrowserContext(
422 web_contents()->GetBrowserContext());
423 FaviconServiceFactory::GetInstance()->SetTestingFactory(
424 profile, NULL);
425 ChromeRenderViewHostTestHarness::TearDown();
428 private:
429 typedef scoped_ptr<ui::test::ScopedSetSupportedScaleFactors>
430 ScopedSetSupportedScaleFactors;
431 ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_;
432 DISALLOW_COPY_AND_ASSIGN(FaviconHandlerTest);
435 TEST_F(FaviconHandlerTest, GetFaviconFromHistory) {
436 const GURL page_url("http://www.google.com");
437 const GURL icon_url("http://www.google.com/favicon");
439 TestFaviconHandlerDelegate delegate;
440 Profile* profile = Profile::FromBrowserContext(
441 web_contents()->GetBrowserContext());
442 TestFaviconHandler helper(page_url, profile,
443 &delegate, FaviconHandler::FAVICON);
445 helper.FetchFavicon(page_url);
446 HistoryRequestHandler* history_handler = helper.history_handler();
447 // Ensure the data given to history is correct.
448 ASSERT_TRUE(history_handler);
449 EXPECT_EQ(page_url, history_handler->page_url_);
450 EXPECT_EQ(GURL(), history_handler->icon_url_);
451 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_);
453 SetFaviconBitmapResult(icon_url, &history_handler->history_results_);
455 // Send history response.
456 history_handler->InvokeCallback();
457 // Verify FaviconHandler status
458 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid);
459 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url);
461 // Simulates update favicon url.
462 std::vector<FaviconURL> urls;
463 urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
464 helper.OnUpdateFaviconURL(0, urls);
466 // Verify FaviconHandler status
467 EXPECT_EQ(1U, helper.urls().size());
468 ASSERT_TRUE(helper.current_candidate());
469 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
470 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
472 // Favicon shouldn't request to download icon.
473 EXPECT_FALSE(helper.download_handler()->HasDownload());
476 TEST_F(FaviconHandlerTest, DownloadFavicon) {
477 const GURL page_url("http://www.google.com");
478 const GURL icon_url("http://www.google.com/favicon");
480 TestFaviconHandlerDelegate delegate;
481 Profile* profile = Profile::FromBrowserContext(
482 web_contents()->GetBrowserContext());
483 TestFaviconHandler helper(page_url, profile,
484 &delegate, FaviconHandler::FAVICON);
486 helper.FetchFavicon(page_url);
487 HistoryRequestHandler* history_handler = helper.history_handler();
488 // Ensure the data given to history is correct.
489 ASSERT_TRUE(history_handler);
490 EXPECT_EQ(page_url, history_handler->page_url_);
491 EXPECT_EQ(GURL(), history_handler->icon_url_);
492 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_);
494 // Set icon data expired
495 SetFaviconBitmapResult(icon_url, chrome::FAVICON, true /* expired */,
496 &history_handler->history_results_);
497 // Send history response.
498 history_handler->InvokeCallback();
499 // Verify FaviconHandler status
500 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid);
501 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url);
503 // Simulates update favicon url.
504 std::vector<FaviconURL> urls;
505 urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
506 helper.OnUpdateFaviconURL(0, urls);
508 // Verify FaviconHandler status
509 EXPECT_EQ(1U, helper.urls().size());
510 ASSERT_TRUE(helper.current_candidate());
511 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
512 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
514 // Favicon should request to download icon now.
515 DownloadHandler* download_handler = helper.download_handler();
516 EXPECT_TRUE(helper.download_handler()->HasDownload());
518 // Verify the download request.
519 EXPECT_EQ(icon_url, download_handler->GetImageUrl());
521 // Reset the history_handler to verify whether favicon is set.
522 helper.set_history_handler(NULL);
524 // Smulates download done.
525 download_handler->InvokeCallback();
527 // New icon should be saved to history backend and navigation entry.
528 history_handler = helper.history_handler();
529 ASSERT_TRUE(history_handler);
530 EXPECT_EQ(icon_url, history_handler->icon_url_);
531 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
532 EXPECT_LT(0U, history_handler->bitmap_data_.size());
533 EXPECT_EQ(page_url, history_handler->page_url_);
535 // Verify NavigationEntry.
536 content::FaviconStatus favicon_status = helper.GetEntry()->GetFavicon();
537 EXPECT_EQ(icon_url, favicon_status.url);
538 EXPECT_TRUE(favicon_status.valid);
539 EXPECT_FALSE(favicon_status.image.IsEmpty());
540 EXPECT_EQ(gfx::kFaviconSize, favicon_status.image.Width());
543 TEST_F(FaviconHandlerTest, UpdateAndDownloadFavicon) {
544 const GURL page_url("http://www.google.com");
545 const GURL icon_url("http://www.google.com/favicon");
546 const GURL new_icon_url("http://www.google.com/new_favicon");
548 TestFaviconHandlerDelegate delegate;
549 Profile* profile = Profile::FromBrowserContext(
550 web_contents()->GetBrowserContext());
551 TestFaviconHandler helper(page_url, profile,
552 &delegate, FaviconHandler::FAVICON);
554 helper.FetchFavicon(page_url);
555 HistoryRequestHandler* history_handler = helper.history_handler();
556 // Ensure the data given to history is correct.
557 ASSERT_TRUE(history_handler);
558 EXPECT_EQ(page_url, history_handler->page_url_);
559 EXPECT_EQ(GURL(), history_handler->icon_url_);
560 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_);
562 // Set valid icon data.
563 SetFaviconBitmapResult(icon_url, &history_handler->history_results_);
565 // Send history response.
566 history_handler->InvokeCallback();
567 // Verify FaviconHandler status.
568 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid);
569 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url);
571 // Reset the history_handler to verify whether new icon is requested from
572 // history.
573 helper.set_history_handler(NULL);
575 // Simulates update with the different favicon url.
576 std::vector<FaviconURL> urls;
577 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
578 helper.OnUpdateFaviconURL(0, urls);
580 // Verify FaviconHandler status.
581 EXPECT_EQ(1U, helper.urls().size());
582 ASSERT_TRUE(helper.current_candidate());
583 ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
584 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
586 // Favicon should be requested from history.
587 history_handler = helper.history_handler();
588 ASSERT_TRUE(history_handler);
589 EXPECT_EQ(new_icon_url, history_handler->icon_url_);
590 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
591 EXPECT_EQ(page_url, history_handler->page_url_);
593 // Simulate not find icon.
594 history_handler->history_results_.clear();
595 history_handler->InvokeCallback();
597 // Favicon should request to download icon now.
598 DownloadHandler* download_handler = helper.download_handler();
599 EXPECT_TRUE(helper.download_handler()->HasDownload());
601 // Verify the download request.
602 EXPECT_EQ(new_icon_url, download_handler->GetImageUrl());
604 // Reset the history_handler to verify whether favicon is set.
605 helper.set_history_handler(NULL);
607 // Smulates download done.
608 download_handler->InvokeCallback();
610 // New icon should be saved to history backend and navigation entry.
611 history_handler = helper.history_handler();
612 ASSERT_TRUE(history_handler);
613 EXPECT_EQ(new_icon_url, history_handler->icon_url_);
614 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
615 EXPECT_LT(0U, history_handler->bitmap_data_.size());
616 EXPECT_EQ(page_url, history_handler->page_url_);
618 // Verify NavigationEntry.
619 content::FaviconStatus favicon_status = helper.GetEntry()->GetFavicon();
620 EXPECT_EQ(new_icon_url, favicon_status.url);
621 EXPECT_TRUE(favicon_status.valid);
622 EXPECT_FALSE(favicon_status.image.IsEmpty());
623 EXPECT_EQ(gfx::kFaviconSize, favicon_status.image.Width());
626 TEST_F(FaviconHandlerTest, FaviconInHistoryInvalid) {
627 const GURL page_url("http://www.google.com");
628 const GURL icon_url("http://www.google.com/favicon");
630 TestFaviconHandlerDelegate delegate;
631 Profile* profile = Profile::FromBrowserContext(
632 web_contents()->GetBrowserContext());
633 TestFaviconHandler helper(page_url, profile,
634 &delegate, FaviconHandler::FAVICON);
636 helper.FetchFavicon(page_url);
637 HistoryRequestHandler* history_handler = helper.history_handler();
638 // Ensure the data given to history is correct.
639 ASSERT_TRUE(history_handler);
640 EXPECT_EQ(page_url, history_handler->page_url_);
641 EXPECT_EQ(GURL(), history_handler->icon_url_);
642 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_);
644 // Set non empty but invalid data.
645 chrome::FaviconBitmapResult bitmap_result;
646 bitmap_result.expired = false;
647 // Empty bitmap data is invalid.
648 bitmap_result.bitmap_data = new base::RefCountedBytes();
649 bitmap_result.pixel_size = gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize);
650 bitmap_result.icon_type = chrome::FAVICON;
651 bitmap_result.icon_url = icon_url;
652 history_handler->history_results_.clear();
653 history_handler->history_results_.push_back(bitmap_result);
655 // Send history response.
656 history_handler->InvokeCallback();
657 // The NavigationEntry should not be set yet as the history data is invalid.
658 EXPECT_FALSE(helper.GetEntry()->GetFavicon().valid);
659 EXPECT_EQ(GURL(), helper.GetEntry()->GetFavicon().url);
661 // Reset the history_handler to verify whether new icon is requested from
662 // history.
663 helper.set_history_handler(NULL);
665 // Simulates update with matching favicon URL.
666 std::vector<FaviconURL> urls;
667 urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
668 helper.OnUpdateFaviconURL(0, urls);
670 // A download for the favicon should be requested, and we should not do
671 // another history request.
672 DownloadHandler* download_handler = helper.download_handler();
673 EXPECT_TRUE(helper.download_handler()->HasDownload());
674 EXPECT_EQ(NULL, helper.history_handler());
676 // Verify the download request.
677 EXPECT_EQ(icon_url, download_handler->GetImageUrl());
679 // Simulates download done.
680 download_handler->InvokeCallback();
682 // New icon should be saved to history backend and navigation entry.
683 history_handler = helper.history_handler();
684 ASSERT_TRUE(history_handler);
685 EXPECT_EQ(icon_url, history_handler->icon_url_);
686 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
687 EXPECT_LT(0U, history_handler->bitmap_data_.size());
688 EXPECT_EQ(page_url, history_handler->page_url_);
690 // Verify NavigationEntry.
691 content::FaviconStatus favicon_status = helper.GetEntry()->GetFavicon();
692 EXPECT_EQ(icon_url, favicon_status.url);
693 EXPECT_TRUE(favicon_status.valid);
694 EXPECT_FALSE(favicon_status.image.IsEmpty());
695 EXPECT_EQ(gfx::kFaviconSize, favicon_status.image.Width());
698 TEST_F(FaviconHandlerTest, UpdateFavicon) {
699 const GURL page_url("http://www.google.com");
700 const GURL icon_url("http://www.google.com/favicon");
701 const GURL new_icon_url("http://www.google.com/new_favicon");
703 TestFaviconHandlerDelegate delegate;
704 Profile* profile = Profile::FromBrowserContext(
705 web_contents()->GetBrowserContext());
706 TestFaviconHandler helper(page_url, profile,
707 &delegate, FaviconHandler::FAVICON);
709 helper.FetchFavicon(page_url);
710 HistoryRequestHandler* history_handler = helper.history_handler();
711 // Ensure the data given to history is correct.
712 ASSERT_TRUE(history_handler);
713 EXPECT_EQ(page_url, history_handler->page_url_);
714 EXPECT_EQ(GURL(), history_handler->icon_url_);
715 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_);
717 SetFaviconBitmapResult(icon_url, &history_handler->history_results_);
719 // Send history response.
720 history_handler->InvokeCallback();
721 // Verify FaviconHandler status.
722 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid);
723 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url);
725 // Reset the history_handler to verify whether new icon is requested from
726 // history.
727 helper.set_history_handler(NULL);
729 // Simulates update with the different favicon url.
730 std::vector<FaviconURL> urls;
731 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
732 helper.OnUpdateFaviconURL(0, urls);
734 // Verify FaviconHandler status.
735 EXPECT_EQ(1U, helper.urls().size());
736 ASSERT_TRUE(helper.current_candidate());
737 ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
738 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
740 // Favicon should be requested from history.
741 history_handler = helper.history_handler();
742 ASSERT_TRUE(history_handler);
743 EXPECT_EQ(new_icon_url, history_handler->icon_url_);
744 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
745 EXPECT_EQ(page_url, history_handler->page_url_);
747 // Simulate find icon.
748 SetFaviconBitmapResult(new_icon_url, &history_handler->history_results_);
749 history_handler->InvokeCallback();
751 // Shouldn't request download favicon
752 EXPECT_FALSE(helper.download_handler()->HasDownload());
754 // Verify the favicon status.
755 EXPECT_EQ(new_icon_url, helper.GetEntry()->GetFavicon().url);
756 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid);
757 EXPECT_FALSE(helper.GetEntry()->GetFavicon().image.IsEmpty());
760 TEST_F(FaviconHandlerTest, Download2ndFaviconURLCandidate) {
761 const GURL page_url("http://www.google.com");
762 const GURL icon_url("http://www.google.com/favicon");
763 const GURL new_icon_url("http://www.google.com/new_favicon");
765 TestFaviconHandlerDelegate delegate;
766 Profile* profile = Profile::FromBrowserContext(
767 web_contents()->GetBrowserContext());
768 TestFaviconHandler helper(page_url, profile,
769 &delegate, FaviconHandler::TOUCH);
771 helper.FetchFavicon(page_url);
772 HistoryRequestHandler* history_handler = helper.history_handler();
773 // Ensure the data given to history is correct.
774 ASSERT_TRUE(history_handler);
775 EXPECT_EQ(page_url, history_handler->page_url_);
776 EXPECT_EQ(GURL(), history_handler->icon_url_);
777 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON,
778 history_handler->icon_type_);
780 // Icon not found.
781 history_handler->history_results_.clear();
782 // Send history response.
783 history_handler->InvokeCallback();
784 // Verify FaviconHandler status.
785 EXPECT_FALSE(helper.GetEntry()->GetFavicon().valid);
786 EXPECT_EQ(GURL(), helper.GetEntry()->GetFavicon().url);
788 // Reset the history_handler to verify whether new icon is requested from
789 // history.
790 helper.set_history_handler(NULL);
792 // Simulates update with the different favicon url.
793 std::vector<FaviconURL> urls;
794 urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON));
795 urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON));
796 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
797 helper.OnUpdateFaviconURL(0, urls);
799 // Verify FaviconHandler status.
800 EXPECT_EQ(2U, helper.urls().size());
801 ASSERT_TRUE(helper.current_candidate());
802 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
803 ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON,
804 helper.current_candidate()->icon_type);
806 // Favicon should be requested from history.
807 history_handler = helper.history_handler();
808 ASSERT_TRUE(history_handler);
809 EXPECT_EQ(icon_url, history_handler->icon_url_);
810 EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
811 EXPECT_EQ(page_url, history_handler->page_url_);
813 // Simulate not find icon.
814 history_handler->history_results_.clear();
815 history_handler->InvokeCallback();
817 // Should request download favicon.
818 DownloadHandler* download_handler = helper.download_handler();
819 EXPECT_TRUE(helper.download_handler()->HasDownload());
821 // Verify the download request.
822 EXPECT_EQ(icon_url, download_handler->GetImageUrl());
824 // Reset the history_handler to verify whether favicon is request from
825 // history.
826 helper.set_history_handler(NULL);
827 // Smulates download failed.
828 download_handler->set_failed(true);
829 download_handler->InvokeCallback();
831 // Left 1 url.
832 EXPECT_EQ(1U, helper.urls().size());
833 ASSERT_TRUE(helper.current_candidate());
834 EXPECT_EQ(new_icon_url, helper.current_candidate()->icon_url);
835 EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type);
837 // Favicon should be requested from history.
838 history_handler = helper.history_handler();
839 ASSERT_TRUE(history_handler);
840 EXPECT_EQ(new_icon_url, history_handler->icon_url_);
841 EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
842 EXPECT_EQ(page_url, history_handler->page_url_);
844 // Reset download handler
845 download_handler->Reset();
847 // Simulates getting a expired icon from history.
848 SetFaviconBitmapResult(new_icon_url, chrome::TOUCH_ICON,
849 true /* expired */, &history_handler->history_results_);
850 history_handler->InvokeCallback();
852 // Verify the download request.
853 EXPECT_TRUE(helper.download_handler()->HasDownload());
854 EXPECT_EQ(new_icon_url, download_handler->GetImageUrl());
856 helper.set_history_handler(NULL);
858 // Simulates icon being downloaded.
859 download_handler->InvokeCallback();
861 // New icon should be saved to history backend.
862 history_handler = helper.history_handler();
863 ASSERT_TRUE(history_handler);
864 EXPECT_EQ(new_icon_url, history_handler->icon_url_);
865 EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
866 EXPECT_LT(0U, history_handler->bitmap_data_.size());
867 EXPECT_EQ(page_url, history_handler->page_url_);
870 TEST_F(FaviconHandlerTest, UpdateDuringDownloading) {
871 const GURL page_url("http://www.google.com");
872 const GURL icon_url("http://www.google.com/favicon");
873 const GURL new_icon_url("http://www.google.com/new_favicon");
875 TestFaviconHandlerDelegate delegate;
876 Profile* profile = Profile::FromBrowserContext(
877 web_contents()->GetBrowserContext());
878 TestFaviconHandler helper(page_url, profile,
879 &delegate, FaviconHandler::TOUCH);
881 helper.FetchFavicon(page_url);
882 HistoryRequestHandler* history_handler = helper.history_handler();
883 // Ensure the data given to history is correct.
884 ASSERT_TRUE(history_handler);
885 EXPECT_EQ(page_url, history_handler->page_url_);
886 EXPECT_EQ(GURL(), history_handler->icon_url_);
887 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON,
888 history_handler->icon_type_);
890 // Icon not found.
891 history_handler->history_results_.clear();
892 // Send history response.
893 history_handler->InvokeCallback();
894 // Verify FaviconHandler status.
895 EXPECT_FALSE(helper.GetEntry()->GetFavicon().valid);
896 EXPECT_EQ(GURL(), helper.GetEntry()->GetFavicon().url);
898 // Reset the history_handler to verify whether new icon is requested from
899 // history.
900 helper.set_history_handler(NULL);
902 // Simulates update with the different favicon url.
903 std::vector<FaviconURL> urls;
904 urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON));
905 urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON));
906 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
907 helper.OnUpdateFaviconURL(0, urls);
909 // Verify FaviconHandler status.
910 EXPECT_EQ(2U, helper.urls().size());
911 ASSERT_TRUE(helper.current_candidate());
912 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
913 ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON,
914 helper.current_candidate()->icon_type);
916 // Favicon should be requested from history.
917 history_handler = helper.history_handler();
918 ASSERT_TRUE(history_handler);
919 EXPECT_EQ(icon_url, history_handler->icon_url_);
920 EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
921 EXPECT_EQ(page_url, history_handler->page_url_);
923 // Simulate not find icon.
924 history_handler->history_results_.clear();
925 history_handler->InvokeCallback();
927 // Should request download favicon.
928 DownloadHandler* download_handler = helper.download_handler();
929 EXPECT_TRUE(helper.download_handler()->HasDownload());
931 // Verify the download request.
932 EXPECT_EQ(icon_url, download_handler->GetImageUrl());
934 // Reset the history_handler to verify whether favicon is request from
935 // history.
936 helper.set_history_handler(NULL);
937 const GURL latest_icon_url("http://www.google.com/latest_favicon");
938 std::vector<FaviconURL> latest_urls;
939 latest_urls.push_back(FaviconURL(latest_icon_url, FaviconURL::TOUCH_ICON));
940 helper.OnUpdateFaviconURL(0, latest_urls);
942 EXPECT_EQ(1U, helper.urls().size());
943 EXPECT_EQ(latest_icon_url, helper.current_candidate()->icon_url);
944 EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type);
946 // Whether new icon is requested from history
947 history_handler = helper.history_handler();
948 ASSERT_TRUE(history_handler);
949 EXPECT_EQ(latest_icon_url, history_handler->icon_url_);
950 EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
951 EXPECT_EQ(page_url, history_handler->page_url_);
953 // Reset the history_handler to verify whether favicon is request from
954 // history.
955 // Save the callback for late use.
956 FaviconService::FaviconResultsCallback callback = history_handler->callback_;
957 helper.set_history_handler(NULL);
959 // Simulates download succeed.
960 download_handler->InvokeCallback();
961 // The downloaded icon should be thrown away as there is favicon update.
962 EXPECT_FALSE(helper.history_handler());
964 download_handler->Reset();
966 // Simulates getting the icon from history.
967 scoped_ptr<HistoryRequestHandler> handler;
968 handler.reset(new HistoryRequestHandler(page_url, latest_icon_url,
969 chrome::TOUCH_ICON, callback));
970 SetFaviconBitmapResult(latest_icon_url, chrome::TOUCH_ICON,
971 false /* expired */, &handler->history_results_);
972 handler->InvokeCallback();
974 // No download request.
975 EXPECT_FALSE(download_handler->HasDownload());
978 #if !defined(OS_ANDROID)
980 // Test the favicon which is selected when the web page provides several
981 // favicons and none of the favicons are cached in history.
982 // The goal of this test is to be more of an integration test than
983 // SelectFaviconFramesTest.*.
984 TEST_F(FaviconHandlerTest, MultipleFavicons) {
985 const GURL kPageURL("http://www.google.com");
986 const FaviconURL kSourceIconURLs[] = {
987 FaviconURL(GURL("http://www.google.com/a"), FaviconURL::FAVICON),
988 FaviconURL(GURL("http://www.google.com/b"), FaviconURL::FAVICON),
989 FaviconURL(GURL("http://www.google.com/c"), FaviconURL::FAVICON),
990 FaviconURL(GURL("http://www.google.com/d"), FaviconURL::FAVICON),
991 FaviconURL(GURL("http://www.google.com/e"), FaviconURL::FAVICON)
994 // Set the supported scale factors to 1x and 2x. This affects the behavior of
995 // SelectFaviconFrames().
996 std::vector<ui::ScaleFactor> scale_factors;
997 scale_factors.push_back(ui::SCALE_FACTOR_100P);
998 scale_factors.push_back(ui::SCALE_FACTOR_200P);
999 ui::test::ScopedSetSupportedScaleFactors scoped_supported(scale_factors);
1001 Profile* profile = Profile::FromBrowserContext(
1002 web_contents()->GetBrowserContext());
1004 // 1) Test that if there are several single resolution favicons to choose from
1005 // that the largest exact match is chosen.
1006 TestFaviconHandlerDelegate delegate1;
1007 TestFaviconHandler handler1(kPageURL, profile,
1008 &delegate1, FaviconHandler::FAVICON);
1009 const int kSizes1[] = { 16, 24, 32, 48, 256 };
1010 std::vector<FaviconURL> urls1(kSourceIconURLs,
1011 kSourceIconURLs + arraysize(kSizes1));
1012 DownloadTillDoneIgnoringHistory(&handler1, kPageURL, urls1, kSizes1);
1014 content::FaviconStatus favicon_status1(handler1.GetEntry()->GetFavicon());
1015 EXPECT_EQ(0u, handler1.image_urls().size());
1016 EXPECT_TRUE(favicon_status1.valid);
1017 EXPECT_FALSE(favicon_status1.image.IsEmpty());
1018 EXPECT_EQ(gfx::kFaviconSize, favicon_status1.image.Width());
1020 size_t expected_index = 2u;
1021 EXPECT_EQ(32, kSizes1[expected_index]);
1022 EXPECT_EQ(kSourceIconURLs[expected_index].icon_url,
1023 handler1.GetEntry()->GetFavicon().url);
1025 // 2) Test that if there are several single resolution favicons to choose
1026 // from, the exact match is preferred even if it results in upsampling.
1027 TestFaviconHandlerDelegate delegate2;
1028 TestFaviconHandler handler2(kPageURL, profile,
1029 &delegate2, FaviconHandler::FAVICON);
1030 const int kSizes2[] = { 16, 24, 48, 256 };
1031 std::vector<FaviconURL> urls2(kSourceIconURLs,
1032 kSourceIconURLs + arraysize(kSizes2));
1033 DownloadTillDoneIgnoringHistory(&handler2, kPageURL, urls2, kSizes2);
1034 EXPECT_TRUE(handler2.GetEntry()->GetFavicon().valid);
1035 expected_index = 0u;
1036 EXPECT_EQ(16, kSizes2[expected_index]);
1037 EXPECT_EQ(kSourceIconURLs[expected_index].icon_url,
1038 handler2.GetEntry()->GetFavicon().url);
1040 // 3) Test that favicons which need to be upsampled a little or downsampled
1041 // a little are preferred over huge favicons.
1042 TestFaviconHandlerDelegate delegate3;
1043 TestFaviconHandler handler3(kPageURL, profile,
1044 &delegate3, FaviconHandler::FAVICON);
1045 const int kSizes3[] = { 256, 48 };
1046 std::vector<FaviconURL> urls3(kSourceIconURLs,
1047 kSourceIconURLs + arraysize(kSizes3));
1048 DownloadTillDoneIgnoringHistory(&handler3, kPageURL, urls3, kSizes3);
1049 EXPECT_TRUE(handler3.GetEntry()->GetFavicon().valid);
1050 expected_index = 1u;
1051 EXPECT_EQ(48, kSizes3[expected_index]);
1052 EXPECT_EQ(kSourceIconURLs[expected_index].icon_url,
1053 handler3.GetEntry()->GetFavicon().url);
1055 TestFaviconHandlerDelegate delegate4;
1056 TestFaviconHandler handler4(kPageURL, profile,
1057 &delegate4, FaviconHandler::FAVICON);
1058 const int kSizes4[] = { 17, 256 };
1059 std::vector<FaviconURL> urls4(kSourceIconURLs,
1060 kSourceIconURLs + arraysize(kSizes4));
1061 DownloadTillDoneIgnoringHistory(&handler4, kPageURL, urls4, kSizes4);
1062 EXPECT_TRUE(handler4.GetEntry()->GetFavicon().valid);
1063 expected_index = 0u;
1064 EXPECT_EQ(17, kSizes4[expected_index]);
1065 EXPECT_EQ(kSourceIconURLs[expected_index].icon_url,
1066 handler4.GetEntry()->GetFavicon().url);
1069 #endif
1071 static BrowserContextKeyedService* BuildFaviconService(
1072 content::BrowserContext* profile) {
1073 return new FaviconService(static_cast<Profile*>(profile));
1076 static BrowserContextKeyedService* BuildHistoryService(
1077 content::BrowserContext* profile) {
1078 return NULL;
1081 // Test that Favicon is not requested repeatedly during the same session if
1082 // server returns HTTP 404 status.
1083 TEST_F(FaviconHandlerTest, UnableToDownloadFavicon) {
1084 const GURL missing_icon_url("http://www.google.com/favicon.ico");
1085 const GURL another_icon_url("http://www.youtube.com/favicon.ico");
1087 Profile* profile = Profile::FromBrowserContext(
1088 web_contents()->GetBrowserContext());
1090 FaviconServiceFactory::GetInstance()->SetTestingFactory(
1091 profile, BuildFaviconService);
1093 HistoryServiceFactory::GetInstance()->SetTestingFactory(
1094 profile, BuildHistoryService);
1096 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
1097 profile, Profile::IMPLICIT_ACCESS);
1099 FaviconTabHelper::CreateForWebContents(web_contents());
1100 FaviconTabHelper* favicon_tab_helper =
1101 FaviconTabHelper::FromWebContents(web_contents());
1103 std::vector<SkBitmap> empty_icons;
1104 std::vector<gfx::Size> empty_icon_sizes;
1105 int download_id = 0;
1107 // Try to download missing icon.
1108 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
1109 EXPECT_NE(0, download_id);
1110 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1112 // Report download failure with HTTP 503 status.
1113 favicon_tab_helper->DidDownloadFavicon(download_id, 503, missing_icon_url,
1114 empty_icons, empty_icon_sizes);
1115 // Icon is not marked as UnableToDownload as HTTP status is not 404.
1116 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1118 // Try to download again.
1119 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
1120 EXPECT_NE(0, download_id);
1121 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1123 // Report download failure with HTTP 404 status.
1124 favicon_tab_helper->DidDownloadFavicon(download_id, 404, missing_icon_url,
1125 empty_icons, empty_icon_sizes);
1126 // Icon is marked as UnableToDownload.
1127 EXPECT_TRUE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1129 // Try to download again.
1130 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
1131 // Download is not started and Icon is still marked as UnableToDownload.
1132 EXPECT_EQ(0, download_id);
1133 EXPECT_TRUE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1135 // Try to download another icon.
1136 download_id = favicon_tab_helper->StartDownload(another_icon_url, 0);
1137 // Download is started as another icon URL is not same as missing_icon_url.
1138 EXPECT_NE(0, download_id);
1139 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(another_icon_url));
1141 // Clear the list of missing icons.
1142 favicon_service->ClearUnableToDownloadFavicons();
1143 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1144 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(another_icon_url));
1146 // Try to download again.
1147 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0);
1148 EXPECT_NE(0, download_id);
1149 // Report download success with HTTP 200 status.
1150 favicon_tab_helper->DidDownloadFavicon(download_id, 200, missing_icon_url,
1151 empty_icons, empty_icon_sizes);
1152 // Icon is not marked as UnableToDownload as HTTP status is not 404.
1153 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url));
1156 } // namespace.