summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-05 23:50:35 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-05 23:50:35 +0000
commit06a793f89522301fe42fbaaffba20a301f809d72 (patch)
treea82f89826a1e5baf4c456f0ba60c5d0b846e5df0 /chrome/browser
parent6b1c25b4adfcd0ce330c10a65d3eed22182f59f8 (diff)
downloadchromium_src-06a793f89522301fe42fbaaffba20a301f809d72.zip
chromium_src-06a793f89522301fe42fbaaffba20a301f809d72.tar.gz
chromium_src-06a793f89522301fe42fbaaffba20a301f809d72.tar.bz2
Safari Bookmark/Favicon import.
Review URL: http://codereview.chromium.org/159750 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22556 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/first_run_mac.mm16
-rw-r--r--chrome/browser/importer/firefox3_importer.cc20
-rw-r--r--chrome/browser/importer/safari_importer.h46
-rw-r--r--chrome/browser/importer/safari_importer.mm247
-rw-r--r--chrome/browser/importer/safari_importer_unittest.mm104
5 files changed, 344 insertions, 89 deletions
diff --git a/chrome/browser/first_run_mac.mm b/chrome/browser/first_run_mac.mm
index d839bf4..7242f94 100644
--- a/chrome/browser/first_run_mac.mm
+++ b/chrome/browser/first_run_mac.mm
@@ -91,13 +91,15 @@ bool OpenFirstRunDialog(Profile* profile, ProcessSingleton* process_singleton) {
}
// Import bookmarks.
- const ProfileInfo& source_profile = importer_host->GetSourceProfileInfoAt(
- [dialog.get() browserImportSelectedIndex]);
- int items = SEARCH_ENGINES + HISTORY + FAVORITES + HOME_PAGE + PASSWORDS;
- // TODO(port): Call StartImportingWithUI here instead and launch
- // a new process that does the actual import.
- importer_host->StartImportSettings(source_profile, profile, items,
- new ProfileWriter(profile), true);
+ if ([dialog.get() importBookmarks]) {
+ const ProfileInfo& source_profile = importer_host->GetSourceProfileInfoAt(
+ [dialog.get() browserImportSelectedIndex]);
+ int items = SEARCH_ENGINES + HISTORY + FAVORITES + HOME_PAGE + PASSWORDS;
+ // TODO(port): Call StartImportingWithUI here instead and launch
+ // a new process that does the actual import.
+ importer_host->StartImportSettings(source_profile, profile, items,
+ new ProfileWriter(profile), true);
+ }
#endif // defined(GOOGLE_CHROME_BUILD)
return true;
diff --git a/chrome/browser/importer/firefox3_importer.cc b/chrome/browser/importer/firefox3_importer.cc
index ffdf407..8ee342c 100644
--- a/chrome/browser/importer/firefox3_importer.cc
+++ b/chrome/browser/importer/firefox3_importer.cc
@@ -24,20 +24,6 @@
using base::Time;
using webkit_glue::PasswordForm;
-// Wraps the function sqlite3_close() in a class that is
-// used in scoped_ptr_malloc.
-
-namespace {
-
-class DBClose {
- public:
- inline void operator()(sqlite3* x) const {
- sqlite3_close(x);
- }
-};
-
-} // namespace
-
void Firefox3Importer::StartImport(ProfileInfo profile_info,
uint16 items, ProfileWriter* writer,
MessageLoop* delagate_loop,
@@ -84,7 +70,7 @@ void Firefox3Importer::ImportHistory() {
sqlite3* sqlite;
if (sqlite3_open(WideToUTF8(file).c_str(), &sqlite) != SQLITE_OK)
return;
- scoped_ptr_malloc<sqlite3, DBClose> db(sqlite);
+ sqlite_utils::scoped_sqlite_db_ptr db(sqlite);
SQLStatement s;
// |visit_type| represent the transition type of URLs (typed, click,
@@ -133,7 +119,7 @@ void Firefox3Importer::ImportBookmarks() {
sqlite3* sqlite;
if (sqlite3_open(WideToUTF8(file).c_str(), &sqlite) != SQLITE_OK)
return;
- scoped_ptr_malloc<sqlite3, DBClose> db(sqlite);
+ sqlite_utils::scoped_sqlite_db_ptr db(sqlite);
// Get the bookmark folders that we are interested in.
int toolbar_folder_id = -1;
@@ -329,7 +315,7 @@ void Firefox3Importer::GetSearchEnginesXMLFiles(
sqlite3* sqlite;
if (sqlite3_open(WideToUTF8(file).c_str(), &sqlite) != SQLITE_OK)
return;
- scoped_ptr_malloc<sqlite3, DBClose> db(sqlite);
+ sqlite_utils::scoped_sqlite_db_ptr db(sqlite);
SQLStatement s;
const char* stmt = "SELECT engineid FROM engine_data "
diff --git a/chrome/browser/importer/safari_importer.h b/chrome/browser/importer/safari_importer.h
index 28b939f..75f2a65 100644
--- a/chrome/browser/importer/safari_importer.h
+++ b/chrome/browser/importer/safari_importer.h
@@ -7,6 +7,12 @@
#include "chrome/browser/importer/importer.h"
+#include <map>
+#include <set>
+#include <vector>
+
+#include "chrome/common/sqlite_utils.h"
+
#if __OBJC__
@class NSDictionary;
@class NSString;
@@ -31,14 +37,35 @@ class SafariImporter : public Importer {
ImporterHost* host);
private:
+ FRIEND_TEST(SafariImporterTest, BookmarkImport);
+ FRIEND_TEST(SafariImporterTest, FavIconImport);
FRIEND_TEST(SafariImporterTest, HistoryImport);
+ // Multiple URLs can share the same FavIcon, this is a map
+ // of URLs -> IconIDs that we load as a temporary step before
+ // actually loading the icons.
+ typedef std::map<int64, std::set<GURL> > FaviconMap;
+
void ImportBookmarks();
- void ImportSearchEngines();
void ImportPasswords();
void ImportHistory();
void ImportHomepage();
+ // Parse Safari's stored bookmarks.
+ void ParseBookmarks(std::vector<ProfileWriter::BookmarkEntry>* bookmarks);
+
+ // Function to recursively read Bookmarks out of Safari plist.
+ // |bookmark_folder| The dictionary containing a folder to parse.
+ // |parent_path_elements| Path elements up to this point.
+ // |is_in_toolbar| Is this folder in the toolbar.
+ // |out_bookmarks| BookMark element array to write into.
+ void RecursiveReadBookmarksFolder(
+ NSDictionary* bookmark_folder,
+ const std::vector<std::wstring>& parent_path_elements,
+ bool is_in_toolbar,
+ std::vector<ProfileWriter::BookmarkEntry>* out_bookmarks);
+
+
// Converts history time stored by Safari as a double serialized as a string,
// to seconds-since-UNIX-Ephoch-format used by Chrome.
double HistoryTimeToEpochTime(NSString* history_time);
@@ -46,13 +73,16 @@ class SafariImporter : public Importer {
// Parses Safari's history and loads it into the input array.
void ParseHistoryItems(std::vector<history::URLRow>* history_items);
- // Given the URL of a page and a favicon data URL, adds an appropriate record
- // to the given favicon usage vector. Will do nothing if the favicon is not
- // valid.
- static void DataURLToFaviconUsage(
- const GURL& link_url,
- const GURL& favicon_data,
- std::vector<history::ImportedFavIconUsage>* favicons);
+ // Loads the favicon Database file, returns NULL on failure.
+ sqlite3* OpenFavIconDB();
+
+ // Loads the urls associated with the favicons into favicon_map;
+ void ImportFavIconURLs(sqlite3* db, FaviconMap* favicon_map);
+
+ // Loads and reencodes the individual favicons.
+ void LoadFaviconData(sqlite3* db,
+ const FaviconMap& favicon_map,
+ std::vector<history::ImportedFavIconUsage>* favicons);
ProfileWriter* writer_;
FilePath library_dir_;
diff --git a/chrome/browser/importer/safari_importer.mm b/chrome/browser/importer/safari_importer.mm
index 78e1111..0057aef 100644
--- a/chrome/browser/importer/safari_importer.mm
+++ b/chrome/browser/importer/safari_importer.mm
@@ -6,13 +6,16 @@
#include "chrome/browser/importer/safari_importer.h"
+#include <map>
#include <vector>
+#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/scoped_nsobject.h"
#include "base/string16.h"
#include "base/sys_string_conversions.h"
#include "base/time.h"
+#include "chrome/common/sqlite_utils.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
@@ -57,11 +60,6 @@ void SafariImporter::StartImport(ProfileInfo profile_info,
ImportBookmarks();
NotifyItemEnded(FAVORITES);
}
- if ((items & SEARCH_ENGINES) && !cancelled()) {
- NotifyItemStarted(SEARCH_ENGINES);
- ImportSearchEngines();
- NotifyItemEnded(SEARCH_ENGINES);
- }
if ((items & PASSWORDS) && !cancelled()) {
NotifyItemStarted(PASSWORDS);
ImportPasswords();
@@ -76,11 +74,199 @@ void SafariImporter::StartImport(ProfileInfo profile_info,
}
void SafariImporter::ImportBookmarks() {
- NOTIMPLEMENTED();
+ std::vector<ProfileWriter::BookmarkEntry> bookmarks;
+ ParseBookmarks(&bookmarks);
+
+ // Write bookmarks into profile.
+ if (!bookmarks.empty() && !cancelled()) {
+ main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
+ &ProfileWriter::AddBookmarkEntry, bookmarks,
+ l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_SAFARI),
+ import_to_bookmark_bar() ? ProfileWriter::IMPORT_TO_BOOKMARK_BAR : 0));
+ }
+
+ // Import favicons.
+ sqlite_utils::scoped_sqlite_db_ptr db(OpenFavIconDB());
+ FaviconMap favicon_map;
+ ImportFavIconURLs(db.get(), &favicon_map);
+ // Write favicons into profile.
+ if (!favicon_map.empty() && !cancelled()) {
+ std::vector<history::ImportedFavIconUsage> favicons;
+ LoadFaviconData(db.get(), favicon_map, &favicons);
+ main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
+ &ProfileWriter::AddFavicons, favicons));
+ }
+}
+
+sqlite3* SafariImporter::OpenFavIconDB() {
+ // Construct ~/Library/Safari/WebIcons.db path
+ NSString* library_dir = [NSString
+ stringWithUTF8String:library_dir_.value().c_str()];
+ NSString* safari_dir = [library_dir
+ stringByAppendingPathComponent:@"Safari"];
+ NSString* favicons_db_path = [safari_dir
+ stringByAppendingPathComponent:@"WebpageIcons.db"];
+
+ sqlite3* favicons_db;
+ const char* safariicons_dbname = [favicons_db_path fileSystemRepresentation];
+ if (sqlite3_open(safariicons_dbname, &favicons_db) != SQLITE_OK)
+ return NULL;
+
+ return favicons_db;
+}
+
+void SafariImporter::ImportFavIconURLs(sqlite3* db, FaviconMap* favicon_map) {
+ SQLStatement s;
+ const char* stmt = "SELECT iconID, url FROM PageURL;";
+ if (s.prepare(db, stmt) != SQLITE_OK)
+ return;
+
+ while (s.step() == SQLITE_ROW && !cancelled()) {
+ int64 icon_id = s.column_int(0);
+ GURL url = GURL(s.column_string(1));
+ (*favicon_map)[icon_id].insert(url);
+ }
}
-void SafariImporter::ImportSearchEngines() {
- NOTIMPLEMENTED();
+void SafariImporter::LoadFaviconData(sqlite3* db,
+ const FaviconMap& favicon_map,
+ std::vector<history::ImportedFavIconUsage>* favicons) {
+ SQLStatement s;
+ const char* stmt = "SELECT i.url, d.data "
+ "FROM IconInfo i JOIN IconData d "
+ "ON i.iconID = d.iconID "
+ "WHERE i.iconID = ?;";
+ if (s.prepare(db, stmt) != SQLITE_OK)
+ return;
+
+ for (FaviconMap::const_iterator i = favicon_map.begin();
+ i != favicon_map.end(); ++i) {
+ s.bind_int64(0, i->first);
+ if (s.step() == SQLITE_ROW) {
+ history::ImportedFavIconUsage usage;
+
+ usage.favicon_url = GURL(s.column_string(0));
+ if (!usage.favicon_url.is_valid())
+ continue; // Don't bother importing favicons with invalid URLs.
+
+ std::vector<unsigned char> data;
+ if (!s.column_blob_as_vector(1, &data) || data.empty())
+ continue; // Data definitely invalid.
+
+ if (!ReencodeFavicon(&data[0], data.size(), &usage.png_data))
+ continue; // Unable to decode.
+
+ usage.urls = i->second;
+ favicons->push_back(usage);
+ }
+ s.reset();
+ }
+}
+
+void SafariImporter::RecursiveReadBookmarksFolder(
+ NSDictionary* bookmark_folder,
+ const std::vector<std::wstring>& parent_path_elements,
+ bool is_in_toolbar,
+ std::vector<ProfileWriter::BookmarkEntry>* out_bookmarks) {
+ DCHECK(bookmark_folder);
+
+ NSString* type = [bookmark_folder objectForKey:@"WebBookmarkType"];
+ NSString* title = [bookmark_folder objectForKey:@"Title"];
+
+ // Are we the dictionary that contains all other bookmarks?
+ // We need to know this so we don't add it to the path.
+ bool is_top_level_bookmarks_container = [bookmark_folder
+ objectForKey:@"WebBookmarkFileVersion"] != nil;
+
+ // We're expecting a list of bookmarks here, if that isn't what we got, fail.
+ if (![type isEqualToString:@"WebBookmarkTypeList"] || !title) {
+ DCHECK(false) << "Type =("
+ << (type ? base::SysNSStringToUTF8(type) : "Null Type")
+ << ") Title=(" << (title ? base::SysNSStringToUTF8(title) : "Null title")
+ << ")";
+ return;
+ }
+
+ std::vector<std::wstring> path_elements(parent_path_elements);
+ // Is this the toolbar folder?
+ if ([title isEqualToString:@"BookmarksBar"]) {
+ // Be defensive, the toolbar items shouldn't have a prepended path.
+ path_elements.clear();
+ is_in_toolbar = true;
+ } else if ([title isEqualToString:@"BookmarksMenu"]) {
+ // top level container for normal bookmarks.
+ path_elements.clear();
+ } else if (!is_top_level_bookmarks_container) {
+ if (title)
+ path_elements.push_back(base::SysNSStringToWide(title));
+ }
+
+ NSArray* elements = [bookmark_folder objectForKey:@"Children"];
+ // TODO(jeremy) Does Chrome support importing empty folders?
+ if (!elements)
+ return;
+
+ // Iterate over individual bookmarks.
+ for (NSDictionary* bookmark in elements) {
+ NSString* type = [bookmark objectForKey:@"WebBookmarkType"];
+ if (!type)
+ continue;
+
+ // If this is a folder, recurse.
+ if ([type isEqualToString:@"WebBookmarkTypeList"]) {
+ RecursiveReadBookmarksFolder(bookmark,
+ path_elements,
+ is_in_toolbar,
+ out_bookmarks);
+ }
+
+ // If we didn't see a bookmark folder, then we're expecting a bookmark
+ // item, if that's not what we got then ignore it.
+ if (![type isEqualToString:@"WebBookmarkTypeLeaf"])
+ continue;
+
+ NSString* url = [bookmark objectForKey:@"URLString"];
+ NSString* title = [[bookmark objectForKey:@"URIDictionary"]
+ objectForKey:@"title"];
+
+ if (!url || !title)
+ continue;
+
+ // Output Bookmark.
+ ProfileWriter::BookmarkEntry entry;
+ // Safari doesn't specify a creation time for the bookmark.
+ entry.creation_time = base::Time::Now();
+ entry.title = base::SysNSStringToWide(title);
+ entry.url = GURL(base::SysNSStringToUTF8(url));
+ entry.path = path_elements;
+ entry.in_toolbar = is_in_toolbar;
+
+ out_bookmarks->push_back(entry);
+ }
+}
+
+void SafariImporter::ParseBookmarks(
+ std::vector<ProfileWriter::BookmarkEntry>* bookmarks) {
+ DCHECK(bookmarks);
+
+ // Construct ~/Library/Safari/Bookmarks.plist path
+ NSString* library_dir = [NSString
+ stringWithUTF8String:library_dir_.value().c_str()];
+ NSString* safari_dir = [library_dir
+ stringByAppendingPathComponent:@"Safari"];
+ NSString* bookmarks_plist = [safari_dir
+ stringByAppendingPathComponent:@"Bookmarks.plist"];
+
+ // Load the plist file.
+ NSDictionary* bookmarks_dict = [NSDictionary
+ dictionaryWithContentsOfFile:bookmarks_plist];
+ if (!bookmarks_dict)
+ return;
+
+ // Recursively read in bookmarks.
+ std::vector<std::wstring> parent_path_elements;
+ RecursiveReadBookmarksFolder(bookmarks_dict, parent_path_elements, false,
+ bookmarks);
}
void SafariImporter::ImportPasswords() {
@@ -126,13 +312,15 @@ void SafariImporter::ParseHistoryItems(
// Load the plist file.
NSDictionary* history_dict = [NSDictionary
dictionaryWithContentsOfFile:history_plist];
+ if (!history_dict)
+ return;
- NSArray* safari_history_items = [history_dict valueForKey:@"WebHistoryDates"];
+ NSArray* safari_history_items = [history_dict objectForKey:@"WebHistoryDates"];
for (NSDictionary* history_item in safari_history_items) {
using base::SysNSStringToUTF8;
using base::SysNSStringToWide;
- NSString* url_ns = [history_item valueForKey:@""];
+ NSString* url_ns = [history_item objectForKey:@""];
if (!url_ns)
continue;
@@ -142,7 +330,7 @@ void SafariImporter::ParseHistoryItems(
continue;
history::URLRow row(url);
- NSString* title_ns = [history_item valueForKey:@"title"];
+ NSString* title_ns = [history_item objectForKey:@"title"];
// Sometimes items don't have a title, in which case we just substitue
// the url.
@@ -150,7 +338,7 @@ void SafariImporter::ParseHistoryItems(
title_ns = url_ns;
row.set_title(SysNSStringToWide(title_ns));
- int visit_count = [[history_item valueForKey:@"visitCount"]
+ int visit_count = [[history_item objectForKey:@"visitCount"]
intValue];
row.set_visit_count(visit_count);
// Include imported URLs in autocompletion - don't hide them.
@@ -158,7 +346,7 @@ void SafariImporter::ParseHistoryItems(
// Item was never typed before in the omnibox.
row.set_typed_count(0);
- NSString* last_visit_str = [history_item valueForKey:@"lastVisitedDate"];
+ NSString* last_visit_str = [history_item objectForKey:@"lastVisitedDate"];
// The last visit time should always be in the history item, but if not
/// just continue without this item.
DCHECK(last_visit_str);
@@ -188,36 +376,3 @@ void SafariImporter::ImportHomepage() {
&ProfileWriter::AddHomepage, homepage));
}
}
-
-// TODO(jeremy): This is temporary, just copied from the FF import code in case
-// we need it, clean this up when writing favicon import code.
-// static
-void SafariImporter::DataURLToFaviconUsage(
- const GURL& link_url,
- const GURL& favicon_data,
- std::vector<history::ImportedFavIconUsage>* favicons) {
- if (!link_url.is_valid() || !favicon_data.is_valid() ||
- !favicon_data.SchemeIs(chrome::kDataScheme))
- return;
-
- // Parse the data URL.
- std::string mime_type, char_set, data;
- if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) ||
- data.empty())
- return;
-
- history::ImportedFavIconUsage usage;
- if (!ReencodeFavicon(reinterpret_cast<const unsigned char*>(&data[0]),
- data.size(), &usage.png_data))
- return; // Unable to decode.
-
- // We need to make up a URL for the favicon. We use a version of the page's
- // URL so that we can be sure it will not collide.
- usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec());
-
- // We only have one URL per favicon for Firefox 2 bookmarks.
- usage.urls.insert(link_url);
-
- favicons->push_back(usage);
-}
-
diff --git a/chrome/browser/importer/safari_importer_unittest.mm b/chrome/browser/importer/safari_importer_unittest.mm
index af0ae9e..78b4f65 100644
--- a/chrome/browser/importer/safari_importer_unittest.mm
+++ b/chrome/browser/importer/safari_importer_unittest.mm
@@ -4,6 +4,7 @@
#include "chrome/browser/importer/safari_importer.h"
+#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
@@ -19,28 +20,32 @@ FilePath GetTestSafariLibraryPath() {
std::wstring test_dir_wstring;
PathService::Get(chrome::DIR_TEST_DATA, &test_dir_wstring);
FilePath test_dir = FilePath::FromWStringHack(test_dir_wstring);
-
+
// Our simulated ~/Library directory
test_dir = test_dir.Append("safari_import");
return test_dir;
}
-class SafariImporterTest : public PlatformTest {};
+class SafariImporterTest : public PlatformTest {
+ public:
+ SafariImporter* GetSafariImporter() {
+ FilePath test_library_dir = GetTestSafariLibraryPath();
+ CHECK(file_util::PathExists(test_library_dir)) <<
+ "Missing test data directory";
+
+ return new SafariImporter(test_library_dir);
+ }
+};
TEST_F(SafariImporterTest, HistoryImport) {
- FilePath test_library_dir = GetTestSafariLibraryPath();
- ASSERT_TRUE(file_util::PathExists(test_library_dir)) <<
- "Missing test data directory";
+ scoped_refptr<SafariImporter> importer(GetSafariImporter());
- scoped_refptr<SafariImporter> importer(
- new SafariImporter(test_library_dir));
-
std::vector<history::URLRow> history_items;
importer->ParseHistoryItems(&history_items);
-
+
// Should be 2 history items.
ASSERT_EQ(history_items.size(), 2U);
-
+
history::URLRow& it1 = history_items[0];
EXPECT_EQ(it1.url(), GURL("http://www.firsthistoryitem.com/"));
EXPECT_EQ(it1.title(), L"First History Item Title");
@@ -49,7 +54,7 @@ TEST_F(SafariImporterTest, HistoryImport) {
EXPECT_EQ(it1.typed_count(), 0);
EXPECT_EQ(it1.last_visit().ToDoubleT(),
importer->HistoryTimeToEpochTime(@"270598264.4"));
-
+
history::URLRow& it2 = history_items[1];
std::string second_item_title("http://www.secondhistoryitem.com/");
EXPECT_EQ(it2.url(), GURL(second_item_title));
@@ -61,3 +66,80 @@ TEST_F(SafariImporterTest, HistoryImport) {
EXPECT_EQ(it2.last_visit().ToDoubleT(),
importer->HistoryTimeToEpochTime(@"270598231.4"));
}
+
+TEST_F(SafariImporterTest, BookmarkImport) {
+ // Expected results
+ const struct {
+ bool in_toolbar;
+ GURL url;
+ // If the path array for an element is entry set this to true.
+ bool path_is_empty;
+ // We ony support one level of nesting in paths, this makes testing a little
+ // easier.
+ std::wstring path;
+ std::wstring title;
+ } kImportedBookmarksData[] = {
+ {true, GURL("http://www.apple.com/"), true, L"", L"Apple"},
+ {true, GURL("http://www.yahoo.com/"), true, L"", L"Yahoo!"},
+ {true, GURL("http://www.cnn.com/"), false, L"News", L"CNN"},
+ {true, GURL("http://www.nytimes.com/"), false, L"News",
+ L"The New York Times"},
+ {false, GURL("http://www.reddit.com/"), true, L"",
+ L"reddit.com: what's new online!"},
+ };
+
+ scoped_refptr<SafariImporter> importer(GetSafariImporter());
+ std::vector<ProfileWriter::BookmarkEntry> bookmarks;
+ importer->ParseBookmarks(&bookmarks);
+ size_t num_bookmarks = bookmarks.size();
+ EXPECT_EQ(num_bookmarks, ARRAYSIZE_UNSAFE(kImportedBookmarksData));
+
+ for (size_t i = 0; i < num_bookmarks; ++i) {
+ ProfileWriter::BookmarkEntry& entry = bookmarks[i];
+ EXPECT_EQ(entry.in_toolbar, kImportedBookmarksData[i].in_toolbar);
+ EXPECT_EQ(entry.url, kImportedBookmarksData[i].url);
+ if (kImportedBookmarksData[i].path_is_empty) {
+ EXPECT_EQ(entry.path.size(), 0U);
+ } else {
+ EXPECT_EQ(entry.path.size(), 1U);
+ EXPECT_EQ(entry.path[0], kImportedBookmarksData[i].path);
+ EXPECT_EQ(entry.title, kImportedBookmarksData[i].title);
+ }
+ }
+
+}
+
+TEST_F(SafariImporterTest, FavIconImport) {
+ scoped_refptr<SafariImporter> importer(GetSafariImporter());
+ sqlite_utils::scoped_sqlite_db_ptr db(importer->OpenFavIconDB());
+ ASSERT_TRUE(db.get() != NULL);
+
+ SafariImporter::FaviconMap favicon_map;
+ importer->ImportFavIconURLs(db.get(), &favicon_map);
+
+ std::vector<history::ImportedFavIconUsage> favicons;
+ importer->LoadFaviconData(db.get(), favicon_map, &favicons);
+
+ size_t num_favicons = favicons.size();
+ ASSERT_EQ(num_favicons, 2U);
+
+ history::ImportedFavIconUsage &fav0 = favicons[0];
+ EXPECT_EQ("http://s.ytimg.com/yt/favicon-vfl86270.ico",
+ fav0.favicon_url.spec());
+ EXPECT_GT(fav0.png_data.size(), 0U);
+ EXPECT_EQ(fav0.urls.size(), 1U);
+ EXPECT_TRUE(fav0.urls.find(GURL("http://www.youtube.com/"))
+ != fav0.urls.end());
+
+ history::ImportedFavIconUsage &fav1 = favicons[1];
+ EXPECT_EQ("http://www.opensearch.org/favicon.ico",
+ fav1.favicon_url.spec());
+ EXPECT_GT(fav1.png_data.size(), 0U);
+ EXPECT_EQ(fav1.urls.size(), 2U);
+ EXPECT_TRUE(fav1.urls.find(GURL("http://www.opensearch.org/Home"))
+ != fav1.urls.end());
+
+ EXPECT_TRUE(fav1.urls.find(
+ GURL("http://www.opensearch.org/Special:Search?search=lalala&go=Search"))
+ != fav1.urls.end());
+}