| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "components/bookmarks/core/browser/bookmark_model.h" | |
| 6 | |
| 7 #include <set> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/base_paths.h" | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/command_line.h" | |
| 13 #include "base/compiler_specific.h" | |
| 14 #include "base/containers/hash_tables.h" | |
| 15 #include "base/path_service.h" | |
| 16 #include "base/strings/string16.h" | |
| 17 #include "base/strings/string_number_conversions.h" | |
| 18 #include "base/strings/string_split.h" | |
| 19 #include "base/strings/string_util.h" | |
| 20 #include "base/strings/utf_string_conversions.h" | |
| 21 #include "base/time/time.h" | |
| 22 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
| 23 #include "chrome/test/base/testing_profile.h" | |
| 24 #include "components/bookmarks/core/browser/bookmark_model_observer.h" | |
| 25 #include "components/bookmarks/core/browser/bookmark_utils.h" | |
| 26 #include "components/bookmarks/core/test/bookmark_test_helpers.h" | |
| 27 #include "components/bookmarks/core/test/test_bookmark_client.h" | |
| 28 #include "content/public/test/test_browser_thread_bundle.h" | |
| 29 #include "testing/gtest/include/gtest/gtest.h" | |
| 30 #include "ui/base/models/tree_node_iterator.h" | |
| 31 #include "ui/base/models/tree_node_model.h" | |
| 32 #include "url/gurl.h" | |
| 33 | |
| 34 using base::ASCIIToUTF16; | |
| 35 using base::Time; | |
| 36 using base::TimeDelta; | |
| 37 | |
| 38 namespace { | |
| 39 | |
| 40 // Test cases used to test the removal of extra whitespace when adding | |
| 41 // a new folder/bookmark or updating a title of a folder/bookmark. | |
| 42 static struct { | |
| 43 const std::string input_title; | |
| 44 const std::string expected_title; | |
| 45 } url_whitespace_test_cases[] = { | |
| 46 {"foobar", "foobar"}, | |
| 47 // Newlines. | |
| 48 {"foo\nbar", "foo bar"}, | |
| 49 {"foo\n\nbar", "foo bar"}, | |
| 50 {"foo\n\n\nbar", "foo bar"}, | |
| 51 {"foo\r\nbar", "foo bar"}, | |
| 52 {"foo\r\n\r\nbar", "foo bar"}, | |
| 53 {"\nfoo\nbar\n", "foo bar"}, | |
| 54 // Spaces. | |
| 55 {"foo bar", "foo bar"}, | |
| 56 {" foo bar ", "foo bar"}, | |
| 57 {" foo bar ", "foo bar"}, | |
| 58 // Tabs. | |
| 59 {"\tfoo\tbar\t", "foo bar"}, | |
| 60 {"\tfoo bar\t", "foo bar"}, | |
| 61 // Mixed cases. | |
| 62 {"\tfoo\nbar\t", "foo bar"}, | |
| 63 {"\tfoo\r\nbar\t", "foo bar"}, | |
| 64 {" foo\tbar\n", "foo bar"}, | |
| 65 {"\t foo \t bar \t", "foo bar"}, | |
| 66 {"\n foo\r\n\tbar\n \t", "foo bar"}, | |
| 67 }; | |
| 68 | |
| 69 // Test cases used to test the removal of extra whitespace when adding | |
| 70 // a new folder/bookmark or updating a title of a folder/bookmark. | |
| 71 static struct { | |
| 72 const std::string input_title; | |
| 73 const std::string expected_title; | |
| 74 } title_whitespace_test_cases[] = { | |
| 75 {"foobar", "foobar"}, | |
| 76 // Newlines. | |
| 77 {"foo\nbar", "foo bar"}, | |
| 78 {"foo\n\nbar", "foo bar"}, | |
| 79 {"foo\n\n\nbar", "foo bar"}, | |
| 80 {"foo\r\nbar", "foo bar"}, | |
| 81 {"foo\r\n\r\nbar", "foo bar"}, | |
| 82 {"\nfoo\nbar\n", " foo bar "}, | |
| 83 // Spaces. | |
| 84 {"foo bar", "foo bar"}, | |
| 85 {" foo bar ", " foo bar "}, | |
| 86 {" foo bar ", " foo bar "}, | |
| 87 // Tabs. | |
| 88 {"\tfoo\tbar\t", " foo bar "}, | |
| 89 {"\tfoo bar\t", " foo bar "}, | |
| 90 // Mixed cases. | |
| 91 {"\tfoo\nbar\t", " foo bar "}, | |
| 92 {"\tfoo\r\nbar\t", " foo bar "}, | |
| 93 {" foo\tbar\n", " foo bar "}, | |
| 94 {"\t foo \t bar \t", " foo bar "}, | |
| 95 {"\n foo\r\n\tbar\n \t", " foo bar "}, | |
| 96 }; | |
| 97 | |
| 98 // Helper to get a mutable bookmark node. | |
| 99 BookmarkNode* AsMutable(const BookmarkNode* node) { | |
| 100 return const_cast<BookmarkNode*>(node); | |
| 101 } | |
| 102 | |
| 103 void SwapDateAdded(BookmarkNode* n1, BookmarkNode* n2) { | |
| 104 Time tmp = n1->date_added(); | |
| 105 n1->set_date_added(n2->date_added()); | |
| 106 n2->set_date_added(tmp); | |
| 107 } | |
| 108 | |
| 109 class BookmarkModelTest : public testing::Test, | |
| 110 public BookmarkModelObserver { | |
| 111 public: | |
| 112 struct ObserverDetails { | |
| 113 ObserverDetails() { | |
| 114 Set(NULL, NULL, -1, -1); | |
| 115 } | |
| 116 | |
| 117 void Set(const BookmarkNode* node1, | |
| 118 const BookmarkNode* node2, | |
| 119 int index1, | |
| 120 int index2) { | |
| 121 node1_ = node1; | |
| 122 node2_ = node2; | |
| 123 index1_ = index1; | |
| 124 index2_ = index2; | |
| 125 } | |
| 126 | |
| 127 void ExpectEquals(const BookmarkNode* node1, | |
| 128 const BookmarkNode* node2, | |
| 129 int index1, | |
| 130 int index2) { | |
| 131 EXPECT_EQ(node1_, node1); | |
| 132 EXPECT_EQ(node2_, node2); | |
| 133 EXPECT_EQ(index1_, index1); | |
| 134 EXPECT_EQ(index2_, index2); | |
| 135 } | |
| 136 | |
| 137 private: | |
| 138 const BookmarkNode* node1_; | |
| 139 const BookmarkNode* node2_; | |
| 140 int index1_; | |
| 141 int index2_; | |
| 142 }; | |
| 143 | |
| 144 BookmarkModelTest() : model_(client_.CreateModel(false)) { | |
| 145 model_->AddObserver(this); | |
| 146 ClearCounts(); | |
| 147 } | |
| 148 | |
| 149 virtual void BookmarkModelLoaded(BookmarkModel* model, | |
| 150 bool ids_reassigned) OVERRIDE { | |
| 151 // We never load from the db, so that this should never get invoked. | |
| 152 NOTREACHED(); | |
| 153 } | |
| 154 | |
| 155 virtual void BookmarkNodeMoved(BookmarkModel* model, | |
| 156 const BookmarkNode* old_parent, | |
| 157 int old_index, | |
| 158 const BookmarkNode* new_parent, | |
| 159 int new_index) OVERRIDE { | |
| 160 ++moved_count_; | |
| 161 observer_details_.Set(old_parent, new_parent, old_index, new_index); | |
| 162 } | |
| 163 | |
| 164 virtual void BookmarkNodeAdded(BookmarkModel* model, | |
| 165 const BookmarkNode* parent, | |
| 166 int index) OVERRIDE { | |
| 167 ++added_count_; | |
| 168 observer_details_.Set(parent, NULL, index, -1); | |
| 169 } | |
| 170 | |
| 171 virtual void OnWillRemoveBookmarks(BookmarkModel* model, | |
| 172 const BookmarkNode* parent, | |
| 173 int old_index, | |
| 174 const BookmarkNode* node) OVERRIDE { | |
| 175 ++before_remove_count_; | |
| 176 } | |
| 177 | |
| 178 virtual void BookmarkNodeRemoved( | |
| 179 BookmarkModel* model, | |
| 180 const BookmarkNode* parent, | |
| 181 int old_index, | |
| 182 const BookmarkNode* node, | |
| 183 const std::set<GURL>& removed_urls) OVERRIDE { | |
| 184 ++removed_count_; | |
| 185 observer_details_.Set(parent, NULL, old_index, -1); | |
| 186 } | |
| 187 | |
| 188 virtual void BookmarkNodeChanged(BookmarkModel* model, | |
| 189 const BookmarkNode* node) OVERRIDE { | |
| 190 ++changed_count_; | |
| 191 observer_details_.Set(node, NULL, -1, -1); | |
| 192 } | |
| 193 | |
| 194 virtual void OnWillChangeBookmarkNode(BookmarkModel* model, | |
| 195 const BookmarkNode* node) OVERRIDE { | |
| 196 ++before_change_count_; | |
| 197 } | |
| 198 | |
| 199 virtual void BookmarkNodeChildrenReordered( | |
| 200 BookmarkModel* model, | |
| 201 const BookmarkNode* node) OVERRIDE { | |
| 202 ++reordered_count_; | |
| 203 } | |
| 204 | |
| 205 virtual void OnWillReorderBookmarkNode(BookmarkModel* model, | |
| 206 const BookmarkNode* node) OVERRIDE { | |
| 207 ++before_reorder_count_; | |
| 208 } | |
| 209 | |
| 210 virtual void BookmarkNodeFaviconChanged(BookmarkModel* model, | |
| 211 const BookmarkNode* node) OVERRIDE { | |
| 212 // We never attempt to load favicons, so that this method never | |
| 213 // gets invoked. | |
| 214 } | |
| 215 | |
| 216 virtual void ExtensiveBookmarkChangesBeginning( | |
| 217 BookmarkModel* model) OVERRIDE { | |
| 218 ++extensive_changes_beginning_count_; | |
| 219 } | |
| 220 | |
| 221 virtual void ExtensiveBookmarkChangesEnded(BookmarkModel* model) OVERRIDE { | |
| 222 ++extensive_changes_ended_count_; | |
| 223 } | |
| 224 | |
| 225 virtual void BookmarkAllNodesRemoved( | |
| 226 BookmarkModel* model, | |
| 227 const std::set<GURL>& removed_urls) OVERRIDE { | |
| 228 ++all_bookmarks_removed_; | |
| 229 } | |
| 230 | |
| 231 virtual void OnWillRemoveAllBookmarks(BookmarkModel* model) OVERRIDE { | |
| 232 ++before_remove_all_count_; | |
| 233 } | |
| 234 | |
| 235 void ClearCounts() { | |
| 236 added_count_ = moved_count_ = removed_count_ = changed_count_ = | |
| 237 reordered_count_ = extensive_changes_beginning_count_ = | |
| 238 extensive_changes_ended_count_ = all_bookmarks_removed_ = | |
| 239 before_remove_count_ = before_change_count_ = before_reorder_count_ = | |
| 240 before_remove_all_count_ = 0; | |
| 241 } | |
| 242 | |
| 243 void AssertObserverCount(int added_count, | |
| 244 int moved_count, | |
| 245 int removed_count, | |
| 246 int changed_count, | |
| 247 int reordered_count, | |
| 248 int before_remove_count, | |
| 249 int before_change_count, | |
| 250 int before_reorder_count, | |
| 251 int before_remove_all_count) { | |
| 252 EXPECT_EQ(added_count_, added_count); | |
| 253 EXPECT_EQ(moved_count_, moved_count); | |
| 254 EXPECT_EQ(removed_count_, removed_count); | |
| 255 EXPECT_EQ(changed_count_, changed_count); | |
| 256 EXPECT_EQ(reordered_count_, reordered_count); | |
| 257 EXPECT_EQ(before_remove_count_, before_remove_count); | |
| 258 EXPECT_EQ(before_change_count_, before_change_count); | |
| 259 EXPECT_EQ(before_reorder_count_, before_reorder_count); | |
| 260 EXPECT_EQ(before_remove_all_count_, before_remove_all_count); | |
| 261 } | |
| 262 | |
| 263 void AssertExtensiveChangesObserverCount( | |
| 264 int extensive_changes_beginning_count, | |
| 265 int extensive_changes_ended_count) { | |
| 266 EXPECT_EQ(extensive_changes_beginning_count_, | |
| 267 extensive_changes_beginning_count); | |
| 268 EXPECT_EQ(extensive_changes_ended_count_, extensive_changes_ended_count); | |
| 269 } | |
| 270 | |
| 271 int AllNodesRemovedObserverCount() const { return all_bookmarks_removed_; } | |
| 272 | |
| 273 protected: | |
| 274 test::TestBookmarkClient client_; | |
| 275 scoped_ptr<BookmarkModel> model_; | |
| 276 ObserverDetails observer_details_; | |
| 277 | |
| 278 private: | |
| 279 int added_count_; | |
| 280 int moved_count_; | |
| 281 int removed_count_; | |
| 282 int changed_count_; | |
| 283 int reordered_count_; | |
| 284 int extensive_changes_beginning_count_; | |
| 285 int extensive_changes_ended_count_; | |
| 286 int all_bookmarks_removed_; | |
| 287 int before_remove_count_; | |
| 288 int before_change_count_; | |
| 289 int before_reorder_count_; | |
| 290 int before_remove_all_count_; | |
| 291 | |
| 292 DISALLOW_COPY_AND_ASSIGN(BookmarkModelTest); | |
| 293 }; | |
| 294 | |
| 295 TEST_F(BookmarkModelTest, InitialState) { | |
| 296 const BookmarkNode* bb_node = model_->bookmark_bar_node(); | |
| 297 ASSERT_TRUE(bb_node != NULL); | |
| 298 EXPECT_EQ(0, bb_node->child_count()); | |
| 299 EXPECT_EQ(BookmarkNode::BOOKMARK_BAR, bb_node->type()); | |
| 300 | |
| 301 const BookmarkNode* other_node = model_->other_node(); | |
| 302 ASSERT_TRUE(other_node != NULL); | |
| 303 EXPECT_EQ(0, other_node->child_count()); | |
| 304 EXPECT_EQ(BookmarkNode::OTHER_NODE, other_node->type()); | |
| 305 | |
| 306 const BookmarkNode* mobile_node = model_->mobile_node(); | |
| 307 ASSERT_TRUE(mobile_node != NULL); | |
| 308 EXPECT_EQ(0, mobile_node->child_count()); | |
| 309 EXPECT_EQ(BookmarkNode::MOBILE, mobile_node->type()); | |
| 310 | |
| 311 EXPECT_TRUE(bb_node->id() != other_node->id()); | |
| 312 EXPECT_TRUE(bb_node->id() != mobile_node->id()); | |
| 313 EXPECT_TRUE(other_node->id() != mobile_node->id()); | |
| 314 } | |
| 315 | |
| 316 TEST_F(BookmarkModelTest, AddURL) { | |
| 317 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 318 const base::string16 title(ASCIIToUTF16("foo")); | |
| 319 const GURL url("http://foo.com"); | |
| 320 | |
| 321 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); | |
| 322 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 323 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 324 | |
| 325 ASSERT_EQ(1, root->child_count()); | |
| 326 ASSERT_EQ(title, new_node->GetTitle()); | |
| 327 ASSERT_TRUE(url == new_node->url()); | |
| 328 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
| 329 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
| 330 | |
| 331 EXPECT_TRUE(new_node->id() != root->id() && | |
| 332 new_node->id() != model_->other_node()->id() && | |
| 333 new_node->id() != model_->mobile_node()->id()); | |
| 334 } | |
| 335 | |
| 336 TEST_F(BookmarkModelTest, AddURLWithUnicodeTitle) { | |
| 337 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 338 const base::string16 title(base::WideToUTF16( | |
| 339 L"\u767e\u5ea6\u4e00\u4e0b\uff0c\u4f60\u5c31\u77e5\u9053")); | |
| 340 const GURL url("https://www.baidu.com/"); | |
| 341 | |
| 342 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); | |
| 343 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 344 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 345 | |
| 346 ASSERT_EQ(1, root->child_count()); | |
| 347 ASSERT_EQ(title, new_node->GetTitle()); | |
| 348 ASSERT_TRUE(url == new_node->url()); | |
| 349 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
| 350 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
| 351 | |
| 352 EXPECT_TRUE(new_node->id() != root->id() && | |
| 353 new_node->id() != model_->other_node()->id() && | |
| 354 new_node->id() != model_->mobile_node()->id()); | |
| 355 } | |
| 356 | |
| 357 TEST_F(BookmarkModelTest, AddURLWithWhitespaceTitle) { | |
| 358 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(url_whitespace_test_cases); ++i) { | |
| 359 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 360 const base::string16 title( | |
| 361 ASCIIToUTF16(url_whitespace_test_cases[i].input_title)); | |
| 362 const GURL url("http://foo.com"); | |
| 363 | |
| 364 const BookmarkNode* new_node = model_->AddURL(root, i, title, url); | |
| 365 | |
| 366 int size = i + 1; | |
| 367 EXPECT_EQ(size, root->child_count()); | |
| 368 EXPECT_EQ(ASCIIToUTF16(url_whitespace_test_cases[i].expected_title), | |
| 369 new_node->GetTitle()); | |
| 370 EXPECT_EQ(BookmarkNode::URL, new_node->type()); | |
| 371 } | |
| 372 } | |
| 373 | |
| 374 TEST_F(BookmarkModelTest, AddURLWithCreationTimeAndMetaInfo) { | |
| 375 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 376 const base::string16 title(ASCIIToUTF16("foo")); | |
| 377 const GURL url("http://foo.com"); | |
| 378 const Time time = Time::Now() - TimeDelta::FromDays(1); | |
| 379 BookmarkNode::MetaInfoMap meta_info; | |
| 380 meta_info["foo"] = "bar"; | |
| 381 | |
| 382 const BookmarkNode* new_node = model_->AddURLWithCreationTimeAndMetaInfo( | |
| 383 root, 0, title, url, time, &meta_info); | |
| 384 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 385 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 386 | |
| 387 ASSERT_EQ(1, root->child_count()); | |
| 388 ASSERT_EQ(title, new_node->GetTitle()); | |
| 389 ASSERT_TRUE(url == new_node->url()); | |
| 390 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
| 391 ASSERT_EQ(time, new_node->date_added()); | |
| 392 ASSERT_TRUE(new_node->GetMetaInfoMap()); | |
| 393 ASSERT_EQ(meta_info, *new_node->GetMetaInfoMap()); | |
| 394 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
| 395 | |
| 396 EXPECT_TRUE(new_node->id() != root->id() && | |
| 397 new_node->id() != model_->other_node()->id() && | |
| 398 new_node->id() != model_->mobile_node()->id()); | |
| 399 } | |
| 400 | |
| 401 TEST_F(BookmarkModelTest, AddURLToMobileBookmarks) { | |
| 402 const BookmarkNode* root = model_->mobile_node(); | |
| 403 const base::string16 title(ASCIIToUTF16("foo")); | |
| 404 const GURL url("http://foo.com"); | |
| 405 | |
| 406 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); | |
| 407 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 408 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 409 | |
| 410 ASSERT_EQ(1, root->child_count()); | |
| 411 ASSERT_EQ(title, new_node->GetTitle()); | |
| 412 ASSERT_TRUE(url == new_node->url()); | |
| 413 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
| 414 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
| 415 | |
| 416 EXPECT_TRUE(new_node->id() != root->id() && | |
| 417 new_node->id() != model_->other_node()->id() && | |
| 418 new_node->id() != model_->mobile_node()->id()); | |
| 419 } | |
| 420 | |
| 421 TEST_F(BookmarkModelTest, AddFolder) { | |
| 422 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 423 const base::string16 title(ASCIIToUTF16("foo")); | |
| 424 | |
| 425 const BookmarkNode* new_node = model_->AddFolder(root, 0, title); | |
| 426 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 427 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 428 | |
| 429 ASSERT_EQ(1, root->child_count()); | |
| 430 ASSERT_EQ(title, new_node->GetTitle()); | |
| 431 ASSERT_EQ(BookmarkNode::FOLDER, new_node->type()); | |
| 432 | |
| 433 EXPECT_TRUE(new_node->id() != root->id() && | |
| 434 new_node->id() != model_->other_node()->id() && | |
| 435 new_node->id() != model_->mobile_node()->id()); | |
| 436 | |
| 437 // Add another folder, just to make sure folder_ids are incremented correctly. | |
| 438 ClearCounts(); | |
| 439 model_->AddFolder(root, 0, title); | |
| 440 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 441 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 442 } | |
| 443 | |
| 444 TEST_F(BookmarkModelTest, AddFolderWithWhitespaceTitle) { | |
| 445 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(title_whitespace_test_cases); ++i) { | |
| 446 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 447 const base::string16 title( | |
| 448 ASCIIToUTF16(title_whitespace_test_cases[i].input_title)); | |
| 449 | |
| 450 const BookmarkNode* new_node = model_->AddFolder(root, i, title); | |
| 451 | |
| 452 int size = i + 1; | |
| 453 EXPECT_EQ(size, root->child_count()); | |
| 454 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases[i].expected_title), | |
| 455 new_node->GetTitle()); | |
| 456 EXPECT_EQ(BookmarkNode::FOLDER, new_node->type()); | |
| 457 } | |
| 458 } | |
| 459 | |
| 460 TEST_F(BookmarkModelTest, RemoveURL) { | |
| 461 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 462 const base::string16 title(ASCIIToUTF16("foo")); | |
| 463 const GURL url("http://foo.com"); | |
| 464 model_->AddURL(root, 0, title, url); | |
| 465 ClearCounts(); | |
| 466 | |
| 467 model_->Remove(root, 0); | |
| 468 ASSERT_EQ(0, root->child_count()); | |
| 469 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | |
| 470 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 471 | |
| 472 // Make sure there is no mapping for the URL. | |
| 473 ASSERT_TRUE(model_->GetMostRecentlyAddedNodeForURL(url) == NULL); | |
| 474 } | |
| 475 | |
| 476 TEST_F(BookmarkModelTest, RemoveFolder) { | |
| 477 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 478 const BookmarkNode* folder = model_->AddFolder(root, 0, ASCIIToUTF16("foo")); | |
| 479 | |
| 480 ClearCounts(); | |
| 481 | |
| 482 // Add a URL as a child. | |
| 483 const base::string16 title(ASCIIToUTF16("foo")); | |
| 484 const GURL url("http://foo.com"); | |
| 485 model_->AddURL(folder, 0, title, url); | |
| 486 | |
| 487 ClearCounts(); | |
| 488 | |
| 489 // Now remove the folder. | |
| 490 model_->Remove(root, 0); | |
| 491 ASSERT_EQ(0, root->child_count()); | |
| 492 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | |
| 493 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 494 | |
| 495 // Make sure there is no mapping for the URL. | |
| 496 ASSERT_TRUE(model_->GetMostRecentlyAddedNodeForURL(url) == NULL); | |
| 497 } | |
| 498 | |
| 499 TEST_F(BookmarkModelTest, RemoveAll) { | |
| 500 const BookmarkNode* bookmark_bar_node = model_->bookmark_bar_node(); | |
| 501 | |
| 502 ClearCounts(); | |
| 503 | |
| 504 // Add a url to bookmark bar. | |
| 505 base::string16 title(ASCIIToUTF16("foo")); | |
| 506 GURL url("http://foo.com"); | |
| 507 model_->AddURL(bookmark_bar_node, 0, title, url); | |
| 508 | |
| 509 // Add a folder with child URL. | |
| 510 const BookmarkNode* folder = model_->AddFolder(bookmark_bar_node, 0, title); | |
| 511 model_->AddURL(folder, 0, title, url); | |
| 512 | |
| 513 AssertObserverCount(3, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 514 ClearCounts(); | |
| 515 | |
| 516 model_->RemoveAll(); | |
| 517 | |
| 518 EXPECT_EQ(0, bookmark_bar_node->child_count()); | |
| 519 // No individual BookmarkNodeRemoved events are fired, so removed count | |
| 520 // should be 0. | |
| 521 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 1); | |
| 522 AssertExtensiveChangesObserverCount(1, 1); | |
| 523 EXPECT_EQ(1, AllNodesRemovedObserverCount()); | |
| 524 } | |
| 525 | |
| 526 TEST_F(BookmarkModelTest, SetTitle) { | |
| 527 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 528 base::string16 title(ASCIIToUTF16("foo")); | |
| 529 const GURL url("http://foo.com"); | |
| 530 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
| 531 | |
| 532 ClearCounts(); | |
| 533 | |
| 534 title = ASCIIToUTF16("foo2"); | |
| 535 model_->SetTitle(node, title); | |
| 536 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); | |
| 537 observer_details_.ExpectEquals(node, NULL, -1, -1); | |
| 538 EXPECT_EQ(title, node->GetTitle()); | |
| 539 } | |
| 540 | |
| 541 TEST_F(BookmarkModelTest, SetTitleWithWhitespace) { | |
| 542 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(title_whitespace_test_cases); ++i) { | |
| 543 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 544 base::string16 title(ASCIIToUTF16("dummy")); | |
| 545 const GURL url("http://foo.com"); | |
| 546 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
| 547 | |
| 548 title = ASCIIToUTF16(title_whitespace_test_cases[i].input_title); | |
| 549 model_->SetTitle(node, title); | |
| 550 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases[i].expected_title), | |
| 551 node->GetTitle()); | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 TEST_F(BookmarkModelTest, SetURL) { | |
| 556 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 557 const base::string16 title(ASCIIToUTF16("foo")); | |
| 558 GURL url("http://foo.com"); | |
| 559 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
| 560 | |
| 561 ClearCounts(); | |
| 562 | |
| 563 url = GURL("http://foo2.com"); | |
| 564 model_->SetURL(node, url); | |
| 565 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); | |
| 566 observer_details_.ExpectEquals(node, NULL, -1, -1); | |
| 567 EXPECT_EQ(url, node->url()); | |
| 568 } | |
| 569 | |
| 570 TEST_F(BookmarkModelTest, SetDateAdded) { | |
| 571 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 572 const base::string16 title(ASCIIToUTF16("foo")); | |
| 573 GURL url("http://foo.com"); | |
| 574 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
| 575 | |
| 576 ClearCounts(); | |
| 577 | |
| 578 base::Time new_time = base::Time::Now() + base::TimeDelta::FromMinutes(20); | |
| 579 model_->SetDateAdded(node, new_time); | |
| 580 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 0); | |
| 581 EXPECT_EQ(new_time, node->date_added()); | |
| 582 EXPECT_EQ(new_time, model_->bookmark_bar_node()->date_folder_modified()); | |
| 583 } | |
| 584 | |
| 585 TEST_F(BookmarkModelTest, Move) { | |
| 586 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 587 const base::string16 title(ASCIIToUTF16("foo")); | |
| 588 const GURL url("http://foo.com"); | |
| 589 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
| 590 const BookmarkNode* folder1 = model_->AddFolder(root, 0, ASCIIToUTF16("foo")); | |
| 591 ClearCounts(); | |
| 592 | |
| 593 model_->Move(node, folder1, 0); | |
| 594 | |
| 595 AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0); | |
| 596 observer_details_.ExpectEquals(root, folder1, 1, 0); | |
| 597 EXPECT_TRUE(folder1 == node->parent()); | |
| 598 EXPECT_EQ(1, root->child_count()); | |
| 599 EXPECT_EQ(folder1, root->GetChild(0)); | |
| 600 EXPECT_EQ(1, folder1->child_count()); | |
| 601 EXPECT_EQ(node, folder1->GetChild(0)); | |
| 602 | |
| 603 // And remove the folder. | |
| 604 ClearCounts(); | |
| 605 model_->Remove(root, 0); | |
| 606 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | |
| 607 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
| 608 EXPECT_TRUE(model_->GetMostRecentlyAddedNodeForURL(url) == NULL); | |
| 609 EXPECT_EQ(0, root->child_count()); | |
| 610 } | |
| 611 | |
| 612 TEST_F(BookmarkModelTest, NonMovingMoveCall) { | |
| 613 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 614 const base::string16 title(ASCIIToUTF16("foo")); | |
| 615 const GURL url("http://foo.com"); | |
| 616 const base::Time old_date(base::Time::Now() - base::TimeDelta::FromDays(1)); | |
| 617 | |
| 618 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
| 619 model_->SetDateFolderModified(root, old_date); | |
| 620 | |
| 621 // Since |node| is already at the index 0 of |root|, this is no-op. | |
| 622 model_->Move(node, root, 0); | |
| 623 | |
| 624 // Check that the modification date is kept untouched. | |
| 625 EXPECT_EQ(old_date, root->date_folder_modified()); | |
| 626 } | |
| 627 | |
| 628 TEST_F(BookmarkModelTest, Copy) { | |
| 629 const BookmarkNode* root = model_->bookmark_bar_node(); | |
| 630 static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h "); | |
| 631 test::AddNodesFromModelString(model_.get(), root, model_string); | |
| 632 | |
| 633 // Validate initial model. | |
| 634 std::string actual_model_string = test::ModelStringFromNode(root); | |
| 635 EXPECT_EQ(model_string, actual_model_string); | |
| 636 | |
| 637 // Copy 'd' to be after '1:b': URL item from bar to folder. | |
| 638 const BookmarkNode* node_to_copy = root->GetChild(2); | |
| 639 const BookmarkNode* destination = root->GetChild(1); | |
| 640 model_->Copy(node_to_copy, destination, 1); | |
| 641 actual_model_string = test::ModelStringFromNode(root); | |
| 642 EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string); | |
| 643 | |
| 644 // Copy '1:d' to be after 'a': URL item from folder to bar. | |
| 645 const BookmarkNode* folder = root->GetChild(1); | |
| 646 node_to_copy = folder->GetChild(1); | |
| 647 model_->Copy(node_to_copy, root, 1); | |
| 648 actual_model_string = test::ModelStringFromNode(root); | |
| 649 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string); | |
| 650 | |
| 651 // Copy '1' to be after '2:e': Folder from bar to folder. | |
| 652 node_to_copy = root->GetChild(2); | |
| 653 destination = root->GetChild(4); | |
| 654 model_->Copy(node_to_copy, destination, 1); | |
| 655 actual_model_string = test::ModelStringFromNode(root); | |
| 656 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ", | |
| 657 actual_model_string); | |
| 658 | |
| 659 // Copy '2:1' to be after '2:f': Folder within same folder. | |
| 660 folder = root->GetChild(4); | |
| 661 node_to_copy = folder->GetChild(1); | |
| 662 model_->Copy(node_to_copy, folder, 3); | |
| 663 actual_model_string = test::ModelStringFromNode(root); | |
| 664 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ", | |
| 665 actual_model_string); | |
| 666 | |
| 667 // Copy first 'd' to be after 'h': URL item within the bar. | |
| 668 node_to_copy = root->GetChild(1); | |
| 669 model_->Copy(node_to_copy, root, 6); | |
| 670 actual_model_string = test::ModelStringFromNode(root); | |
| 671 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ", | |
| 672 actual_model_string); | |
| 673 | |
| 674 // Copy '2' to be after 'a': Folder within the bar. | |
| 675 node_to_copy = root->GetChild(4); | |
| 676 model_->Copy(node_to_copy, root, 1); | |
| 677 actual_model_string = test::ModelStringFromNode(root); | |
| 678 EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] " | |
| 679 "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ", | |
| 680 actual_model_string); | |
| 681 } | |
| 682 | |
| 683 // Tests that adding a URL to a folder updates the last modified time. | |
| 684 TEST_F(BookmarkModelTest, ParentForNewNodes) { | |
| 685 ASSERT_EQ(model_->bookmark_bar_node(), model_->GetParentForNewNodes()); | |
| 686 | |
| 687 const base::string16 title(ASCIIToUTF16("foo")); | |
| 688 const GURL url("http://foo.com"); | |
| 689 | |
| 690 model_->AddURL(model_->other_node(), 0, title, url); | |
| 691 ASSERT_EQ(model_->other_node(), model_->GetParentForNewNodes()); | |
| 692 } | |
| 693 | |
| 694 // Tests that adding a URL to a folder updates the last modified time. | |
| 695 TEST_F(BookmarkModelTest, ParentForNewMobileNodes) { | |
| 696 ASSERT_EQ(model_->bookmark_bar_node(), model_->GetParentForNewNodes()); | |
| 697 | |
| 698 const base::string16 title(ASCIIToUTF16("foo")); | |
| 699 const GURL url("http://foo.com"); | |
| 700 | |
| 701 model_->AddURL(model_->mobile_node(), 0, title, url); | |
| 702 ASSERT_EQ(model_->mobile_node(), model_->GetParentForNewNodes()); | |
| 703 } | |
| 704 | |
| 705 // Make sure recently modified stays in sync when adding a URL. | |
| 706 TEST_F(BookmarkModelTest, MostRecentlyModifiedFolders) { | |
| 707 // Add a folder. | |
| 708 const BookmarkNode* folder = | |
| 709 model_->AddFolder(model_->other_node(), 0, ASCIIToUTF16("foo")); | |
| 710 // Add a URL to it. | |
| 711 model_->AddURL(folder, 0, ASCIIToUTF16("blah"), GURL("http://foo.com")); | |
| 712 | |
| 713 // Make sure folder is in the most recently modified. | |
| 714 std::vector<const BookmarkNode*> most_recent_folders = | |
| 715 bookmark_utils::GetMostRecentlyModifiedFolders(model_.get(), 1); | |
| 716 ASSERT_EQ(1U, most_recent_folders.size()); | |
| 717 ASSERT_EQ(folder, most_recent_folders[0]); | |
| 718 | |
| 719 // Nuke the folder and do another fetch, making sure folder isn't in the | |
| 720 // returned list. | |
| 721 model_->Remove(folder->parent(), 0); | |
| 722 most_recent_folders = | |
| 723 bookmark_utils::GetMostRecentlyModifiedFolders(model_.get(), 1); | |
| 724 ASSERT_EQ(1U, most_recent_folders.size()); | |
| 725 ASSERT_TRUE(most_recent_folders[0] != folder); | |
| 726 } | |
| 727 | |
| 728 // Make sure MostRecentlyAddedEntries stays in sync. | |
| 729 TEST_F(BookmarkModelTest, MostRecentlyAddedEntries) { | |
| 730 // Add a couple of nodes such that the following holds for the time of the | |
| 731 // nodes: n1 > n2 > n3 > n4. | |
| 732 Time base_time = Time::Now(); | |
| 733 BookmarkNode* n1 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
| 734 0, | |
| 735 ASCIIToUTF16("blah"), | |
| 736 GURL("http://foo.com/0"))); | |
| 737 BookmarkNode* n2 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
| 738 1, | |
| 739 ASCIIToUTF16("blah"), | |
| 740 GURL("http://foo.com/1"))); | |
| 741 BookmarkNode* n3 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
| 742 2, | |
| 743 ASCIIToUTF16("blah"), | |
| 744 GURL("http://foo.com/2"))); | |
| 745 BookmarkNode* n4 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
| 746 3, | |
| 747 ASCIIToUTF16("blah"), | |
| 748 GURL("http://foo.com/3"))); | |
| 749 n1->set_date_added(base_time + TimeDelta::FromDays(4)); | |
| 750 n2->set_date_added(base_time + TimeDelta::FromDays(3)); | |
| 751 n3->set_date_added(base_time + TimeDelta::FromDays(2)); | |
| 752 n4->set_date_added(base_time + TimeDelta::FromDays(1)); | |
| 753 | |
| 754 // Make sure order is honored. | |
| 755 std::vector<const BookmarkNode*> recently_added; | |
| 756 bookmark_utils::GetMostRecentlyAddedEntries(model_.get(), 2, &recently_added); | |
| 757 ASSERT_EQ(2U, recently_added.size()); | |
| 758 ASSERT_TRUE(n1 == recently_added[0]); | |
| 759 ASSERT_TRUE(n2 == recently_added[1]); | |
| 760 | |
| 761 // swap 1 and 2, then check again. | |
| 762 recently_added.clear(); | |
| 763 SwapDateAdded(n1, n2); | |
| 764 bookmark_utils::GetMostRecentlyAddedEntries(model_.get(), 4, &recently_added); | |
| 765 ASSERT_EQ(4U, recently_added.size()); | |
| 766 ASSERT_TRUE(n2 == recently_added[0]); | |
| 767 ASSERT_TRUE(n1 == recently_added[1]); | |
| 768 ASSERT_TRUE(n3 == recently_added[2]); | |
| 769 ASSERT_TRUE(n4 == recently_added[3]); | |
| 770 } | |
| 771 | |
| 772 // Makes sure GetMostRecentlyAddedNodeForURL stays in sync. | |
| 773 TEST_F(BookmarkModelTest, GetMostRecentlyAddedNodeForURL) { | |
| 774 // Add a couple of nodes such that the following holds for the time of the | |
| 775 // nodes: n1 > n2 | |
| 776 Time base_time = Time::Now(); | |
| 777 const GURL url("http://foo.com/0"); | |
| 778 BookmarkNode* n1 = AsMutable(model_->AddURL( | |
| 779 model_->bookmark_bar_node(), 0, ASCIIToUTF16("blah"), url)); | |
| 780 BookmarkNode* n2 = AsMutable(model_->AddURL( | |
| 781 model_->bookmark_bar_node(), 1, ASCIIToUTF16("blah"), url)); | |
| 782 n1->set_date_added(base_time + TimeDelta::FromDays(4)); | |
| 783 n2->set_date_added(base_time + TimeDelta::FromDays(3)); | |
| 784 | |
| 785 // Make sure order is honored. | |
| 786 ASSERT_EQ(n1, model_->GetMostRecentlyAddedNodeForURL(url)); | |
| 787 | |
| 788 // swap 1 and 2, then check again. | |
| 789 SwapDateAdded(n1, n2); | |
| 790 ASSERT_EQ(n2, model_->GetMostRecentlyAddedNodeForURL(url)); | |
| 791 } | |
| 792 | |
| 793 // Makes sure GetBookmarks removes duplicates. | |
| 794 TEST_F(BookmarkModelTest, GetBookmarksWithDups) { | |
| 795 const GURL url("http://foo.com/0"); | |
| 796 const base::string16 title(ASCIIToUTF16("blah")); | |
| 797 model_->AddURL(model_->bookmark_bar_node(), 0, title, url); | |
| 798 model_->AddURL(model_->bookmark_bar_node(), 1, title, url); | |
| 799 | |
| 800 std::vector<BookmarkService::URLAndTitle> bookmarks; | |
| 801 model_->GetBookmarks(&bookmarks); | |
| 802 ASSERT_EQ(1U, bookmarks.size()); | |
| 803 EXPECT_EQ(url, bookmarks[0].url); | |
| 804 EXPECT_EQ(title, bookmarks[0].title); | |
| 805 | |
| 806 model_->AddURL(model_->bookmark_bar_node(), 2, ASCIIToUTF16("Title2"), url); | |
| 807 // Only one returned, even titles are different. | |
| 808 bookmarks.clear(); | |
| 809 model_->GetBookmarks(&bookmarks); | |
| 810 EXPECT_EQ(1U, bookmarks.size()); | |
| 811 } | |
| 812 | |
| 813 TEST_F(BookmarkModelTest, HasBookmarks) { | |
| 814 const GURL url("http://foo.com/"); | |
| 815 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("bar"), url); | |
| 816 | |
| 817 EXPECT_TRUE(model_->HasBookmarks()); | |
| 818 } | |
| 819 | |
| 820 // See comment in PopulateNodeFromString. | |
| 821 typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode; | |
| 822 | |
| 823 // Does the work of PopulateNodeFromString. index gives the index of the current | |
| 824 // element in description to process. | |
| 825 void PopulateNodeImpl(const std::vector<std::string>& description, | |
| 826 size_t* index, | |
| 827 TestNode* parent) { | |
| 828 while (*index < description.size()) { | |
| 829 const std::string& element = description[*index]; | |
| 830 (*index)++; | |
| 831 if (element == "[") { | |
| 832 // Create a new folder and recurse to add all the children. | |
| 833 // Folders are given a unique named by way of an ever increasing integer | |
| 834 // value. The folders need not have a name, but one is assigned to help | |
| 835 // in debugging. | |
| 836 static int next_folder_id = 1; | |
| 837 TestNode* new_node = | |
| 838 new TestNode(base::IntToString16(next_folder_id++), | |
| 839 BookmarkNode::FOLDER); | |
| 840 parent->Add(new_node, parent->child_count()); | |
| 841 PopulateNodeImpl(description, index, new_node); | |
| 842 } else if (element == "]") { | |
| 843 // End the current folder. | |
| 844 return; | |
| 845 } else { | |
| 846 // Add a new URL. | |
| 847 | |
| 848 // All tokens must be space separated. If there is a [ or ] in the name it | |
| 849 // likely means a space was forgotten. | |
| 850 DCHECK(element.find('[') == std::string::npos); | |
| 851 DCHECK(element.find(']') == std::string::npos); | |
| 852 parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL), | |
| 853 parent->child_count()); | |
| 854 } | |
| 855 } | |
| 856 } | |
| 857 | |
| 858 // Creates and adds nodes to parent based on description. description consists | |
| 859 // of the following tokens (all space separated): | |
| 860 // [ : creates a new USER_FOLDER node. All elements following the [ until the | |
| 861 // next balanced ] is encountered are added as children to the node. | |
| 862 // ] : closes the last folder created by [ so that any further nodes are added | |
| 863 // to the current folders parent. | |
| 864 // text: creates a new URL node. | |
| 865 // For example, "a [b] c" creates the following nodes: | |
| 866 // a 1 c | |
| 867 // | | |
| 868 // b | |
| 869 // In words: a node of type URL with the title a, followed by a folder node with | |
| 870 // the title 1 having the single child of type url with name b, followed by | |
| 871 // the url node with the title c. | |
| 872 // | |
| 873 // NOTE: each name must be unique, and folders are assigned a unique title by | |
| 874 // way of an increasing integer. | |
| 875 void PopulateNodeFromString(const std::string& description, TestNode* parent) { | |
| 876 std::vector<std::string> elements; | |
| 877 base::SplitStringAlongWhitespace(description, &elements); | |
| 878 size_t index = 0; | |
| 879 PopulateNodeImpl(elements, &index, parent); | |
| 880 } | |
| 881 | |
| 882 // Populates the BookmarkNode with the children of parent. | |
| 883 void PopulateBookmarkNode(TestNode* parent, | |
| 884 BookmarkModel* model, | |
| 885 const BookmarkNode* bb_node) { | |
| 886 for (int i = 0; i < parent->child_count(); ++i) { | |
| 887 TestNode* child = parent->GetChild(i); | |
| 888 if (child->value == BookmarkNode::FOLDER) { | |
| 889 const BookmarkNode* new_bb_node = | |
| 890 model->AddFolder(bb_node, i, child->GetTitle()); | |
| 891 PopulateBookmarkNode(child, model, new_bb_node); | |
| 892 } else { | |
| 893 model->AddURL(bb_node, i, child->GetTitle(), | |
| 894 GURL("http://" + base::UTF16ToASCII(child->GetTitle()))); | |
| 895 } | |
| 896 } | |
| 897 } | |
| 898 | |
| 899 // Test class that creates a BookmarkModel with a real history backend. | |
| 900 class BookmarkModelTestWithProfile : public testing::Test { | |
| 901 public: | |
| 902 BookmarkModelTestWithProfile() | |
| 903 : bb_model_(NULL) {} | |
| 904 | |
| 905 // testing::Test: | |
| 906 virtual void TearDown() OVERRIDE { | |
| 907 profile_.reset(NULL); | |
| 908 } | |
| 909 | |
| 910 protected: | |
| 911 // Verifies the contents of the bookmark bar node match the contents of the | |
| 912 // TestNode. | |
| 913 void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) { | |
| 914 ASSERT_EQ(expected->child_count(), actual->child_count()); | |
| 915 for (int i = 0; i < expected->child_count(); ++i) { | |
| 916 TestNode* expected_child = expected->GetChild(i); | |
| 917 const BookmarkNode* actual_child = actual->GetChild(i); | |
| 918 ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle()); | |
| 919 if (expected_child->value == BookmarkNode::FOLDER) { | |
| 920 ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER); | |
| 921 // Recurse throught children. | |
| 922 VerifyModelMatchesNode(expected_child, actual_child); | |
| 923 if (HasFatalFailure()) | |
| 924 return; | |
| 925 } else { | |
| 926 // No need to check the URL, just the title is enough. | |
| 927 ASSERT_TRUE(actual_child->is_url()); | |
| 928 } | |
| 929 } | |
| 930 } | |
| 931 | |
| 932 void VerifyNoDuplicateIDs(BookmarkModel* model) { | |
| 933 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); | |
| 934 base::hash_set<int64> ids; | |
| 935 while (it.has_next()) | |
| 936 ASSERT_TRUE(ids.insert(it.Next()->id()).second); | |
| 937 } | |
| 938 | |
| 939 void BlockTillBookmarkModelLoaded() { | |
| 940 bb_model_ = BookmarkModelFactory::GetForProfile(profile_.get()); | |
| 941 test::WaitForBookmarkModelToLoad(bb_model_); | |
| 942 } | |
| 943 | |
| 944 // The profile. | |
| 945 scoped_ptr<TestingProfile> profile_; | |
| 946 BookmarkModel* bb_model_; | |
| 947 | |
| 948 private: | |
| 949 content::TestBrowserThreadBundle thread_bundle_; | |
| 950 }; | |
| 951 | |
| 952 // Creates a set of nodes in the bookmark bar model, then recreates the | |
| 953 // bookmark bar model which triggers loading from the db and checks the loaded | |
| 954 // structure to make sure it is what we first created. | |
| 955 TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) { | |
| 956 struct TestData { | |
| 957 // Structure of the children of the bookmark bar model node. | |
| 958 const std::string bbn_contents; | |
| 959 // Structure of the children of the other node. | |
| 960 const std::string other_contents; | |
| 961 // Structure of the children of the synced node. | |
| 962 const std::string mobile_contents; | |
| 963 } data[] = { | |
| 964 // See PopulateNodeFromString for a description of these strings. | |
| 965 { "", "" }, | |
| 966 { "a", "b" }, | |
| 967 { "a [ b ]", "" }, | |
| 968 { "", "[ b ] a [ c [ d e [ f ] ] ]" }, | |
| 969 { "a [ b ]", "" }, | |
| 970 { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, | |
| 971 }; | |
| 972 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { | |
| 973 // Recreate the profile. We need to reset with NULL first so that the last | |
| 974 // HistoryService releases the locks on the files it creates and we can | |
| 975 // delete them. | |
| 976 profile_.reset(NULL); | |
| 977 profile_.reset(new TestingProfile()); | |
| 978 profile_->CreateBookmarkModel(true); | |
| 979 ASSERT_TRUE(profile_->CreateHistoryService(true, false)); | |
| 980 BlockTillBookmarkModelLoaded(); | |
| 981 | |
| 982 TestNode bbn; | |
| 983 PopulateNodeFromString(data[i].bbn_contents, &bbn); | |
| 984 PopulateBookmarkNode(&bbn, bb_model_, bb_model_->bookmark_bar_node()); | |
| 985 | |
| 986 TestNode other; | |
| 987 PopulateNodeFromString(data[i].other_contents, &other); | |
| 988 PopulateBookmarkNode(&other, bb_model_, bb_model_->other_node()); | |
| 989 | |
| 990 TestNode mobile; | |
| 991 PopulateNodeFromString(data[i].mobile_contents, &mobile); | |
| 992 PopulateBookmarkNode(&mobile, bb_model_, bb_model_->mobile_node()); | |
| 993 | |
| 994 profile_->CreateBookmarkModel(false); | |
| 995 BlockTillBookmarkModelLoaded(); | |
| 996 | |
| 997 VerifyModelMatchesNode(&bbn, bb_model_->bookmark_bar_node()); | |
| 998 VerifyModelMatchesNode(&other, bb_model_->other_node()); | |
| 999 VerifyModelMatchesNode(&mobile, bb_model_->mobile_node()); | |
| 1000 VerifyNoDuplicateIDs(bb_model_); | |
| 1001 } | |
| 1002 } | |
| 1003 | |
| 1004 TEST_F(BookmarkModelTest, Sort) { | |
| 1005 // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'. | |
| 1006 // 'C' and 'a' are folders. | |
| 1007 TestNode bbn; | |
| 1008 PopulateNodeFromString("B [ a ] d [ a ]", &bbn); | |
| 1009 const BookmarkNode* parent = model_->bookmark_bar_node(); | |
| 1010 PopulateBookmarkNode(&bbn, model_.get(), parent); | |
| 1011 | |
| 1012 BookmarkNode* child1 = AsMutable(parent->GetChild(1)); | |
| 1013 child1->SetTitle(ASCIIToUTF16("a")); | |
| 1014 delete child1->Remove(child1->GetChild(0)); | |
| 1015 BookmarkNode* child3 = AsMutable(parent->GetChild(3)); | |
| 1016 child3->SetTitle(ASCIIToUTF16("C")); | |
| 1017 delete child3->Remove(child3->GetChild(0)); | |
| 1018 | |
| 1019 ClearCounts(); | |
| 1020 | |
| 1021 // Sort the children of the bookmark bar node. | |
| 1022 model_->SortChildren(parent); | |
| 1023 | |
| 1024 // Make sure we were notified. | |
| 1025 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0); | |
| 1026 | |
| 1027 // Make sure the order matches (remember, 'a' and 'C' are folders and | |
| 1028 // come first). | |
| 1029 EXPECT_EQ(parent->GetChild(0)->GetTitle(), ASCIIToUTF16("a")); | |
| 1030 EXPECT_EQ(parent->GetChild(1)->GetTitle(), ASCIIToUTF16("C")); | |
| 1031 EXPECT_EQ(parent->GetChild(2)->GetTitle(), ASCIIToUTF16("B")); | |
| 1032 EXPECT_EQ(parent->GetChild(3)->GetTitle(), ASCIIToUTF16("d")); | |
| 1033 } | |
| 1034 | |
| 1035 TEST_F(BookmarkModelTest, Reorder) { | |
| 1036 // Populate the bookmark bar node with nodes 'A', 'B', 'C' and 'D'. | |
| 1037 TestNode bbn; | |
| 1038 PopulateNodeFromString("A B C D", &bbn); | |
| 1039 BookmarkNode* parent = AsMutable(model_->bookmark_bar_node()); | |
| 1040 PopulateBookmarkNode(&bbn, model_.get(), parent); | |
| 1041 | |
| 1042 ClearCounts(); | |
| 1043 | |
| 1044 // Reorder bar node's bookmarks in reverse order. | |
| 1045 std::vector<const BookmarkNode*> new_order; | |
| 1046 new_order.push_back(parent->GetChild(3)); | |
| 1047 new_order.push_back(parent->GetChild(2)); | |
| 1048 new_order.push_back(parent->GetChild(1)); | |
| 1049 new_order.push_back(parent->GetChild(0)); | |
| 1050 model_->ReorderChildren(parent, new_order); | |
| 1051 | |
| 1052 // Make sure we were notified. | |
| 1053 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0); | |
| 1054 | |
| 1055 // Make sure the order matches is correct (it should be reversed). | |
| 1056 ASSERT_EQ(4, parent->child_count()); | |
| 1057 EXPECT_EQ("D", base::UTF16ToASCII(parent->GetChild(0)->GetTitle())); | |
| 1058 EXPECT_EQ("C", base::UTF16ToASCII(parent->GetChild(1)->GetTitle())); | |
| 1059 EXPECT_EQ("B", base::UTF16ToASCII(parent->GetChild(2)->GetTitle())); | |
| 1060 EXPECT_EQ("A", base::UTF16ToASCII(parent->GetChild(3)->GetTitle())); | |
| 1061 } | |
| 1062 | |
| 1063 TEST_F(BookmarkModelTest, NodeVisibility) { | |
| 1064 // Mobile node invisible by default | |
| 1065 EXPECT_TRUE(model_->bookmark_bar_node()->IsVisible()); | |
| 1066 EXPECT_TRUE(model_->other_node()->IsVisible()); | |
| 1067 EXPECT_FALSE(model_->mobile_node()->IsVisible()); | |
| 1068 | |
| 1069 // Visibility of permanent node can only be changed if they are not | |
| 1070 // forced to be visible by the client. | |
| 1071 model_->SetPermanentNodeVisible(BookmarkNode::BOOKMARK_BAR, false); | |
| 1072 EXPECT_TRUE(model_->bookmark_bar_node()->IsVisible()); | |
| 1073 model_->SetPermanentNodeVisible(BookmarkNode::OTHER_NODE, false); | |
| 1074 EXPECT_TRUE(model_->other_node()->IsVisible()); | |
| 1075 model_->SetPermanentNodeVisible(BookmarkNode::MOBILE, true); | |
| 1076 EXPECT_TRUE(model_->mobile_node()->IsVisible()); | |
| 1077 model_->SetPermanentNodeVisible(BookmarkNode::MOBILE, false); | |
| 1078 EXPECT_FALSE(model_->mobile_node()->IsVisible()); | |
| 1079 | |
| 1080 // Arbitrary node should be visible | |
| 1081 TestNode bbn; | |
| 1082 PopulateNodeFromString("B", &bbn); | |
| 1083 const BookmarkNode* parent = model_->mobile_node(); | |
| 1084 PopulateBookmarkNode(&bbn, model_.get(), parent); | |
| 1085 EXPECT_TRUE(parent->GetChild(0)->IsVisible()); | |
| 1086 | |
| 1087 // Mobile folder should be visible now that it has a child. | |
| 1088 EXPECT_TRUE(model_->mobile_node()->IsVisible()); | |
| 1089 } | |
| 1090 | |
| 1091 TEST_F(BookmarkModelTest, MobileNodeVisibileWithChildren) { | |
| 1092 const BookmarkNode* root = model_->mobile_node(); | |
| 1093 const base::string16 title(ASCIIToUTF16("foo")); | |
| 1094 const GURL url("http://foo.com"); | |
| 1095 | |
| 1096 model_->AddURL(root, 0, title, url); | |
| 1097 EXPECT_TRUE(model_->mobile_node()->IsVisible()); | |
| 1098 } | |
| 1099 | |
| 1100 TEST_F(BookmarkModelTest, ExtensiveChangesObserver) { | |
| 1101 AssertExtensiveChangesObserverCount(0, 0); | |
| 1102 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
| 1103 model_->BeginExtensiveChanges(); | |
| 1104 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
| 1105 AssertExtensiveChangesObserverCount(1, 0); | |
| 1106 model_->EndExtensiveChanges(); | |
| 1107 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
| 1108 AssertExtensiveChangesObserverCount(1, 1); | |
| 1109 } | |
| 1110 | |
| 1111 TEST_F(BookmarkModelTest, MultipleExtensiveChangesObserver) { | |
| 1112 AssertExtensiveChangesObserverCount(0, 0); | |
| 1113 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
| 1114 model_->BeginExtensiveChanges(); | |
| 1115 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
| 1116 AssertExtensiveChangesObserverCount(1, 0); | |
| 1117 model_->BeginExtensiveChanges(); | |
| 1118 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
| 1119 AssertExtensiveChangesObserverCount(1, 0); | |
| 1120 model_->EndExtensiveChanges(); | |
| 1121 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
| 1122 AssertExtensiveChangesObserverCount(1, 0); | |
| 1123 model_->EndExtensiveChanges(); | |
| 1124 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
| 1125 AssertExtensiveChangesObserverCount(1, 1); | |
| 1126 } | |
| 1127 | |
| 1128 TEST(BookmarkNodeTest, NodeMetaInfo) { | |
| 1129 GURL url; | |
| 1130 BookmarkNode node(url); | |
| 1131 EXPECT_FALSE(node.GetMetaInfoMap()); | |
| 1132 | |
| 1133 EXPECT_TRUE(node.SetMetaInfo("key1", "value1")); | |
| 1134 std::string out_value; | |
| 1135 EXPECT_TRUE(node.GetMetaInfo("key1", &out_value)); | |
| 1136 EXPECT_EQ("value1", out_value); | |
| 1137 EXPECT_FALSE(node.SetMetaInfo("key1", "value1")); | |
| 1138 | |
| 1139 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value)); | |
| 1140 EXPECT_TRUE(node.SetMetaInfo("key2.subkey1", "value2")); | |
| 1141 EXPECT_TRUE(node.GetMetaInfo("key2.subkey1", &out_value)); | |
| 1142 EXPECT_EQ("value2", out_value); | |
| 1143 | |
| 1144 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | |
| 1145 EXPECT_TRUE(node.SetMetaInfo("key2.subkey2.leaf", "")); | |
| 1146 EXPECT_TRUE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | |
| 1147 EXPECT_EQ("", out_value); | |
| 1148 | |
| 1149 EXPECT_TRUE(node.DeleteMetaInfo("key1")); | |
| 1150 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey1")); | |
| 1151 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey2.leaf")); | |
| 1152 EXPECT_FALSE(node.DeleteMetaInfo("key3")); | |
| 1153 EXPECT_FALSE(node.GetMetaInfo("key1", &out_value)); | |
| 1154 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value)); | |
| 1155 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2", &out_value)); | |
| 1156 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | |
| 1157 EXPECT_FALSE(node.GetMetaInfoMap()); | |
| 1158 } | |
| 1159 | |
| 1160 } // namespace | |
| OLD | NEW |