1// Copyright (c) 2011 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.
4
5#include "chrome/browser/favicon_helper.h"
6
7#include "content/browser/renderer_host/test_render_view_host.h"
8#include "content/browser/tab_contents/navigation_entry.h"
9#include "content/browser/tab_contents/test_tab_contents.h"
10#include "ui/gfx/codec/png_codec.h"
11#include "ui/gfx/favicon_size.h"
12
13class TestFaviconHelper;
14
15namespace {
16
17// Fill the given bmp with valid png data.
18void FillDataToBitmap(int w, int h, SkBitmap* bmp) {
19  bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
20  bmp->allocPixels();
21
22  unsigned char* src_data =
23      reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0));
24  for (int i = 0; i < w * h; i++) {
25    src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255);
26    src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255);
27    src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255);
28    src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255);
29  }
30}
31
32// Fill the given data buffer with valid png data.
33void FillBitmap(int w, int h, std::vector<unsigned char>* output) {
34  SkBitmap bitmap;
35  FillDataToBitmap(w, h, &bitmap);
36  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, output);
37}
38
39// This class is used to save the download request for verifying with test case.
40// It also will be used to invoke the onDidDownload callback.
41class DownloadHandler {
42 public:
43  DownloadHandler(int download_id,
44                  const GURL& image_url,
45                  int image_size,
46                  TestFaviconHelper* favicon_helper)
47    : image_url_(image_url),
48      image_size_(image_size),
49      failed_(false),
50      download_id_(download_id),
51      favicon_helper_(favicon_helper) {
52    FillDataToBitmap(16, 16, &bitmap_);
53  }
54
55  virtual ~DownloadHandler() {
56  }
57
58  static void UpdateFaviconURL(FaviconHelper* helper,
59                               const std::vector<FaviconURL> urls);
60
61  void InvokeCallback();
62
63  void UpdateFaviconURL(const std::vector<FaviconURL> urls);
64
65  const GURL image_url_;
66  const int image_size_;
67
68  // Simulates download failed or not.
69  bool failed_;
70
71 private:
72  // Identified the specific download, will also be passed in
73  // OnDidDownloadFavicon callback.
74  int download_id_;
75  TestFaviconHelper* favicon_helper_;
76  SkBitmap bitmap_;
77
78  DISALLOW_COPY_AND_ASSIGN(DownloadHandler);
79};
80
81// This class is used to save the history request for verifying with test case.
82// It also will be used to simulate the history response.
83class HistoryRequestHandler {
84 public:
85  HistoryRequestHandler(const GURL& page_url,
86                        const GURL& icon_url,
87                        int icon_type,
88                        FaviconService::FaviconDataCallback* callback)
89    : page_url_(page_url),
90      icon_url_(icon_url),
91      icon_type_(icon_type),
92      callback_(callback) {
93  }
94
95  HistoryRequestHandler(const GURL& page_url,
96                        const GURL& icon_url,
97                        int icon_type,
98                        const std::vector<unsigned char>& image_data,
99                        FaviconService::FaviconDataCallback* callback)
100    : page_url_(page_url),
101      icon_url_(icon_url),
102      icon_type_(icon_type),
103      image_data_(image_data),
104      callback_(callback) {
105  }
106
107  virtual ~HistoryRequestHandler() {
108    delete callback_;
109  }
110  void InvokeCallback();
111
112  const GURL page_url_;
113  const GURL icon_url_;
114  const int icon_type_;
115  const std::vector<unsigned char> image_data_;
116  history::FaviconData favicon_data_;
117  FaviconService::FaviconDataCallback* callback_;
118
119 private:
120  DISALLOW_COPY_AND_ASSIGN(HistoryRequestHandler);
121};
122
123}  // namespace
124
125// This class is used to catch the FaviconHelper's download and history request,
126// and also provide the methods to access the FaviconHelper internal.
127class TestFaviconHelper : public FaviconHelper {
128 public:
129  TestFaviconHelper(const GURL& page_url,
130                    TabContents* tab_contents,
131                    Type type)
132    : FaviconHelper(tab_contents, type),
133      download_image_size_(0),
134      download_id_(0),
135      tab_contents_(tab_contents){
136    entry_.set_url(page_url);
137  }
138
139  virtual ~TestFaviconHelper() {
140  }
141
142  HistoryRequestHandler* history_handler() {
143    return history_handler_.get();
144  }
145
146  // This method will take the ownership of the given handler.
147  void set_history_handler(HistoryRequestHandler* handler) {
148    history_handler_.reset(handler);
149  }
150
151  DownloadHandler* download_handler() {
152    return download_handler_.get();
153  }
154
155  // This method will take the ownership of the given download_handler.
156  void set_download_handler(DownloadHandler* download_handler) {
157    download_handler_.reset(download_handler);
158  }
159
160  virtual NavigationEntry* GetEntry() {
161    return &entry_;
162  }
163
164  const std::vector<FaviconURL>& urls() {
165    return urls_;
166  }
167
168  void FetchFavicon(const GURL& url) {
169    FaviconHelper::FetchFavicon(url);
170  }
171
172  // The methods to access favicon internal.
173  FaviconURL* current_candidate() {
174    return FaviconHelper::current_candidate();
175  }
176
177  void OnDidDownloadFavicon(int id,
178                            const GURL& image_url,
179                            bool errored,
180                            const SkBitmap& image) {
181    FaviconHelper::OnDidDownloadFavicon(id, image_url, errored, image);
182  }
183
184 protected:
185  virtual void UpdateFaviconMappingAndFetch(
186      const GURL& page_url,
187      const GURL& icon_url,
188      history::IconType icon_type,
189      CancelableRequestConsumerBase* consumer,
190      FaviconService::FaviconDataCallback* callback) OVERRIDE {
191    history_handler_.reset(new HistoryRequestHandler(page_url, icon_url,
192                                                     icon_type, callback));
193  }
194
195  virtual void GetFavicon(
196      const GURL& icon_url,
197      history::IconType icon_type,
198      CancelableRequestConsumerBase* consumer,
199      FaviconService::FaviconDataCallback* callback) OVERRIDE {
200    history_handler_.reset(new HistoryRequestHandler(GURL(), icon_url,
201                                                     icon_type, callback));
202  }
203
204  virtual void GetFaviconForURL(
205      const GURL& page_url,
206      int icon_types,
207      CancelableRequestConsumerBase* consumer,
208      FaviconService::FaviconDataCallback* callback) OVERRIDE {
209    history_handler_.reset(new HistoryRequestHandler(page_url, GURL(),
210                                                     icon_types, callback));
211  }
212
213  virtual int DownloadFavicon(const GURL& image_url, int image_size) OVERRIDE {
214    download_id_++;
215    download_handler_.reset(new DownloadHandler(download_id_, image_url,
216                                                image_size, this));
217    return download_id_;
218  }
219
220  virtual void SetHistoryFavicon(const GURL& page_url,
221                                 const GURL& icon_url,
222                                 const std::vector<unsigned char>& image_data,
223                                 history::IconType icon_type) OVERRIDE {
224    history_handler_.reset(new HistoryRequestHandler(page_url, icon_url,
225        icon_type, image_data, NULL));
226  }
227
228  virtual FaviconService* GetFaviconService() OVERRIDE {
229    // Just give none NULL value, so overridden methods can be hit.
230    return (FaviconService*)(1);
231  }
232
233  virtual bool ShouldSaveFavicon(const GURL& url) OVERRIDE {
234    return true;
235  }
236
237  GURL page_url_;
238
239  GURL download_image_url_;
240  int download_image_size_;
241
242 private:
243  NavigationEntry entry_;
244
245  // The unique id of a download request. It will be returned to a
246  // FaviconHelper.
247  int download_id_;
248
249  TabContents* tab_contents_;
250  scoped_ptr<DownloadHandler> download_handler_;
251  scoped_ptr<HistoryRequestHandler> history_handler_;
252
253  DISALLOW_COPY_AND_ASSIGN(TestFaviconHelper);
254};
255
256namespace {
257
258void DownloadHandler::UpdateFaviconURL(FaviconHelper* helper,
259                                       const std::vector<FaviconURL> urls) {
260  helper->OnUpdateFaviconURL(0, urls);
261}
262
263void DownloadHandler::UpdateFaviconURL(const std::vector<FaviconURL> urls) {
264  UpdateFaviconURL(favicon_helper_, urls);
265}
266
267void DownloadHandler::InvokeCallback() {
268  favicon_helper_->OnDidDownloadFavicon(download_id_, image_url_, failed_,
269                                        bitmap_);
270}
271
272void HistoryRequestHandler::InvokeCallback() {
273  callback_->Run(0, favicon_data_);
274}
275
276class FaviconHelperTest : public RenderViewHostTestHarness {
277};
278
279TEST_F(FaviconHelperTest, GetFaviconFromHistory) {
280  const GURL page_url("http://www.google.com");
281  const GURL icon_url("http://www.google.com/favicon");
282
283  TestFaviconHelper helper(page_url, contents(), FaviconHelper::FAVICON);
284
285  helper.FetchFavicon(page_url);
286  HistoryRequestHandler* history_handler = helper.history_handler();
287  // Ensure the data given to history is correct.
288  ASSERT_TRUE(history_handler);
289  EXPECT_EQ(page_url, history_handler->page_url_);
290  EXPECT_EQ(GURL(), history_handler->icon_url_);
291  EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
292
293  // Set valid icon data.
294  history_handler->favicon_data_.known_icon = true;
295  history_handler->favicon_data_.icon_type = history::FAVICON;
296  history_handler->favicon_data_.expired = false;
297  history_handler->favicon_data_.icon_url = icon_url;
298  scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
299  FillBitmap(kFaviconSize, kFaviconSize, &data->data);
300  history_handler->favicon_data_.image_data = data;
301
302  // Send history response.
303  history_handler->InvokeCallback();
304  // Verify FaviconHelper status
305  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
306  EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
307
308  // Simulates update favicon url.
309  std::vector<FaviconURL> urls;
310  urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
311  DownloadHandler::UpdateFaviconURL(&helper, urls);
312
313  // Verify FaviconHelper status
314  EXPECT_EQ(1U, helper.urls().size());
315  ASSERT_TRUE(helper.current_candidate());
316  ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
317  ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
318
319  // Favicon shouldn't request to download icon.
320  DownloadHandler* download_handler = helper.download_handler();
321  ASSERT_FALSE(download_handler);
322}
323
324TEST_F(FaviconHelperTest, DownloadFavicon) {
325  const GURL page_url("http://www.google.com");
326  const GURL icon_url("http://www.google.com/favicon");
327
328  TestFaviconHelper helper(page_url, contents(), FaviconHelper::FAVICON);
329
330  helper.FetchFavicon(page_url);
331  HistoryRequestHandler* history_handler = helper.history_handler();
332  // Ensure the data given to history is correct.
333  ASSERT_TRUE(history_handler);
334  EXPECT_EQ(page_url, history_handler->page_url_);
335  EXPECT_EQ(GURL(), history_handler->icon_url_);
336  EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
337
338  // Set icon data expired
339  history_handler->favicon_data_.known_icon = true;
340  history_handler->favicon_data_.icon_type = history::FAVICON;
341  history_handler->favicon_data_.expired = true;
342  history_handler->favicon_data_.icon_url = icon_url;
343  // Send history response.
344  history_handler->InvokeCallback();
345  // Verify FaviconHelper status
346  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
347  EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
348
349  // Simulates update favicon url.
350  std::vector<FaviconURL> urls;
351  urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
352  DownloadHandler::UpdateFaviconURL(&helper, urls);
353
354  // Verify FaviconHelper status
355  EXPECT_EQ(1U, helper.urls().size());
356  ASSERT_TRUE(helper.current_candidate());
357  ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
358  ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
359
360  // Favicon should request to download icon now.
361  DownloadHandler* download_handler = helper.download_handler();
362  ASSERT_TRUE(download_handler);
363  // Verify the download request.
364  EXPECT_EQ(icon_url, download_handler->image_url_);
365  EXPECT_EQ(kFaviconSize, download_handler->image_size_);
366
367  // Reset the history_handler to verify whether favicon is set.
368  helper.set_history_handler(NULL);
369
370  // Smulates download done.
371  download_handler->InvokeCallback();
372
373  // New icon should be saved to history backend and navigation entry.
374  history_handler = helper.history_handler();
375  ASSERT_TRUE(history_handler);
376  EXPECT_EQ(icon_url, history_handler->icon_url_);
377  EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
378  EXPECT_LT(0U, history_handler->image_data_.size());
379  EXPECT_EQ(page_url, history_handler->page_url_);
380
381  // Verify NavigationEntry.
382  EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
383  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
384  EXPECT_FALSE(helper.GetEntry()->favicon().bitmap().empty());
385}
386
387TEST_F(FaviconHelperTest, UpdateAndDownloadFavicon) {
388  const GURL page_url("http://www.google.com");
389  const GURL icon_url("http://www.google.com/favicon");
390  const GURL new_icon_url("http://www.google.com/new_favicon");
391
392  TestFaviconHelper helper(page_url, contents(), FaviconHelper::FAVICON);
393
394  helper.FetchFavicon(page_url);
395  HistoryRequestHandler* history_handler = helper.history_handler();
396  // Ensure the data given to history is correct.
397  ASSERT_TRUE(history_handler);
398  EXPECT_EQ(page_url, history_handler->page_url_);
399  EXPECT_EQ(GURL(), history_handler->icon_url_);
400  EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
401
402  // Set valid icon data.
403  history_handler->favicon_data_.known_icon = true;
404  history_handler->favicon_data_.icon_type = history::FAVICON;
405  history_handler->favicon_data_.expired = false;
406  history_handler->favicon_data_.icon_url = icon_url;
407  scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
408  FillBitmap(kFaviconSize, kFaviconSize, &data->data);
409  history_handler->favicon_data_.image_data = data;
410
411  // Send history response.
412  history_handler->InvokeCallback();
413  // Verify FaviconHelper status.
414  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
415  EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
416
417  // Reset the history_handler to verify whether new icon is requested from
418  // history.
419  helper.set_history_handler(NULL);
420
421  // Simulates update with the different favicon url.
422  std::vector<FaviconURL> urls;
423  urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
424  DownloadHandler::UpdateFaviconURL(&helper, urls);
425
426  // Verify FaviconHelper status.
427  EXPECT_EQ(1U, helper.urls().size());
428  ASSERT_TRUE(helper.current_candidate());
429  ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
430  ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
431  // The favicon status's url should be updated.
432  ASSERT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
433
434  // Favicon should be requested from history.
435  history_handler = helper.history_handler();
436  ASSERT_TRUE(history_handler);
437  EXPECT_EQ(new_icon_url, history_handler->icon_url_);
438  EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
439  EXPECT_EQ(page_url, history_handler->page_url_);
440
441  // Simulate not find icon.
442  history_handler->favicon_data_.known_icon = false;
443  history_handler->InvokeCallback();
444
445  // Favicon should request to download icon now.
446  DownloadHandler* download_handler = helper.download_handler();
447  ASSERT_TRUE(download_handler);
448  // Verify the download request.
449  EXPECT_EQ(new_icon_url, download_handler->image_url_);
450  EXPECT_EQ(kFaviconSize, download_handler->image_size_);
451
452  // Reset the history_handler to verify whether favicon is set.
453  helper.set_history_handler(NULL);
454
455  // Smulates download done.
456  download_handler->InvokeCallback();
457
458  // New icon should be saved to history backend and navigation entry.
459  history_handler = helper.history_handler();
460  ASSERT_TRUE(history_handler);
461  EXPECT_EQ(new_icon_url, history_handler->icon_url_);
462  EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
463  EXPECT_LT(0U, history_handler->image_data_.size());
464  EXPECT_EQ(page_url, history_handler->page_url_);
465
466  // Verify NavigationEntry.
467  EXPECT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
468  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
469  EXPECT_FALSE(helper.GetEntry()->favicon().bitmap().empty());
470}
471
472TEST_F(FaviconHelperTest, UpdateFavicon) {
473  const GURL page_url("http://www.google.com");
474  const GURL icon_url("http://www.google.com/favicon");
475  const GURL new_icon_url("http://www.google.com/new_favicon");
476
477  TestFaviconHelper helper(page_url, contents(), FaviconHelper::FAVICON);
478
479  helper.FetchFavicon(page_url);
480  HistoryRequestHandler* history_handler = helper.history_handler();
481  // Ensure the data given to history is correct.
482  ASSERT_TRUE(history_handler);
483  EXPECT_EQ(page_url, history_handler->page_url_);
484  EXPECT_EQ(GURL(), history_handler->icon_url_);
485  EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
486
487  // Set valid icon data.
488  history_handler->favicon_data_.known_icon = true;
489  history_handler->favicon_data_.icon_type = history::FAVICON;
490  history_handler->favicon_data_.expired = false;
491  history_handler->favicon_data_.icon_url = icon_url;
492  scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
493  FillBitmap(kFaviconSize, kFaviconSize, &data->data);
494  history_handler->favicon_data_.image_data = data;
495
496  // Send history response.
497  history_handler->InvokeCallback();
498  // Verify FaviconHelper status.
499  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
500  EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
501
502  // Reset the history_handler to verify whether new icon is requested from
503  // history.
504  helper.set_history_handler(NULL);
505
506  // Simulates update with the different favicon url.
507  std::vector<FaviconURL> urls;
508  urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
509  DownloadHandler::UpdateFaviconURL(&helper, urls);
510
511  // Verify FaviconHelper status.
512  EXPECT_EQ(1U, helper.urls().size());
513  ASSERT_TRUE(helper.current_candidate());
514  ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
515  ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
516  // The favicon status's url should be updated.
517  ASSERT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
518
519  // Favicon should be requested from history.
520  history_handler = helper.history_handler();
521  ASSERT_TRUE(history_handler);
522  EXPECT_EQ(new_icon_url, history_handler->icon_url_);
523  EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
524  EXPECT_EQ(page_url, history_handler->page_url_);
525
526  // Simulate find icon.
527  history_handler->favicon_data_.known_icon = true;
528  history_handler->favicon_data_.icon_type = history::FAVICON;
529  history_handler->favicon_data_.expired = false;
530  history_handler->favicon_data_.icon_url = new_icon_url;
531  history_handler->favicon_data_.image_data = data;
532  history_handler->InvokeCallback();
533
534  // Shouldn't request download favicon
535  EXPECT_FALSE(helper.download_handler());
536
537  // Verify the favicon status.
538  EXPECT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
539  EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
540  EXPECT_FALSE(helper.GetEntry()->favicon().bitmap().empty());
541}
542
543TEST_F(FaviconHelperTest, Download2ndFaviconURLCandidate) {
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");
547
548  TestFaviconHelper helper(page_url, contents(), FaviconHelper::TOUCH);
549
550  helper.FetchFavicon(page_url);
551  HistoryRequestHandler* history_handler = helper.history_handler();
552  // Ensure the data given to history is correct.
553  ASSERT_TRUE(history_handler);
554  EXPECT_EQ(page_url, history_handler->page_url_);
555  EXPECT_EQ(GURL(), history_handler->icon_url_);
556  EXPECT_EQ(history::TOUCH_PRECOMPOSED_ICON | history::TOUCH_ICON,
557            history_handler->icon_type_);
558
559  // Icon not found.
560  history_handler->favicon_data_.known_icon = false;
561  // Send history response.
562  history_handler->InvokeCallback();
563  // Verify FaviconHelper status.
564  EXPECT_FALSE(helper.GetEntry()->favicon().is_valid());
565  EXPECT_EQ(GURL(), helper.GetEntry()->favicon().url());
566
567  // Reset the history_handler to verify whether new icon is requested from
568  // history.
569  helper.set_history_handler(NULL);
570
571  // Simulates update with the different favicon url.
572  std::vector<FaviconURL> urls;
573  urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON));
574  urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON));
575  urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
576
577  DownloadHandler::UpdateFaviconURL(&helper, urls);
578
579  // Verify FaviconHelper status.
580  EXPECT_EQ(2U, helper.urls().size());
581  ASSERT_TRUE(helper.current_candidate());
582  ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
583  ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON,
584            helper.current_candidate()->icon_type);
585
586  // Favicon should be requested from history.
587  history_handler = helper.history_handler();
588  ASSERT_TRUE(history_handler);
589  EXPECT_EQ(icon_url, history_handler->icon_url_);
590  EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
591  EXPECT_EQ(page_url, history_handler->page_url_);
592
593  // Simulate not find icon.
594  history_handler->favicon_data_.known_icon = false;
595  history_handler->InvokeCallback();
596
597  // Should request download favicon.
598  DownloadHandler* download_handler = helper.download_handler();
599  EXPECT_TRUE(download_handler);
600  // Verify the download request.
601  EXPECT_EQ(icon_url, download_handler->image_url_);
602  EXPECT_EQ(0, download_handler->image_size_);
603
604  // Reset the history_handler to verify whether favicon is request from
605  // history.
606  helper.set_history_handler(NULL);
607  // Smulates download failed.
608  download_handler->failed_ = true;
609  download_handler->InvokeCallback();
610
611  // Left 1 url.
612  EXPECT_EQ(1U, helper.urls().size());
613  ASSERT_TRUE(helper.current_candidate());
614  EXPECT_EQ(new_icon_url, helper.current_candidate()->icon_url);
615  EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type);
616
617  // Favicon should be requested from history.
618  history_handler = helper.history_handler();
619  ASSERT_TRUE(history_handler);
620  EXPECT_EQ(new_icon_url, history_handler->icon_url_);
621  EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
622  EXPECT_EQ(page_url, history_handler->page_url_);
623
624  // Reset download handler
625  helper.set_download_handler(NULL);
626
627  // Smulates getting a expired icon from history.
628  history_handler->favicon_data_.known_icon = true;
629  history_handler->favicon_data_.icon_type = history::TOUCH_ICON;
630  history_handler->favicon_data_.expired = true;
631  history_handler->favicon_data_.icon_url = new_icon_url;
632  scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
633  FillBitmap(kFaviconSize, kFaviconSize, &data->data);
634  history_handler->favicon_data_.image_data = data;
635  history_handler->InvokeCallback();
636
637  // Verify the download request.
638  download_handler = helper.download_handler();
639  EXPECT_TRUE(download_handler);
640  EXPECT_EQ(new_icon_url, download_handler->image_url_);
641  EXPECT_EQ(0, download_handler->image_size_);
642
643  helper.set_history_handler(NULL);
644
645  // Simulates icon being downloaded.
646  download_handler->InvokeCallback();
647
648  // New icon should be saved to history backend.
649  history_handler = helper.history_handler();
650  ASSERT_TRUE(history_handler);
651  EXPECT_EQ(new_icon_url, history_handler->icon_url_);
652  EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
653  EXPECT_LT(0U, history_handler->image_data_.size());
654  EXPECT_EQ(page_url, history_handler->page_url_);
655}
656
657TEST_F(FaviconHelperTest, UpdateDuringDownloading) {
658  const GURL page_url("http://www.google.com");
659  const GURL icon_url("http://www.google.com/favicon");
660  const GURL new_icon_url("http://www.google.com/new_favicon");
661
662  TestFaviconHelper helper(page_url, contents(), FaviconHelper::TOUCH);
663
664  helper.FetchFavicon(page_url);
665  HistoryRequestHandler* history_handler = helper.history_handler();
666  // Ensure the data given to history is correct.
667  ASSERT_TRUE(history_handler);
668  EXPECT_EQ(page_url, history_handler->page_url_);
669  EXPECT_EQ(GURL(), history_handler->icon_url_);
670  EXPECT_EQ(history::TOUCH_PRECOMPOSED_ICON | history::TOUCH_ICON,
671            history_handler->icon_type_);
672
673  // Icon not found.
674  history_handler->favicon_data_.known_icon = false;
675  // Send history response.
676  history_handler->InvokeCallback();
677  // Verify FaviconHelper status.
678  EXPECT_FALSE(helper.GetEntry()->favicon().is_valid());
679  EXPECT_EQ(GURL(), helper.GetEntry()->favicon().url());
680
681  // Reset the history_handler to verify whether new icon is requested from
682  // history.
683  helper.set_history_handler(NULL);
684
685  // Simulates update with the different favicon url.
686  std::vector<FaviconURL> urls;
687  urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON));
688  urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON));
689  urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
690
691  DownloadHandler::UpdateFaviconURL(&helper, urls);
692
693  // Verify FaviconHelper status.
694  EXPECT_EQ(2U, helper.urls().size());
695  ASSERT_TRUE(helper.current_candidate());
696  ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
697  ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON,
698            helper.current_candidate()->icon_type);
699
700  // Favicon should be requested from history.
701  history_handler = helper.history_handler();
702  ASSERT_TRUE(history_handler);
703  EXPECT_EQ(icon_url, history_handler->icon_url_);
704  EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
705  EXPECT_EQ(page_url, history_handler->page_url_);
706
707  // Simulate not find icon.
708  history_handler->favicon_data_.known_icon = false;
709  history_handler->InvokeCallback();
710
711  // Should request download favicon.
712  DownloadHandler* download_handler = helper.download_handler();
713  EXPECT_TRUE(download_handler);
714  // Verify the download request.
715  EXPECT_EQ(icon_url, download_handler->image_url_);
716  EXPECT_EQ(0, download_handler->image_size_);
717
718  // Reset the history_handler to verify whether favicon is request from
719  // history.
720  helper.set_history_handler(NULL);
721  const GURL latest_icon_url("http://www.google.com/latest_favicon");
722  std::vector<FaviconURL> latest_urls;
723  latest_urls.push_back(FaviconURL(latest_icon_url, FaviconURL::TOUCH_ICON));
724  DownloadHandler::UpdateFaviconURL(&helper, latest_urls);
725  EXPECT_EQ(1U, helper.urls().size());
726  EXPECT_EQ(latest_icon_url, helper.current_candidate()->icon_url);
727  EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type);
728
729  // Whether new icon is requested from history
730  history_handler = helper.history_handler();
731  ASSERT_TRUE(history_handler);
732  EXPECT_EQ(latest_icon_url, history_handler->icon_url_);
733  EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
734  EXPECT_EQ(page_url, history_handler->page_url_);
735
736  // Reset the history_handler to verify whether favicon is request from
737  // history.
738  // Save the callback for late use.
739  FaviconService::FaviconDataCallback* callback = history_handler->callback_;
740  // Prevent the callback from being released.
741  history_handler->callback_ = NULL;
742  helper.set_history_handler(NULL);
743
744  // Smulates download succeed.
745  download_handler->InvokeCallback();
746  // The downloaded icon should be thrown away as there is faviocn update.
747  EXPECT_FALSE(helper.history_handler());
748
749  helper.set_download_handler(NULL);
750
751  // Smulates getting the icon from history.
752  scoped_ptr<HistoryRequestHandler> handler;
753  handler.reset(new HistoryRequestHandler(page_url, latest_icon_url,
754                                          history::TOUCH_ICON, callback));
755  handler->favicon_data_.known_icon = true;
756  handler->favicon_data_.expired = false;
757  handler->favicon_data_.icon_type = history::TOUCH_ICON;
758  handler->favicon_data_.icon_url = latest_icon_url;
759  scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
760  FillBitmap(kFaviconSize, kFaviconSize, &data->data);
761  handler->favicon_data_.image_data = data;
762
763  handler->InvokeCallback();
764
765  // No download request.
766  EXPECT_FALSE(helper.download_handler());
767}
768
769}  // namespace.
770