Home | History | Annotate | Download | only in bookmarks
      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 "testing/gtest/include/gtest/gtest.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/message_loop.h"
      9 #include "base/path_service.h"
     10 #include "base/string16.h"
     11 #include "base/string_util.h"
     12 #include "base/time.h"
     13 #include "base/utf_string_conversions.h"
     14 #include "base/i18n/time_formatting.h"
     15 #include "base/memory/scoped_temp_dir.h"
     16 #include "chrome/browser/bookmarks/bookmark_html_writer.h"
     17 #include "chrome/browser/bookmarks/bookmark_model.h"
     18 #include "chrome/browser/importer/firefox2_importer.h"
     19 #include "chrome/test/testing_browser_process_test.h"
     20 #include "chrome/test/testing_profile.h"
     21 #include "content/browser/browser_thread.h"
     22 #include "grit/generated_resources.h"
     23 #include "third_party/skia/include/core/SkBitmap.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 #include "ui/gfx/codec/png_codec.h"
     26 
     27 namespace {
     28 
     29 static const int kIconWidth = 16;
     30 static const int kIconHeight = 16;
     31 
     32 void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) {
     33   bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
     34   bmp->allocPixels();
     35 
     36   uint32_t* src_data = bmp->getAddr32(0, 0);
     37   for (int i = 0; i < w * h; i++) {
     38     src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
     39   }
     40 }
     41 
     42 }  // namespace
     43 
     44 class BookmarkHTMLWriterTest : public TestingBrowserProcessTest {
     45  protected:
     46   virtual void SetUp() {
     47     TestingBrowserProcessTest::SetUp();
     48     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     49     path_ = temp_dir_.path().AppendASCII("bookmarks.html");
     50   }
     51 
     52   // Converts a BookmarkEntry to a string suitable for assertion testing.
     53   string16 BookmarkEntryToString(
     54       const ProfileWriter::BookmarkEntry& entry) {
     55     string16 result;
     56     result.append(ASCIIToUTF16("on_toolbar="));
     57     if (entry.in_toolbar)
     58       result.append(ASCIIToUTF16("false"));
     59     else
     60       result.append(ASCIIToUTF16("true"));
     61 
     62     result.append(ASCIIToUTF16(" url=") + UTF8ToUTF16(entry.url.spec()));
     63 
     64     result.append(ASCIIToUTF16(" path="));
     65     for (size_t i = 0; i < entry.path.size(); ++i) {
     66       if (i != 0)
     67         result.append(ASCIIToUTF16("/"));
     68       result.append(entry.path[i]);
     69     }
     70 
     71     result.append(ASCIIToUTF16(" title="));
     72     result.append(entry.title);
     73 
     74     result.append(ASCIIToUTF16(" time="));
     75     result.append(base::TimeFormatFriendlyDateAndTime(entry.creation_time));
     76     return result;
     77   }
     78 
     79   // Creates a set of bookmark values to a string for assertion testing.
     80   string16 BookmarkValuesToString(bool on_toolbar,
     81                                   const GURL& url,
     82                                   const string16& title,
     83                                   base::Time creation_time,
     84                                   const string16& f1,
     85                                   const string16& f2,
     86                                   const string16& f3) {
     87     ProfileWriter::BookmarkEntry entry;
     88     entry.in_toolbar = on_toolbar;
     89     entry.url = url;
     90     // The first path element should always be 'x', as that is what we passed
     91     // to the importer.
     92     entry.path.push_back(ASCIIToUTF16("x"));
     93     if (!f1.empty()) {
     94       entry.path.push_back(f1);
     95       if (!f2.empty()) {
     96         entry.path.push_back(f2);
     97         if (!f3.empty())
     98           entry.path.push_back(f3);
     99       }
    100     }
    101     entry.title = title;
    102     entry.creation_time = creation_time;
    103     return BookmarkEntryToString(entry);
    104   }
    105 
    106   void AssertBookmarkEntryEquals(const ProfileWriter::BookmarkEntry& entry,
    107                                  bool on_toolbar,
    108                                  const GURL& url,
    109                                  const string16& title,
    110                                  base::Time creation_time,
    111                                  const string16& f1,
    112                                  const string16& f2,
    113                                  const string16& f3) {
    114     EXPECT_EQ(BookmarkValuesToString(on_toolbar, url, title, creation_time,
    115                                      f1, f2, f3),
    116               BookmarkEntryToString(entry));
    117   }
    118 
    119   ScopedTempDir temp_dir_;
    120   FilePath path_;
    121 };
    122 
    123 // Class that will notify message loop when file is written.
    124 class BookmarksObserver : public BookmarksExportObserver {
    125  public:
    126   explicit BookmarksObserver(MessageLoop* loop) : loop_(loop) {
    127     DCHECK(loop);
    128   }
    129 
    130   virtual void OnExportFinished() {
    131     loop_->Quit();
    132   }
    133 
    134  private:
    135   MessageLoop* loop_;
    136   DISALLOW_COPY_AND_ASSIGN(BookmarksObserver);
    137 };
    138 
    139 // Tests bookmark_html_writer by populating a BookmarkModel, writing it out by
    140 // way of bookmark_html_writer, then using the importer to read it back in.
    141 TEST_F(BookmarkHTMLWriterTest, Test) {
    142   MessageLoop message_loop;
    143   BrowserThread fake_ui_thread(BrowserThread::UI, &message_loop);
    144   BrowserThread fake_file_thread(BrowserThread::FILE, &message_loop);
    145 
    146   TestingProfile profile;
    147   profile.CreateHistoryService(true, false);
    148   profile.BlockUntilHistoryProcessesPendingRequests();
    149   profile.CreateFaviconService();
    150   profile.CreateBookmarkModel(true);
    151   profile.BlockUntilBookmarkModelLoaded();
    152   BookmarkModel* model = profile.GetBookmarkModel();
    153 
    154   // Create test PNG representing favicon for url1.
    155   SkBitmap bitmap;
    156   MakeTestSkBitmap(kIconWidth, kIconHeight, &bitmap);
    157   std::vector<unsigned char> icon_data;
    158   gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_data);
    159 
    160   // Populate the BookmarkModel. This creates the following bookmark structure:
    161   // Bookmarks bar
    162   //   F1
    163   //     url1
    164   //     F2
    165   //       url2
    166   //   url3
    167   //   url4
    168   // Other
    169   //   url1
    170   //   url2
    171   //   F3
    172   //     F4
    173   //       url1
    174   string16 f1_title = ASCIIToUTF16("F\"&;<1\"");
    175   string16 f2_title = ASCIIToUTF16("F2");
    176   string16 f3_title = ASCIIToUTF16("F 3");
    177   string16 f4_title = ASCIIToUTF16("F4");
    178   string16 url1_title = ASCIIToUTF16("url 1");
    179   string16 url2_title = ASCIIToUTF16("url&2");
    180   string16 url3_title = ASCIIToUTF16("url\"3");
    181   string16 url4_title = ASCIIToUTF16("url\"&;");
    182   GURL url1("http://url1");
    183   GURL url1_favicon("http://url1/icon.ico");
    184   GURL url2("http://url2");
    185   GURL url3("http://url3");
    186   GURL url4("javascript:alert(\"Hello!\");");
    187   base::Time t1(base::Time::Now());
    188   base::Time t2(t1 + base::TimeDelta::FromHours(1));
    189   base::Time t3(t1 + base::TimeDelta::FromHours(1));
    190   base::Time t4(t1 + base::TimeDelta::FromHours(1));
    191   const BookmarkNode* f1 = model->AddFolder(
    192       model->GetBookmarkBarNode(), 0, f1_title);
    193   model->AddURLWithCreationTime(f1, 0, url1_title, url1, t1);
    194   profile.GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(url1,
    195       history::SOURCE_BROWSED);
    196   profile.GetFaviconService(Profile::EXPLICIT_ACCESS)->SetFavicon(url1,
    197       url1_favicon, icon_data, history::FAVICON);
    198   message_loop.RunAllPending();
    199   const BookmarkNode* f2 = model->AddFolder(f1, 1, f2_title);
    200   model->AddURLWithCreationTime(f2, 0, url2_title, url2, t2);
    201   model->AddURLWithCreationTime(model->GetBookmarkBarNode(),
    202                                 1, url3_title, url3, t3);
    203 
    204   model->AddURLWithCreationTime(model->other_node(), 0, url1_title, url1, t1);
    205   model->AddURLWithCreationTime(model->other_node(), 1, url2_title, url2, t2);
    206   const BookmarkNode* f3 = model->AddFolder(model->other_node(), 2, f3_title);
    207   const BookmarkNode* f4 = model->AddFolder(f3, 0, f4_title);
    208   model->AddURLWithCreationTime(f4, 0, url1_title, url1, t1);
    209   model->AddURLWithCreationTime(model->GetBookmarkBarNode(), 2, url4_title,
    210                                 url4, t4);
    211 
    212   // Write to a temp file.
    213   BookmarksObserver observer(&message_loop);
    214   bookmark_html_writer::WriteBookmarks(&profile, path_, &observer);
    215   message_loop.Run();
    216 
    217   // Clear favicon so that it would be read from file.
    218   std::vector<unsigned char> empty_data;
    219   profile.GetFaviconService(Profile::EXPLICIT_ACCESS)->SetFavicon(url1,
    220       url1_favicon, empty_data, history::FAVICON);
    221   message_loop.RunAllPending();
    222 
    223   // Read the bookmarks back in.
    224   std::vector<ProfileWriter::BookmarkEntry> parsed_bookmarks;
    225   std::vector<history::ImportedFaviconUsage> favicons;
    226   Firefox2Importer::ImportBookmarksFile(path_,
    227                                         std::set<GURL>(),
    228                                         false,
    229                                         ASCIIToUTF16("x"),
    230                                         NULL,
    231                                         &parsed_bookmarks,
    232                                         NULL,
    233                                         &favicons);
    234 
    235   // Check loaded favicon (url1 is represents by 3 separate bookmarks).
    236   EXPECT_EQ(3U, favicons.size());
    237   for (size_t i = 0; i < favicons.size(); i++) {
    238     if (url1_favicon == favicons[i].favicon_url) {
    239       EXPECT_EQ(1U, favicons[i].urls.size());
    240       std::set<GURL>::const_iterator iter = favicons[i].urls.find(url1);
    241       ASSERT_TRUE(iter != favicons[i].urls.end());
    242       ASSERT_TRUE(*iter == url1);
    243       ASSERT_TRUE(favicons[i].png_data == icon_data);
    244     }
    245   }
    246 
    247   // Verify we got back what we wrote.
    248   ASSERT_EQ(7U, parsed_bookmarks.size());
    249   // Windows and ChromeOS builds use Sentence case.
    250   string16 bookmark_folder_name =
    251       l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_FOLDER_NAME);
    252   AssertBookmarkEntryEquals(parsed_bookmarks[0], false, url1, url1_title, t1,
    253                             bookmark_folder_name, f1_title, string16());
    254   AssertBookmarkEntryEquals(parsed_bookmarks[1], false, url2, url2_title, t2,
    255                             bookmark_folder_name, f1_title, f2_title);
    256   AssertBookmarkEntryEquals(parsed_bookmarks[2], false, url3, url3_title, t3,
    257                             bookmark_folder_name, string16(), string16());
    258   AssertBookmarkEntryEquals(parsed_bookmarks[3], false, url4, url4_title, t4,
    259                             bookmark_folder_name, string16(), string16());
    260   AssertBookmarkEntryEquals(parsed_bookmarks[4], false, url1, url1_title, t1,
    261                             string16(), string16(), string16());
    262   AssertBookmarkEntryEquals(parsed_bookmarks[5], false, url2, url2_title, t2,
    263                             string16(), string16(), string16());
    264   AssertBookmarkEntryEquals(parsed_bookmarks[6], false, url1, url1_title, t1,
    265                             f3_title, f4_title, string16());
    266 }
    267