firefox_importer_browsertest.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/file_util.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/file_path.h" 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/scoped_temp_dir.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/message_loop.h" 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/path_service.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/stl_util.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/string16.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/string_util.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/utf_string_conversions.h" 14a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/bookmarks/imported_bookmark_entry.h" 15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/favicon/imported_favicon_usage.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/external_process_importer_host.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/firefox_importer_unittest_utils.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_data_types.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_host.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_progress_observer.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_unittest_utils.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/search_engines/template_url.h" 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/browser.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_paths.h" 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/test/base/in_process_browser_test.h" 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/common/password_form.h" 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(estade): some of these are disabled on mac. http://crbug.com/48007 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(jschuh): Disabled on Win64 build. http://crbug.com/179688 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_MACOSX) || (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define MAYBE_IMPORTER(x) DISABLED_##x 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define MAYBE_IMPORTER(x) x 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const BookmarkInfo kFirefox2Bookmarks[] = { 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {true, 2, {L"Bookmarks Toolbar Folder", L"Folder"}, 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"On Toolbar's Subfolder", 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://on.toolbar/bookmark/folder"}, 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {true, 1, {L"Bookmarks Toolbar Folder"}, 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"On Bookmark Toolbar", 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://on.toolbar/bookmark"}, 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 1, {L"Folder"}, 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"New Bookmark", 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://domain/"}, 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 0, {}, 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"<Name>", 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://domain.com/q?a=%22er%22&b=%3C%20%20%3E"}, 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 0, {}, 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"Google Home Page", 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.google.com/"}, 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 0, {}, 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"\x4E2D\x6587", 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://chinese.site.cn/path?query=1#ref"}, 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 1, {L"< > & \" ' \\ /"}, 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"< > & \" ' \\ /", 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://g.cn/"}, 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 0, {}, 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"mail", 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "mailto:username@host"}, 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)struct PasswordInfo { 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char* origin; 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char* action; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char* realm; 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const wchar_t* username_element; 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const wchar_t* username; 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const wchar_t* password_element; 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const wchar_t* password; 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool blacklisted; 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const PasswordInfo kFirefox2Passwords[] = { 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"https://www.google.com/", "", "https://www.google.com/", 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"", L"", L"", L"", true}, 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"http://localhost:8080/", "", "http://localhost:8080/corp.google.com", 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"", L"http", L"", L"Http1+1abcdefg", false}, 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"http://localhost:8080/", "http://localhost:8080/", "http://localhost:8080/", 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"loginuser", L"usr", L"loginpass", L"pwd", false}, 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"http://localhost:8080/", "http://localhost:8080/", "http://localhost:8080/", 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"loginuser", L"firefox", L"loginpass", L"firefox", false}, 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"http://localhost/", "", "http://localhost/", 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"loginuser", L"hello", L"", L"world", false}, 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)struct KeywordInfo { 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const wchar_t* keyword; 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char* url; 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const KeywordInfo kFirefox2Keywords[] = { 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Searh plugins 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"amazon.com", 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.amazon.com/exec/obidos/external-search/?field-keywords=" 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "{searchTerms}&mode=blended" }, 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"answers.com", 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.answers.com/main/ntquery?s={searchTerms}&gwp=13" }, 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"search.creativecommons.org", 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://search.creativecommons.org/?q={searchTerms}" }, 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"search.ebay.com", 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://search.ebay.com/search/search.dll?query={searchTerms}&" 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "MfcISAPICommand=GetResult&ht=1&ebaytag1=ebayreg&srchdesc=n&" 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "maxRecordsReturned=300&maxRecordsPerPage=50&SortProperty=MetaEndSort" }, 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"google.com", 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.google.com/search?q={searchTerms}&ie=utf-8&oe=utf-8&aq=t" }, 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"search.yahoo.com", 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8" }, 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"flickr.com", 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.flickr.com/photos/tags/?q={searchTerms}" }, 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"imdb.com", 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.imdb.com/find?q={searchTerms}" }, 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"webster.com", 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.webster.com/cgi-bin/dictionary?va={searchTerms}" }, 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Search keywords. 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"google", "http://www.google.com/" }, 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"< > & \" ' \\ /", "http://g.cn/"}, 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kDefaultFirefox2KeywordIndex = 8; 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class FirefoxObserver : public ProfileWriter, 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public importer::ImporterProgressObserver { 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FirefoxObserver() : ProfileWriter(NULL) { 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bookmark_count_ = 0; 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) history_count_ = 0; 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) password_count_ = 0; 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) keyword_count_ = 0; 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // importer::ImporterProgressObserver: 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportStarted() OVERRIDE {} 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportEnded() OVERRIDE { 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MessageLoop::current()->Quit(); 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(arraysize(kFirefox2Bookmarks), bookmark_count_); 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(1U, history_count_); 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(arraysize(kFirefox2Passwords), password_count_); 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(arraysize(kFirefox2Keywords), keyword_count_); 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual bool BookmarkModelIsLoaded() const OVERRIDE { 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Profile is ready for writing. 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual bool TemplateURLServiceIsLoaded() const OVERRIDE { 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddPasswordForm(const content::PasswordForm& form) OVERRIDE { 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) PasswordInfo p = kFirefox2Passwords[password_count_]; 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.origin, form.origin.spec()); 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.realm, form.signon_realm); 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.action, form.action.spec()); 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.username_element), form.username_element); 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.username), form.username_value); 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.password_element), form.password_element); 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.password), form.password_value); 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.blacklisted, form.blacklisted_by_user); 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++password_count_; 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddHistoryPage(const history::URLRows& page, 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) history::VisitSource visit_source) OVERRIDE { 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_EQ(1U, page.size()); 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ("http://en-us.www.mozilla.com/", page[0].url().spec()); 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(ASCIIToUTF16("Firefox Updated"), page[0].title()); 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED, visit_source); 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++history_count_; 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) virtual void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks, 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const string16& top_level_folder_name) OVERRIDE { 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_LE(bookmark_count_ + bookmarks.size(), 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) arraysize(kFirefox2Bookmarks)); 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Importer should import the FF favorites the same as the list, in the same 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // order. 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < bookmarks.size(); ++i) { 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_NO_FATAL_FAILURE( 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TestEqualBookmarkEntry(bookmarks[i], 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kFirefox2Bookmarks[bookmark_count_])) << i; 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++bookmark_count_; 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddKeywords(ScopedVector<TemplateURL> template_urls, 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool unique_on_host_and_path) OVERRIDE { 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < template_urls.size(); ++i) { 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The order might not be deterministic, look in the expected list for 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // that template URL. 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool found = false; 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16 keyword = template_urls[i]->keyword(); 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t j = 0; j < arraysize(kFirefox2Keywords); ++j) { 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (template_urls[i]->keyword() == 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WideToUTF16Hack(kFirefox2Keywords[j].keyword)) { 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(kFirefox2Keywords[j].url, template_urls[i]->url()); 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) found = true; 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(found); 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++keyword_count_; 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddFavicons( 213a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const std::vector<ImportedFaviconUsage>& favicons) OVERRIDE { 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~FirefoxObserver() {} 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t bookmark_count_; 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t history_count_; 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t password_count_; 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t keyword_count_; 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const BookmarkInfo kFirefox3Bookmarks[] = { 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {true, 1, {L"Bookmarks Toolbar"}, 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"Toolbar", 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://site/"}, 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {false, 0, {}, 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"Title", 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.google.com/"}, 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const PasswordInfo kFirefox3Passwords[] = { 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"http://localhost:8080/", "http://localhost:8080/", "http://localhost:8080/", 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"loginuser", L"abc", L"loginpass", L"123", false}, 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"http://localhost:8080/", "", "http://localhost:8080/localhost", 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) L"", L"http", L"", L"Http1+1abcdefg", false}, 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const KeywordInfo kFirefox3Keywords[] = { 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"amazon.com", 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.amazon.com/exec/obidos/external-search/?field-keywords=" 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "{searchTerms}&mode=blended" }, 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"answers.com", 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.answers.com/main/ntquery?s={searchTerms}&gwp=13" }, 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"search.creativecommons.org", 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://search.creativecommons.org/?q={searchTerms}" }, 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"search.ebay.com", 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://search.ebay.com/search/search.dll?query={searchTerms}&" 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "MfcISAPICommand=GetResult&ht=1&ebaytag1=ebayreg&srchdesc=n&" 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "maxRecordsReturned=300&maxRecordsPerPage=50&SortProperty=MetaEndSort" }, 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"google.com", 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.google.com/search?q={searchTerms}&ie=utf-8&oe=utf-8&aq=t" }, 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"en.wikipedia.org", 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://en.wikipedia.org/wiki/Special:Search?search={searchTerms}" }, 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"search.yahoo.com", 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8" }, 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"flickr.com", 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.flickr.com/photos/tags/?q={searchTerms}" }, 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"imdb.com", 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.imdb.com/find?q={searchTerms}" }, 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"webster.com", 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "http://www.webster.com/cgi-bin/dictionary?va={searchTerms}" }, 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Search keywords. 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { L"\x4E2D\x6587", "http://www.google.com/" }, 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kDefaultFirefox3KeywordIndex = 8; 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class Firefox3Observer : public ProfileWriter, 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public importer::ImporterProgressObserver { 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Firefox3Observer() 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : ProfileWriter(NULL), bookmark_count_(0), history_count_(0), 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) password_count_(0), keyword_count_(0), import_search_engines_(true) { 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) explicit Firefox3Observer(bool import_search_engines) 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : ProfileWriter(NULL), bookmark_count_(0), history_count_(0), 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) password_count_(0), keyword_count_(0), 282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) import_search_engines_(import_search_engines) { 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // importer::ImporterProgressObserver: 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportStarted() OVERRIDE {} 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportEnded() OVERRIDE { 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MessageLoop::current()->Quit(); 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(arraysize(kFirefox3Bookmarks), bookmark_count_); 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(1U, history_count_); 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(arraysize(kFirefox3Passwords), password_count_); 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (import_search_engines_) 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(arraysize(kFirefox3Keywords), keyword_count_); 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual bool BookmarkModelIsLoaded() const OVERRIDE { 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Profile is ready for writing. 300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual bool TemplateURLServiceIsLoaded() const OVERRIDE { 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddPasswordForm(const content::PasswordForm& form) OVERRIDE { 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) PasswordInfo p = kFirefox3Passwords[password_count_]; 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.origin, form.origin.spec()); 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.realm, form.signon_realm); 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.action, form.action.spec()); 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.username_element), form.username_element); 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.username), form.username_value); 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.password_element), form.password_element); 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(WideToUTF16(p.password), form.password_value); 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(p.blacklisted, form.blacklisted_by_user); 317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++password_count_; 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddHistoryPage(const history::URLRows& page, 321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) history::VisitSource visit_source) OVERRIDE { 322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_EQ(3U, page.size()); 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ("http://www.google.com/", page[0].url().spec()); 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(ASCIIToUTF16("Google"), page[0].title()); 325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ("http://www.google.com/", page[1].url().spec()); 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(ASCIIToUTF16("Google"), page[1].title()); 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ("http://www.cs.unc.edu/~jbs/resources/perl/perl-cgi/programs/" 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "form1-POST.html", page[2].url().spec()); 329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(ASCIIToUTF16("example form (POST)"), page[2].title()); 330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED, visit_source); 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++history_count_; 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 334a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) virtual void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks, 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const string16& top_level_folder_name) OVERRIDE { 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_LE(bookmark_count_ + bookmarks.size(), 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) arraysize(kFirefox3Bookmarks)); 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Importer should import the FF favorites the same as the list, in the same 340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // order. 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < bookmarks.size(); ++i) { 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_NO_FATAL_FAILURE( 343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TestEqualBookmarkEntry(bookmarks[i], 344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kFirefox3Bookmarks[bookmark_count_])) << i; 345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++bookmark_count_; 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddKeywords(ScopedVector<TemplateURL> template_urls, 350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool unique_on_host_and_path) OVERRIDE { 351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < template_urls.size(); ++i) { 352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The order might not be deterministic, look in the expected list for 353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // that template URL. 354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool found = false; 355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16 keyword = template_urls[i]->keyword(); 356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t j = 0; j < arraysize(kFirefox3Keywords); ++j) { 357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (template_urls[i]->keyword() == 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WideToUTF16Hack(kFirefox3Keywords[j].keyword)) { 359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_EQ(kFirefox3Keywords[j].url, template_urls[i]->url()); 360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) found = true; 361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) break; 362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EXPECT_TRUE(found); 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++keyword_count_; 366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void AddFavicons( 370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const std::vector<ImportedFaviconUsage>& favicons) OVERRIDE { 371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~Firefox3Observer() {} 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t bookmark_count_; 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t history_count_; 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t password_count_; 379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t keyword_count_; 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool import_search_engines_; 381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// These tests need to be browser tests in order to be able to run the OOP 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// import (via ExternalProcessImporterHost) which launches a utility process on 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// supported platforms. 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class FirefoxProfileImporterBrowserTest : public InProcessBrowserTest { 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected: 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void SetUp() OVERRIDE { 391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Creates a new profile in a new subdirectory in the temp directory. 392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath test_path = temp_dir_.path().AppendASCII("ImporterTest"); 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) file_util::Delete(test_path, true); 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) file_util::CreateDirectory(test_path); 396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_path_ = test_path.AppendASCII("profile"); 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) app_path_ = test_path.AppendASCII("app"); 398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) file_util::CreateDirectory(app_path_); 399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // This will launch the browser test and thus needs to happen last. 401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) InProcessBrowserTest::SetUp(); 402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void Firefox3xImporterBrowserTest( 405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string profile_dir, 406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) importer::ImporterProgressObserver* observer, 407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ProfileWriter* writer, 408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool import_search_plugins) { 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath data_path; 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_path = data_path.AppendASCII(profile_dir); 412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(file_util::CopyDirectory(data_path, profile_path_, true)); 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_path = data_path.AppendASCII("firefox3_nss"); 415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(file_util::CopyDirectory(data_path, profile_path_, false)); 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath search_engine_path = app_path_; 418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) search_engine_path = search_engine_path.AppendASCII("searchplugins"); 419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) file_util::CreateDirectory(search_engine_path); 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (import_search_plugins) { 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_path = data_path.AppendASCII("firefox3_searchplugins"); 423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!file_util::PathExists(data_path)) { 424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(maruel): Create search test data that we can open source! 425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << L"Missing internal test data"; 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(file_util::CopyDirectory(data_path, 429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) search_engine_path, false)); 430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) importer::SourceProfile source_profile; 433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile.importer_type = importer::TYPE_FIREFOX3; 434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile.app_path = app_path_; 435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile.source_path = profile_path_; 436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int items = importer::HISTORY | importer::PASSWORDS | importer::FAVORITES; 438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (import_search_plugins) 439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) items = items | importer::SEARCH_ENGINES; 440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Deletes itself. 442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(gab): Use ExternalProcessImporterHost on both Windows and Linux. 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ImporterHost* host; 444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_MACOSX) 445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host = new ExternalProcessImporterHost; 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host = new ImporterHost; 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host->SetObserver(observer); 450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host->StartImportSettings(source_profile, browser()->profile(), 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) items, make_scoped_refptr(writer)); 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MessageLoop::current()->Run(); 453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::ScopedTempDir temp_dir_; 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath profile_path_; 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath app_path_; 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest, 461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MAYBE_IMPORTER(Firefox2Importer)) { 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath data_path; 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_path = data_path.AppendASCII("firefox2_profile"); 465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(file_util::CopyDirectory(data_path, profile_path_, true)); 466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_path = data_path.AppendASCII("firefox2_nss"); 468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(file_util::CopyDirectory(data_path, profile_path_, false)); 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath search_engine_path = app_path_; 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) search_engine_path = search_engine_path.AppendASCII("searchplugins"); 472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) file_util::CreateDirectory(search_engine_path); 473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) data_path = data_path.AppendASCII("firefox2_searchplugins"); 475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!file_util::PathExists(data_path)) { 476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(maruel): Create test data that we can open source! 477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << L"Missing internal test data"; 478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ASSERT_TRUE(file_util::CopyDirectory(data_path, search_engine_path, false)); 481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) importer::SourceProfile source_profile; 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile.importer_type = importer::TYPE_FIREFOX2; 484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile.app_path = app_path_; 485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile.source_path = profile_path_; 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Deletes itself. 488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(gab): Use ExternalProcessImporterHost on both Windows and Linux. 489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ImporterHost* host; 490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_MACOSX) 491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host = new ExternalProcessImporterHost; 492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else 493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host = new ImporterHost; 494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FirefoxObserver* observer = new FirefoxObserver(); 497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host->SetObserver(observer); 498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) host->StartImportSettings( 499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) source_profile, 500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) browser()->profile(), 501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) importer::HISTORY | importer::PASSWORDS | 502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) importer::FAVORITES | importer::SEARCH_ENGINES, 503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) make_scoped_refptr(observer)); 504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MessageLoop::current()->Run(); 505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest, 508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MAYBE_IMPORTER(Firefox30Importer)) { 509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_refptr<Firefox3Observer> observer(new Firefox3Observer()); 510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Firefox3xImporterBrowserTest("firefox3_profile", observer.get(), 511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observer.get(), true); 512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest, 515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MAYBE_IMPORTER(Firefox35Importer)) { 516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool import_search_engines = false; 517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_refptr<Firefox3Observer> observer( 518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new Firefox3Observer(import_search_engines)); 519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Firefox3xImporterBrowserTest("firefox35_profile", observer.get(), 520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observer.get(), import_search_engines); 521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 522