| Index: chrome/browser/importer/ie_importer_browsertest_win.cc
|
| diff --git a/chrome/browser/importer/ie_importer_unittest_win.cc b/chrome/browser/importer/ie_importer_browsertest_win.cc
|
| similarity index 84%
|
| copy from chrome/browser/importer/ie_importer_unittest_win.cc
|
| copy to chrome/browser/importer/ie_importer_browsertest_win.cc
|
| index 85b915be57fd2c8035b5df8a7503a3fe8c4b82b3..d7f9bf338a943bf33642091764d00c2900127bd6 100644
|
| --- a/chrome/browser/importer/ie_importer_unittest_win.cc
|
| +++ b/chrome/browser/importer/ie_importer_browsertest_win.cc
|
| @@ -1,652 +1,608 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "testing/gtest/include/gtest/gtest.h"
|
| -
|
| -// The order of these includes is important.
|
| -#include <windows.h>
|
| -#include <unknwn.h>
|
| -#include <intshcut.h>
|
| -#include <shlguid.h>
|
| -#include <urlhist.h>
|
| -#include <shlobj.h>
|
| -#include <propvarutil.h>
|
| -
|
| -#include <algorithm>
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "base/file_util.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/path_service.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/string_util.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "base/win/registry.h"
|
| -#include "base/win/scoped_com_initializer.h"
|
| -#include "base/win/scoped_comptr.h"
|
| -#include "base/win/scoped_propvariant.h"
|
| -#include "base/win/windows_version.h"
|
| -#include "chrome/browser/history/history_types.h"
|
| -#include "chrome/browser/importer/ie_importer.h"
|
| -#include "chrome/browser/importer/importer_bridge.h"
|
| -#include "chrome/browser/importer/importer_data_types.h"
|
| -#include "chrome/browser/importer/importer_host.h"
|
| -#include "chrome/browser/importer/importer_progress_observer.h"
|
| -#include "chrome/browser/importer/importer_unittest_utils.h"
|
| -#include "chrome/browser/importer/pstore_declarations.h"
|
| -#include "chrome/browser/search_engines/template_url.h"
|
| -#include "chrome/common/chrome_paths.h"
|
| -#include "chrome/test/base/testing_profile.h"
|
| -#include "components/webdata/encryptor/ie7_password.h"
|
| -#include "content/public/common/password_form.h"
|
| -
|
| -namespace {
|
| -
|
| -const char16 kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests";
|
| -const char16 kUnitTestUserOverrideSubKey[] =
|
| - L"SOFTWARE\\Chromium Unit Tests\\HKCU Override";
|
| -
|
| -const BookmarkInfo kIEBookmarks[] = {
|
| - {true, 2, {L"Links", L"SubFolderOfLinks"},
|
| - L"SubLink",
|
| - "http://www.links-sublink.com/"},
|
| - {true, 1, {L"Links"},
|
| - L"TheLink",
|
| - "http://www.links-thelink.com/"},
|
| - {false, 0, {},
|
| - L"Google Home Page",
|
| - "http://www.google.com/"},
|
| - {false, 0, {},
|
| - L"TheLink",
|
| - "http://www.links-thelink.com/"},
|
| - {false, 1, {L"SubFolder"},
|
| - L"Title",
|
| - "http://www.link.com/"},
|
| - {false, 0, {},
|
| - L"WithPortAndQuery",
|
| - "http://host:8080/cgi?q=query"},
|
| - {false, 1, {L"a"},
|
| - L"\x4E2D\x6587",
|
| - "http://chinese-title-favorite/"},
|
| - {false, 0, {},
|
| - L"SubFolder",
|
| - "http://www.subfolder.com/"},
|
| -};
|
| -
|
| -const BookmarkInfo kIESortedBookmarks[] = {
|
| - {false, 0, {}, L"a", "http://www.google.com/0"},
|
| - {false, 1, {L"b"}, L"a", "http://www.google.com/1"},
|
| - {false, 1, {L"b"}, L"b", "http://www.google.com/2"},
|
| - {false, 0, {}, L"c", "http://www.google.com/3"},
|
| -};
|
| -
|
| -const char16 kIEIdentifyUrl[] =
|
| - L"http://A79029D6-753E-4e27-B807-3D46AB1545DF.com:8080/path?key=value";
|
| -const char16 kIEIdentifyTitle[] =
|
| - L"Unittest GUID";
|
| -
|
| -const char16 kIEFavoritesOrderKey[] =
|
| - L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\"
|
| - L"MenuOrder\\Favorites";
|
| -
|
| -const char16 kFaviconStreamSuffix[] = L"url:favicon:$DATA";
|
| -const char kDummyFaviconImageData[] =
|
| - "\x42\x4D" // Magic signature 'BM'
|
| - "\x1E\x00\x00\x00" // File size
|
| - "\x00\x00\x00\x00" // Reserved
|
| - "\x1A\x00\x00\x00" // Offset of the pixel data
|
| - "\x0C\x00\x00\x00" // Header Size
|
| - "\x01\x00\x01\x00" // Size: 1x1
|
| - "\x01\x00" // Reserved
|
| - "\x18\x00" // 24-bits
|
| - "\x00\xFF\x00\x00"; // The pixel
|
| -
|
| -struct FaviconGroup {
|
| - const char16* favicon_url;
|
| - const char16* site_url[2];
|
| -};
|
| -
|
| -const FaviconGroup kIEFaviconGroup[2] = {
|
| - {L"http://www.google.com/favicon.ico",
|
| - {L"http://www.google.com/",
|
| - L"http://www.subfolder.com/"}},
|
| - {L"http://example.com/favicon.ico",
|
| - {L"http://host:8080/cgi?q=query",
|
| - L"http://chinese-title-favorite/"}},
|
| -};
|
| -
|
| -bool CreateOrderBlob(const base::FilePath& favorites_folder,
|
| - const string16& path,
|
| - const std::vector<string16>& entries) {
|
| - if (entries.size() > 255)
|
| - return false;
|
| -
|
| - // Create a binary sequence for setting a specific order of favorites.
|
| - // The format depends on the version of Shell32.dll, so we cannot embed
|
| - // a binary constant here.
|
| - std::vector<uint8> blob(20, 0);
|
| - blob[16] = static_cast<uint8>(entries.size());
|
| -
|
| - for (size_t i = 0; i < entries.size(); ++i) {
|
| - PIDLIST_ABSOLUTE id_list_full = ILCreateFromPath(
|
| - favorites_folder.Append(path).Append(entries[i]).value().c_str());
|
| - PUITEMID_CHILD id_list = ILFindLastID(id_list_full);
|
| - // Include the trailing zero-length item id. Don't include the single
|
| - // element array.
|
| - size_t id_list_size = id_list->mkid.cb + sizeof(id_list->mkid.cb);
|
| -
|
| - blob.resize(blob.size() + 8);
|
| - uint32 total_size = id_list_size + 8;
|
| - memcpy(&blob[blob.size() - 8], &total_size, 4);
|
| - uint32 sort_index = i;
|
| - memcpy(&blob[blob.size() - 4], &sort_index, 4);
|
| - blob.resize(blob.size() + id_list_size);
|
| - memcpy(&blob[blob.size() - id_list_size], id_list, id_list_size);
|
| - ILFree(id_list_full);
|
| - }
|
| -
|
| - string16 key_path = kIEFavoritesOrderKey;
|
| - if (!path.empty())
|
| - key_path += L"\\" + path;
|
| - base::win::RegKey key;
|
| - if (key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE) !=
|
| - ERROR_SUCCESS) {
|
| - return false;
|
| - }
|
| - if (key.WriteValue(L"Order", &blob[0], blob.size(), REG_BINARY) !=
|
| - ERROR_SUCCESS) {
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool CreateUrlFileWithFavicon(const base::FilePath& file,
|
| - const std::wstring& url,
|
| - const std::wstring& favicon_url) {
|
| - base::win::ScopedComPtr<IUniformResourceLocator> locator;
|
| - HRESULT result = locator.CreateInstance(CLSID_InternetShortcut, NULL,
|
| - CLSCTX_INPROC_SERVER);
|
| - if (FAILED(result))
|
| - return false;
|
| - base::win::ScopedComPtr<IPersistFile> persist_file;
|
| - result = persist_file.QueryFrom(locator);
|
| - if (FAILED(result))
|
| - return false;
|
| - result = locator->SetURL(url.c_str(), 0);
|
| - if (FAILED(result))
|
| - return false;
|
| -
|
| - // Write favicon url if specified.
|
| - if (!favicon_url.empty()) {
|
| - base::win::ScopedComPtr<IPropertySetStorage> property_set_storage;
|
| - if (FAILED(property_set_storage.QueryFrom(locator)))
|
| - return false;
|
| - base::win::ScopedComPtr<IPropertyStorage> property_storage;
|
| - if (FAILED(property_set_storage->Open(FMTID_Intshcut,
|
| - STGM_WRITE,
|
| - property_storage.Receive()))) {
|
| - return false;
|
| - }
|
| - PROPSPEC properties[] = {{PRSPEC_PROPID, PID_IS_ICONFILE}};
|
| - // WriteMultiple takes an array of PROPVARIANTs, but since this code only
|
| - // needs an array of size 1: a pointer to |pv_icon| is equivalent.
|
| - base::win::ScopedPropVariant pv_icon;
|
| - if (FAILED(InitPropVariantFromString(favicon_url.c_str(),
|
| - pv_icon.Receive())) ||
|
| - FAILED(property_storage->WriteMultiple(1, properties, &pv_icon, 0))) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // Save the .url file.
|
| - result = persist_file->Save(file.value().c_str(), TRUE);
|
| - if (FAILED(result))
|
| - return false;
|
| -
|
| - // Write dummy favicon image data in NTFS alternate data stream.
|
| - return favicon_url.empty() || (file_util::WriteFile(
|
| - file.ReplaceExtension(kFaviconStreamSuffix), kDummyFaviconImageData,
|
| - sizeof kDummyFaviconImageData) != -1);
|
| -}
|
| -
|
| -bool CreateUrlFile(const base::FilePath& file, const std::wstring& url) {
|
| - return CreateUrlFileWithFavicon(file, url, std::wstring());
|
| -}
|
| -
|
| -void ClearPStoreType(IPStore* pstore, const GUID* type, const GUID* subtype) {
|
| - base::win::ScopedComPtr<IEnumPStoreItems, NULL> item;
|
| - HRESULT result = pstore->EnumItems(0, type, subtype, 0, item.Receive());
|
| - if (result == PST_E_OK) {
|
| - char16* item_name;
|
| - while (SUCCEEDED(item->Next(1, &item_name, 0))) {
|
| - pstore->DeleteItem(0, type, subtype, item_name, NULL, 0);
|
| - CoTaskMemFree(item_name);
|
| - }
|
| - }
|
| - pstore->DeleteSubtype(0, type, subtype, 0);
|
| - pstore->DeleteType(0, type, 0);
|
| -}
|
| -
|
| -void WritePStore(IPStore* pstore, const GUID* type, const GUID* subtype) {
|
| - struct PStoreItem {
|
| - char16* name;
|
| - int data_size;
|
| - char* data;
|
| - } items[] = {
|
| - {L"http://localhost:8080/security/index.htm#ref:StringData", 8,
|
| - "\x31\x00\x00\x00\x32\x00\x00\x00"},
|
| - {L"http://localhost:8080/security/index.htm#ref:StringIndex", 20,
|
| - "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00"
|
| - "\x00\x00\x2f\x00\x74\x00\x01\x00\x00\x00"},
|
| - {L"user:StringData", 4,
|
| - "\x31\x00\x00\x00"},
|
| - {L"user:StringIndex", 20,
|
| - "\x57\x49\x43\x4b\x18\x00\x00\x00\x01\x00"
|
| - "\x00\x00\x2f\x00\x74\x00\x00\x00\x00\x00"},
|
| - };
|
| -
|
| - for (int i = 0; i < arraysize(items); ++i) {
|
| - HRESULT res = pstore->WriteItem(0, type, subtype, items[i].name,
|
| - items[i].data_size, reinterpret_cast<BYTE*>(items[i].data),
|
| - NULL, 0, 0);
|
| - ASSERT_TRUE(res == PST_E_OK);
|
| - }
|
| -}
|
| -
|
| -class TestObserver : public ProfileWriter,
|
| - public importer::ImporterProgressObserver {
|
| - public:
|
| - TestObserver() : ProfileWriter(NULL) {
|
| - bookmark_count_ = 0;
|
| - history_count_ = 0;
|
| - password_count_ = 0;
|
| - favicon_count_ = 0;
|
| - }
|
| -
|
| - // importer::ImporterProgressObserver:
|
| - virtual void ImportStarted() OVERRIDE {}
|
| - virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
|
| - virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
|
| - virtual void ImportEnded() OVERRIDE {
|
| - MessageLoop::current()->Quit();
|
| - EXPECT_EQ(arraysize(kIEBookmarks), bookmark_count_);
|
| - EXPECT_EQ(1, history_count_);
|
| - EXPECT_EQ(arraysize(kIEFaviconGroup), favicon_count_);
|
| - }
|
| -
|
| - virtual bool BookmarkModelIsLoaded() const {
|
| - // Profile is ready for writing.
|
| - return true;
|
| - }
|
| -
|
| - virtual bool TemplateURLServiceIsLoaded() const {
|
| - return true;
|
| - }
|
| -
|
| - virtual void AddPasswordForm(const content::PasswordForm& form) {
|
| - // Importer should obtain this password form only.
|
| - EXPECT_EQ(GURL("http://localhost:8080/security/index.htm"), form.origin);
|
| - EXPECT_EQ("http://localhost:8080/", form.signon_realm);
|
| - EXPECT_EQ(L"user", form.username_element);
|
| - EXPECT_EQ(L"1", form.username_value);
|
| - EXPECT_EQ(L"", form.password_element);
|
| - EXPECT_EQ(L"2", form.password_value);
|
| - EXPECT_EQ("", form.action.spec());
|
| - ++password_count_;
|
| - }
|
| -
|
| - virtual void AddHistoryPage(const history::URLRows& page,
|
| - history::VisitSource visit_source) {
|
| - // Importer should read the specified URL.
|
| - for (size_t i = 0; i < page.size(); ++i) {
|
| - if (page[i].title() == kIEIdentifyTitle &&
|
| - page[i].url() == GURL(kIEIdentifyUrl))
|
| - ++history_count_;
|
| - }
|
| - EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_source);
|
| - }
|
| -
|
| - virtual void AddBookmarks(const std::vector<BookmarkEntry>& bookmarks,
|
| - const string16& top_level_folder_name) OVERRIDE {
|
| - ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kIEBookmarks));
|
| - // Importer should import the IE Favorites folder the same as the list,
|
| - // in the same order.
|
| - for (size_t i = 0; i < bookmarks.size(); ++i) {
|
| - EXPECT_TRUE(EqualBookmarkEntry(bookmarks[i],
|
| - kIEBookmarks[bookmark_count_]));
|
| - ++bookmark_count_;
|
| - }
|
| - }
|
| -
|
| - virtual void AddKeyword(std::vector<TemplateURL*> template_url,
|
| - int default_keyword_index) {
|
| - // TODO(jcampan): bug 1169230: we should test keyword importing for IE.
|
| - // In order to do that we'll probably need to mock the Windows registry.
|
| - NOTREACHED();
|
| - STLDeleteContainerPointers(template_url.begin(), template_url.end());
|
| - }
|
| -
|
| - virtual void AddFavicons(
|
| - const std::vector<history::ImportedFaviconUsage>& usage) OVERRIDE {
|
| - // Importer should group the favicon information for each favicon URL.
|
| - for (size_t i = 0; i < arraysize(kIEFaviconGroup); ++i) {
|
| - GURL favicon_url(kIEFaviconGroup[i].favicon_url);
|
| - std::set<GURL> urls;
|
| - for (size_t j = 0; j < arraysize(kIEFaviconGroup[i].site_url); ++j)
|
| - urls.insert(GURL(kIEFaviconGroup[i].site_url[j]));
|
| -
|
| - SCOPED_TRACE(testing::Message() << "Expected Favicon: " << favicon_url);
|
| -
|
| - bool expected_favicon_url_found = false;
|
| - for (size_t j = 0; j < usage.size(); ++j) {
|
| - if (usage[j].favicon_url == favicon_url) {
|
| - EXPECT_EQ(urls, usage[j].urls);
|
| - expected_favicon_url_found = true;
|
| - break;
|
| - }
|
| - }
|
| - EXPECT_TRUE(expected_favicon_url_found);
|
| - }
|
| -
|
| - favicon_count_ += usage.size();
|
| - }
|
| -
|
| - private:
|
| - ~TestObserver() {}
|
| -
|
| - size_t bookmark_count_;
|
| - size_t history_count_;
|
| - size_t password_count_;
|
| - size_t favicon_count_;
|
| -};
|
| -
|
| -class MalformedFavoritesRegistryTestObserver
|
| - : public ProfileWriter,
|
| - public importer::ImporterProgressObserver {
|
| - public:
|
| - MalformedFavoritesRegistryTestObserver() : ProfileWriter(NULL) {
|
| - bookmark_count_ = 0;
|
| - }
|
| -
|
| - // importer::ImporterProgressObserver:
|
| - virtual void ImportStarted() OVERRIDE {}
|
| - virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
|
| - virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
|
| - virtual void ImportEnded() OVERRIDE {
|
| - MessageLoop::current()->Quit();
|
| - EXPECT_EQ(arraysize(kIESortedBookmarks), bookmark_count_);
|
| - }
|
| -
|
| - virtual bool BookmarkModelIsLoaded() const { return true; }
|
| - virtual bool TemplateURLServiceIsLoaded() const { return true; }
|
| -
|
| - virtual void AddPasswordForm(const content::PasswordForm& form) {}
|
| - virtual void AddHistoryPage(const history::URLRows& page,
|
| - history::VisitSource visit_source) {}
|
| - virtual void AddKeyword(std::vector<TemplateURL*> template_url,
|
| - int default_keyword_index) {}
|
| - virtual void AddBookmarks(const std::vector<BookmarkEntry>& bookmarks,
|
| - const string16& top_level_folder_name) OVERRIDE {
|
| - ASSERT_LE(bookmark_count_ + bookmarks.size(),
|
| - arraysize(kIESortedBookmarks));
|
| - for (size_t i = 0; i < bookmarks.size(); ++i) {
|
| - EXPECT_TRUE(EqualBookmarkEntry(bookmarks[i],
|
| - kIESortedBookmarks[bookmark_count_]));
|
| - ++bookmark_count_;
|
| - }
|
| - }
|
| -
|
| - private:
|
| - ~MalformedFavoritesRegistryTestObserver() {}
|
| -
|
| - size_t bookmark_count_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -class IEImporterTest : public ImporterTest {
|
| - protected:
|
| - virtual void SetUp() OVERRIDE {
|
| - ImporterTest::SetUp();
|
| - StartRegistryOverride();
|
| - }
|
| -
|
| - virtual void TearDown() OVERRIDE {
|
| - EndRegistryOverride();
|
| - }
|
| -
|
| - void StartRegistryOverride() {
|
| - EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
|
| - temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
|
| - kUnitTestUserOverrideSubKey,
|
| - KEY_ALL_ACCESS);
|
| - EXPECT_TRUE(temp_hkcu_hive_key_.Valid());
|
| - EXPECT_EQ(ERROR_SUCCESS,
|
| - RegOverridePredefKey(HKEY_CURRENT_USER,
|
| - temp_hkcu_hive_key_.Handle()));
|
| - }
|
| -
|
| - void EndRegistryOverride() {
|
| - EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
|
| - temp_hkcu_hive_key_.Close();
|
| - base::win::RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey,
|
| - KEY_ALL_ACCESS);
|
| - key.DeleteKey(L"");
|
| - }
|
| -
|
| - base::win::RegKey temp_hkcu_hive_key_;
|
| -};
|
| -
|
| -TEST_F(IEImporterTest, IEImporter) {
|
| - // Sets up a favorites folder.
|
| - base::win::ScopedCOMInitializer com_init;
|
| - base::FilePath path = temp_dir_.path().AppendASCII("Favorites");
|
| - CreateDirectory(path.value().c_str(), NULL);
|
| - CreateDirectory(path.AppendASCII("SubFolder").value().c_str(), NULL);
|
| - base::FilePath links_path = path.AppendASCII("Links");
|
| - CreateDirectory(links_path.value().c_str(), NULL);
|
| - CreateDirectory(links_path.AppendASCII("SubFolderOfLinks").value().c_str(),
|
| - NULL);
|
| - CreateDirectory(path.AppendASCII("\x0061").value().c_str(), NULL);
|
| - ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("Google Home Page.url"),
|
| - L"http://www.google.com/",
|
| - L"http://www.google.com/favicon.ico"));
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("SubFolder\\Title.url"),
|
| - L"http://www.link.com/"));
|
| - ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("SubFolder.url"),
|
| - L"http://www.subfolder.com/",
|
| - L"http://www.google.com/favicon.ico"));
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("TheLink.url"),
|
| - L"http://www.links-thelink.com/"));
|
| - ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("WithPortAndQuery.url"),
|
| - L"http://host:8080/cgi?q=query",
|
| - L"http://example.com/favicon.ico"));
|
| - ASSERT_TRUE(CreateUrlFileWithFavicon(
|
| - path.AppendASCII("\x0061").Append(L"\x4E2D\x6587.url"),
|
| - L"http://chinese-title-favorite/",
|
| - L"http://example.com/favicon.ico"));
|
| - ASSERT_TRUE(CreateUrlFile(links_path.AppendASCII("TheLink.url"),
|
| - L"http://www.links-thelink.com/"));
|
| - ASSERT_TRUE(CreateUrlFile(
|
| - links_path.AppendASCII("SubFolderOfLinks").AppendASCII("SubLink.url"),
|
| - L"http://www.links-sublink.com/"));
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("IEDefaultLink.url"),
|
| - L"http://go.microsoft.com/fwlink/?linkid=140813"));
|
| - file_util::WriteFile(path.AppendASCII("InvalidUrlFile.url"), "x", 1);
|
| - file_util::WriteFile(path.AppendASCII("PlainTextFile.txt"), "x", 1);
|
| -
|
| - const char16* root_links[] = {
|
| - L"Links",
|
| - L"Google Home Page.url",
|
| - L"TheLink.url",
|
| - L"SubFolder",
|
| - L"WithPortAndQuery.url",
|
| - L"a",
|
| - L"SubFolder.url",
|
| - };
|
| - ASSERT_TRUE(CreateOrderBlob(
|
| - base::FilePath(path), L"",
|
| - std::vector<string16>(root_links, root_links + arraysize(root_links))));
|
| -
|
| - HRESULT res;
|
| -
|
| - // Sets up a special history link.
|
| - base::win::ScopedComPtr<IUrlHistoryStg2> url_history_stg2;
|
| - res = url_history_stg2.CreateInstance(CLSID_CUrlHistory, NULL,
|
| - CLSCTX_INPROC_SERVER);
|
| - ASSERT_TRUE(res == S_OK);
|
| - res = url_history_stg2->AddUrl(kIEIdentifyUrl, kIEIdentifyTitle, 0);
|
| - ASSERT_TRUE(res == S_OK);
|
| -
|
| - // Starts to import the above settings.
|
| - MessageLoop* loop = MessageLoop::current();
|
| - scoped_refptr<ImporterHost> host(new ImporterHost);
|
| -
|
| - TestObserver* observer = new TestObserver();
|
| - host->SetObserver(observer);
|
| - importer::SourceProfile source_profile;
|
| - source_profile.importer_type = importer::TYPE_IE;
|
| - source_profile.source_path = temp_dir_.path();
|
| -
|
| - // IUrlHistoryStg2::AddUrl seems to reset the override. Ensure it here.
|
| - StartRegistryOverride();
|
| -
|
| - loop->PostTask(FROM_HERE, base::Bind(
|
| - &ImporterHost::StartImportSettings,
|
| - host.get(),
|
| - source_profile,
|
| - profile_.get(),
|
| - importer::HISTORY | importer::PASSWORDS | importer::FAVORITES,
|
| - observer));
|
| - loop->Run();
|
| -
|
| - // Cleans up.
|
| - url_history_stg2->DeleteUrl(kIEIdentifyUrl, 0);
|
| - url_history_stg2.Release();
|
| -}
|
| -
|
| -TEST_F(IEImporterTest, IEImporterMalformedFavoritesRegistry) {
|
| - // Sets up a favorites folder.
|
| - base::win::ScopedCOMInitializer com_init;
|
| - base::FilePath path = temp_dir_.path().AppendASCII("Favorites");
|
| - CreateDirectory(path.value().c_str(), NULL);
|
| - CreateDirectory(path.AppendASCII("b").value().c_str(), NULL);
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("a.url"),
|
| - L"http://www.google.com/0"));
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("a.url"),
|
| - L"http://www.google.com/1"));
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("b.url"),
|
| - L"http://www.google.com/2"));
|
| - ASSERT_TRUE(CreateUrlFile(path.AppendASCII("c.url"),
|
| - L"http://www.google.com/3"));
|
| -
|
| - struct BadBinaryData {
|
| - const char* data;
|
| - int length;
|
| - };
|
| - static const BadBinaryData kBadBinary[] = {
|
| - // number_of_items field is truncated
|
| - {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x00\xff\xff\xff", 17},
|
| - // number_of_items = 0xffff, but the byte sequence is too short.
|
| - {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| - "\xff\xff\x00\x00", 20},
|
| - // number_of_items = 1, size_of_item is too big.
|
| - {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x01\x00\x00\x00"
|
| - "\xff\xff\x00\x00\x00\x00\x00\x00"
|
| - "\x00\x00\x00\x00", 32},
|
| - // number_of_items = 1, size_of_item = 16, size_of_shid is too big.
|
| - {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x01\x00\x00\x00"
|
| - "\x10\x00\x00\x00\x00\x00\x00\x00"
|
| - "\xff\x7f\x00\x00" "\x00\x00\x00\x00", 36},
|
| - // number_of_items = 1, size_of_item = 16, size_of_shid is too big.
|
| - {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x01\x00\x00\x00"
|
| - "\x10\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x06\x00\x00\x00" "\x00\x00\x00\x00", 36},
|
| - };
|
| -
|
| - // Verify malformed registry data are safely ignored and alphabetical
|
| - // sort is performed.
|
| - for (size_t i = 0; i < arraysize(kBadBinary); ++i) {
|
| - base::win::RegKey key;
|
| - ASSERT_EQ(ERROR_SUCCESS,
|
| - key.Create(HKEY_CURRENT_USER, kIEFavoritesOrderKey, KEY_WRITE));
|
| - ASSERT_EQ(ERROR_SUCCESS,
|
| - key.WriteValue(L"Order", kBadBinary[i].data, kBadBinary[i].length,
|
| - REG_BINARY));
|
| -
|
| - // Starts to import the above settings.
|
| - MessageLoop* loop = MessageLoop::current();
|
| - scoped_refptr<ImporterHost> host(new ImporterHost);
|
| -
|
| - MalformedFavoritesRegistryTestObserver* observer =
|
| - new MalformedFavoritesRegistryTestObserver();
|
| - host->SetObserver(observer);
|
| - importer::SourceProfile source_profile;
|
| - source_profile.importer_type = importer::TYPE_IE;
|
| - source_profile.source_path = temp_dir_.path();
|
| -
|
| - loop->PostTask(FROM_HERE, base::Bind(
|
| - &ImporterHost::StartImportSettings,
|
| - host.get(),
|
| - source_profile,
|
| - profile_.get(),
|
| - importer::FAVORITES,
|
| - observer));
|
| - loop->Run();
|
| - }
|
| -}
|
| -
|
| -TEST_F(IEImporterTest, IE7Importer) {
|
| - // This is the unencrypted values of my keys under Storage2.
|
| - // The passwords have been manually changed to abcdef... but the size remains
|
| - // the same.
|
| - unsigned char data1[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
|
| - "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
|
| - "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
|
| - "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
|
| - "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
|
| - "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
|
| - "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
|
| - "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
|
| - "\x6c\x00\x00\x00";
|
| -
|
| - unsigned char data2[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x24\x00\x00\x00"
|
| - "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
|
| - "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
|
| - "\x00\x00\x00\x00\xa8\xea\xf4\xe5\x9f\x9a\xc8\x01"
|
| - "\x09\x00\x00\x00\x14\x00\x00\x00\xa8\xea\xf4\xe5"
|
| - "\x9f\x9a\xc8\x01\x07\x00\x00\x00\x61\x00\x62\x00"
|
| - "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
|
| - "\x69\x00\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00"
|
| - "\x65\x00\x66\x00\x67\x00\x00\x00";
|
| -
|
| -
|
| -
|
| - std::vector<unsigned char> decrypted_data1;
|
| - decrypted_data1.resize(arraysize(data1));
|
| - memcpy(&decrypted_data1.front(), data1, sizeof(data1));
|
| -
|
| - std::vector<unsigned char> decrypted_data2;
|
| - decrypted_data2.resize(arraysize(data2));
|
| - memcpy(&decrypted_data2.front(), data2, sizeof(data2));
|
| -
|
| - string16 password;
|
| - string16 username;
|
| - ASSERT_TRUE(ie7_password::GetUserPassFromData(decrypted_data1, &username,
|
| - &password));
|
| - EXPECT_EQ(L"abcdefgh", username);
|
| - EXPECT_EQ(L"abcdefghijkl", password);
|
| -
|
| - ASSERT_TRUE(ie7_password::GetUserPassFromData(decrypted_data2, &username,
|
| - &password));
|
| - EXPECT_EQ(L"abcdefghi", username);
|
| - EXPECT_EQ(L"abcdefg", password);
|
| -}
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// The order of these includes is important.
|
| +#include <windows.h>
|
| +#include <unknwn.h>
|
| +#include <intshcut.h>
|
| +#include <shlguid.h>
|
| +#include <urlhist.h>
|
| +#include <shlobj.h>
|
| +#include <propvarutil.h>
|
| +
|
| +#include <algorithm>
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/file_util.h"
|
| +#include "base/files/scoped_temp_dir.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/path_service.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/string16.h"
|
| +#include "base/string_util.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "base/win/registry.h"
|
| +#include "base/win/scoped_comptr.h"
|
| +#include "base/win/scoped_propvariant.h"
|
| +#include "base/win/windows_version.h"
|
| +#include "chrome/browser/history/history_types.h"
|
| +#include "chrome/browser/importer/ie_importer.h"
|
| +#include "chrome/browser/importer/importer_bridge.h"
|
| +#include "chrome/browser/importer/importer_data_types.h"
|
| +#include "chrome/browser/importer/importer_host.h"
|
| +#include "chrome/browser/importer/importer_progress_observer.h"
|
| +#include "chrome/browser/importer/importer_unittest_utils.h"
|
| +#include "chrome/browser/importer/pstore_declarations.h"
|
| +#include "chrome/browser/search_engines/template_url.h"
|
| +#include "chrome/browser/ui/browser.h"
|
| +#include "chrome/common/chrome_paths.h"
|
| +#include "chrome/test/base/in_process_browser_test.h"
|
| +#include "chrome/test/base/testing_profile.h"
|
| +#include "content/public/common/password_form.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace {
|
| +
|
| +const char16 kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests";
|
| +const char16 kUnitTestUserOverrideSubKey[] =
|
| + L"SOFTWARE\\Chromium Unit Tests\\HKCU Override";
|
| +
|
| +const BookmarkInfo kIEBookmarks[] = {
|
| + {true, 2, {L"Links", L"SubFolderOfLinks"},
|
| + L"SubLink",
|
| + "http://www.links-sublink.com/"},
|
| + {true, 1, {L"Links"},
|
| + L"TheLink",
|
| + "http://www.links-thelink.com/"},
|
| + {false, 0, {},
|
| + L"Google Home Page",
|
| + "http://www.google.com/"},
|
| + {false, 0, {},
|
| + L"TheLink",
|
| + "http://www.links-thelink.com/"},
|
| + {false, 1, {L"SubFolder"},
|
| + L"Title",
|
| + "http://www.link.com/"},
|
| + {false, 0, {},
|
| + L"WithPortAndQuery",
|
| + "http://host:8080/cgi?q=query"},
|
| + {false, 1, {L"a"},
|
| + L"\x4E2D\x6587",
|
| + "http://chinese-title-favorite/"},
|
| + {false, 0, {},
|
| + L"SubFolder",
|
| + "http://www.subfolder.com/"},
|
| +};
|
| +
|
| +const BookmarkInfo kIESortedBookmarks[] = {
|
| + {false, 0, {}, L"a", "http://www.google.com/0"},
|
| + {false, 1, {L"b"}, L"a", "http://www.google.com/1"},
|
| + {false, 1, {L"b"}, L"b", "http://www.google.com/2"},
|
| + {false, 0, {}, L"c", "http://www.google.com/3"},
|
| +};
|
| +
|
| +const char16 kIEIdentifyUrl[] =
|
| + L"http://A79029D6-753E-4e27-B807-3D46AB1545DF.com:8080/path?key=value";
|
| +const char16 kIEIdentifyTitle[] =
|
| + L"Unittest GUID";
|
| +
|
| +const char16 kIEFavoritesOrderKey[] =
|
| + L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\"
|
| + L"MenuOrder\\Favorites";
|
| +
|
| +const char16 kFaviconStreamSuffix[] = L"url:favicon:$DATA";
|
| +const char kDummyFaviconImageData[] =
|
| + "\x42\x4D" // Magic signature 'BM'
|
| + "\x1E\x00\x00\x00" // File size
|
| + "\x00\x00\x00\x00" // Reserved
|
| + "\x1A\x00\x00\x00" // Offset of the pixel data
|
| + "\x0C\x00\x00\x00" // Header Size
|
| + "\x01\x00\x01\x00" // Size: 1x1
|
| + "\x01\x00" // Reserved
|
| + "\x18\x00" // 24-bits
|
| + "\x00\xFF\x00\x00"; // The pixel
|
| +
|
| +struct FaviconGroup {
|
| + const char16* favicon_url;
|
| + const char16* site_url[2];
|
| +};
|
| +
|
| +const FaviconGroup kIEFaviconGroup[2] = {
|
| + {L"http://www.google.com/favicon.ico",
|
| + {L"http://www.google.com/",
|
| + L"http://www.subfolder.com/"}},
|
| + {L"http://example.com/favicon.ico",
|
| + {L"http://host:8080/cgi?q=query",
|
| + L"http://chinese-title-favorite/"}},
|
| +};
|
| +
|
| +bool CreateOrderBlob(const base::FilePath& favorites_folder,
|
| + const string16& path,
|
| + const std::vector<string16>& entries) {
|
| + if (entries.size() > 255)
|
| + return false;
|
| +
|
| + // Create a binary sequence for setting a specific order of favorites.
|
| + // The format depends on the version of Shell32.dll, so we cannot embed
|
| + // a binary constant here.
|
| + std::vector<uint8> blob(20, 0);
|
| + blob[16] = static_cast<uint8>(entries.size());
|
| +
|
| + for (size_t i = 0; i < entries.size(); ++i) {
|
| + PIDLIST_ABSOLUTE id_list_full = ILCreateFromPath(
|
| + favorites_folder.Append(path).Append(entries[i]).value().c_str());
|
| + PUITEMID_CHILD id_list = ILFindLastID(id_list_full);
|
| + // Include the trailing zero-length item id. Don't include the single
|
| + // element array.
|
| + size_t id_list_size = id_list->mkid.cb + sizeof(id_list->mkid.cb);
|
| +
|
| + blob.resize(blob.size() + 8);
|
| + uint32 total_size = id_list_size + 8;
|
| + memcpy(&blob[blob.size() - 8], &total_size, 4);
|
| + uint32 sort_index = i;
|
| + memcpy(&blob[blob.size() - 4], &sort_index, 4);
|
| + blob.resize(blob.size() + id_list_size);
|
| + memcpy(&blob[blob.size() - id_list_size], id_list, id_list_size);
|
| + ILFree(id_list_full);
|
| + }
|
| +
|
| + string16 key_path = kIEFavoritesOrderKey;
|
| + if (!path.empty())
|
| + key_path += L"\\" + path;
|
| + base::win::RegKey key;
|
| + if (key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE) !=
|
| + ERROR_SUCCESS) {
|
| + return false;
|
| + }
|
| + if (key.WriteValue(L"Order", &blob[0], blob.size(), REG_BINARY) !=
|
| + ERROR_SUCCESS) {
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool CreateUrlFileWithFavicon(const base::FilePath& file,
|
| + const string16& url,
|
| + const string16& favicon_url) {
|
| + base::win::ScopedComPtr<IUniformResourceLocator> locator;
|
| + HRESULT result = locator.CreateInstance(CLSID_InternetShortcut, NULL,
|
| + CLSCTX_INPROC_SERVER);
|
| + if (FAILED(result))
|
| + return false;
|
| + base::win::ScopedComPtr<IPersistFile> persist_file;
|
| + result = persist_file.QueryFrom(locator);
|
| + if (FAILED(result))
|
| + return false;
|
| + result = locator->SetURL(url.c_str(), 0);
|
| + if (FAILED(result))
|
| + return false;
|
| +
|
| + // Write favicon url if specified.
|
| + if (!favicon_url.empty()) {
|
| + base::win::ScopedComPtr<IPropertySetStorage> property_set_storage;
|
| + if (FAILED(property_set_storage.QueryFrom(locator)))
|
| + return false;
|
| + base::win::ScopedComPtr<IPropertyStorage> property_storage;
|
| + if (FAILED(property_set_storage->Open(FMTID_Intshcut,
|
| + STGM_WRITE,
|
| + property_storage.Receive()))) {
|
| + return false;
|
| + }
|
| + PROPSPEC properties[] = {{PRSPEC_PROPID, PID_IS_ICONFILE}};
|
| + // WriteMultiple takes an array of PROPVARIANTs, but since this code only
|
| + // needs an array of size 1: a pointer to |pv_icon| is equivalent.
|
| + base::win::ScopedPropVariant pv_icon;
|
| + if (FAILED(InitPropVariantFromString(favicon_url.c_str(),
|
| + pv_icon.Receive())) ||
|
| + FAILED(property_storage->WriteMultiple(1, properties, &pv_icon, 0))) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + // Save the .url file.
|
| + result = persist_file->Save(file.value().c_str(), TRUE);
|
| + if (FAILED(result))
|
| + return false;
|
| +
|
| + // Write dummy favicon image data in NTFS alternate data stream.
|
| + return favicon_url.empty() || (file_util::WriteFile(
|
| + file.ReplaceExtension(kFaviconStreamSuffix), kDummyFaviconImageData,
|
| + sizeof kDummyFaviconImageData) != -1);
|
| +}
|
| +
|
| +bool CreateUrlFile(const base::FilePath& file, const string16& url) {
|
| + return CreateUrlFileWithFavicon(file, url, string16());
|
| +}
|
| +
|
| +void ClearPStoreType(IPStore* pstore, const GUID* type, const GUID* subtype) {
|
| + base::win::ScopedComPtr<IEnumPStoreItems, NULL> item;
|
| + HRESULT result = pstore->EnumItems(0, type, subtype, 0, item.Receive());
|
| + if (result == PST_E_OK) {
|
| + char16* item_name;
|
| + while (SUCCEEDED(item->Next(1, &item_name, 0))) {
|
| + pstore->DeleteItem(0, type, subtype, item_name, NULL, 0);
|
| + CoTaskMemFree(item_name);
|
| + }
|
| + }
|
| + pstore->DeleteSubtype(0, type, subtype, 0);
|
| + pstore->DeleteType(0, type, 0);
|
| +}
|
| +
|
| +void WritePStore(IPStore* pstore, const GUID* type, const GUID* subtype) {
|
| + struct PStoreItem {
|
| + char16* name;
|
| + int data_size;
|
| + char* data;
|
| + } items[] = {
|
| + {L"http://localhost:8080/security/index.htm#ref:StringData", 8,
|
| + "\x31\x00\x00\x00\x32\x00\x00\x00"},
|
| + {L"http://localhost:8080/security/index.htm#ref:StringIndex", 20,
|
| + "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00"
|
| + "\x00\x00\x2f\x00\x74\x00\x01\x00\x00\x00"},
|
| + {L"user:StringData", 4,
|
| + "\x31\x00\x00\x00"},
|
| + {L"user:StringIndex", 20,
|
| + "\x57\x49\x43\x4b\x18\x00\x00\x00\x01\x00"
|
| + "\x00\x00\x2f\x00\x74\x00\x00\x00\x00\x00"},
|
| + };
|
| +
|
| + for (int i = 0; i < arraysize(items); ++i) {
|
| + HRESULT res = pstore->WriteItem(0, type, subtype, items[i].name,
|
| + items[i].data_size, reinterpret_cast<BYTE*>(items[i].data),
|
| + NULL, 0, 0);
|
| + ASSERT_TRUE(res == PST_E_OK);
|
| + }
|
| +}
|
| +
|
| +class TestObserver : public ProfileWriter,
|
| + public importer::ImporterProgressObserver {
|
| + public:
|
| + TestObserver() : ProfileWriter(NULL) {
|
| + bookmark_count_ = 0;
|
| + history_count_ = 0;
|
| + password_count_ = 0;
|
| + favicon_count_ = 0;
|
| + }
|
| +
|
| + // importer::ImporterProgressObserver:
|
| + virtual void ImportStarted() OVERRIDE {}
|
| + virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
|
| + virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
|
| + virtual void ImportEnded() OVERRIDE {
|
| + MessageLoop::current()->Quit();
|
| + EXPECT_EQ(arraysize(kIEBookmarks), bookmark_count_);
|
| + EXPECT_EQ(1, history_count_);
|
| + EXPECT_EQ(arraysize(kIEFaviconGroup), favicon_count_);
|
| + }
|
| +
|
| + virtual bool BookmarkModelIsLoaded() const {
|
| + // Profile is ready for writing.
|
| + return true;
|
| + }
|
| +
|
| + virtual bool TemplateURLServiceIsLoaded() const {
|
| + return true;
|
| + }
|
| +
|
| + virtual void AddPasswordForm(const content::PasswordForm& form) {
|
| + // Importer should obtain this password form only.
|
| + EXPECT_EQ(GURL("http://localhost:8080/security/index.htm"), form.origin);
|
| + EXPECT_EQ("http://localhost:8080/", form.signon_realm);
|
| + EXPECT_EQ(L"user", form.username_element);
|
| + EXPECT_EQ(L"1", form.username_value);
|
| + EXPECT_EQ(L"", form.password_element);
|
| + EXPECT_EQ(L"2", form.password_value);
|
| + EXPECT_EQ("", form.action.spec());
|
| + ++password_count_;
|
| + }
|
| +
|
| + virtual void AddHistoryPage(const history::URLRows& page,
|
| + history::VisitSource visit_source) {
|
| + // Importer should read the specified URL.
|
| + for (size_t i = 0; i < page.size(); ++i) {
|
| + if (page[i].title() == kIEIdentifyTitle &&
|
| + page[i].url() == GURL(kIEIdentifyUrl))
|
| + ++history_count_;
|
| + }
|
| + EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_source);
|
| + }
|
| +
|
| + virtual void AddBookmarks(const std::vector<BookmarkEntry>& bookmarks,
|
| + const string16& top_level_folder_name) OVERRIDE {
|
| + ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kIEBookmarks));
|
| + // Importer should import the IE Favorites folder the same as the list,
|
| + // in the same order.
|
| + for (size_t i = 0; i < bookmarks.size(); ++i) {
|
| + EXPECT_NO_FATAL_FAILURE(
|
| + TestEqualBookmarkEntry(bookmarks[i],
|
| + kIEBookmarks[bookmark_count_])) << i;
|
| + ++bookmark_count_;
|
| + }
|
| + }
|
| +
|
| + virtual void AddKeyword(std::vector<TemplateURL*> template_url,
|
| + int default_keyword_index) {
|
| + // TODO(jcampan): bug 1169230: we should test keyword importing for IE.
|
| + // In order to do that we'll probably need to mock the Windows registry.
|
| + NOTREACHED();
|
| + STLDeleteContainerPointers(template_url.begin(), template_url.end());
|
| + }
|
| +
|
| + virtual void AddFavicons(
|
| + const std::vector<history::ImportedFaviconUsage>& usage) OVERRIDE {
|
| + // Importer should group the favicon information for each favicon URL.
|
| + for (size_t i = 0; i < arraysize(kIEFaviconGroup); ++i) {
|
| + GURL favicon_url(kIEFaviconGroup[i].favicon_url);
|
| + std::set<GURL> urls;
|
| + for (size_t j = 0; j < arraysize(kIEFaviconGroup[i].site_url); ++j)
|
| + urls.insert(GURL(kIEFaviconGroup[i].site_url[j]));
|
| +
|
| + SCOPED_TRACE(testing::Message() << "Expected Favicon: " << favicon_url);
|
| +
|
| + bool expected_favicon_url_found = false;
|
| + for (size_t j = 0; j < usage.size(); ++j) {
|
| + if (usage[j].favicon_url == favicon_url) {
|
| + EXPECT_EQ(urls, usage[j].urls);
|
| + expected_favicon_url_found = true;
|
| + break;
|
| + }
|
| + }
|
| + EXPECT_TRUE(expected_favicon_url_found);
|
| + }
|
| +
|
| + favicon_count_ += usage.size();
|
| + }
|
| +
|
| + private:
|
| + ~TestObserver() {}
|
| +
|
| + size_t bookmark_count_;
|
| + size_t history_count_;
|
| + size_t password_count_;
|
| + size_t favicon_count_;
|
| +};
|
| +
|
| +class MalformedFavoritesRegistryTestObserver
|
| + : public ProfileWriter,
|
| + public importer::ImporterProgressObserver {
|
| + public:
|
| + MalformedFavoritesRegistryTestObserver() : ProfileWriter(NULL) {
|
| + bookmark_count_ = 0;
|
| + }
|
| +
|
| + // importer::ImporterProgressObserver:
|
| + virtual void ImportStarted() OVERRIDE {}
|
| + virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
|
| + virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
|
| + virtual void ImportEnded() OVERRIDE {
|
| + MessageLoop::current()->Quit();
|
| + EXPECT_EQ(arraysize(kIESortedBookmarks), bookmark_count_);
|
| + }
|
| +
|
| + virtual bool BookmarkModelIsLoaded() const { return true; }
|
| + virtual bool TemplateURLServiceIsLoaded() const { return true; }
|
| +
|
| + virtual void AddPasswordForm(const content::PasswordForm& form) {}
|
| + virtual void AddHistoryPage(const history::URLRows& page,
|
| + history::VisitSource visit_source) {}
|
| + virtual void AddKeyword(std::vector<TemplateURL*> template_url,
|
| + int default_keyword_index) {}
|
| + virtual void AddBookmarks(const std::vector<BookmarkEntry>& bookmarks,
|
| + const string16& top_level_folder_name) OVERRIDE {
|
| + ASSERT_LE(bookmark_count_ + bookmarks.size(),
|
| + arraysize(kIESortedBookmarks));
|
| + for (size_t i = 0; i < bookmarks.size(); ++i) {
|
| + EXPECT_NO_FATAL_FAILURE(
|
| + TestEqualBookmarkEntry(bookmarks[i],
|
| + kIESortedBookmarks[bookmark_count_])) << i;
|
| + ++bookmark_count_;
|
| + }
|
| + }
|
| +
|
| + private:
|
| + ~MalformedFavoritesRegistryTestObserver() {}
|
| +
|
| + size_t bookmark_count_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +// These tests need to be browser tests in order to be able to run the OOP
|
| +// import (via ExternalProcessImporterHost) which launches a utility process.
|
| +class IEImporterBrowserTest : public InProcessBrowserTest {
|
| + protected:
|
| + virtual void SetUp() OVERRIDE {
|
| + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
|
| + StartRegistryOverride();
|
| +
|
| + // This will launch the browser test and thus needs to happen last.
|
| + InProcessBrowserTest::SetUp();
|
| + }
|
| +
|
| + virtual void TearDown() OVERRIDE {
|
| + EndRegistryOverride();
|
| + }
|
| +
|
| + void StartRegistryOverride() {
|
| + EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
|
| + temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
|
| + kUnitTestUserOverrideSubKey,
|
| + KEY_ALL_ACCESS);
|
| + EXPECT_TRUE(temp_hkcu_hive_key_.Valid());
|
| + EXPECT_EQ(ERROR_SUCCESS,
|
| + RegOverridePredefKey(HKEY_CURRENT_USER,
|
| + temp_hkcu_hive_key_.Handle()));
|
| + }
|
| +
|
| + void EndRegistryOverride() {
|
| + EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
|
| + temp_hkcu_hive_key_.Close();
|
| + base::win::RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey,
|
| + KEY_ALL_ACCESS);
|
| + key.DeleteKey(L"");
|
| + }
|
| +
|
| + base::ScopedTempDir temp_dir_;
|
| + base::win::RegKey temp_hkcu_hive_key_;
|
| +};
|
| +
|
| +IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest, IEImporter) {
|
| + // Sets up a favorites folder.
|
| + base::FilePath path = temp_dir_.path().AppendASCII("Favorites");
|
| + CreateDirectory(path.value().c_str(), NULL);
|
| + CreateDirectory(path.AppendASCII("SubFolder").value().c_str(), NULL);
|
| + base::FilePath links_path = path.AppendASCII("Links");
|
| + CreateDirectory(links_path.value().c_str(), NULL);
|
| + CreateDirectory(links_path.AppendASCII("SubFolderOfLinks").value().c_str(),
|
| + NULL);
|
| + CreateDirectory(path.AppendASCII("\x0061").value().c_str(), NULL);
|
| + ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("Google Home Page.url"),
|
| + L"http://www.google.com/",
|
| + L"http://www.google.com/favicon.ico"));
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("SubFolder\\Title.url"),
|
| + L"http://www.link.com/"));
|
| + ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("SubFolder.url"),
|
| + L"http://www.subfolder.com/",
|
| + L"http://www.google.com/favicon.ico"));
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("TheLink.url"),
|
| + L"http://www.links-thelink.com/"));
|
| + ASSERT_TRUE(CreateUrlFileWithFavicon(path.AppendASCII("WithPortAndQuery.url"),
|
| + L"http://host:8080/cgi?q=query",
|
| + L"http://example.com/favicon.ico"));
|
| + ASSERT_TRUE(CreateUrlFileWithFavicon(
|
| + path.AppendASCII("\x0061").Append(L"\x4E2D\x6587.url"),
|
| + L"http://chinese-title-favorite/",
|
| + L"http://example.com/favicon.ico"));
|
| + ASSERT_TRUE(CreateUrlFile(links_path.AppendASCII("TheLink.url"),
|
| + L"http://www.links-thelink.com/"));
|
| + ASSERT_TRUE(CreateUrlFile(
|
| + links_path.AppendASCII("SubFolderOfLinks").AppendASCII("SubLink.url"),
|
| + L"http://www.links-sublink.com/"));
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("IEDefaultLink.url"),
|
| + L"http://go.microsoft.com/fwlink/?linkid=140813"));
|
| + file_util::WriteFile(path.AppendASCII("InvalidUrlFile.url"), "x", 1);
|
| + file_util::WriteFile(path.AppendASCII("PlainTextFile.txt"), "x", 1);
|
| +
|
| + const char16* root_links[] = {
|
| + L"Links",
|
| + L"Google Home Page.url",
|
| + L"TheLink.url",
|
| + L"SubFolder",
|
| + L"WithPortAndQuery.url",
|
| + L"a",
|
| + L"SubFolder.url",
|
| + };
|
| + ASSERT_TRUE(CreateOrderBlob(
|
| + base::FilePath(path), L"",
|
| + std::vector<string16>(root_links, root_links + arraysize(root_links))));
|
| +
|
| + HRESULT res;
|
| +
|
| + // Sets up a special history link.
|
| + base::win::ScopedComPtr<IUrlHistoryStg2> url_history_stg2;
|
| + res = url_history_stg2.CreateInstance(CLSID_CUrlHistory, NULL,
|
| + CLSCTX_INPROC_SERVER);
|
| + ASSERT_TRUE(res == S_OK);
|
| + res = url_history_stg2->AddUrl(kIEIdentifyUrl, kIEIdentifyTitle, 0);
|
| + ASSERT_TRUE(res == S_OK);
|
| +
|
| + // Starts to import the above settings.
|
| + // TODO(gab): Use ExternalProcessImporterHost on Windows.
|
| + scoped_refptr<ImporterHost> host(new ImporterHost);
|
| + TestObserver* observer = new TestObserver();
|
| + host->SetObserver(observer);
|
| +
|
| + importer::SourceProfile source_profile;
|
| + source_profile.importer_type = importer::TYPE_IE;
|
| + source_profile.source_path = temp_dir_.path();
|
| +
|
| + // IUrlHistoryStg2::AddUrl seems to reset the override. Ensure it here.
|
| + StartRegistryOverride();
|
| +
|
| + host->StartImportSettings(
|
| + source_profile,
|
| + browser()->profile(),
|
| + importer::HISTORY | importer::PASSWORDS | importer::FAVORITES,
|
| + observer);
|
| + MessageLoop::current()->Run();
|
| +
|
| + // Cleans up.
|
| + url_history_stg2->DeleteUrl(kIEIdentifyUrl, 0);
|
| + url_history_stg2.Release();
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(IEImporterBrowserTest,
|
| + IEImporterMalformedFavoritesRegistry) {
|
| + // Sets up a favorites folder.
|
| + base::FilePath path = temp_dir_.path().AppendASCII("Favorites");
|
| + CreateDirectory(path.value().c_str(), NULL);
|
| + CreateDirectory(path.AppendASCII("b").value().c_str(), NULL);
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("a.url"),
|
| + L"http://www.google.com/0"));
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("a.url"),
|
| + L"http://www.google.com/1"));
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("b").AppendASCII("b.url"),
|
| + L"http://www.google.com/2"));
|
| + ASSERT_TRUE(CreateUrlFile(path.AppendASCII("c.url"),
|
| + L"http://www.google.com/3"));
|
| +
|
| + struct BadBinaryData {
|
| + const char* data;
|
| + int length;
|
| + };
|
| + static const BadBinaryData kBadBinary[] = {
|
| + // number_of_items field is truncated
|
| + {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| + "\x00\xff\xff\xff", 17},
|
| + // number_of_items = 0xffff, but the byte sequence is too short.
|
| + {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| + "\xff\xff\x00\x00", 20},
|
| + // number_of_items = 1, size_of_item is too big.
|
| + {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| + "\x01\x00\x00\x00"
|
| + "\xff\xff\x00\x00\x00\x00\x00\x00"
|
| + "\x00\x00\x00\x00", 32},
|
| + // number_of_items = 1, size_of_item = 16, size_of_shid is too big.
|
| + {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| + "\x01\x00\x00\x00"
|
| + "\x10\x00\x00\x00\x00\x00\x00\x00"
|
| + "\xff\x7f\x00\x00" "\x00\x00\x00\x00", 36},
|
| + // number_of_items = 1, size_of_item = 16, size_of_shid is too big.
|
| + {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
| + "\x01\x00\x00\x00"
|
| + "\x10\x00\x00\x00\x00\x00\x00\x00"
|
| + "\x06\x00\x00\x00" "\x00\x00\x00\x00", 36},
|
| + };
|
| +
|
| + // Verify malformed registry data are safely ignored and alphabetical
|
| + // sort is performed.
|
| + for (size_t i = 0; i < arraysize(kBadBinary); ++i) {
|
| + base::win::RegKey key;
|
| + ASSERT_EQ(ERROR_SUCCESS,
|
| + key.Create(HKEY_CURRENT_USER, kIEFavoritesOrderKey, KEY_WRITE));
|
| + ASSERT_EQ(ERROR_SUCCESS,
|
| + key.WriteValue(L"Order", kBadBinary[i].data, kBadBinary[i].length,
|
| + REG_BINARY));
|
| +
|
| + // Starts to import the above settings.
|
| + // TODO(gab): Use ExternalProcessImporterHost on Windows.
|
| + scoped_refptr<ImporterHost> host(new ImporterHost);
|
| + MalformedFavoritesRegistryTestObserver* observer =
|
| + new MalformedFavoritesRegistryTestObserver();
|
| + host->SetObserver(observer);
|
| +
|
| + importer::SourceProfile source_profile;
|
| + source_profile.importer_type = importer::TYPE_IE;
|
| + source_profile.source_path = temp_dir_.path();
|
| +
|
| + host->StartImportSettings(
|
| + source_profile,
|
| + browser()->profile(),
|
| + importer::FAVORITES,
|
| + observer);
|
| + MessageLoop::current()->Run();
|
| + }
|
| +}
|
|
|