#include "chrome/utility/importer/firefox_importer.h"
#include <string>
#include <string_view>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/importer/mock_importer_bridge.h"
#include "components/favicon_base/favicon_usage_data.h"
#include "components/user_data_importer/common/imported_bookmark_entry.h"
#include "components/user_data_importer/common/importer_data_types.h"
#include "components/user_data_importer/common/importer_url_row.h"
#include "content/public/test/browser_task_environment.h"
#include "sql/database.h"
#include "sql/test/test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
class FirefoxImporterTest : public testing::Test {
public:
void ImportBookmarksFromVersion(
std::string_view firefox_version,
std::vector<user_data_importer::ImportedBookmarkEntry>* bookmarks,
favicon_base::FaviconUsageDataList* favicons) {
base::FilePath places_path;
ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &places_path));
places_path =
places_path.AppendASCII("import").AppendASCII("firefox").AppendASCII(
firefox_version);
ASSERT_TRUE(base::DirectoryExists(places_path));
user_data_importer::SourceProfile profile;
profile.source_path = places_path;
EXPECT_CALL(*bridge_, NotifyStarted());
EXPECT_CALL(*bridge_, NotifyItemStarted(user_data_importer::FAVORITES));
EXPECT_CALL(*bridge_, AddBookmarks(_, _))
.WillOnce(::testing::SaveArg<0>(bookmarks));
EXPECT_CALL(*bridge_, SetFavicons(_))
.WillOnce(::testing::SaveArg<0>(favicons));
EXPECT_CALL(*bridge_, NotifyItemEnded(user_data_importer::FAVORITES));
EXPECT_CALL(*bridge_, NotifyEnded());
importer_->StartImport(profile, user_data_importer::FAVORITES,
bridge_.get());
}
private:
content::BrowserTaskEnvironment task_environment_;
scoped_refptr<MockImporterBridge> bridge_ =
base::MakeRefCounted<MockImporterBridge>();
scoped_refptr<FirefoxImporter> importer_ =
base::MakeRefCounted<FirefoxImporter>();
};
TEST_F(FirefoxImporterTest, ImportBookmarks_Firefox48) {
std::vector<user_data_importer::ImportedBookmarkEntry> bookmarks;
favicon_base::FaviconUsageDataList favicons;
ImportBookmarksFromVersion("48.0.2", &bookmarks, &favicons);
ASSERT_EQ(6u, bookmarks.size());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/central/",
bookmarks[0].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/help/",
bookmarks[1].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/customize/",
bookmarks[2].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/contribute/",
bookmarks[3].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/about/", bookmarks[4].url.spec());
EXPECT_EQ("https://www.google.com/", bookmarks[5].url.spec());
ASSERT_EQ(5u, favicons.size());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/0-1473403921346",
favicons[0].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/1-1473403921347",
favicons[1].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/2-1473403921348",
favicons[2].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/3-1473403921349",
favicons[3].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/4-1473403921349",
favicons[4].favicon_url.spec());
}
TEST_F(FirefoxImporterTest, ImportBookmarks_Firefox57) {
std::vector<user_data_importer::ImportedBookmarkEntry> bookmarks;
favicon_base::FaviconUsageDataList favicons;
ImportBookmarksFromVersion("57.0.1", &bookmarks, &favicons);
ASSERT_EQ(6u, bookmarks.size());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/central/",
bookmarks[0].url.spec());
EXPECT_EQ("https://support.mozilla.org/en-US/products/firefox",
bookmarks[1].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/customize/",
bookmarks[2].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/contribute/",
bookmarks[3].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/about/", bookmarks[4].url.spec());
EXPECT_EQ("https://www.google.com/", bookmarks[5].url.spec());
ASSERT_EQ(4u, favicons.size());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/0-1513248843421",
favicons[0].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/1-1513248843424",
favicons[1].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/3-1513248843427",
favicons[2].favicon_url.spec());
EXPECT_EQ("http://www.mozilla.org/2005/made-up-favicon/4-1513248843429",
favicons[3].favicon_url.spec());
}
TEST_F(FirefoxImporterTest, ImportBookmarksWithCorruptedDb) {
base::ScopedTempDir source_temp_dir;
ASSERT_TRUE(source_temp_dir.CreateUniqueTempDir());
base::FilePath places_file =
source_temp_dir.GetPath().AppendASCII("places.sqlite");
{
sql::Database db(sql::test::kTestTag);
ASSERT_TRUE(db.Open(places_file));
ASSERT_TRUE(
db.Execute("CREATE TABLE moz_bookmarks (type INTEGER, fk INTEGER, "
"parent INTEGER, position INTEGER)"));
ASSERT_TRUE(db.Execute(
"CREATE TABLE moz_anno_attributes (attr_id INTEGER PRIMARY KEY, "
"name TEXT)"));
ASSERT_TRUE(
db.Execute("CREATE TABLE moz_items_annos (item_id INTEGER, "
"anno_attribute_id INTEGER)"));
ASSERT_TRUE(db.Execute("INSERT INTO moz_bookmarks VALUES (2, NULL, 0, 0)"));
ASSERT_TRUE(db.Execute("INSERT INTO moz_bookmarks VALUES (2, NULL, 1, 0)"));
}
scoped_refptr<FirefoxImporter> first_importer =
base::MakeRefCounted<FirefoxImporter>();
user_data_importer::SourceProfile profile;
profile.source_path = source_temp_dir.GetPath();
scoped_refptr<MockImporterBridge> bridge =
base::MakeRefCounted<MockImporterBridge>();
EXPECT_CALL(*bridge, NotifyStarted());
EXPECT_CALL(*bridge, NotifyItemStarted(user_data_importer::FAVORITES));
EXPECT_CALL(*bridge, AddBookmarks(_, _)).Times(0);
EXPECT_CALL(*bridge, SetFavicons(_)).Times(0);
EXPECT_CALL(*bridge, NotifyItemEnded(user_data_importer::FAVORITES));
EXPECT_CALL(*bridge, NotifyEnded());
first_importer->StartImport(profile, user_data_importer::FAVORITES,
bridge.get());
base::ScopedTempDir second_source_dir;
ASSERT_TRUE(second_source_dir.CreateUniqueTempDir());
base::FilePath second_places_file =
second_source_dir.GetPath().AppendASCII("places.sqlite");
{
sql::Database db(sql::test::kTestTag);
ASSERT_TRUE(db.Open(second_places_file));
ASSERT_TRUE(db.Execute(
"CREATE TABLE moz_bookmarks (id INTEGER PRIMARY KEY, type INTEGER, "
"parent INTEGER, position INTEGER, title TEXT, "
"guid TEXT)"));
ASSERT_TRUE(
db.Execute("INSERT INTO moz_bookmarks VALUES (1, 2, 0, 0, 'root', "
"'root________')"));
ASSERT_TRUE(
db.Execute("INSERT INTO moz_bookmarks VALUES (2, 2, 1, 0, 'toolbar', "
"'toolbar_____')"));
ASSERT_TRUE(
db.Execute("INSERT INTO moz_bookmarks VALUES (3, 2, 1, 1, 'menu', "
"'menu________')"));
ASSERT_TRUE(
db.Execute("CREATE TABLE moz_anno_attributes (id INTEGER PRIMARY KEY, "
"name TEXT)"));
ASSERT_TRUE(
db.Execute("CREATE TABLE moz_items_annos (item_id INTEGER, "
"anno_attribute_id INTEGER)"));
}
scoped_refptr<FirefoxImporter> second_importer =
base::MakeRefCounted<FirefoxImporter>();
user_data_importer::SourceProfile second_profile;
second_profile.source_path = second_source_dir.GetPath();
scoped_refptr<MockImporterBridge> second_bridge =
base::MakeRefCounted<MockImporterBridge>();
EXPECT_CALL(*second_bridge, NotifyStarted());
EXPECT_CALL(*second_bridge, NotifyItemStarted(user_data_importer::FAVORITES));
EXPECT_CALL(*second_bridge, AddBookmarks(_, _)).Times(0);
EXPECT_CALL(*second_bridge, SetFavicons(_)).Times(0);
EXPECT_CALL(*second_bridge, NotifyItemEnded(user_data_importer::FAVORITES));
EXPECT_CALL(*second_bridge, NotifyEnded());
second_importer->StartImport(second_profile, user_data_importer::FAVORITES,
second_bridge.get());
}
TEST_F(FirefoxImporterTest, ImportHistorySchema) {
base::FilePath places_path;
ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &places_path));
places_path =
places_path.AppendASCII("import").AppendASCII("firefox").AppendASCII(
"48.0.2");
scoped_refptr<FirefoxImporter> ff_importer =
base::MakeRefCounted<FirefoxImporter>();
user_data_importer::SourceProfile profile;
profile.source_path = places_path;
scoped_refptr<MockImporterBridge> bridge =
base::MakeRefCounted<MockImporterBridge>();
std::vector<user_data_importer::ImporterURLRow> history;
EXPECT_CALL(*bridge, NotifyStarted());
EXPECT_CALL(*bridge, NotifyItemStarted(user_data_importer::HISTORY));
EXPECT_CALL(*bridge, SetHistoryItems(_, _))
.WillOnce(::testing::SaveArg<0>(&history));
EXPECT_CALL(*bridge, NotifyItemEnded(user_data_importer::HISTORY));
EXPECT_CALL(*bridge, NotifyEnded());
ff_importer->StartImport(profile, user_data_importer::HISTORY, bridge.get());
ASSERT_EQ(3u, history.size());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/48.0.2/firstrun/learnmore/",
history[0].url.spec());
EXPECT_EQ("https://www.mozilla.org/en-US/firefox/48.0.2/firstrun/",
history[1].url.spec());
EXPECT_EQ("http://google.com/", history[2].url.spec());
}
TEST_F(FirefoxImporterTest, ImportHistoryWithCorruptedDb) {
base::ScopedTempDir source_temp_dir;
ASSERT_TRUE(source_temp_dir.CreateUniqueTempDir());
base::FilePath places_file =
source_temp_dir.GetPath().AppendASCII("places.sqlite");
{
sql::Database db(sql::test::kTestTag);
ASSERT_TRUE(db.Open(places_file));
ASSERT_TRUE(db.Execute("CREATE TABLE moz_places (partial_url TEXT)"));
ASSERT_TRUE(db.Execute(
"CREATE TABLE moz_historyvisits (visit_id INTEGER PRIMARY KEY)"));
ASSERT_TRUE(db.Execute("INSERT INTO moz_places VALUES ('invalid-url')"));
ASSERT_TRUE(db.Execute("INSERT INTO moz_historyvisits VALUES (1)"));
}
scoped_refptr<FirefoxImporter> ff_importer =
base::MakeRefCounted<FirefoxImporter>();
user_data_importer::SourceProfile profile;
profile.source_path = source_temp_dir.GetPath();
scoped_refptr<MockImporterBridge> bridge =
base::MakeRefCounted<MockImporterBridge>();
EXPECT_CALL(*bridge, NotifyStarted());
EXPECT_CALL(*bridge, NotifyItemStarted(user_data_importer::HISTORY));
EXPECT_CALL(*bridge, SetHistoryItems(_, _)).Times(0);
EXPECT_CALL(*bridge, NotifyItemEnded(user_data_importer::HISTORY));
EXPECT_CALL(*bridge, NotifyEnded());
ff_importer->StartImport(profile, user_data_importer::HISTORY, bridge.get());
}
TEST_F(FirefoxImporterTest, ImportAutofillFormDataWithCorruptedDb) {
base::ScopedTempDir source_temp_dir;
ASSERT_TRUE(source_temp_dir.CreateUniqueTempDir());
base::FilePath form_history_file =
source_temp_dir.GetPath().AppendASCII("formhistory.sqlite");
{
sql::Database db(sql::test::kTestTag);
ASSERT_TRUE(db.Open(form_history_file));
ASSERT_TRUE(
db.Execute("CREATE TABLE moz_formhistory (partial_field TEXT)"));
ASSERT_TRUE(
db.Execute("INSERT INTO moz_formhistory VALUES ('invalid-data')"));
}
scoped_refptr<FirefoxImporter> ff_importer =
base::MakeRefCounted<FirefoxImporter>();
user_data_importer::SourceProfile profile;
profile.source_path = source_temp_dir.GetPath();
scoped_refptr<MockImporterBridge> bridge =
base::MakeRefCounted<MockImporterBridge>();
EXPECT_CALL(*bridge, NotifyStarted());
EXPECT_CALL(*bridge,
NotifyItemStarted(user_data_importer::AUTOFILL_FORM_DATA));
EXPECT_CALL(*bridge, SetAutofillFormData(_)).Times(0);
EXPECT_CALL(*bridge, NotifyItemEnded(user_data_importer::AUTOFILL_FORM_DATA));
EXPECT_CALL(*bridge, NotifyEnded());
ff_importer->StartImport(profile, user_data_importer::AUTOFILL_FORM_DATA,
bridge.get());
}