bookmark_undo_service_test.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 "chrome/browser/undo/bookmark_undo_service.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "chrome/browser/bookmarks/bookmark_model.h"
9#include "chrome/browser/bookmarks/bookmark_model_factory.h"
10#include "chrome/browser/bookmarks/bookmark_test_helpers.h"
11#include "chrome/browser/undo/bookmark_undo_service_factory.h"
12#include "chrome/test/base/testing_profile.h"
13#include "content/public/test/test_browser_thread_bundle.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace {
17
18class BookmarkUndoServiceTest : public testing::Test {
19 public:
20  BookmarkUndoServiceTest();
21
22  virtual void SetUp() OVERRIDE;
23  virtual void TearDown() OVERRIDE;
24
25  BookmarkModel* GetModel();
26  BookmarkUndoService* GetUndoService();
27
28 private:
29  scoped_ptr<TestingProfile> profile_;
30  content::TestBrowserThreadBundle thread_bundle_;
31
32  DISALLOW_COPY_AND_ASSIGN(BookmarkUndoServiceTest);
33};
34
35BookmarkUndoServiceTest::BookmarkUndoServiceTest() {}
36
37void BookmarkUndoServiceTest::SetUp() {
38  profile_.reset(new TestingProfile);
39  profile_->CreateBookmarkModel(true);
40  test::WaitForBookmarkModelToLoad(GetModel());
41}
42
43BookmarkModel* BookmarkUndoServiceTest::GetModel() {
44  return BookmarkModelFactory::GetForProfile(profile_.get());
45}
46
47BookmarkUndoService* BookmarkUndoServiceTest::GetUndoService() {
48  return BookmarkUndoServiceFactory::GetForProfile(profile_.get());
49}
50
51void BookmarkUndoServiceTest::TearDown() {
52  profile_.reset(NULL);
53}
54
55TEST_F(BookmarkUndoServiceTest, AddBookmark) {
56  BookmarkModel* model = GetModel();
57  BookmarkUndoService* undo_service = GetUndoService();
58  model->AddObserver(undo_service);
59
60  const BookmarkNode* parent = model->other_node();
61  model->AddURL(parent, 0, ASCIIToUTF16("foo"), GURL("http://www.bar.com"));
62
63  // Undo bookmark creation and test for no bookmarks.
64  undo_service->undo_manager()->Undo();
65  EXPECT_EQ(0, model->other_node()->child_count());
66
67  // Redo bookmark creation and ensure bookmark information is valid.
68  undo_service->undo_manager()->Redo();
69  const BookmarkNode* node = parent->GetChild(0);
70  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
71  EXPECT_EQ(node->url(), GURL("http://www.bar.com"));
72}
73
74// Test that a bookmark removal action can be undone and redone.
75TEST_F(BookmarkUndoServiceTest, UndoBookmarkRemove) {
76  BookmarkModel* model = GetModel();
77  BookmarkUndoService* undo_service = GetUndoService();
78  model->AddObserver(undo_service);
79
80  const BookmarkNode* parent = model->other_node();
81  model->AddURL(parent, 0, ASCIIToUTF16("foo"), GURL("http://www.bar.com"));
82  model->Remove(parent, 0);
83
84  EXPECT_EQ(2U, undo_service->undo_manager()->undo_count());
85  EXPECT_EQ(0U, undo_service->undo_manager()->redo_count());
86
87  // Undo the deletion of the only bookmark and check the bookmark values.
88  undo_service->undo_manager()->Undo();
89  EXPECT_EQ(1, model->other_node()->child_count());
90  const BookmarkNode* node = parent->GetChild(0);
91  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
92  EXPECT_EQ(node->url(), GURL("http://www.bar.com"));
93
94  EXPECT_EQ(1U, undo_service->undo_manager()->undo_count());
95  EXPECT_EQ(1U, undo_service->undo_manager()->redo_count());
96
97  // Redo the deletion and check that there are no bookmarks left.
98  undo_service->undo_manager()->Redo();
99  EXPECT_EQ(0, model->other_node()->child_count());
100
101  EXPECT_EQ(2U, undo_service->undo_manager()->undo_count());
102  EXPECT_EQ(0U, undo_service->undo_manager()->redo_count());
103}
104
105// Ensure the undo/redo works for editing of bookmark information grouped into
106// one action.
107TEST_F(BookmarkUndoServiceTest, UndoBookmarkGroupedAction) {
108  BookmarkModel* model = GetModel();
109  BookmarkUndoService* undo_service = GetUndoService();
110  model->AddObserver(undo_service);
111
112  const BookmarkNode* n1 = model->AddURL(model->other_node(),
113                                        0,
114                                        ASCIIToUTF16("foo"),
115                                        GURL("http://www.foo.com"));
116  undo_service->undo_manager()->StartGroupingActions();
117  model->SetTitle(n1, ASCIIToUTF16("bar"));
118  model->SetURL(n1, GURL("http://www.bar.com"));
119  undo_service->undo_manager()->EndGroupingActions();
120
121  EXPECT_EQ(2U, undo_service->undo_manager()->undo_count());
122  EXPECT_EQ(0U, undo_service->undo_manager()->redo_count());
123
124  // Undo the modification of the bookmark and check for the original values.
125  undo_service->undo_manager()->Undo();
126  EXPECT_EQ(1, model->other_node()->child_count());
127  const BookmarkNode* node = model->other_node()->GetChild(0);
128  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
129  EXPECT_EQ(node->url(), GURL("http://www.foo.com"));
130
131  // Redo the modifications and ensure the newer values are present.
132  undo_service->undo_manager()->Redo();
133  EXPECT_EQ(1, model->other_node()->child_count());
134  node = model->other_node()->GetChild(0);
135  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("bar"));
136  EXPECT_EQ(node->url(), GURL("http://www.bar.com"));
137
138  EXPECT_EQ(2U, undo_service->undo_manager()->undo_count());
139  EXPECT_EQ(0U, undo_service->undo_manager()->redo_count());
140}
141
142// Test moving bookmarks within a folder and between folders.
143TEST_F(BookmarkUndoServiceTest, UndoBookmarkMoveWithinFolder) {
144  BookmarkModel* model = GetModel();
145  BookmarkUndoService* undo_service = GetUndoService();
146  model->AddObserver(undo_service);
147
148  const BookmarkNode* n1 = model->AddURL(model->other_node(),
149                                        0,
150                                        ASCIIToUTF16("foo"),
151                                        GURL("http://www.foo.com"));
152  const BookmarkNode* n2 = model->AddURL(model->other_node(),
153                                        1,
154                                        ASCIIToUTF16("moo"),
155                                        GURL("http://www.moo.com"));
156  const BookmarkNode* n3 = model->AddURL(model->other_node(),
157                                        2,
158                                        ASCIIToUTF16("bar"),
159                                        GURL("http://www.bar.com"));
160  model->Move(n1, model->other_node(), 3);
161
162  // Undo the move and check that the nodes are in order.
163  undo_service->undo_manager()->Undo();
164  EXPECT_EQ(model->other_node()->GetChild(0), n1);
165  EXPECT_EQ(model->other_node()->GetChild(1), n2);
166  EXPECT_EQ(model->other_node()->GetChild(2), n3);
167
168  // Redo the move and check that the first node is in the last position.
169  undo_service->undo_manager()->Redo();
170  EXPECT_EQ(model->other_node()->GetChild(0), n2);
171  EXPECT_EQ(model->other_node()->GetChild(1), n3);
172  EXPECT_EQ(model->other_node()->GetChild(2), n1);
173}
174
175// Test undo of a bookmark moved to a different folder.
176TEST_F(BookmarkUndoServiceTest, UndoBookmarkMoveToOtherFolder) {
177  BookmarkModel* model = GetModel();
178  BookmarkUndoService* undo_service = GetUndoService();
179  model->AddObserver(undo_service);
180
181  const BookmarkNode* n1 = model->AddURL(model->other_node(),
182                                        0,
183                                        ASCIIToUTF16("foo"),
184                                        GURL("http://www.foo.com"));
185  const BookmarkNode* n2 = model->AddURL(model->other_node(),
186                                        1,
187                                        ASCIIToUTF16("moo"),
188                                        GURL("http://www.moo.com"));
189  const BookmarkNode* n3 = model->AddURL(model->other_node(),
190                                        2,
191                                        ASCIIToUTF16("bar"),
192                                        GURL("http://www.bar.com"));
193  const BookmarkNode* f1 =
194      model->AddFolder(model->other_node(), 3, ASCIIToUTF16("folder"));
195  model->Move(n3, f1, 0);
196
197  // Undo the move and check that the bookmark and folder are in place.
198  undo_service->undo_manager()->Undo();
199  ASSERT_EQ(4, model->other_node()->child_count());
200  EXPECT_EQ(model->other_node()->GetChild(0), n1);
201  EXPECT_EQ(model->other_node()->GetChild(1), n2);
202  EXPECT_EQ(model->other_node()->GetChild(2), n3);
203  EXPECT_EQ(model->other_node()->GetChild(3), f1);
204  EXPECT_EQ(0, f1->child_count());
205
206  // Redo the move back into the folder and check validity.
207  undo_service->undo_manager()->Redo();
208  ASSERT_EQ(3, model->other_node()->child_count());
209  EXPECT_EQ(model->other_node()->GetChild(0), n1);
210  EXPECT_EQ(model->other_node()->GetChild(1), n2);
211  EXPECT_EQ(model->other_node()->GetChild(2), f1);
212  ASSERT_EQ(1, f1->child_count());
213  EXPECT_EQ(f1->GetChild(0), n3);
214}
215
216// Tests the handling of multiple modifications that include renumbering of the
217// bookmark identifiers.
218TEST_F(BookmarkUndoServiceTest, UndoBookmarkRenameDelete) {
219  BookmarkModel* model = GetModel();
220  BookmarkUndoService* undo_service = GetUndoService();
221  model->AddObserver(undo_service);
222
223  const BookmarkNode* f1 = model->AddFolder(model->other_node(),
224                                           0,
225                                           ASCIIToUTF16("folder"));
226  model->AddURL(f1, 0, ASCIIToUTF16("foo"), GURL("http://www.foo.com"));
227  model->SetTitle(f1, ASCIIToUTF16("Renamed"));
228  model->Remove(model->other_node(), 0);
229
230  // Undo the folder removal and ensure the folder and bookmark were restored.
231  undo_service->undo_manager()->Undo();
232  ASSERT_EQ(1, model->other_node()->child_count());
233  ASSERT_EQ(1, model->other_node()->GetChild(0)->child_count());
234  const BookmarkNode* node = model->other_node()->GetChild(0);
235  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("Renamed"));
236
237  node = model->other_node()->GetChild(0)->GetChild(0);
238  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
239  EXPECT_EQ(node->url(), GURL("http://www.foo.com"));
240
241  // Undo the title change and ensure the folder was updated even though the
242  // id has changed.
243  undo_service->undo_manager()->Undo();
244  node = model->other_node()->GetChild(0);
245  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("folder"));
246
247  // Undo bookmark creation and test for removal of bookmark.
248  undo_service->undo_manager()->Undo();
249  ASSERT_EQ(0, model->other_node()->GetChild(0)->child_count());
250
251  // Undo folder creation and confirm the bookmark model is empty.
252  undo_service->undo_manager()->Undo();
253  ASSERT_EQ(0, model->other_node()->child_count());
254
255  // Redo all the actions and ensure the folder and bookmark are restored.
256  undo_service->undo_manager()->Redo(); // folder creation
257  undo_service->undo_manager()->Redo(); // bookmark creation
258  undo_service->undo_manager()->Redo(); // bookmark title change
259  ASSERT_EQ(1, model->other_node()->child_count());
260  ASSERT_EQ(1, model->other_node()->GetChild(0)->child_count());
261  node = model->other_node()->GetChild(0);
262  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("Renamed"));
263  node = model->other_node()->GetChild(0)->GetChild(0);
264  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
265  EXPECT_EQ(node->url(), GURL("http://www.foo.com"));
266
267  undo_service->undo_manager()->Redo(); // folder deletion
268  EXPECT_EQ(0, model->other_node()->child_count());
269}
270
271// Test the undo of SortChildren and ReorderChildren.
272TEST_F(BookmarkUndoServiceTest, UndoBookmarkReorder) {
273  BookmarkModel* model = GetModel();
274  BookmarkUndoService* undo_service = GetUndoService();
275  model->AddObserver(undo_service);
276
277  const BookmarkNode* parent = model->other_node();
278  model->AddURL(parent, 0, ASCIIToUTF16("foo"), GURL("http://www.foo.com"));
279  model->AddURL(parent, 1, ASCIIToUTF16("moo"), GURL("http://www.moo.com"));
280  model->AddURL(parent, 2, ASCIIToUTF16("bar"), GURL("http://www.bar.com"));
281  model->SortChildren(parent);
282
283  // Test the undo of SortChildren.
284  undo_service->undo_manager()->Undo();
285  const BookmarkNode* node = parent->GetChild(0);
286  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
287  EXPECT_EQ(node->url(), GURL("http://www.foo.com"));
288
289  node = parent->GetChild(1);
290  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("moo"));
291  EXPECT_EQ(node->url(), GURL("http://www.moo.com"));
292
293  node = parent->GetChild(2);
294  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("bar"));
295  EXPECT_EQ(node->url(), GURL("http://www.bar.com"));
296
297  // Test the redo of SortChildren.
298  undo_service->undo_manager()->Redo();
299  node = parent->GetChild(0);
300  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("bar"));
301  EXPECT_EQ(node->url(), GURL("http://www.bar.com"));
302
303  node = parent->GetChild(1);
304  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
305  EXPECT_EQ(node->url(), GURL("http://www.foo.com"));
306
307  node = parent->GetChild(2);
308  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("moo"));
309  EXPECT_EQ(node->url(), GURL("http://www.moo.com"));
310
311}
312
313TEST_F(BookmarkUndoServiceTest, UndoBookmarkRemoveAll) {
314  BookmarkModel* model = GetModel();
315  BookmarkUndoService* undo_service = GetUndoService();
316  model->AddObserver(undo_service);
317
318  // Setup bookmarks in the Other Bookmarks and the Bookmark Bar.
319  const BookmarkNode* new_folder;
320  const BookmarkNode* parent = model->other_node();
321  model->AddURL(parent, 0, ASCIIToUTF16("foo"), GURL("http://www.google.com"));
322  new_folder= model->AddFolder(parent, 1, ASCIIToUTF16("folder"));
323  model->AddURL(new_folder, 0, ASCIIToUTF16("bar"), GURL("http://www.bar.com"));
324
325  parent = model->bookmark_bar_node();
326  model->AddURL(parent, 0, ASCIIToUTF16("a"), GURL("http://www.a.com"));
327  new_folder = model->AddFolder(parent, 1, ASCIIToUTF16("folder"));
328  model->AddURL(new_folder, 0, ASCIIToUTF16("b"), GURL("http://www.b.com"));
329
330  model->RemoveAll();
331
332  // Test that the undo of RemoveAll restores all folders and bookmarks.
333  undo_service->undo_manager()->Undo();
334
335  ASSERT_EQ(2, model->other_node()->child_count());
336  EXPECT_EQ(1, model->other_node()->GetChild(1)->child_count());
337  const BookmarkNode* node = model->other_node()->GetChild(1)->GetChild(0);
338  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("bar"));
339  EXPECT_EQ(node->url(), GURL("http://www.bar.com"));
340
341  ASSERT_EQ(2, model->bookmark_bar_node()->child_count());
342  EXPECT_EQ(1, model->bookmark_bar_node()->GetChild(1)->child_count());
343  node = model->bookmark_bar_node()->GetChild(1)->GetChild(0);
344  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("b"));
345  EXPECT_EQ(node->url(), GURL("http://www.b.com"));
346
347  // Test that the redo removes all folders and bookmarks.
348  undo_service->undo_manager()->Redo();
349  EXPECT_EQ(0, model->other_node()->child_count());
350  EXPECT_EQ(0, model->bookmark_bar_node()->child_count());
351}
352
353TEST_F(BookmarkUndoServiceTest, TestUpperLimit) {
354  BookmarkModel* model = GetModel();
355  BookmarkUndoService* undo_service = GetUndoService();
356  model->AddObserver(undo_service);
357
358  // This maximum is set in undo_manager.cc
359  const size_t kMaxUndoGroups = 100;
360
361  const BookmarkNode* parent = model->other_node();
362  model->AddURL(parent, 0, ASCIIToUTF16("foo"), GURL("http://www.foo.com"));
363  for (size_t i = 1; i < kMaxUndoGroups + 1; ++i)
364    model->AddURL(parent, i, ASCIIToUTF16("bar"), GURL("http://www.bar.com"));
365
366  EXPECT_EQ(kMaxUndoGroups, undo_service->undo_manager()->undo_count());
367
368  // Undo as many operations as possible.
369  while (undo_service->undo_manager()->undo_count())
370    undo_service->undo_manager()->Undo();
371
372  EXPECT_EQ(1, parent->child_count());
373  const BookmarkNode* node = model->other_node()->GetChild(0);
374  EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("foo"));
375  EXPECT_EQ(node->url(), GURL("http://www.foo.com"));
376}
377
378} // namespace
379