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