closure: fix compile error by adding missing externs
[chromium-blink-merge.git] / components / bookmarks / browser / bookmark_model_unittest.cc
blob1ee3554e3cf0773b44bb6e163cc9776d25cc22aa
1 // Copyright 2014 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.
5 #include "components/bookmarks/browser/bookmark_model.h"
7 #include <set>
8 #include <string>
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/strings/string16.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h"
21 #include "components/bookmarks/browser/bookmark_model_observer.h"
22 #include "components/bookmarks/browser/bookmark_utils.h"
23 #include "components/bookmarks/test/bookmark_test_helpers.h"
24 #include "components/bookmarks/test/test_bookmark_client.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "ui/base/models/tree_node_iterator.h"
27 #include "ui/base/models/tree_node_model.h"
28 #include "url/gurl.h"
30 using base::ASCIIToUTF16;
31 using base::Time;
32 using base::TimeDelta;
34 namespace bookmarks {
35 namespace {
37 // Test cases used to test the removal of extra whitespace when adding
38 // a new folder/bookmark or updating a title of a folder/bookmark.
39 static struct {
40 const std::string input_title;
41 const std::string expected_title;
42 } url_whitespace_test_cases[] = {
43 {"foobar", "foobar"},
44 // Newlines.
45 {"foo\nbar", "foo bar"},
46 {"foo\n\nbar", "foo bar"},
47 {"foo\n\n\nbar", "foo bar"},
48 {"foo\r\nbar", "foo bar"},
49 {"foo\r\n\r\nbar", "foo bar"},
50 {"\nfoo\nbar\n", "foo bar"},
51 // Spaces.
52 {"foo bar", "foo bar"},
53 {" foo bar ", "foo bar"},
54 {" foo bar ", "foo bar"},
55 // Tabs.
56 {"\tfoo\tbar\t", "foo bar"},
57 {"\tfoo bar\t", "foo bar"},
58 // Mixed cases.
59 {"\tfoo\nbar\t", "foo bar"},
60 {"\tfoo\r\nbar\t", "foo bar"},
61 {" foo\tbar\n", "foo bar"},
62 {"\t foo \t bar \t", "foo bar"},
63 {"\n foo\r\n\tbar\n \t", "foo bar"},
66 // Test cases used to test the removal of extra whitespace when adding
67 // a new folder/bookmark or updating a title of a folder/bookmark.
68 static struct {
69 const std::string input_title;
70 const std::string expected_title;
71 } title_whitespace_test_cases[] = {
72 {"foobar", "foobar"},
73 // Newlines.
74 {"foo\nbar", "foo bar"},
75 {"foo\n\nbar", "foo bar"},
76 {"foo\n\n\nbar", "foo bar"},
77 {"foo\r\nbar", "foo bar"},
78 {"foo\r\n\r\nbar", "foo bar"},
79 {"\nfoo\nbar\n", " foo bar "},
80 // Spaces.
81 {"foo bar", "foo bar"},
82 {" foo bar ", " foo bar "},
83 {" foo bar ", " foo bar "},
84 // Tabs.
85 {"\tfoo\tbar\t", " foo bar "},
86 {"\tfoo bar\t", " foo bar "},
87 // Mixed cases.
88 {"\tfoo\nbar\t", " foo bar "},
89 {"\tfoo\r\nbar\t", " foo bar "},
90 {" foo\tbar\n", " foo bar "},
91 {"\t foo \t bar \t", " foo bar "},
92 {"\n foo\r\n\tbar\n \t", " foo bar "},
95 // Helper to get a mutable bookmark node.
96 BookmarkNode* AsMutable(const BookmarkNode* node) {
97 return const_cast<BookmarkNode*>(node);
100 void SwapDateAdded(BookmarkNode* n1, BookmarkNode* n2) {
101 Time tmp = n1->date_added();
102 n1->set_date_added(n2->date_added());
103 n2->set_date_added(tmp);
106 class BookmarkModelTest : public testing::Test,
107 public BookmarkModelObserver {
108 public:
109 struct ObserverDetails {
110 ObserverDetails() {
111 Set(NULL, NULL, -1, -1);
114 void Set(const BookmarkNode* node1,
115 const BookmarkNode* node2,
116 int index1,
117 int index2) {
118 node1_ = node1;
119 node2_ = node2;
120 index1_ = index1;
121 index2_ = index2;
124 void ExpectEquals(const BookmarkNode* node1,
125 const BookmarkNode* node2,
126 int index1,
127 int index2) {
128 EXPECT_EQ(node1_, node1);
129 EXPECT_EQ(node2_, node2);
130 EXPECT_EQ(index1_, index1);
131 EXPECT_EQ(index2_, index2);
134 private:
135 const BookmarkNode* node1_;
136 const BookmarkNode* node2_;
137 int index1_;
138 int index2_;
141 BookmarkModelTest() : model_(client_.CreateModel()) {
142 model_->AddObserver(this);
143 ClearCounts();
146 void BookmarkModelLoaded(BookmarkModel* model, bool ids_reassigned) override {
147 // We never load from the db, so that this should never get invoked.
148 NOTREACHED();
151 void BookmarkNodeMoved(BookmarkModel* model,
152 const BookmarkNode* old_parent,
153 int old_index,
154 const BookmarkNode* new_parent,
155 int new_index) override {
156 ++moved_count_;
157 observer_details_.Set(old_parent, new_parent, old_index, new_index);
160 void BookmarkNodeAdded(BookmarkModel* model,
161 const BookmarkNode* parent,
162 int index) override {
163 ++added_count_;
164 observer_details_.Set(parent, NULL, index, -1);
167 void OnWillRemoveBookmarks(BookmarkModel* model,
168 const BookmarkNode* parent,
169 int old_index,
170 const BookmarkNode* node) override {
171 ++before_remove_count_;
174 void BookmarkNodeRemoved(BookmarkModel* model,
175 const BookmarkNode* parent,
176 int old_index,
177 const BookmarkNode* node,
178 const std::set<GURL>& removed_urls) override {
179 ++removed_count_;
180 observer_details_.Set(parent, NULL, old_index, -1);
183 void BookmarkNodeChanged(BookmarkModel* model,
184 const BookmarkNode* node) override {
185 ++changed_count_;
186 observer_details_.Set(node, NULL, -1, -1);
189 void OnWillChangeBookmarkNode(BookmarkModel* model,
190 const BookmarkNode* node) override {
191 ++before_change_count_;
194 void BookmarkNodeChildrenReordered(BookmarkModel* model,
195 const BookmarkNode* node) override {
196 ++reordered_count_;
199 void OnWillReorderBookmarkNode(BookmarkModel* model,
200 const BookmarkNode* node) override {
201 ++before_reorder_count_;
204 void BookmarkNodeFaviconChanged(BookmarkModel* model,
205 const BookmarkNode* node) override {
206 // We never attempt to load favicons, so that this method never
207 // gets invoked.
210 void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) override {
211 ++extensive_changes_beginning_count_;
214 void ExtensiveBookmarkChangesEnded(BookmarkModel* model) override {
215 ++extensive_changes_ended_count_;
218 void BookmarkAllUserNodesRemoved(
219 BookmarkModel* model,
220 const std::set<GURL>& removed_urls) override {
221 ++all_bookmarks_removed_;
224 void OnWillRemoveAllUserBookmarks(BookmarkModel* model) override {
225 ++before_remove_all_count_;
228 void ClearCounts() {
229 added_count_ = moved_count_ = removed_count_ = changed_count_ =
230 reordered_count_ = extensive_changes_beginning_count_ =
231 extensive_changes_ended_count_ = all_bookmarks_removed_ =
232 before_remove_count_ = before_change_count_ = before_reorder_count_ =
233 before_remove_all_count_ = 0;
236 void AssertObserverCount(int added_count,
237 int moved_count,
238 int removed_count,
239 int changed_count,
240 int reordered_count,
241 int before_remove_count,
242 int before_change_count,
243 int before_reorder_count,
244 int before_remove_all_count) {
245 EXPECT_EQ(added_count, added_count_);
246 EXPECT_EQ(moved_count, moved_count_);
247 EXPECT_EQ(removed_count, removed_count_);
248 EXPECT_EQ(changed_count, changed_count_);
249 EXPECT_EQ(reordered_count, reordered_count_);
250 EXPECT_EQ(before_remove_count, before_remove_count_);
251 EXPECT_EQ(before_change_count, before_change_count_);
252 EXPECT_EQ(before_reorder_count, before_reorder_count_);
253 EXPECT_EQ(before_remove_all_count, before_remove_all_count_);
256 void AssertExtensiveChangesObserverCount(
257 int extensive_changes_beginning_count,
258 int extensive_changes_ended_count) {
259 EXPECT_EQ(extensive_changes_beginning_count,
260 extensive_changes_beginning_count_);
261 EXPECT_EQ(extensive_changes_ended_count, extensive_changes_ended_count_);
264 int AllNodesRemovedObserverCount() const { return all_bookmarks_removed_; }
266 BookmarkPermanentNode* ReloadModelWithExtraNode() {
267 BookmarkPermanentNode* extra_node = new BookmarkPermanentNode(100);
268 BookmarkPermanentNodeList extra_nodes;
269 extra_nodes.push_back(extra_node);
270 client_.SetExtraNodesToLoad(extra_nodes.Pass());
272 model_->RemoveObserver(this);
273 model_ = client_.CreateModel();
274 model_->AddObserver(this);
275 ClearCounts();
277 if (model_->root_node()->GetIndexOf(extra_node) == -1)
278 ADD_FAILURE();
280 return extra_node;
283 protected:
284 TestBookmarkClient client_;
285 scoped_ptr<BookmarkModel> model_;
286 ObserverDetails observer_details_;
288 private:
289 int added_count_;
290 int moved_count_;
291 int removed_count_;
292 int changed_count_;
293 int reordered_count_;
294 int extensive_changes_beginning_count_;
295 int extensive_changes_ended_count_;
296 int all_bookmarks_removed_;
297 int before_remove_count_;
298 int before_change_count_;
299 int before_reorder_count_;
300 int before_remove_all_count_;
302 DISALLOW_COPY_AND_ASSIGN(BookmarkModelTest);
305 TEST_F(BookmarkModelTest, InitialState) {
306 const BookmarkNode* bb_node = model_->bookmark_bar_node();
307 ASSERT_TRUE(bb_node != NULL);
308 EXPECT_EQ(0, bb_node->child_count());
309 EXPECT_EQ(BookmarkNode::BOOKMARK_BAR, bb_node->type());
311 const BookmarkNode* other_node = model_->other_node();
312 ASSERT_TRUE(other_node != NULL);
313 EXPECT_EQ(0, other_node->child_count());
314 EXPECT_EQ(BookmarkNode::OTHER_NODE, other_node->type());
316 const BookmarkNode* mobile_node = model_->mobile_node();
317 ASSERT_TRUE(mobile_node != NULL);
318 EXPECT_EQ(0, mobile_node->child_count());
319 EXPECT_EQ(BookmarkNode::MOBILE, mobile_node->type());
321 EXPECT_TRUE(bb_node->id() != other_node->id());
322 EXPECT_TRUE(bb_node->id() != mobile_node->id());
323 EXPECT_TRUE(other_node->id() != mobile_node->id());
326 TEST_F(BookmarkModelTest, AddURL) {
327 const BookmarkNode* root = model_->bookmark_bar_node();
328 const base::string16 title(ASCIIToUTF16("foo"));
329 const GURL url("http://foo.com");
331 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url);
332 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
333 observer_details_.ExpectEquals(root, NULL, 0, -1);
335 ASSERT_EQ(1, root->child_count());
336 ASSERT_EQ(title, new_node->GetTitle());
337 ASSERT_TRUE(url == new_node->url());
338 ASSERT_EQ(BookmarkNode::URL, new_node->type());
339 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedUserNodeForURL(url));
341 EXPECT_TRUE(new_node->id() != root->id() &&
342 new_node->id() != model_->other_node()->id() &&
343 new_node->id() != model_->mobile_node()->id());
346 TEST_F(BookmarkModelTest, AddURLWithUnicodeTitle) {
347 const BookmarkNode* root = model_->bookmark_bar_node();
348 const base::string16 title(base::WideToUTF16(
349 L"\u767e\u5ea6\u4e00\u4e0b\uff0c\u4f60\u5c31\u77e5\u9053"));
350 const GURL url("https://www.baidu.com/");
352 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url);
353 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
354 observer_details_.ExpectEquals(root, NULL, 0, -1);
356 ASSERT_EQ(1, root->child_count());
357 ASSERT_EQ(title, new_node->GetTitle());
358 ASSERT_TRUE(url == new_node->url());
359 ASSERT_EQ(BookmarkNode::URL, new_node->type());
360 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedUserNodeForURL(url));
362 EXPECT_TRUE(new_node->id() != root->id() &&
363 new_node->id() != model_->other_node()->id() &&
364 new_node->id() != model_->mobile_node()->id());
367 TEST_F(BookmarkModelTest, AddURLWithWhitespaceTitle) {
368 for (size_t i = 0; i < arraysize(url_whitespace_test_cases); ++i) {
369 const BookmarkNode* root = model_->bookmark_bar_node();
370 const base::string16 title(
371 ASCIIToUTF16(url_whitespace_test_cases[i].input_title));
372 const GURL url("http://foo.com");
374 const BookmarkNode* new_node = model_->AddURL(root, i, title, url);
376 int size = i + 1;
377 EXPECT_EQ(size, root->child_count());
378 EXPECT_EQ(ASCIIToUTF16(url_whitespace_test_cases[i].expected_title),
379 new_node->GetTitle());
380 EXPECT_EQ(BookmarkNode::URL, new_node->type());
384 TEST_F(BookmarkModelTest, AddURLWithCreationTimeAndMetaInfo) {
385 const BookmarkNode* root = model_->bookmark_bar_node();
386 const base::string16 title(ASCIIToUTF16("foo"));
387 const GURL url("http://foo.com");
388 const Time time = Time::Now() - TimeDelta::FromDays(1);
389 BookmarkNode::MetaInfoMap meta_info;
390 meta_info["foo"] = "bar";
392 const BookmarkNode* new_node = model_->AddURLWithCreationTimeAndMetaInfo(
393 root, 0, title, url, time, &meta_info);
394 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
395 observer_details_.ExpectEquals(root, NULL, 0, -1);
397 ASSERT_EQ(1, root->child_count());
398 ASSERT_EQ(title, new_node->GetTitle());
399 ASSERT_TRUE(url == new_node->url());
400 ASSERT_EQ(BookmarkNode::URL, new_node->type());
401 ASSERT_EQ(time, new_node->date_added());
402 ASSERT_TRUE(new_node->GetMetaInfoMap());
403 ASSERT_EQ(meta_info, *new_node->GetMetaInfoMap());
404 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedUserNodeForURL(url));
406 EXPECT_TRUE(new_node->id() != root->id() &&
407 new_node->id() != model_->other_node()->id() &&
408 new_node->id() != model_->mobile_node()->id());
411 TEST_F(BookmarkModelTest, AddURLToMobileBookmarks) {
412 const BookmarkNode* root = model_->mobile_node();
413 const base::string16 title(ASCIIToUTF16("foo"));
414 const GURL url("http://foo.com");
416 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url);
417 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
418 observer_details_.ExpectEquals(root, NULL, 0, -1);
420 ASSERT_EQ(1, root->child_count());
421 ASSERT_EQ(title, new_node->GetTitle());
422 ASSERT_TRUE(url == new_node->url());
423 ASSERT_EQ(BookmarkNode::URL, new_node->type());
424 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedUserNodeForURL(url));
426 EXPECT_TRUE(new_node->id() != root->id() &&
427 new_node->id() != model_->other_node()->id() &&
428 new_node->id() != model_->mobile_node()->id());
431 TEST_F(BookmarkModelTest, AddFolder) {
432 const BookmarkNode* root = model_->bookmark_bar_node();
433 const base::string16 title(ASCIIToUTF16("foo"));
435 const BookmarkNode* new_node = model_->AddFolder(root, 0, title);
436 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
437 observer_details_.ExpectEquals(root, NULL, 0, -1);
439 ASSERT_EQ(1, root->child_count());
440 ASSERT_EQ(title, new_node->GetTitle());
441 ASSERT_EQ(BookmarkNode::FOLDER, new_node->type());
443 EXPECT_TRUE(new_node->id() != root->id() &&
444 new_node->id() != model_->other_node()->id() &&
445 new_node->id() != model_->mobile_node()->id());
447 // Add another folder, just to make sure folder_ids are incremented correctly.
448 ClearCounts();
449 model_->AddFolder(root, 0, title);
450 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
451 observer_details_.ExpectEquals(root, NULL, 0, -1);
454 TEST_F(BookmarkModelTest, AddFolderWithWhitespaceTitle) {
455 for (size_t i = 0; i < arraysize(title_whitespace_test_cases); ++i) {
456 const BookmarkNode* root = model_->bookmark_bar_node();
457 const base::string16 title(
458 ASCIIToUTF16(title_whitespace_test_cases[i].input_title));
460 const BookmarkNode* new_node = model_->AddFolder(root, i, title);
462 int size = i + 1;
463 EXPECT_EQ(size, root->child_count());
464 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases[i].expected_title),
465 new_node->GetTitle());
466 EXPECT_EQ(BookmarkNode::FOLDER, new_node->type());
470 TEST_F(BookmarkModelTest, RemoveURL) {
471 const BookmarkNode* root = model_->bookmark_bar_node();
472 const base::string16 title(ASCIIToUTF16("foo"));
473 const GURL url("http://foo.com");
474 model_->AddURL(root, 0, title, url);
475 ClearCounts();
477 model_->Remove(root, 0);
478 ASSERT_EQ(0, root->child_count());
479 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0);
480 observer_details_.ExpectEquals(root, NULL, 0, -1);
482 // Make sure there is no mapping for the URL.
483 ASSERT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == NULL);
486 TEST_F(BookmarkModelTest, RemoveFolder) {
487 const BookmarkNode* root = model_->bookmark_bar_node();
488 const BookmarkNode* folder = model_->AddFolder(root, 0, ASCIIToUTF16("foo"));
490 ClearCounts();
492 // Add a URL as a child.
493 const base::string16 title(ASCIIToUTF16("foo"));
494 const GURL url("http://foo.com");
495 model_->AddURL(folder, 0, title, url);
497 ClearCounts();
499 // Now remove the folder.
500 model_->Remove(root, 0);
501 ASSERT_EQ(0, root->child_count());
502 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0);
503 observer_details_.ExpectEquals(root, NULL, 0, -1);
505 // Make sure there is no mapping for the URL.
506 ASSERT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == NULL);
509 TEST_F(BookmarkModelTest, RemoveAllUserBookmarks) {
510 const BookmarkNode* bookmark_bar_node = model_->bookmark_bar_node();
512 ClearCounts();
514 // Add a url to bookmark bar.
515 base::string16 title(ASCIIToUTF16("foo"));
516 GURL url("http://foo.com");
517 model_->AddURL(bookmark_bar_node, 0, title, url);
519 // Add a folder with child URL.
520 const BookmarkNode* folder = model_->AddFolder(bookmark_bar_node, 0, title);
521 model_->AddURL(folder, 0, title, url);
523 AssertObserverCount(3, 0, 0, 0, 0, 0, 0, 0, 0);
524 ClearCounts();
526 model_->RemoveAllUserBookmarks();
528 EXPECT_EQ(0, bookmark_bar_node->child_count());
529 // No individual BookmarkNodeRemoved events are fired, so removed count
530 // should be 0.
531 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 1);
532 AssertExtensiveChangesObserverCount(1, 1);
533 EXPECT_EQ(1, AllNodesRemovedObserverCount());
536 TEST_F(BookmarkModelTest, SetTitle) {
537 const BookmarkNode* root = model_->bookmark_bar_node();
538 base::string16 title(ASCIIToUTF16("foo"));
539 const GURL url("http://foo.com");
540 const BookmarkNode* node = model_->AddURL(root, 0, title, url);
542 ClearCounts();
544 title = ASCIIToUTF16("foo2");
545 model_->SetTitle(node, title);
546 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0);
547 observer_details_.ExpectEquals(node, NULL, -1, -1);
548 EXPECT_EQ(title, node->GetTitle());
551 TEST_F(BookmarkModelTest, SetTitleWithWhitespace) {
552 for (size_t i = 0; i < arraysize(title_whitespace_test_cases); ++i) {
553 const BookmarkNode* root = model_->bookmark_bar_node();
554 base::string16 title(ASCIIToUTF16("dummy"));
555 const GURL url("http://foo.com");
556 const BookmarkNode* node = model_->AddURL(root, 0, title, url);
558 title = ASCIIToUTF16(title_whitespace_test_cases[i].input_title);
559 model_->SetTitle(node, title);
560 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases[i].expected_title),
561 node->GetTitle());
565 TEST_F(BookmarkModelTest, SetURL) {
566 const BookmarkNode* root = model_->bookmark_bar_node();
567 const base::string16 title(ASCIIToUTF16("foo"));
568 GURL url("http://foo.com");
569 const BookmarkNode* node = model_->AddURL(root, 0, title, url);
571 ClearCounts();
573 url = GURL("http://foo2.com");
574 model_->SetURL(node, url);
575 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0);
576 observer_details_.ExpectEquals(node, NULL, -1, -1);
577 EXPECT_EQ(url, node->url());
580 TEST_F(BookmarkModelTest, SetDateAdded) {
581 const BookmarkNode* root = model_->bookmark_bar_node();
582 const base::string16 title(ASCIIToUTF16("foo"));
583 GURL url("http://foo.com");
584 const BookmarkNode* node = model_->AddURL(root, 0, title, url);
586 ClearCounts();
588 base::Time new_time = base::Time::Now() + base::TimeDelta::FromMinutes(20);
589 model_->SetDateAdded(node, new_time);
590 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 0);
591 EXPECT_EQ(new_time, node->date_added());
592 EXPECT_EQ(new_time, model_->bookmark_bar_node()->date_folder_modified());
595 TEST_F(BookmarkModelTest, Move) {
596 const BookmarkNode* root = model_->bookmark_bar_node();
597 const base::string16 title(ASCIIToUTF16("foo"));
598 const GURL url("http://foo.com");
599 const BookmarkNode* node = model_->AddURL(root, 0, title, url);
600 const BookmarkNode* folder1 = model_->AddFolder(root, 0, ASCIIToUTF16("foo"));
601 ClearCounts();
603 model_->Move(node, folder1, 0);
605 AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0);
606 observer_details_.ExpectEquals(root, folder1, 1, 0);
607 EXPECT_TRUE(folder1 == node->parent());
608 EXPECT_EQ(1, root->child_count());
609 EXPECT_EQ(folder1, root->GetChild(0));
610 EXPECT_EQ(1, folder1->child_count());
611 EXPECT_EQ(node, folder1->GetChild(0));
613 // And remove the folder.
614 ClearCounts();
615 model_->Remove(root, 0);
616 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0);
617 observer_details_.ExpectEquals(root, NULL, 0, -1);
618 EXPECT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == NULL);
619 EXPECT_EQ(0, root->child_count());
622 TEST_F(BookmarkModelTest, NonMovingMoveCall) {
623 const BookmarkNode* root = model_->bookmark_bar_node();
624 const base::string16 title(ASCIIToUTF16("foo"));
625 const GURL url("http://foo.com");
626 const base::Time old_date(base::Time::Now() - base::TimeDelta::FromDays(1));
628 const BookmarkNode* node = model_->AddURL(root, 0, title, url);
629 model_->SetDateFolderModified(root, old_date);
631 // Since |node| is already at the index 0 of |root|, this is no-op.
632 model_->Move(node, root, 0);
634 // Check that the modification date is kept untouched.
635 EXPECT_EQ(old_date, root->date_folder_modified());
638 TEST_F(BookmarkModelTest, Copy) {
639 const BookmarkNode* root = model_->bookmark_bar_node();
640 static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h ");
641 test::AddNodesFromModelString(model_.get(), root, model_string);
643 // Validate initial model.
644 std::string actual_model_string = test::ModelStringFromNode(root);
645 EXPECT_EQ(model_string, actual_model_string);
647 // Copy 'd' to be after '1:b': URL item from bar to folder.
648 const BookmarkNode* node_to_copy = root->GetChild(2);
649 const BookmarkNode* destination = root->GetChild(1);
650 model_->Copy(node_to_copy, destination, 1);
651 actual_model_string = test::ModelStringFromNode(root);
652 EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string);
654 // Copy '1:d' to be after 'a': URL item from folder to bar.
655 const BookmarkNode* folder = root->GetChild(1);
656 node_to_copy = folder->GetChild(1);
657 model_->Copy(node_to_copy, root, 1);
658 actual_model_string = test::ModelStringFromNode(root);
659 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string);
661 // Copy '1' to be after '2:e': Folder from bar to folder.
662 node_to_copy = root->GetChild(2);
663 destination = root->GetChild(4);
664 model_->Copy(node_to_copy, destination, 1);
665 actual_model_string = test::ModelStringFromNode(root);
666 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ",
667 actual_model_string);
669 // Copy '2:1' to be after '2:f': Folder within same folder.
670 folder = root->GetChild(4);
671 node_to_copy = folder->GetChild(1);
672 model_->Copy(node_to_copy, folder, 3);
673 actual_model_string = test::ModelStringFromNode(root);
674 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ",
675 actual_model_string);
677 // Copy first 'd' to be after 'h': URL item within the bar.
678 node_to_copy = root->GetChild(1);
679 model_->Copy(node_to_copy, root, 6);
680 actual_model_string = test::ModelStringFromNode(root);
681 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
682 actual_model_string);
684 // Copy '2' to be after 'a': Folder within the bar.
685 node_to_copy = root->GetChild(4);
686 model_->Copy(node_to_copy, root, 1);
687 actual_model_string = test::ModelStringFromNode(root);
688 EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] "
689 "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
690 actual_model_string);
693 // Tests that adding a URL to a folder updates the last modified time.
694 TEST_F(BookmarkModelTest, ParentForNewNodes) {
695 ASSERT_EQ(model_->bookmark_bar_node(), model_->GetParentForNewNodes());
697 const base::string16 title(ASCIIToUTF16("foo"));
698 const GURL url("http://foo.com");
700 model_->AddURL(model_->other_node(), 0, title, url);
701 ASSERT_EQ(model_->other_node(), model_->GetParentForNewNodes());
704 // Tests that adding a URL to a folder updates the last modified time.
705 TEST_F(BookmarkModelTest, ParentForNewMobileNodes) {
706 ASSERT_EQ(model_->bookmark_bar_node(), model_->GetParentForNewNodes());
708 const base::string16 title(ASCIIToUTF16("foo"));
709 const GURL url("http://foo.com");
711 model_->AddURL(model_->mobile_node(), 0, title, url);
712 ASSERT_EQ(model_->mobile_node(), model_->GetParentForNewNodes());
715 // Make sure recently modified stays in sync when adding a URL.
716 TEST_F(BookmarkModelTest, MostRecentlyModifiedFolders) {
717 // Add a folder.
718 const BookmarkNode* folder =
719 model_->AddFolder(model_->other_node(), 0, ASCIIToUTF16("foo"));
720 // Add a URL to it.
721 model_->AddURL(folder, 0, ASCIIToUTF16("blah"), GURL("http://foo.com"));
723 // Make sure folder is in the most recently modified.
724 std::vector<const BookmarkNode*> most_recent_folders =
725 GetMostRecentlyModifiedUserFolders(model_.get(), 1);
726 ASSERT_EQ(1U, most_recent_folders.size());
727 ASSERT_EQ(folder, most_recent_folders[0]);
729 // Nuke the folder and do another fetch, making sure folder isn't in the
730 // returned list.
731 model_->Remove(folder->parent(), 0);
732 most_recent_folders = GetMostRecentlyModifiedUserFolders(model_.get(), 1);
733 ASSERT_EQ(1U, most_recent_folders.size());
734 ASSERT_TRUE(most_recent_folders[0] != folder);
737 // Make sure MostRecentlyAddedEntries stays in sync.
738 TEST_F(BookmarkModelTest, MostRecentlyAddedEntries) {
739 // Add a couple of nodes such that the following holds for the time of the
740 // nodes: n1 > n2 > n3 > n4.
741 Time base_time = Time::Now();
742 BookmarkNode* n1 = AsMutable(model_->AddURL(model_->bookmark_bar_node(),
744 ASCIIToUTF16("blah"),
745 GURL("http://foo.com/0")));
746 BookmarkNode* n2 = AsMutable(model_->AddURL(model_->bookmark_bar_node(),
748 ASCIIToUTF16("blah"),
749 GURL("http://foo.com/1")));
750 BookmarkNode* n3 = AsMutable(model_->AddURL(model_->bookmark_bar_node(),
752 ASCIIToUTF16("blah"),
753 GURL("http://foo.com/2")));
754 BookmarkNode* n4 = AsMutable(model_->AddURL(model_->bookmark_bar_node(),
756 ASCIIToUTF16("blah"),
757 GURL("http://foo.com/3")));
758 n1->set_date_added(base_time + TimeDelta::FromDays(4));
759 n2->set_date_added(base_time + TimeDelta::FromDays(3));
760 n3->set_date_added(base_time + TimeDelta::FromDays(2));
761 n4->set_date_added(base_time + TimeDelta::FromDays(1));
763 // Make sure order is honored.
764 std::vector<const BookmarkNode*> recently_added;
765 GetMostRecentlyAddedEntries(model_.get(), 2, &recently_added);
766 ASSERT_EQ(2U, recently_added.size());
767 ASSERT_TRUE(n1 == recently_added[0]);
768 ASSERT_TRUE(n2 == recently_added[1]);
770 // swap 1 and 2, then check again.
771 recently_added.clear();
772 SwapDateAdded(n1, n2);
773 GetMostRecentlyAddedEntries(model_.get(), 4, &recently_added);
774 ASSERT_EQ(4U, recently_added.size());
775 ASSERT_TRUE(n2 == recently_added[0]);
776 ASSERT_TRUE(n1 == recently_added[1]);
777 ASSERT_TRUE(n3 == recently_added[2]);
778 ASSERT_TRUE(n4 == recently_added[3]);
781 // Makes sure GetMostRecentlyAddedUserNodeForURL stays in sync.
782 TEST_F(BookmarkModelTest, GetMostRecentlyAddedUserNodeForURL) {
783 // Add a couple of nodes such that the following holds for the time of the
784 // nodes: n1 > n2
785 Time base_time = Time::Now();
786 const GURL url("http://foo.com/0");
787 BookmarkNode* n1 = AsMutable(model_->AddURL(
788 model_->bookmark_bar_node(), 0, ASCIIToUTF16("blah"), url));
789 BookmarkNode* n2 = AsMutable(model_->AddURL(
790 model_->bookmark_bar_node(), 1, ASCIIToUTF16("blah"), url));
791 n1->set_date_added(base_time + TimeDelta::FromDays(4));
792 n2->set_date_added(base_time + TimeDelta::FromDays(3));
794 // Make sure order is honored.
795 ASSERT_EQ(n1, model_->GetMostRecentlyAddedUserNodeForURL(url));
797 // swap 1 and 2, then check again.
798 SwapDateAdded(n1, n2);
799 ASSERT_EQ(n2, model_->GetMostRecentlyAddedUserNodeForURL(url));
802 // Makes sure GetBookmarks removes duplicates.
803 TEST_F(BookmarkModelTest, GetBookmarksWithDups) {
804 const GURL url("http://foo.com/0");
805 const base::string16 title(ASCIIToUTF16("blah"));
806 model_->AddURL(model_->bookmark_bar_node(), 0, title, url);
807 model_->AddURL(model_->bookmark_bar_node(), 1, title, url);
809 std::vector<BookmarkModel::URLAndTitle> bookmarks;
810 model_->GetBookmarks(&bookmarks);
811 ASSERT_EQ(1U, bookmarks.size());
812 EXPECT_EQ(url, bookmarks[0].url);
813 EXPECT_EQ(title, bookmarks[0].title);
815 model_->AddURL(model_->bookmark_bar_node(), 2, ASCIIToUTF16("Title2"), url);
816 // Only one returned, even titles are different.
817 bookmarks.clear();
818 model_->GetBookmarks(&bookmarks);
819 EXPECT_EQ(1U, bookmarks.size());
822 TEST_F(BookmarkModelTest, HasBookmarks) {
823 const GURL url("http://foo.com/");
824 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("bar"), url);
826 EXPECT_TRUE(model_->HasBookmarks());
829 // See comment in PopulateNodeFromString.
830 typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode;
832 // Does the work of PopulateNodeFromString. index gives the index of the current
833 // element in description to process.
834 void PopulateNodeImpl(const std::vector<std::string>& description,
835 size_t* index,
836 TestNode* parent) {
837 while (*index < description.size()) {
838 const std::string& element = description[*index];
839 (*index)++;
840 if (element == "[") {
841 // Create a new folder and recurse to add all the children.
842 // Folders are given a unique named by way of an ever increasing integer
843 // value. The folders need not have a name, but one is assigned to help
844 // in debugging.
845 static int next_folder_id = 1;
846 TestNode* new_node =
847 new TestNode(base::IntToString16(next_folder_id++),
848 BookmarkNode::FOLDER);
849 parent->Add(new_node, parent->child_count());
850 PopulateNodeImpl(description, index, new_node);
851 } else if (element == "]") {
852 // End the current folder.
853 return;
854 } else {
855 // Add a new URL.
857 // All tokens must be space separated. If there is a [ or ] in the name it
858 // likely means a space was forgotten.
859 DCHECK(element.find('[') == std::string::npos);
860 DCHECK(element.find(']') == std::string::npos);
861 parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL),
862 parent->child_count());
867 // Creates and adds nodes to parent based on description. description consists
868 // of the following tokens (all space separated):
869 // [ : creates a new USER_FOLDER node. All elements following the [ until the
870 // next balanced ] is encountered are added as children to the node.
871 // ] : closes the last folder created by [ so that any further nodes are added
872 // to the current folders parent.
873 // text: creates a new URL node.
874 // For example, "a [b] c" creates the following nodes:
875 // a 1 c
876 // |
877 // b
878 // In words: a node of type URL with the title a, followed by a folder node with
879 // the title 1 having the single child of type url with name b, followed by
880 // the url node with the title c.
882 // NOTE: each name must be unique, and folders are assigned a unique title by
883 // way of an increasing integer.
884 void PopulateNodeFromString(const std::string& description, TestNode* parent) {
885 std::vector<std::string> elements;
886 base::SplitStringAlongWhitespace(description, &elements);
887 size_t index = 0;
888 PopulateNodeImpl(elements, &index, parent);
891 // Populates the BookmarkNode with the children of parent.
892 void PopulateBookmarkNode(TestNode* parent,
893 BookmarkModel* model,
894 const BookmarkNode* bb_node) {
895 for (int i = 0; i < parent->child_count(); ++i) {
896 TestNode* child = parent->GetChild(i);
897 if (child->value == BookmarkNode::FOLDER) {
898 const BookmarkNode* new_bb_node =
899 model->AddFolder(bb_node, i, child->GetTitle());
900 PopulateBookmarkNode(child, model, new_bb_node);
901 } else {
902 model->AddURL(bb_node, i, child->GetTitle(),
903 GURL("http://" + base::UTF16ToASCII(child->GetTitle())));
908 // Test class that creates a BookmarkModel with a real history backend.
909 class BookmarkModelTestWithProfile : public testing::Test {
910 public:
911 BookmarkModelTestWithProfile() {}
913 protected:
914 // Verifies the contents of the bookmark bar node match the contents of the
915 // TestNode.
916 void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) {
917 ASSERT_EQ(expected->child_count(), actual->child_count());
918 for (int i = 0; i < expected->child_count(); ++i) {
919 TestNode* expected_child = expected->GetChild(i);
920 const BookmarkNode* actual_child = actual->GetChild(i);
921 ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle());
922 if (expected_child->value == BookmarkNode::FOLDER) {
923 ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER);
924 // Recurse throught children.
925 VerifyModelMatchesNode(expected_child, actual_child);
926 if (HasFatalFailure())
927 return;
928 } else {
929 // No need to check the URL, just the title is enough.
930 ASSERT_TRUE(actual_child->is_url());
935 void VerifyNoDuplicateIDs(BookmarkModel* model) {
936 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node());
937 base::hash_set<int64> ids;
938 while (it.has_next())
939 ASSERT_TRUE(ids.insert(it.Next()->id()).second);
942 TestBookmarkClient client_;
943 scoped_ptr<BookmarkModel> model_;
946 // Creates a set of nodes in the bookmark bar model, then recreates the
947 // bookmark bar model which triggers loading from the db and checks the loaded
948 // structure to make sure it is what we first created.
949 TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) {
950 struct TestData {
951 // Structure of the children of the bookmark bar model node.
952 const std::string bbn_contents;
953 // Structure of the children of the other node.
954 const std::string other_contents;
955 // Structure of the children of the synced node.
956 const std::string mobile_contents;
957 } data[] = {
958 // See PopulateNodeFromString for a description of these strings.
959 { "", "" },
960 { "a", "b" },
961 { "a [ b ]", "" },
962 { "", "[ b ] a [ c [ d e [ f ] ] ]" },
963 { "a [ b ]", "" },
964 { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"},
966 for (size_t i = 0; i < arraysize(data); ++i) {
967 model_ = client_.CreateModel();
969 TestNode bbn;
970 PopulateNodeFromString(data[i].bbn_contents, &bbn);
971 PopulateBookmarkNode(&bbn, model_.get(), model_->bookmark_bar_node());
973 TestNode other;
974 PopulateNodeFromString(data[i].other_contents, &other);
975 PopulateBookmarkNode(&other, model_.get(), model_->other_node());
977 TestNode mobile;
978 PopulateNodeFromString(data[i].mobile_contents, &mobile);
979 PopulateBookmarkNode(&mobile, model_.get(), model_->mobile_node());
981 VerifyModelMatchesNode(&bbn, model_->bookmark_bar_node());
982 VerifyModelMatchesNode(&other, model_->other_node());
983 VerifyModelMatchesNode(&mobile, model_->mobile_node());
984 VerifyNoDuplicateIDs(model_.get());
988 // http://crbug.com/450464
989 TEST_F(BookmarkModelTest, DISABLED_Sort) {
990 // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'.
991 // 'C' and 'a' are folders.
992 TestNode bbn;
993 PopulateNodeFromString("B [ a ] d [ a ]", &bbn);
994 const BookmarkNode* parent = model_->bookmark_bar_node();
995 PopulateBookmarkNode(&bbn, model_.get(), parent);
997 BookmarkNode* child1 = AsMutable(parent->GetChild(1));
998 child1->SetTitle(ASCIIToUTF16("a"));
999 delete child1->Remove(child1->GetChild(0));
1000 BookmarkNode* child3 = AsMutable(parent->GetChild(3));
1001 child3->SetTitle(ASCIIToUTF16("C"));
1002 delete child3->Remove(child3->GetChild(0));
1004 ClearCounts();
1006 // Sort the children of the bookmark bar node.
1007 model_->SortChildren(parent);
1009 // Make sure we were notified.
1010 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0);
1012 // Make sure the order matches (remember, 'a' and 'C' are folders and
1013 // come first).
1014 EXPECT_EQ(parent->GetChild(0)->GetTitle(), ASCIIToUTF16("a"));
1015 EXPECT_EQ(parent->GetChild(1)->GetTitle(), ASCIIToUTF16("C"));
1016 EXPECT_EQ(parent->GetChild(2)->GetTitle(), ASCIIToUTF16("B"));
1017 EXPECT_EQ(parent->GetChild(3)->GetTitle(), ASCIIToUTF16("d"));
1020 TEST_F(BookmarkModelTest, Reorder) {
1021 // Populate the bookmark bar node with nodes 'A', 'B', 'C' and 'D'.
1022 TestNode bbn;
1023 PopulateNodeFromString("A B C D", &bbn);
1024 BookmarkNode* parent = AsMutable(model_->bookmark_bar_node());
1025 PopulateBookmarkNode(&bbn, model_.get(), parent);
1027 ClearCounts();
1029 // Reorder bar node's bookmarks in reverse order.
1030 std::vector<const BookmarkNode*> new_order;
1031 new_order.push_back(parent->GetChild(3));
1032 new_order.push_back(parent->GetChild(2));
1033 new_order.push_back(parent->GetChild(1));
1034 new_order.push_back(parent->GetChild(0));
1035 model_->ReorderChildren(parent, new_order);
1037 // Make sure we were notified.
1038 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0);
1040 // Make sure the order matches is correct (it should be reversed).
1041 ASSERT_EQ(4, parent->child_count());
1042 EXPECT_EQ("D", base::UTF16ToASCII(parent->GetChild(0)->GetTitle()));
1043 EXPECT_EQ("C", base::UTF16ToASCII(parent->GetChild(1)->GetTitle()));
1044 EXPECT_EQ("B", base::UTF16ToASCII(parent->GetChild(2)->GetTitle()));
1045 EXPECT_EQ("A", base::UTF16ToASCII(parent->GetChild(3)->GetTitle()));
1048 TEST_F(BookmarkModelTest, NodeVisibility) {
1049 // Mobile node invisible by default
1050 EXPECT_TRUE(model_->bookmark_bar_node()->IsVisible());
1051 EXPECT_TRUE(model_->other_node()->IsVisible());
1052 EXPECT_FALSE(model_->mobile_node()->IsVisible());
1054 // Visibility of permanent node can only be changed if they are not
1055 // forced to be visible by the client.
1056 model_->SetPermanentNodeVisible(BookmarkNode::BOOKMARK_BAR, false);
1057 EXPECT_TRUE(model_->bookmark_bar_node()->IsVisible());
1058 model_->SetPermanentNodeVisible(BookmarkNode::OTHER_NODE, false);
1059 EXPECT_TRUE(model_->other_node()->IsVisible());
1060 model_->SetPermanentNodeVisible(BookmarkNode::MOBILE, true);
1061 EXPECT_TRUE(model_->mobile_node()->IsVisible());
1062 model_->SetPermanentNodeVisible(BookmarkNode::MOBILE, false);
1063 EXPECT_FALSE(model_->mobile_node()->IsVisible());
1065 // Arbitrary node should be visible
1066 TestNode bbn;
1067 PopulateNodeFromString("B", &bbn);
1068 const BookmarkNode* parent = model_->mobile_node();
1069 PopulateBookmarkNode(&bbn, model_.get(), parent);
1070 EXPECT_TRUE(parent->GetChild(0)->IsVisible());
1072 // Mobile folder should be visible now that it has a child.
1073 EXPECT_TRUE(model_->mobile_node()->IsVisible());
1076 TEST_F(BookmarkModelTest, MobileNodeVisibileWithChildren) {
1077 const BookmarkNode* root = model_->mobile_node();
1078 const base::string16 title(ASCIIToUTF16("foo"));
1079 const GURL url("http://foo.com");
1081 model_->AddURL(root, 0, title, url);
1082 EXPECT_TRUE(model_->mobile_node()->IsVisible());
1085 TEST_F(BookmarkModelTest, ExtensiveChangesObserver) {
1086 AssertExtensiveChangesObserverCount(0, 0);
1087 EXPECT_FALSE(model_->IsDoingExtensiveChanges());
1088 model_->BeginExtensiveChanges();
1089 EXPECT_TRUE(model_->IsDoingExtensiveChanges());
1090 AssertExtensiveChangesObserverCount(1, 0);
1091 model_->EndExtensiveChanges();
1092 EXPECT_FALSE(model_->IsDoingExtensiveChanges());
1093 AssertExtensiveChangesObserverCount(1, 1);
1096 TEST_F(BookmarkModelTest, MultipleExtensiveChangesObserver) {
1097 AssertExtensiveChangesObserverCount(0, 0);
1098 EXPECT_FALSE(model_->IsDoingExtensiveChanges());
1099 model_->BeginExtensiveChanges();
1100 EXPECT_TRUE(model_->IsDoingExtensiveChanges());
1101 AssertExtensiveChangesObserverCount(1, 0);
1102 model_->BeginExtensiveChanges();
1103 EXPECT_TRUE(model_->IsDoingExtensiveChanges());
1104 AssertExtensiveChangesObserverCount(1, 0);
1105 model_->EndExtensiveChanges();
1106 EXPECT_TRUE(model_->IsDoingExtensiveChanges());
1107 AssertExtensiveChangesObserverCount(1, 0);
1108 model_->EndExtensiveChanges();
1109 EXPECT_FALSE(model_->IsDoingExtensiveChanges());
1110 AssertExtensiveChangesObserverCount(1, 1);
1113 // Verifies that IsBookmarked is true if any bookmark matches the given URL,
1114 // and that IsBookmarkedByUser is true only if at least one of the matching
1115 // bookmarks can be edited by the user.
1116 TEST_F(BookmarkModelTest, IsBookmarked) {
1117 // Reload the model with an extra node that is not editable by the user.
1118 BookmarkPermanentNode* extra_node = ReloadModelWithExtraNode();
1120 // "google.com" is a "user" bookmark.
1121 model_->AddURL(model_->other_node(), 0, base::ASCIIToUTF16("User"),
1122 GURL("http://google.com"));
1123 // "youtube.com" is not.
1124 model_->AddURL(extra_node, 0, base::ASCIIToUTF16("Extra"),
1125 GURL("http://youtube.com"));
1127 EXPECT_TRUE(model_->IsBookmarked(GURL("http://google.com")));
1128 EXPECT_TRUE(model_->IsBookmarked(GURL("http://youtube.com")));
1129 EXPECT_FALSE(model_->IsBookmarked(GURL("http://reddit.com")));
1131 EXPECT_TRUE(IsBookmarkedByUser(model_.get(), GURL("http://google.com")));
1132 EXPECT_FALSE(IsBookmarkedByUser(model_.get(), GURL("http://youtube.com")));
1133 EXPECT_FALSE(IsBookmarkedByUser(model_.get(), GURL("http://reddit.com")));
1136 // Verifies that GetMostRecentlyAddedUserNodeForURL skips bookmarks that
1137 // are not owned by the user.
1138 TEST_F(BookmarkModelTest, GetMostRecentlyAddedUserNodeForURLSkipsManagedNodes) {
1139 // Reload the model with an extra node that is not editable by the user.
1140 BookmarkPermanentNode* extra_node = ReloadModelWithExtraNode();
1142 const base::string16 title = base::ASCIIToUTF16("Title");
1143 const BookmarkNode* user_parent = model_->other_node();
1144 const BookmarkNode* managed_parent = extra_node;
1145 const GURL url("http://google.com");
1147 // |url| is not bookmarked yet.
1148 EXPECT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == NULL);
1150 // Having a managed node doesn't count.
1151 model_->AddURL(managed_parent, 0, title, url);
1152 EXPECT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == NULL);
1154 // Now add a user node.
1155 const BookmarkNode* user = model_->AddURL(user_parent, 0, title, url);
1156 EXPECT_EQ(user, model_->GetMostRecentlyAddedUserNodeForURL(url));
1158 // Having a more recent managed node doesn't count either.
1159 const BookmarkNode* managed = model_->AddURL(managed_parent, 0, title, url);
1160 EXPECT_GE(managed->date_added(), user->date_added());
1161 EXPECT_EQ(user, model_->GetMostRecentlyAddedUserNodeForURL(url));
1164 TEST(BookmarkNodeTest, NodeMetaInfo) {
1165 GURL url;
1166 BookmarkNode node(url);
1167 EXPECT_FALSE(node.GetMetaInfoMap());
1169 EXPECT_TRUE(node.SetMetaInfo("key1", "value1"));
1170 std::string out_value;
1171 EXPECT_TRUE(node.GetMetaInfo("key1", &out_value));
1172 EXPECT_EQ("value1", out_value);
1173 EXPECT_FALSE(node.SetMetaInfo("key1", "value1"));
1175 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value));
1176 EXPECT_TRUE(node.SetMetaInfo("key2.subkey1", "value2"));
1177 EXPECT_TRUE(node.GetMetaInfo("key2.subkey1", &out_value));
1178 EXPECT_EQ("value2", out_value);
1180 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value));
1181 EXPECT_TRUE(node.SetMetaInfo("key2.subkey2.leaf", ""));
1182 EXPECT_TRUE(node.GetMetaInfo("key2.subkey2.leaf", &out_value));
1183 EXPECT_EQ("", out_value);
1185 EXPECT_TRUE(node.DeleteMetaInfo("key1"));
1186 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey1"));
1187 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey2.leaf"));
1188 EXPECT_FALSE(node.DeleteMetaInfo("key3"));
1189 EXPECT_FALSE(node.GetMetaInfo("key1", &out_value));
1190 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value));
1191 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2", &out_value));
1192 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value));
1193 EXPECT_FALSE(node.GetMetaInfoMap());
1196 } // namespace
1197 } // namespace bookmarks