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"
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 "components/bookmarks/browser/bookmark_model_observer.h"
23 #include "components/bookmarks/browser/bookmark_utils.h"
24 #include "components/bookmarks/test/bookmark_test_helpers.h"
25 #include "components/bookmarks/test/test_bookmark_client.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "ui/base/models/tree_node_iterator.h"
28 #include "ui/base/models/tree_node_model.h"
31 using base::ASCIIToUTF16
;
33 using base::TimeDelta
;
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.
40 const std::string input_title
;
41 const std::string expected_title
;
42 } url_whitespace_test_cases
[] = {
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"},
52 {"foo bar", "foo bar"},
53 {" foo bar ", "foo bar"},
54 {" foo bar ", "foo bar"},
56 {"\tfoo\tbar\t", "foo bar"},
57 {"\tfoo bar\t", "foo bar"},
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.
69 const std::string input_title
;
70 const std::string expected_title
;
71 } title_whitespace_test_cases
[] = {
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 "},
81 {"foo bar", "foo bar"},
82 {" foo bar ", " foo bar "},
83 {" foo bar ", " foo bar "},
85 {"\tfoo\tbar\t", " foo bar "},
86 {"\tfoo bar\t", " foo bar "},
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
{
109 struct ObserverDetails
{
111 Set(NULL
, NULL
, -1, -1);
114 void Set(const BookmarkNode
* node1
,
115 const BookmarkNode
* node2
,
124 void ExpectEquals(const BookmarkNode
* node1
,
125 const BookmarkNode
* node2
,
128 EXPECT_EQ(node1_
, node1
);
129 EXPECT_EQ(node2_
, node2
);
130 EXPECT_EQ(index1_
, index1
);
131 EXPECT_EQ(index2_
, index2
);
135 const BookmarkNode
* node1_
;
136 const BookmarkNode
* node2_
;
141 BookmarkModelTest() : model_(client_
.CreateModel()) {
142 model_
->AddObserver(this);
146 virtual void BookmarkModelLoaded(BookmarkModel
* model
,
147 bool ids_reassigned
) OVERRIDE
{
148 // We never load from the db, so that this should never get invoked.
152 virtual void BookmarkNodeMoved(BookmarkModel
* model
,
153 const BookmarkNode
* old_parent
,
155 const BookmarkNode
* new_parent
,
156 int new_index
) OVERRIDE
{
158 observer_details_
.Set(old_parent
, new_parent
, old_index
, new_index
);
161 virtual void OnWillAddBookmarkNode(BookmarkModel
* model
,
162 BookmarkNode
* node
) OVERRIDE
{
164 EXPECT_TRUE(node
->parent() == NULL
);
167 virtual void BookmarkNodeAdded(BookmarkModel
* model
,
168 const BookmarkNode
* parent
,
169 int index
) OVERRIDE
{
171 observer_details_
.Set(parent
, NULL
, index
, -1);
174 virtual void OnWillRemoveBookmarks(BookmarkModel
* model
,
175 const BookmarkNode
* parent
,
177 const BookmarkNode
* node
) OVERRIDE
{
178 ++before_remove_count_
;
181 virtual void BookmarkNodeRemoved(
182 BookmarkModel
* model
,
183 const BookmarkNode
* parent
,
185 const BookmarkNode
* node
,
186 const std::set
<GURL
>& removed_urls
) OVERRIDE
{
188 observer_details_
.Set(parent
, NULL
, old_index
, -1);
191 virtual void BookmarkNodeChanged(BookmarkModel
* model
,
192 const BookmarkNode
* node
) OVERRIDE
{
194 observer_details_
.Set(node
, NULL
, -1, -1);
197 virtual void OnWillChangeBookmarkNode(BookmarkModel
* model
,
198 const BookmarkNode
* node
) OVERRIDE
{
199 ++before_change_count_
;
202 virtual void BookmarkNodeChildrenReordered(
203 BookmarkModel
* model
,
204 const BookmarkNode
* node
) OVERRIDE
{
208 virtual void OnWillReorderBookmarkNode(BookmarkModel
* model
,
209 const BookmarkNode
* node
) OVERRIDE
{
210 ++before_reorder_count_
;
213 virtual void BookmarkNodeFaviconChanged(BookmarkModel
* model
,
214 const BookmarkNode
* node
) OVERRIDE
{
215 // We never attempt to load favicons, so that this method never
219 virtual void ExtensiveBookmarkChangesBeginning(
220 BookmarkModel
* model
) OVERRIDE
{
221 ++extensive_changes_beginning_count_
;
224 virtual void ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) OVERRIDE
{
225 ++extensive_changes_ended_count_
;
228 virtual void BookmarkAllUserNodesRemoved(
229 BookmarkModel
* model
,
230 const std::set
<GURL
>& removed_urls
) OVERRIDE
{
231 ++all_bookmarks_removed_
;
234 virtual void OnWillRemoveAllUserBookmarks(BookmarkModel
* model
) OVERRIDE
{
235 ++before_remove_all_count_
;
239 will_add_count_
= added_count_
= moved_count_
= removed_count_
=
240 changed_count_
= reordered_count_
= extensive_changes_beginning_count_
=
241 extensive_changes_ended_count_
= all_bookmarks_removed_
=
242 before_remove_count_
= before_change_count_
= before_reorder_count_
=
243 before_remove_all_count_
= 0;
246 void AssertObserverCount(int will_add_count
,
252 int before_remove_count
,
253 int before_change_count
,
254 int before_reorder_count
,
255 int before_remove_all_count
) {
256 EXPECT_EQ(will_add_count_
, will_add_count
);
257 EXPECT_EQ(added_count_
, added_count
);
258 EXPECT_EQ(moved_count_
, moved_count
);
259 EXPECT_EQ(removed_count_
, removed_count
);
260 EXPECT_EQ(changed_count_
, changed_count
);
261 EXPECT_EQ(reordered_count_
, reordered_count
);
262 EXPECT_EQ(before_remove_count_
, before_remove_count
);
263 EXPECT_EQ(before_change_count_
, before_change_count
);
264 EXPECT_EQ(before_reorder_count_
, before_reorder_count
);
265 EXPECT_EQ(before_remove_all_count_
, before_remove_all_count
);
268 void AssertExtensiveChangesObserverCount(
269 int extensive_changes_beginning_count
,
270 int extensive_changes_ended_count
) {
271 EXPECT_EQ(extensive_changes_beginning_count_
,
272 extensive_changes_beginning_count
);
273 EXPECT_EQ(extensive_changes_ended_count_
, extensive_changes_ended_count
);
276 int AllNodesRemovedObserverCount() const { return all_bookmarks_removed_
; }
278 BookmarkPermanentNode
* ReloadModelWithExtraNode() {
279 BookmarkPermanentNode
* extra_node
= new BookmarkPermanentNode(100);
280 bookmarks::BookmarkPermanentNodeList extra_nodes
;
281 extra_nodes
.push_back(extra_node
);
282 client_
.SetExtraNodesToLoad(extra_nodes
.Pass());
284 model_
->RemoveObserver(this);
285 model_
= client_
.CreateModel();
286 model_
->AddObserver(this);
289 if (model_
->root_node()->GetIndexOf(extra_node
) == -1)
296 test::TestBookmarkClient client_
;
297 scoped_ptr
<BookmarkModel
> model_
;
298 ObserverDetails observer_details_
;
306 int reordered_count_
;
307 int extensive_changes_beginning_count_
;
308 int extensive_changes_ended_count_
;
309 int all_bookmarks_removed_
;
310 int before_remove_count_
;
311 int before_change_count_
;
312 int before_reorder_count_
;
313 int before_remove_all_count_
;
315 DISALLOW_COPY_AND_ASSIGN(BookmarkModelTest
);
318 TEST_F(BookmarkModelTest
, InitialState
) {
319 const BookmarkNode
* bb_node
= model_
->bookmark_bar_node();
320 ASSERT_TRUE(bb_node
!= NULL
);
321 EXPECT_EQ(0, bb_node
->child_count());
322 EXPECT_EQ(BookmarkNode::BOOKMARK_BAR
, bb_node
->type());
324 const BookmarkNode
* other_node
= model_
->other_node();
325 ASSERT_TRUE(other_node
!= NULL
);
326 EXPECT_EQ(0, other_node
->child_count());
327 EXPECT_EQ(BookmarkNode::OTHER_NODE
, other_node
->type());
329 const BookmarkNode
* mobile_node
= model_
->mobile_node();
330 ASSERT_TRUE(mobile_node
!= NULL
);
331 EXPECT_EQ(0, mobile_node
->child_count());
332 EXPECT_EQ(BookmarkNode::MOBILE
, mobile_node
->type());
334 EXPECT_TRUE(bb_node
->id() != other_node
->id());
335 EXPECT_TRUE(bb_node
->id() != mobile_node
->id());
336 EXPECT_TRUE(other_node
->id() != mobile_node
->id());
339 TEST_F(BookmarkModelTest
, AddURL
) {
340 const BookmarkNode
* root
= model_
->bookmark_bar_node();
341 const base::string16
title(ASCIIToUTF16("foo"));
342 const GURL
url("http://foo.com");
344 const BookmarkNode
* new_node
= model_
->AddURL(root
, 0, title
, url
);
345 AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
346 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
348 ASSERT_EQ(1, root
->child_count());
349 ASSERT_EQ(title
, new_node
->GetTitle());
350 ASSERT_TRUE(url
== new_node
->url());
351 ASSERT_EQ(BookmarkNode::URL
, new_node
->type());
352 ASSERT_TRUE(new_node
== model_
->GetMostRecentlyAddedUserNodeForURL(url
));
354 EXPECT_TRUE(new_node
->id() != root
->id() &&
355 new_node
->id() != model_
->other_node()->id() &&
356 new_node
->id() != model_
->mobile_node()->id());
359 TEST_F(BookmarkModelTest
, AddURLWithUnicodeTitle
) {
360 const BookmarkNode
* root
= model_
->bookmark_bar_node();
361 const base::string16
title(base::WideToUTF16(
362 L
"\u767e\u5ea6\u4e00\u4e0b\uff0c\u4f60\u5c31\u77e5\u9053"));
363 const GURL
url("https://www.baidu.com/");
365 const BookmarkNode
* new_node
= model_
->AddURL(root
, 0, title
, url
);
366 AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
367 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
369 ASSERT_EQ(1, root
->child_count());
370 ASSERT_EQ(title
, new_node
->GetTitle());
371 ASSERT_TRUE(url
== new_node
->url());
372 ASSERT_EQ(BookmarkNode::URL
, new_node
->type());
373 ASSERT_TRUE(new_node
== model_
->GetMostRecentlyAddedUserNodeForURL(url
));
375 EXPECT_TRUE(new_node
->id() != root
->id() &&
376 new_node
->id() != model_
->other_node()->id() &&
377 new_node
->id() != model_
->mobile_node()->id());
380 TEST_F(BookmarkModelTest
, AddURLWithWhitespaceTitle
) {
381 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(url_whitespace_test_cases
); ++i
) {
382 const BookmarkNode
* root
= model_
->bookmark_bar_node();
383 const base::string16
title(
384 ASCIIToUTF16(url_whitespace_test_cases
[i
].input_title
));
385 const GURL
url("http://foo.com");
387 const BookmarkNode
* new_node
= model_
->AddURL(root
, i
, title
, url
);
390 EXPECT_EQ(size
, root
->child_count());
391 EXPECT_EQ(ASCIIToUTF16(url_whitespace_test_cases
[i
].expected_title
),
392 new_node
->GetTitle());
393 EXPECT_EQ(BookmarkNode::URL
, new_node
->type());
397 TEST_F(BookmarkModelTest
, AddURLWithCreationTimeAndMetaInfo
) {
398 const BookmarkNode
* root
= model_
->bookmark_bar_node();
399 const base::string16
title(ASCIIToUTF16("foo"));
400 const GURL
url("http://foo.com");
401 const Time time
= Time::Now() - TimeDelta::FromDays(1);
402 BookmarkNode::MetaInfoMap meta_info
;
403 meta_info
["foo"] = "bar";
405 const BookmarkNode
* new_node
= model_
->AddURLWithCreationTimeAndMetaInfo(
406 root
, 0, title
, url
, time
, &meta_info
);
407 AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
408 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
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_EQ(time
, new_node
->date_added());
415 ASSERT_TRUE(new_node
->GetMetaInfoMap());
416 ASSERT_EQ(meta_info
, *new_node
->GetMetaInfoMap());
417 ASSERT_TRUE(new_node
== model_
->GetMostRecentlyAddedUserNodeForURL(url
));
419 EXPECT_TRUE(new_node
->id() != root
->id() &&
420 new_node
->id() != model_
->other_node()->id() &&
421 new_node
->id() != model_
->mobile_node()->id());
424 TEST_F(BookmarkModelTest
, AddURLToMobileBookmarks
) {
425 const BookmarkNode
* root
= model_
->mobile_node();
426 const base::string16
title(ASCIIToUTF16("foo"));
427 const GURL
url("http://foo.com");
429 const BookmarkNode
* new_node
= model_
->AddURL(root
, 0, title
, url
);
430 AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
431 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
433 ASSERT_EQ(1, root
->child_count());
434 ASSERT_EQ(title
, new_node
->GetTitle());
435 ASSERT_TRUE(url
== new_node
->url());
436 ASSERT_EQ(BookmarkNode::URL
, new_node
->type());
437 ASSERT_TRUE(new_node
== model_
->GetMostRecentlyAddedUserNodeForURL(url
));
439 EXPECT_TRUE(new_node
->id() != root
->id() &&
440 new_node
->id() != model_
->other_node()->id() &&
441 new_node
->id() != model_
->mobile_node()->id());
444 TEST_F(BookmarkModelTest
, AddFolder
) {
445 const BookmarkNode
* root
= model_
->bookmark_bar_node();
446 const base::string16
title(ASCIIToUTF16("foo"));
448 const BookmarkNode
* new_node
= model_
->AddFolder(root
, 0, title
);
449 AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
450 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
452 ASSERT_EQ(1, root
->child_count());
453 ASSERT_EQ(title
, new_node
->GetTitle());
454 ASSERT_EQ(BookmarkNode::FOLDER
, new_node
->type());
456 EXPECT_TRUE(new_node
->id() != root
->id() &&
457 new_node
->id() != model_
->other_node()->id() &&
458 new_node
->id() != model_
->mobile_node()->id());
460 // Add another folder, just to make sure folder_ids are incremented correctly.
462 model_
->AddFolder(root
, 0, title
);
463 AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
464 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
467 TEST_F(BookmarkModelTest
, AddFolderWithWhitespaceTitle
) {
468 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(title_whitespace_test_cases
); ++i
) {
469 const BookmarkNode
* root
= model_
->bookmark_bar_node();
470 const base::string16
title(
471 ASCIIToUTF16(title_whitespace_test_cases
[i
].input_title
));
473 const BookmarkNode
* new_node
= model_
->AddFolder(root
, i
, title
);
476 EXPECT_EQ(size
, root
->child_count());
477 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases
[i
].expected_title
),
478 new_node
->GetTitle());
479 EXPECT_EQ(BookmarkNode::FOLDER
, new_node
->type());
483 TEST_F(BookmarkModelTest
, RemoveURL
) {
484 const BookmarkNode
* root
= model_
->bookmark_bar_node();
485 const base::string16
title(ASCIIToUTF16("foo"));
486 const GURL
url("http://foo.com");
487 model_
->AddURL(root
, 0, title
, url
);
490 model_
->Remove(root
, 0);
491 ASSERT_EQ(0, root
->child_count());
492 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0, 0);
493 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
495 // Make sure there is no mapping for the URL.
496 ASSERT_TRUE(model_
->GetMostRecentlyAddedUserNodeForURL(url
) == NULL
);
499 TEST_F(BookmarkModelTest
, RemoveFolder
) {
500 const BookmarkNode
* root
= model_
->bookmark_bar_node();
501 const BookmarkNode
* folder
= model_
->AddFolder(root
, 0, ASCIIToUTF16("foo"));
505 // Add a URL as a child.
506 const base::string16
title(ASCIIToUTF16("foo"));
507 const GURL
url("http://foo.com");
508 model_
->AddURL(folder
, 0, title
, url
);
512 // Now remove the folder.
513 model_
->Remove(root
, 0);
514 ASSERT_EQ(0, root
->child_count());
515 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0, 0);
516 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
518 // Make sure there is no mapping for the URL.
519 ASSERT_TRUE(model_
->GetMostRecentlyAddedUserNodeForURL(url
) == NULL
);
522 TEST_F(BookmarkModelTest
, RemoveAllUserBookmarks
) {
523 const BookmarkNode
* bookmark_bar_node
= model_
->bookmark_bar_node();
527 // Add a url to bookmark bar.
528 base::string16
title(ASCIIToUTF16("foo"));
529 GURL
url("http://foo.com");
530 model_
->AddURL(bookmark_bar_node
, 0, title
, url
);
532 // Add a folder with child URL.
533 const BookmarkNode
* folder
= model_
->AddFolder(bookmark_bar_node
, 0, title
);
534 model_
->AddURL(folder
, 0, title
, url
);
536 AssertObserverCount(3, 3, 0, 0, 0, 0, 0, 0, 0, 0);
539 model_
->RemoveAllUserBookmarks();
541 EXPECT_EQ(0, bookmark_bar_node
->child_count());
542 // No individual BookmarkNodeRemoved events are fired, so removed count
544 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
545 AssertExtensiveChangesObserverCount(1, 1);
546 EXPECT_EQ(1, AllNodesRemovedObserverCount());
549 TEST_F(BookmarkModelTest
, SetTitle
) {
550 const BookmarkNode
* root
= model_
->bookmark_bar_node();
551 base::string16
title(ASCIIToUTF16("foo"));
552 const GURL
url("http://foo.com");
553 const BookmarkNode
* node
= model_
->AddURL(root
, 0, title
, url
);
557 title
= ASCIIToUTF16("foo2");
558 model_
->SetTitle(node
, title
);
559 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0, 0);
560 observer_details_
.ExpectEquals(node
, NULL
, -1, -1);
561 EXPECT_EQ(title
, node
->GetTitle());
564 TEST_F(BookmarkModelTest
, SetTitleWithWhitespace
) {
565 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(title_whitespace_test_cases
); ++i
) {
566 const BookmarkNode
* root
= model_
->bookmark_bar_node();
567 base::string16
title(ASCIIToUTF16("dummy"));
568 const GURL
url("http://foo.com");
569 const BookmarkNode
* node
= model_
->AddURL(root
, 0, title
, url
);
571 title
= ASCIIToUTF16(title_whitespace_test_cases
[i
].input_title
);
572 model_
->SetTitle(node
, title
);
573 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases
[i
].expected_title
),
578 TEST_F(BookmarkModelTest
, SetURL
) {
579 const BookmarkNode
* root
= model_
->bookmark_bar_node();
580 const base::string16
title(ASCIIToUTF16("foo"));
581 GURL
url("http://foo.com");
582 const BookmarkNode
* node
= model_
->AddURL(root
, 0, title
, url
);
586 url
= GURL("http://foo2.com");
587 model_
->SetURL(node
, url
);
588 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0, 0);
589 observer_details_
.ExpectEquals(node
, NULL
, -1, -1);
590 EXPECT_EQ(url
, node
->url());
593 TEST_F(BookmarkModelTest
, SetDateAdded
) {
594 const BookmarkNode
* root
= model_
->bookmark_bar_node();
595 const base::string16
title(ASCIIToUTF16("foo"));
596 GURL
url("http://foo.com");
597 const BookmarkNode
* node
= model_
->AddURL(root
, 0, title
, url
);
601 base::Time new_time
= base::Time::Now() + base::TimeDelta::FromMinutes(20);
602 model_
->SetDateAdded(node
, new_time
);
603 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
604 EXPECT_EQ(new_time
, node
->date_added());
605 EXPECT_EQ(new_time
, model_
->bookmark_bar_node()->date_folder_modified());
608 TEST_F(BookmarkModelTest
, Move
) {
609 const BookmarkNode
* root
= model_
->bookmark_bar_node();
610 const base::string16
title(ASCIIToUTF16("foo"));
611 const GURL
url("http://foo.com");
612 const BookmarkNode
* node
= model_
->AddURL(root
, 0, title
, url
);
613 const BookmarkNode
* folder1
= model_
->AddFolder(root
, 0, ASCIIToUTF16("foo"));
616 model_
->Move(node
, folder1
, 0);
618 AssertObserverCount(0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
619 observer_details_
.ExpectEquals(root
, folder1
, 1, 0);
620 EXPECT_TRUE(folder1
== node
->parent());
621 EXPECT_EQ(1, root
->child_count());
622 EXPECT_EQ(folder1
, root
->GetChild(0));
623 EXPECT_EQ(1, folder1
->child_count());
624 EXPECT_EQ(node
, folder1
->GetChild(0));
626 // And remove the folder.
628 model_
->Remove(root
, 0);
629 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0, 0);
630 observer_details_
.ExpectEquals(root
, NULL
, 0, -1);
631 EXPECT_TRUE(model_
->GetMostRecentlyAddedUserNodeForURL(url
) == NULL
);
632 EXPECT_EQ(0, root
->child_count());
635 TEST_F(BookmarkModelTest
, NonMovingMoveCall
) {
636 const BookmarkNode
* root
= model_
->bookmark_bar_node();
637 const base::string16
title(ASCIIToUTF16("foo"));
638 const GURL
url("http://foo.com");
639 const base::Time
old_date(base::Time::Now() - base::TimeDelta::FromDays(1));
641 const BookmarkNode
* node
= model_
->AddURL(root
, 0, title
, url
);
642 model_
->SetDateFolderModified(root
, old_date
);
644 // Since |node| is already at the index 0 of |root|, this is no-op.
645 model_
->Move(node
, root
, 0);
647 // Check that the modification date is kept untouched.
648 EXPECT_EQ(old_date
, root
->date_folder_modified());
651 TEST_F(BookmarkModelTest
, Copy
) {
652 const BookmarkNode
* root
= model_
->bookmark_bar_node();
653 static const std::string
model_string("a 1:[ b c ] d 2:[ e f g ] h ");
654 test::AddNodesFromModelString(model_
.get(), root
, model_string
);
656 // Validate initial model.
657 std::string actual_model_string
= test::ModelStringFromNode(root
);
658 EXPECT_EQ(model_string
, actual_model_string
);
660 // Copy 'd' to be after '1:b': URL item from bar to folder.
661 const BookmarkNode
* node_to_copy
= root
->GetChild(2);
662 const BookmarkNode
* destination
= root
->GetChild(1);
663 model_
->Copy(node_to_copy
, destination
, 1);
664 actual_model_string
= test::ModelStringFromNode(root
);
665 EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string
);
667 // Copy '1:d' to be after 'a': URL item from folder to bar.
668 const BookmarkNode
* folder
= root
->GetChild(1);
669 node_to_copy
= folder
->GetChild(1);
670 model_
->Copy(node_to_copy
, root
, 1);
671 actual_model_string
= test::ModelStringFromNode(root
);
672 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string
);
674 // Copy '1' to be after '2:e': Folder from bar to folder.
675 node_to_copy
= root
->GetChild(2);
676 destination
= root
->GetChild(4);
677 model_
->Copy(node_to_copy
, destination
, 1);
678 actual_model_string
= test::ModelStringFromNode(root
);
679 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ",
680 actual_model_string
);
682 // Copy '2:1' to be after '2:f': Folder within same folder.
683 folder
= root
->GetChild(4);
684 node_to_copy
= folder
->GetChild(1);
685 model_
->Copy(node_to_copy
, folder
, 3);
686 actual_model_string
= test::ModelStringFromNode(root
);
687 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ",
688 actual_model_string
);
690 // Copy first 'd' to be after 'h': URL item within the bar.
691 node_to_copy
= root
->GetChild(1);
692 model_
->Copy(node_to_copy
, root
, 6);
693 actual_model_string
= test::ModelStringFromNode(root
);
694 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
695 actual_model_string
);
697 // Copy '2' to be after 'a': Folder within the bar.
698 node_to_copy
= root
->GetChild(4);
699 model_
->Copy(node_to_copy
, root
, 1);
700 actual_model_string
= test::ModelStringFromNode(root
);
701 EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] "
702 "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
703 actual_model_string
);
706 // Tests that adding a URL to a folder updates the last modified time.
707 TEST_F(BookmarkModelTest
, ParentForNewNodes
) {
708 ASSERT_EQ(model_
->bookmark_bar_node(), model_
->GetParentForNewNodes());
710 const base::string16
title(ASCIIToUTF16("foo"));
711 const GURL
url("http://foo.com");
713 model_
->AddURL(model_
->other_node(), 0, title
, url
);
714 ASSERT_EQ(model_
->other_node(), model_
->GetParentForNewNodes());
717 // Tests that adding a URL to a folder updates the last modified time.
718 TEST_F(BookmarkModelTest
, ParentForNewMobileNodes
) {
719 ASSERT_EQ(model_
->bookmark_bar_node(), model_
->GetParentForNewNodes());
721 const base::string16
title(ASCIIToUTF16("foo"));
722 const GURL
url("http://foo.com");
724 model_
->AddURL(model_
->mobile_node(), 0, title
, url
);
725 ASSERT_EQ(model_
->mobile_node(), model_
->GetParentForNewNodes());
728 // Make sure recently modified stays in sync when adding a URL.
729 TEST_F(BookmarkModelTest
, MostRecentlyModifiedFolders
) {
731 const BookmarkNode
* folder
=
732 model_
->AddFolder(model_
->other_node(), 0, ASCIIToUTF16("foo"));
734 model_
->AddURL(folder
, 0, ASCIIToUTF16("blah"), GURL("http://foo.com"));
736 // Make sure folder is in the most recently modified.
737 std::vector
<const BookmarkNode
*> most_recent_folders
=
738 bookmarks::GetMostRecentlyModifiedUserFolders(model_
.get(), 1);
739 ASSERT_EQ(1U, most_recent_folders
.size());
740 ASSERT_EQ(folder
, most_recent_folders
[0]);
742 // Nuke the folder and do another fetch, making sure folder isn't in the
744 model_
->Remove(folder
->parent(), 0);
745 most_recent_folders
=
746 bookmarks::GetMostRecentlyModifiedUserFolders(model_
.get(), 1);
747 ASSERT_EQ(1U, most_recent_folders
.size());
748 ASSERT_TRUE(most_recent_folders
[0] != folder
);
751 // Make sure MostRecentlyAddedEntries stays in sync.
752 TEST_F(BookmarkModelTest
, MostRecentlyAddedEntries
) {
753 // Add a couple of nodes such that the following holds for the time of the
754 // nodes: n1 > n2 > n3 > n4.
755 Time base_time
= Time::Now();
756 BookmarkNode
* n1
= AsMutable(model_
->AddURL(model_
->bookmark_bar_node(),
758 ASCIIToUTF16("blah"),
759 GURL("http://foo.com/0")));
760 BookmarkNode
* n2
= AsMutable(model_
->AddURL(model_
->bookmark_bar_node(),
762 ASCIIToUTF16("blah"),
763 GURL("http://foo.com/1")));
764 BookmarkNode
* n3
= AsMutable(model_
->AddURL(model_
->bookmark_bar_node(),
766 ASCIIToUTF16("blah"),
767 GURL("http://foo.com/2")));
768 BookmarkNode
* n4
= AsMutable(model_
->AddURL(model_
->bookmark_bar_node(),
770 ASCIIToUTF16("blah"),
771 GURL("http://foo.com/3")));
772 n1
->set_date_added(base_time
+ TimeDelta::FromDays(4));
773 n2
->set_date_added(base_time
+ TimeDelta::FromDays(3));
774 n3
->set_date_added(base_time
+ TimeDelta::FromDays(2));
775 n4
->set_date_added(base_time
+ TimeDelta::FromDays(1));
777 // Make sure order is honored.
778 std::vector
<const BookmarkNode
*> recently_added
;
779 bookmarks::GetMostRecentlyAddedEntries(model_
.get(), 2, &recently_added
);
780 ASSERT_EQ(2U, recently_added
.size());
781 ASSERT_TRUE(n1
== recently_added
[0]);
782 ASSERT_TRUE(n2
== recently_added
[1]);
784 // swap 1 and 2, then check again.
785 recently_added
.clear();
786 SwapDateAdded(n1
, n2
);
787 bookmarks::GetMostRecentlyAddedEntries(model_
.get(), 4, &recently_added
);
788 ASSERT_EQ(4U, recently_added
.size());
789 ASSERT_TRUE(n2
== recently_added
[0]);
790 ASSERT_TRUE(n1
== recently_added
[1]);
791 ASSERT_TRUE(n3
== recently_added
[2]);
792 ASSERT_TRUE(n4
== recently_added
[3]);
795 // Makes sure GetMostRecentlyAddedUserNodeForURL stays in sync.
796 TEST_F(BookmarkModelTest
, GetMostRecentlyAddedUserNodeForURL
) {
797 // Add a couple of nodes such that the following holds for the time of the
799 Time base_time
= Time::Now();
800 const GURL
url("http://foo.com/0");
801 BookmarkNode
* n1
= AsMutable(model_
->AddURL(
802 model_
->bookmark_bar_node(), 0, ASCIIToUTF16("blah"), url
));
803 BookmarkNode
* n2
= AsMutable(model_
->AddURL(
804 model_
->bookmark_bar_node(), 1, ASCIIToUTF16("blah"), url
));
805 n1
->set_date_added(base_time
+ TimeDelta::FromDays(4));
806 n2
->set_date_added(base_time
+ TimeDelta::FromDays(3));
808 // Make sure order is honored.
809 ASSERT_EQ(n1
, model_
->GetMostRecentlyAddedUserNodeForURL(url
));
811 // swap 1 and 2, then check again.
812 SwapDateAdded(n1
, n2
);
813 ASSERT_EQ(n2
, model_
->GetMostRecentlyAddedUserNodeForURL(url
));
816 // Makes sure GetBookmarks removes duplicates.
817 TEST_F(BookmarkModelTest
, GetBookmarksWithDups
) {
818 const GURL
url("http://foo.com/0");
819 const base::string16
title(ASCIIToUTF16("blah"));
820 model_
->AddURL(model_
->bookmark_bar_node(), 0, title
, url
);
821 model_
->AddURL(model_
->bookmark_bar_node(), 1, title
, url
);
823 std::vector
<BookmarkModel::URLAndTitle
> bookmarks
;
824 model_
->GetBookmarks(&bookmarks
);
825 ASSERT_EQ(1U, bookmarks
.size());
826 EXPECT_EQ(url
, bookmarks
[0].url
);
827 EXPECT_EQ(title
, bookmarks
[0].title
);
829 model_
->AddURL(model_
->bookmark_bar_node(), 2, ASCIIToUTF16("Title2"), url
);
830 // Only one returned, even titles are different.
832 model_
->GetBookmarks(&bookmarks
);
833 EXPECT_EQ(1U, bookmarks
.size());
836 TEST_F(BookmarkModelTest
, HasBookmarks
) {
837 const GURL
url("http://foo.com/");
838 model_
->AddURL(model_
->bookmark_bar_node(), 0, ASCIIToUTF16("bar"), url
);
840 EXPECT_TRUE(model_
->HasBookmarks());
843 // See comment in PopulateNodeFromString.
844 typedef ui::TreeNodeWithValue
<BookmarkNode::Type
> TestNode
;
846 // Does the work of PopulateNodeFromString. index gives the index of the current
847 // element in description to process.
848 void PopulateNodeImpl(const std::vector
<std::string
>& description
,
851 while (*index
< description
.size()) {
852 const std::string
& element
= description
[*index
];
854 if (element
== "[") {
855 // Create a new folder and recurse to add all the children.
856 // Folders are given a unique named by way of an ever increasing integer
857 // value. The folders need not have a name, but one is assigned to help
859 static int next_folder_id
= 1;
861 new TestNode(base::IntToString16(next_folder_id
++),
862 BookmarkNode::FOLDER
);
863 parent
->Add(new_node
, parent
->child_count());
864 PopulateNodeImpl(description
, index
, new_node
);
865 } else if (element
== "]") {
866 // End the current folder.
871 // All tokens must be space separated. If there is a [ or ] in the name it
872 // likely means a space was forgotten.
873 DCHECK(element
.find('[') == std::string::npos
);
874 DCHECK(element
.find(']') == std::string::npos
);
875 parent
->Add(new TestNode(base::UTF8ToUTF16(element
), BookmarkNode::URL
),
876 parent
->child_count());
881 // Creates and adds nodes to parent based on description. description consists
882 // of the following tokens (all space separated):
883 // [ : creates a new USER_FOLDER node. All elements following the [ until the
884 // next balanced ] is encountered are added as children to the node.
885 // ] : closes the last folder created by [ so that any further nodes are added
886 // to the current folders parent.
887 // text: creates a new URL node.
888 // For example, "a [b] c" creates the following nodes:
892 // In words: a node of type URL with the title a, followed by a folder node with
893 // the title 1 having the single child of type url with name b, followed by
894 // the url node with the title c.
896 // NOTE: each name must be unique, and folders are assigned a unique title by
897 // way of an increasing integer.
898 void PopulateNodeFromString(const std::string
& description
, TestNode
* parent
) {
899 std::vector
<std::string
> elements
;
900 base::SplitStringAlongWhitespace(description
, &elements
);
902 PopulateNodeImpl(elements
, &index
, parent
);
905 // Populates the BookmarkNode with the children of parent.
906 void PopulateBookmarkNode(TestNode
* parent
,
907 BookmarkModel
* model
,
908 const BookmarkNode
* bb_node
) {
909 for (int i
= 0; i
< parent
->child_count(); ++i
) {
910 TestNode
* child
= parent
->GetChild(i
);
911 if (child
->value
== BookmarkNode::FOLDER
) {
912 const BookmarkNode
* new_bb_node
=
913 model
->AddFolder(bb_node
, i
, child
->GetTitle());
914 PopulateBookmarkNode(child
, model
, new_bb_node
);
916 model
->AddURL(bb_node
, i
, child
->GetTitle(),
917 GURL("http://" + base::UTF16ToASCII(child
->GetTitle())));
922 // Test class that creates a BookmarkModel with a real history backend.
923 class BookmarkModelTestWithProfile
: public testing::Test
{
925 BookmarkModelTestWithProfile() {}
928 // Verifies the contents of the bookmark bar node match the contents of the
930 void VerifyModelMatchesNode(TestNode
* expected
, const BookmarkNode
* actual
) {
931 ASSERT_EQ(expected
->child_count(), actual
->child_count());
932 for (int i
= 0; i
< expected
->child_count(); ++i
) {
933 TestNode
* expected_child
= expected
->GetChild(i
);
934 const BookmarkNode
* actual_child
= actual
->GetChild(i
);
935 ASSERT_EQ(expected_child
->GetTitle(), actual_child
->GetTitle());
936 if (expected_child
->value
== BookmarkNode::FOLDER
) {
937 ASSERT_TRUE(actual_child
->type() == BookmarkNode::FOLDER
);
938 // Recurse throught children.
939 VerifyModelMatchesNode(expected_child
, actual_child
);
940 if (HasFatalFailure())
943 // No need to check the URL, just the title is enough.
944 ASSERT_TRUE(actual_child
->is_url());
949 void VerifyNoDuplicateIDs(BookmarkModel
* model
) {
950 ui::TreeNodeIterator
<const BookmarkNode
> it(model
->root_node());
951 base::hash_set
<int64
> ids
;
952 while (it
.has_next())
953 ASSERT_TRUE(ids
.insert(it
.Next()->id()).second
);
956 test::TestBookmarkClient client_
;
957 scoped_ptr
<BookmarkModel
> model_
;
960 // Creates a set of nodes in the bookmark bar model, then recreates the
961 // bookmark bar model which triggers loading from the db and checks the loaded
962 // structure to make sure it is what we first created.
963 TEST_F(BookmarkModelTestWithProfile
, CreateAndRestore
) {
965 // Structure of the children of the bookmark bar model node.
966 const std::string bbn_contents
;
967 // Structure of the children of the other node.
968 const std::string other_contents
;
969 // Structure of the children of the synced node.
970 const std::string mobile_contents
;
972 // See PopulateNodeFromString for a description of these strings.
976 { "", "[ b ] a [ c [ d e [ f ] ] ]" },
978 { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"},
980 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(data
); ++i
) {
981 model_
= client_
.CreateModel();
984 PopulateNodeFromString(data
[i
].bbn_contents
, &bbn
);
985 PopulateBookmarkNode(&bbn
, model_
.get(), model_
->bookmark_bar_node());
988 PopulateNodeFromString(data
[i
].other_contents
, &other
);
989 PopulateBookmarkNode(&other
, model_
.get(), model_
->other_node());
992 PopulateNodeFromString(data
[i
].mobile_contents
, &mobile
);
993 PopulateBookmarkNode(&mobile
, model_
.get(), model_
->mobile_node());
995 VerifyModelMatchesNode(&bbn
, model_
->bookmark_bar_node());
996 VerifyModelMatchesNode(&other
, model_
->other_node());
997 VerifyModelMatchesNode(&mobile
, model_
->mobile_node());
998 VerifyNoDuplicateIDs(model_
.get());
1002 TEST_F(BookmarkModelTest
, Sort
) {
1003 // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'.
1004 // 'C' and 'a' are folders.
1006 PopulateNodeFromString("B [ a ] d [ a ]", &bbn
);
1007 const BookmarkNode
* parent
= model_
->bookmark_bar_node();
1008 PopulateBookmarkNode(&bbn
, model_
.get(), parent
);
1010 BookmarkNode
* child1
= AsMutable(parent
->GetChild(1));
1011 child1
->SetTitle(ASCIIToUTF16("a"));
1012 delete child1
->Remove(child1
->GetChild(0));
1013 BookmarkNode
* child3
= AsMutable(parent
->GetChild(3));
1014 child3
->SetTitle(ASCIIToUTF16("C"));
1015 delete child3
->Remove(child3
->GetChild(0));
1019 // Sort the children of the bookmark bar node.
1020 model_
->SortChildren(parent
);
1022 // Make sure we were notified.
1023 AssertObserverCount(0, 0, 0, 0, 0, 1, 0, 0, 1, 0);
1025 // Make sure the order matches (remember, 'a' and 'C' are folders and
1027 EXPECT_EQ(parent
->GetChild(0)->GetTitle(), ASCIIToUTF16("a"));
1028 EXPECT_EQ(parent
->GetChild(1)->GetTitle(), ASCIIToUTF16("C"));
1029 EXPECT_EQ(parent
->GetChild(2)->GetTitle(), ASCIIToUTF16("B"));
1030 EXPECT_EQ(parent
->GetChild(3)->GetTitle(), ASCIIToUTF16("d"));
1033 TEST_F(BookmarkModelTest
, Reorder
) {
1034 // Populate the bookmark bar node with nodes 'A', 'B', 'C' and 'D'.
1036 PopulateNodeFromString("A B C D", &bbn
);
1037 BookmarkNode
* parent
= AsMutable(model_
->bookmark_bar_node());
1038 PopulateBookmarkNode(&bbn
, model_
.get(), parent
);
1042 // Reorder bar node's bookmarks in reverse order.
1043 std::vector
<const BookmarkNode
*> new_order
;
1044 new_order
.push_back(parent
->GetChild(3));
1045 new_order
.push_back(parent
->GetChild(2));
1046 new_order
.push_back(parent
->GetChild(1));
1047 new_order
.push_back(parent
->GetChild(0));
1048 model_
->ReorderChildren(parent
, new_order
);
1050 // Make sure we were notified.
1051 AssertObserverCount(0, 0, 0, 0, 0, 1, 0, 0, 1, 0);
1053 // Make sure the order matches is correct (it should be reversed).
1054 ASSERT_EQ(4, parent
->child_count());
1055 EXPECT_EQ("D", base::UTF16ToASCII(parent
->GetChild(0)->GetTitle()));
1056 EXPECT_EQ("C", base::UTF16ToASCII(parent
->GetChild(1)->GetTitle()));
1057 EXPECT_EQ("B", base::UTF16ToASCII(parent
->GetChild(2)->GetTitle()));
1058 EXPECT_EQ("A", base::UTF16ToASCII(parent
->GetChild(3)->GetTitle()));
1061 TEST_F(BookmarkModelTest
, NodeVisibility
) {
1062 // Mobile node invisible by default
1063 EXPECT_TRUE(model_
->bookmark_bar_node()->IsVisible());
1064 EXPECT_TRUE(model_
->other_node()->IsVisible());
1065 EXPECT_FALSE(model_
->mobile_node()->IsVisible());
1067 // Visibility of permanent node can only be changed if they are not
1068 // forced to be visible by the client.
1069 model_
->SetPermanentNodeVisible(BookmarkNode::BOOKMARK_BAR
, false);
1070 EXPECT_TRUE(model_
->bookmark_bar_node()->IsVisible());
1071 model_
->SetPermanentNodeVisible(BookmarkNode::OTHER_NODE
, false);
1072 EXPECT_TRUE(model_
->other_node()->IsVisible());
1073 model_
->SetPermanentNodeVisible(BookmarkNode::MOBILE
, true);
1074 EXPECT_TRUE(model_
->mobile_node()->IsVisible());
1075 model_
->SetPermanentNodeVisible(BookmarkNode::MOBILE
, false);
1076 EXPECT_FALSE(model_
->mobile_node()->IsVisible());
1078 // Arbitrary node should be visible
1080 PopulateNodeFromString("B", &bbn
);
1081 const BookmarkNode
* parent
= model_
->mobile_node();
1082 PopulateBookmarkNode(&bbn
, model_
.get(), parent
);
1083 EXPECT_TRUE(parent
->GetChild(0)->IsVisible());
1085 // Mobile folder should be visible now that it has a child.
1086 EXPECT_TRUE(model_
->mobile_node()->IsVisible());
1089 TEST_F(BookmarkModelTest
, MobileNodeVisibileWithChildren
) {
1090 const BookmarkNode
* root
= model_
->mobile_node();
1091 const base::string16
title(ASCIIToUTF16("foo"));
1092 const GURL
url("http://foo.com");
1094 model_
->AddURL(root
, 0, title
, url
);
1095 EXPECT_TRUE(model_
->mobile_node()->IsVisible());
1098 TEST_F(BookmarkModelTest
, ExtensiveChangesObserver
) {
1099 AssertExtensiveChangesObserverCount(0, 0);
1100 EXPECT_FALSE(model_
->IsDoingExtensiveChanges());
1101 model_
->BeginExtensiveChanges();
1102 EXPECT_TRUE(model_
->IsDoingExtensiveChanges());
1103 AssertExtensiveChangesObserverCount(1, 0);
1104 model_
->EndExtensiveChanges();
1105 EXPECT_FALSE(model_
->IsDoingExtensiveChanges());
1106 AssertExtensiveChangesObserverCount(1, 1);
1109 TEST_F(BookmarkModelTest
, MultipleExtensiveChangesObserver
) {
1110 AssertExtensiveChangesObserverCount(0, 0);
1111 EXPECT_FALSE(model_
->IsDoingExtensiveChanges());
1112 model_
->BeginExtensiveChanges();
1113 EXPECT_TRUE(model_
->IsDoingExtensiveChanges());
1114 AssertExtensiveChangesObserverCount(1, 0);
1115 model_
->BeginExtensiveChanges();
1116 EXPECT_TRUE(model_
->IsDoingExtensiveChanges());
1117 AssertExtensiveChangesObserverCount(1, 0);
1118 model_
->EndExtensiveChanges();
1119 EXPECT_TRUE(model_
->IsDoingExtensiveChanges());
1120 AssertExtensiveChangesObserverCount(1, 0);
1121 model_
->EndExtensiveChanges();
1122 EXPECT_FALSE(model_
->IsDoingExtensiveChanges());
1123 AssertExtensiveChangesObserverCount(1, 1);
1126 // Verifies that IsBookmarked is true if any bookmark matches the given URL,
1127 // and that IsBookmarkedByUser is true only if at least one of the matching
1128 // bookmarks can be edited by the user.
1129 TEST_F(BookmarkModelTest
, IsBookmarked
) {
1130 // Reload the model with an extra node that is not editable by the user.
1131 BookmarkPermanentNode
* extra_node
= ReloadModelWithExtraNode();
1133 // "google.com" is a "user" bookmark.
1134 model_
->AddURL(model_
->other_node(), 0, base::ASCIIToUTF16("User"),
1135 GURL("http://google.com"));
1136 // "youtube.com" is not.
1137 model_
->AddURL(extra_node
, 0, base::ASCIIToUTF16("Extra"),
1138 GURL("http://youtube.com"));
1140 EXPECT_TRUE(model_
->IsBookmarked(GURL("http://google.com")));
1141 EXPECT_TRUE(model_
->IsBookmarked(GURL("http://youtube.com")));
1142 EXPECT_FALSE(model_
->IsBookmarked(GURL("http://reddit.com")));
1145 bookmarks::IsBookmarkedByUser(model_
.get(), GURL("http://google.com")));
1147 bookmarks::IsBookmarkedByUser(model_
.get(), GURL("http://youtube.com")));
1149 bookmarks::IsBookmarkedByUser(model_
.get(), GURL("http://reddit.com")));
1152 // Verifies that GetMostRecentlyAddedUserNodeForURL skips bookmarks that
1153 // are not owned by the user.
1154 TEST_F(BookmarkModelTest
, GetMostRecentlyAddedUserNodeForURLSkipsManagedNodes
) {
1155 // Reload the model with an extra node that is not editable by the user.
1156 BookmarkPermanentNode
* extra_node
= ReloadModelWithExtraNode();
1158 const base::string16 title
= base::ASCIIToUTF16("Title");
1159 const BookmarkNode
* user_parent
= model_
->other_node();
1160 const BookmarkNode
* managed_parent
= extra_node
;
1161 const GURL
url("http://google.com");
1163 // |url| is not bookmarked yet.
1164 EXPECT_TRUE(model_
->GetMostRecentlyAddedUserNodeForURL(url
) == NULL
);
1166 // Having a managed node doesn't count.
1167 model_
->AddURL(managed_parent
, 0, title
, url
);
1168 EXPECT_TRUE(model_
->GetMostRecentlyAddedUserNodeForURL(url
) == NULL
);
1170 // Now add a user node.
1171 const BookmarkNode
* user
= model_
->AddURL(user_parent
, 0, title
, url
);
1172 EXPECT_EQ(user
, model_
->GetMostRecentlyAddedUserNodeForURL(url
));
1174 // Having a more recent managed node doesn't count either.
1175 const BookmarkNode
* managed
= model_
->AddURL(managed_parent
, 0, title
, url
);
1176 EXPECT_GE(managed
->date_added(), user
->date_added());
1177 EXPECT_EQ(user
, model_
->GetMostRecentlyAddedUserNodeForURL(url
));
1180 TEST(BookmarkNodeTest
, NodeMetaInfo
) {
1182 BookmarkNode
node(url
);
1183 EXPECT_FALSE(node
.GetMetaInfoMap());
1185 EXPECT_TRUE(node
.SetMetaInfo("key1", "value1"));
1186 std::string out_value
;
1187 EXPECT_TRUE(node
.GetMetaInfo("key1", &out_value
));
1188 EXPECT_EQ("value1", out_value
);
1189 EXPECT_FALSE(node
.SetMetaInfo("key1", "value1"));
1191 EXPECT_FALSE(node
.GetMetaInfo("key2.subkey1", &out_value
));
1192 EXPECT_TRUE(node
.SetMetaInfo("key2.subkey1", "value2"));
1193 EXPECT_TRUE(node
.GetMetaInfo("key2.subkey1", &out_value
));
1194 EXPECT_EQ("value2", out_value
);
1196 EXPECT_FALSE(node
.GetMetaInfo("key2.subkey2.leaf", &out_value
));
1197 EXPECT_TRUE(node
.SetMetaInfo("key2.subkey2.leaf", ""));
1198 EXPECT_TRUE(node
.GetMetaInfo("key2.subkey2.leaf", &out_value
));
1199 EXPECT_EQ("", out_value
);
1201 EXPECT_TRUE(node
.DeleteMetaInfo("key1"));
1202 EXPECT_TRUE(node
.DeleteMetaInfo("key2.subkey1"));
1203 EXPECT_TRUE(node
.DeleteMetaInfo("key2.subkey2.leaf"));
1204 EXPECT_FALSE(node
.DeleteMetaInfo("key3"));
1205 EXPECT_FALSE(node
.GetMetaInfo("key1", &out_value
));
1206 EXPECT_FALSE(node
.GetMetaInfo("key2.subkey1", &out_value
));
1207 EXPECT_FALSE(node
.GetMetaInfo("key2.subkey2", &out_value
));
1208 EXPECT_FALSE(node
.GetMetaInfo("key2.subkey2.leaf", &out_value
));
1209 EXPECT_FALSE(node
.GetMetaInfoMap());