1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6
7#include "base/message_loop/message_loop.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/bookmarks/bookmark_model.h"
10#include "chrome/browser/bookmarks/bookmark_model_factory.h"
11#include "chrome/browser/bookmarks/bookmark_title_match.h"
12#include "chrome/browser/bookmarks/bookmark_utils.h"
13#include "chrome/browser/history/history_service_factory.h"
14#include "chrome/browser/history/history_types.h"
15#include "chrome/browser/importer/importer_unittest_utils.h"
16#include "chrome/browser/importer/profile_writer.h"
17#include "chrome/common/importer/imported_bookmark_entry.h"
18#include "chrome/test/base/testing_profile.h"
19#include "chrome/test/base/ui_test_utils.h"
20#include "content/public/test/test_browser_thread.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23using content::BrowserThread;
24
25class TestProfileWriter : public ProfileWriter {
26 public:
27  explicit TestProfileWriter(Profile* profile) : ProfileWriter(profile) {}
28 protected:
29  virtual ~TestProfileWriter() {}
30};
31
32class ProfileWriterTest : public testing::Test {
33 public:
34  ProfileWriterTest()
35      : loop_(base::MessageLoop::TYPE_DEFAULT),
36        ui_thread_(BrowserThread::UI, &loop_),
37        file_thread_(BrowserThread::FILE, &loop_) {
38  }
39  virtual ~ProfileWriterTest() {}
40
41  // Create test bookmark entries to be added to ProfileWriter to
42  // simulate bookmark importing.
43  void CreateImportedBookmarksEntries() {
44    AddImportedBookmarkEntry(GURL("http://www.google.com"),
45                             ASCIIToUTF16("Google"));
46    AddImportedBookmarkEntry(GURL("http://www.yahoo.com"),
47                             ASCIIToUTF16("Yahoo"));
48  }
49
50  // Helper function to create history entries.
51  history::URLRow MakeURLRow(const char* url,
52                             string16 title,
53                             int visit_count,
54                             int days_since_last_visit,
55                             int typed_count) {
56    history::URLRow row(GURL(url), 0);
57    row.set_title(title);
58    row.set_visit_count(visit_count);
59    row.set_typed_count(typed_count);
60    row.set_last_visit(base::Time::NowFromSystemTime() -
61                       base::TimeDelta::FromDays(days_since_last_visit));
62    return row;
63  }
64
65  // Create test history entries to be added to ProfileWriter to
66  // simulate history importing.
67  void CreateHistoryPageEntries() {
68    history::URLRow row1(
69        MakeURLRow("http://www.google.com", ASCIIToUTF16("Google"), 3, 10, 1));
70    history::URLRow row2(
71        MakeURLRow("http://www.yahoo.com", ASCIIToUTF16("Yahoo"), 3, 30, 10));
72    pages_.push_back(row1);
73    pages_.push_back(row2);
74  }
75
76  void VerifyBookmarksCount(
77      const std::vector<BookmarkService::URLAndTitle>& bookmarks_record,
78      BookmarkModel* bookmark_model,
79      size_t expected) {
80    std::vector<BookmarkTitleMatch> matches;
81    for (size_t i = 0; i < bookmarks_record.size(); ++i) {
82      bookmark_model->GetBookmarksWithTitlesMatching(bookmarks_record[i].title,
83                                                     10,
84                                                     &matches);
85      EXPECT_EQ(expected, matches.size());
86      matches.clear();
87    }
88  }
89
90  void VerifyHistoryCount(Profile* profile) {
91    HistoryService* history_service =
92        HistoryServiceFactory::GetForProfile(profile,
93                                             Profile::EXPLICIT_ACCESS);
94    history::QueryOptions options;
95    CancelableRequestConsumer history_request_consumer;
96    history_service->QueryHistory(
97        string16(),
98        options,
99        &history_request_consumer,
100        base::Bind(&ProfileWriterTest::HistoryQueryComplete,
101                   base::Unretained(this)));
102    base::MessageLoop::current()->Run();
103  }
104
105  void HistoryQueryComplete(HistoryService::Handle handle,
106                            history::QueryResults* results) {
107    base::MessageLoop::current()->Quit();
108    history_count_ = results->size();
109  }
110
111 protected:
112  std::vector<ImportedBookmarkEntry> bookmarks_;
113  history::URLRows pages_;
114  size_t history_count_;
115
116 private:
117  void AddImportedBookmarkEntry(const GURL& url, const string16& title) {
118    base::Time date;
119    ImportedBookmarkEntry entry;
120    entry.creation_time = date;
121    entry.url = url;
122    entry.title = title;
123    entry.in_toolbar = true;
124    entry.is_folder = false;
125    bookmarks_.push_back(entry);
126  }
127
128  base::MessageLoop loop_;
129  content::TestBrowserThread ui_thread_;
130  content::TestBrowserThread file_thread_;
131
132  DISALLOW_COPY_AND_ASSIGN(ProfileWriterTest);
133};
134
135// Add bookmarks via ProfileWriter to profile1 when profile2 also exists.
136TEST_F(ProfileWriterTest, CheckBookmarksWithMultiProfile) {
137  TestingProfile profile2;
138  profile2.CreateBookmarkModel(true);
139
140  BookmarkModel* bookmark_model2 =
141      BookmarkModelFactory::GetForProfile(&profile2);
142  ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model2);
143  bookmark_utils::AddIfNotBookmarked(bookmark_model2,
144                                     GURL("http://www.bing.com"),
145                                     ASCIIToUTF16("Bing"));
146  TestingProfile profile1;
147  profile1.CreateBookmarkModel(true);
148
149  CreateImportedBookmarksEntries();
150  BookmarkModel* bookmark_model1 =
151      BookmarkModelFactory::GetForProfile(&profile1);
152  ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model1);
153
154  scoped_refptr<TestProfileWriter> profile_writer(
155      new TestProfileWriter(&profile1));
156  profile_writer->AddBookmarks(bookmarks_,
157                               ASCIIToUTF16("Imported from Firefox"));
158
159  std::vector<BookmarkService::URLAndTitle> url_record1;
160  bookmark_model1->GetBookmarks(&url_record1);
161  EXPECT_EQ(2u, url_record1.size());
162
163  std::vector<BookmarkService::URLAndTitle> url_record2;
164  bookmark_model2->GetBookmarks(&url_record2);
165  EXPECT_EQ(1u, url_record2.size());
166}
167
168// Verify that bookmarks are duplicated when added twice.
169TEST_F(ProfileWriterTest, CheckBookmarksAfterWritingDataTwice) {
170  TestingProfile profile;
171  profile.CreateBookmarkModel(true);
172
173  CreateImportedBookmarksEntries();
174  BookmarkModel* bookmark_model =
175      BookmarkModelFactory::GetForProfile(&profile);
176  ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model);
177
178  scoped_refptr<TestProfileWriter> profile_writer(
179      new TestProfileWriter(&profile));
180  profile_writer->AddBookmarks(bookmarks_,
181                               ASCIIToUTF16("Imported from Firefox"));
182  std::vector<BookmarkService::URLAndTitle> bookmarks_record;
183  bookmark_model->GetBookmarks(&bookmarks_record);
184  EXPECT_EQ(2u, bookmarks_record.size());
185
186  VerifyBookmarksCount(bookmarks_record, bookmark_model, 1);
187
188  profile_writer->AddBookmarks(bookmarks_,
189                               ASCIIToUTF16("Imported from Firefox"));
190  // Verify that duplicate bookmarks exist.
191  VerifyBookmarksCount(bookmarks_record, bookmark_model, 2);
192}
193
194// Verify that history entires are not duplicated when added twice.
195TEST_F(ProfileWriterTest, CheckHistoryAfterWritingDataTwice) {
196  TestingProfile profile;
197  ASSERT_TRUE(profile.CreateHistoryService(true, false));
198  profile.BlockUntilHistoryProcessesPendingRequests();
199
200  CreateHistoryPageEntries();
201  scoped_refptr<TestProfileWriter> profile_writer(
202      new TestProfileWriter(&profile));
203  profile_writer->AddHistoryPage(pages_, history::SOURCE_FIREFOX_IMPORTED);
204  VerifyHistoryCount(&profile);
205  size_t original_history_count = history_count_;
206  history_count_ = 0;
207
208  profile_writer->AddHistoryPage(pages_, history::SOURCE_FIREFOX_IMPORTED);
209  VerifyHistoryCount(&profile);
210  EXPECT_EQ(original_history_count, history_count_);
211}
212