bookmark_html_writer_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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. 4 5#include "testing/gtest/include/gtest/gtest.h" 6 7#include "base/file_util.h" 8#include "base/i18n/time_formatting.h" 9#include "base/message_loop.h" 10#include "base/path_service.h" 11#include "base/scoped_temp_dir.h" 12#include "base/string16.h" 13#include "base/string_util.h" 14#include "base/time.h" 15#include "base/utf_string_conversions.h" 16#include "chrome/browser/bookmarks/bookmark_html_writer.h" 17#include "chrome/browser/bookmarks/bookmark_model.h" 18#include "chrome/browser/bookmarks/bookmark_model_factory.h" 19#include "chrome/browser/favicon/favicon_service_factory.h" 20#include "chrome/browser/history/history_service_factory.h" 21#include "chrome/browser/importer/firefox2_importer.h" 22#include "chrome/test/base/testing_profile.h" 23#include "content/public/test/test_browser_thread.h" 24#include "grit/generated_resources.h" 25#include "third_party/skia/include/core/SkBitmap.h" 26#include "ui/base/l10n/l10n_util.h" 27#include "ui/gfx/codec/png_codec.h" 28 29using content::BrowserThread; 30 31namespace { 32 33static const int kIconWidth = 16; 34static const int kIconHeight = 16; 35 36void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) { 37 bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h); 38 bmp->allocPixels(); 39 40 uint32_t* src_data = bmp->getAddr32(0, 0); 41 for (int i = 0; i < w * h; i++) { 42 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240); 43 } 44} 45 46} // namespace 47 48class BookmarkHTMLWriterTest : public testing::Test { 49 protected: 50 virtual void SetUp() { 51 testing::Test::SetUp(); 52 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 53 path_ = temp_dir_.path().AppendASCII("bookmarks.html"); 54 } 55 56 // Converts a BookmarkEntry to a string suitable for assertion testing. 57 string16 BookmarkEntryToString(const ProfileWriter::BookmarkEntry& entry) { 58 string16 result; 59 result.append(ASCIIToUTF16("on_toolbar=")); 60 if (entry.in_toolbar) 61 result.append(ASCIIToUTF16("true")); 62 else 63 result.append(ASCIIToUTF16("false")); 64 65 result.append(ASCIIToUTF16(" url=") + UTF8ToUTF16(entry.url.spec())); 66 67 result.append(ASCIIToUTF16(" path=")); 68 for (size_t i = 0; i < entry.path.size(); ++i) { 69 if (i != 0) 70 result.append(ASCIIToUTF16("/")); 71 result.append(entry.path[i]); 72 } 73 74 result.append(ASCIIToUTF16(" title=")); 75 result.append(entry.title); 76 77 result.append(ASCIIToUTF16(" time=")); 78 result.append(base::TimeFormatFriendlyDateAndTime(entry.creation_time)); 79 return result; 80 } 81 82 // Creates a set of bookmark values to a string for assertion testing. 83 string16 BookmarkValuesToString(bool on_toolbar, 84 const GURL& url, 85 const string16& title, 86 base::Time creation_time, 87 const string16& f1, 88 const string16& f2, 89 const string16& f3) { 90 ProfileWriter::BookmarkEntry entry; 91 entry.in_toolbar = on_toolbar; 92 entry.url = url; 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. 124class 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. 141TEST_F(BookmarkHTMLWriterTest, Test) { 142 MessageLoop message_loop; 143 content::TestBrowserThread fake_ui_thread(BrowserThread::UI, &message_loop); 144 content::TestBrowserThread fake_file_thread(BrowserThread::FILE, 145 &message_loop); 146 147 TestingProfile profile; 148 profile.CreateHistoryService(true, false); 149 profile.BlockUntilHistoryProcessesPendingRequests(); 150 profile.CreateFaviconService(); 151 profile.CreateBookmarkModel(true); 152 profile.BlockUntilBookmarkModelLoaded(); 153 BookmarkModel* model = BookmarkModelFactory::GetForProfile(&profile); 154 155 // Create test PNG representing favicon for url1. 156 SkBitmap bitmap; 157 MakeTestSkBitmap(kIconWidth, kIconHeight, &bitmap); 158 std::vector<unsigned char> icon_data; 159 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_data); 160 161 // Populate the BookmarkModel. This creates the following bookmark structure: 162 // Bookmarks bar 163 // F1 164 // url1 165 // F2 166 // url2 167 // url3 168 // url4 169 // Other 170 // url1 171 // url2 172 // F3 173 // F4 174 // url1 175 // Mobile 176 // url1 177 string16 f1_title = ASCIIToUTF16("F\"&;<1\""); 178 string16 f2_title = ASCIIToUTF16("F2"); 179 string16 f3_title = ASCIIToUTF16("F 3"); 180 string16 f4_title = ASCIIToUTF16("F4"); 181 string16 url1_title = ASCIIToUTF16("url 1"); 182 string16 url2_title = ASCIIToUTF16("url&2"); 183 string16 url3_title = ASCIIToUTF16("url\"3"); 184 string16 url4_title = ASCIIToUTF16("url\"&;"); 185 GURL url1("http://url1"); 186 GURL url1_favicon("http://url1/icon.ico"); 187 GURL url2("http://url2"); 188 GURL url3("http://url3"); 189 GURL url4("javascript:alert(\"Hello!\");"); 190 base::Time t1(base::Time::Now()); 191 base::Time t2(t1 + base::TimeDelta::FromHours(1)); 192 base::Time t3(t1 + base::TimeDelta::FromHours(1)); 193 base::Time t4(t1 + base::TimeDelta::FromHours(1)); 194 const BookmarkNode* f1 = model->AddFolder( 195 model->bookmark_bar_node(), 0, f1_title); 196 model->AddURLWithCreationTime(f1, 0, url1_title, url1, t1); 197 HistoryServiceFactory::GetForProfile(&profile, Profile::EXPLICIT_ACCESS)-> 198 AddPage(url1, base::Time::Now(), history::SOURCE_BROWSED); 199 FaviconServiceFactory::GetForProfile( 200 &profile, Profile::EXPLICIT_ACCESS)->SetFavicons( 201 url1, url1_favicon, history::FAVICON, gfx::Image(bitmap)); 202 message_loop.RunAllPending(); 203 const BookmarkNode* f2 = model->AddFolder(f1, 1, f2_title); 204 model->AddURLWithCreationTime(f2, 0, url2_title, url2, t2); 205 model->AddURLWithCreationTime(model->bookmark_bar_node(), 206 1, url3_title, url3, t3); 207 208 model->AddURLWithCreationTime(model->other_node(), 0, url1_title, url1, t1); 209 model->AddURLWithCreationTime(model->other_node(), 1, url2_title, url2, t2); 210 const BookmarkNode* f3 = model->AddFolder(model->other_node(), 2, f3_title); 211 const BookmarkNode* f4 = model->AddFolder(f3, 0, f4_title); 212 model->AddURLWithCreationTime(f4, 0, url1_title, url1, t1); 213 model->AddURLWithCreationTime(model->bookmark_bar_node(), 2, url4_title, 214 url4, t4); 215 model->AddURLWithCreationTime(model->mobile_node(), 0, url1_title, url1, t1); 216 217 // Write to a temp file. 218 BookmarksObserver observer(&message_loop); 219 bookmark_html_writer::WriteBookmarks(&profile, path_, &observer); 220 message_loop.Run(); 221 222 // Clear favicon so that it would be read from file. 223 FaviconServiceFactory::GetForProfile( 224 &profile, Profile::EXPLICIT_ACCESS)->SetFavicons( 225 url1, url1_favicon, history::FAVICON, gfx::Image()); 226 message_loop.RunAllPending(); 227 228 // Read the bookmarks back in. 229 std::vector<ProfileWriter::BookmarkEntry> parsed_bookmarks; 230 std::vector<history::ImportedFaviconUsage> favicons; 231 Firefox2Importer::ImportBookmarksFile(path_, 232 std::set<GURL>(), 233 NULL, 234 &parsed_bookmarks, 235 NULL, 236 &favicons); 237 238 // Check loaded favicon (url1 is represented by 4 separate bookmarks). 239 EXPECT_EQ(4U, favicons.size()); 240 for (size_t i = 0; i < favicons.size(); i++) { 241 if (url1_favicon == favicons[i].favicon_url) { 242 EXPECT_EQ(1U, favicons[i].urls.size()); 243 std::set<GURL>::const_iterator iter = favicons[i].urls.find(url1); 244 ASSERT_TRUE(iter != favicons[i].urls.end()); 245 ASSERT_TRUE(*iter == url1); 246 ASSERT_TRUE(favicons[i].png_data == icon_data); 247 } 248 } 249 250 // Verify we got back what we wrote. 251 ASSERT_EQ(8U, parsed_bookmarks.size()); 252 // Windows and ChromeOS builds use Sentence case. 253 string16 bookmark_folder_name = 254 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME); 255 AssertBookmarkEntryEquals(parsed_bookmarks[0], true, url1, url1_title, t1, 256 bookmark_folder_name, f1_title, string16()); 257 AssertBookmarkEntryEquals(parsed_bookmarks[1], true, url2, url2_title, t2, 258 bookmark_folder_name, f1_title, f2_title); 259 AssertBookmarkEntryEquals(parsed_bookmarks[2], true, url3, url3_title, t3, 260 bookmark_folder_name, string16(), string16()); 261 AssertBookmarkEntryEquals(parsed_bookmarks[3], true, url4, url4_title, t4, 262 bookmark_folder_name, string16(), string16()); 263 AssertBookmarkEntryEquals(parsed_bookmarks[4], false, url1, url1_title, t1, 264 string16(), string16(), string16()); 265 AssertBookmarkEntryEquals(parsed_bookmarks[5], false, url2, url2_title, t2, 266 string16(), string16(), string16()); 267 AssertBookmarkEntryEquals(parsed_bookmarks[6], false, url1, url1_title, t1, 268 f3_title, f4_title, string16()); 269 AssertBookmarkEntryEquals(parsed_bookmarks[7], false, url1, url1_title, t1, 270 string16(), string16(), string16()); 271} 272