Home | History | Annotate | Download | only in browser
      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.
      4 
      5 #include "components/bookmarks/browser/bookmark_utils.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
     12 #include "components/bookmarks/browser/bookmark_model.h"
     13 #include "components/bookmarks/browser/bookmark_node_data.h"
     14 #include "components/bookmarks/test/test_bookmark_client.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #include "ui/base/clipboard/clipboard.h"
     17 #include "ui/base/clipboard/scoped_clipboard_writer.h"
     18 
     19 using base::ASCIIToUTF16;
     20 using std::string;
     21 
     22 namespace bookmarks {
     23 namespace {
     24 
     25 class BookmarkUtilsTest : public testing::Test,
     26                           public BaseBookmarkModelObserver {
     27  public:
     28   BookmarkUtilsTest()
     29       : grouped_changes_beginning_count_(0),
     30         grouped_changes_ended_count_(0) {}
     31   virtual ~BookmarkUtilsTest() {}
     32 
     33 // Copy and paste is not yet supported on iOS. http://crbug.com/228147
     34 #if !defined(OS_IOS)
     35   virtual void TearDown() OVERRIDE {
     36     ui::Clipboard::DestroyClipboardForCurrentThread();
     37   }
     38 #endif  // !defined(OS_IOS)
     39 
     40   // Certain user actions require multiple changes to the bookmark model,
     41   // however these modifications need to be atomic for the undo framework. The
     42   // BaseBookmarkModelObserver is used to inform the boundaries of the user
     43   // action. For example, when multiple bookmarks are cut to the clipboard we
     44   // expect one call each to GroupedBookmarkChangesBeginning/Ended.
     45   void ExpectGroupedChangeCount(int expected_beginning_count,
     46                                 int expected_ended_count) {
     47     // The undo framework is not used under Android.  Thus the group change
     48     // events will not be fired and so should not be tested for Android.
     49 #if !defined(OS_ANDROID)
     50     EXPECT_EQ(grouped_changes_beginning_count_, expected_beginning_count);
     51     EXPECT_EQ(grouped_changes_ended_count_, expected_ended_count);
     52 #endif
     53   }
     54 
     55  private:
     56   // BaseBookmarkModelObserver:
     57   virtual void BookmarkModelChanged() OVERRIDE {}
     58 
     59   virtual void GroupedBookmarkChangesBeginning(BookmarkModel* model) OVERRIDE {
     60     ++grouped_changes_beginning_count_;
     61   }
     62 
     63   virtual void GroupedBookmarkChangesEnded(BookmarkModel* model) OVERRIDE {
     64     ++grouped_changes_ended_count_;
     65   }
     66 
     67   int grouped_changes_beginning_count_;
     68   int grouped_changes_ended_count_;
     69 
     70   // Clipboard requires a message loop.
     71   base::MessageLoopForUI loop_;
     72 
     73   DISALLOW_COPY_AND_ASSIGN(BookmarkUtilsTest);
     74 };
     75 
     76 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesWordPhraseQuery) {
     77   TestBookmarkClient client;
     78   scoped_ptr<BookmarkModel> model(client.CreateModel());
     79   const BookmarkNode* node1 = model->AddURL(model->other_node(),
     80                                             0,
     81                                             ASCIIToUTF16("foo bar"),
     82                                             GURL("http://www.google.com"));
     83   const BookmarkNode* node2 = model->AddURL(model->other_node(),
     84                                             0,
     85                                             ASCIIToUTF16("baz buz"),
     86                                             GURL("http://www.cnn.com"));
     87   const BookmarkNode* folder1 =
     88       model->AddFolder(model->other_node(), 0, ASCIIToUTF16("foo"));
     89   std::vector<const BookmarkNode*> nodes;
     90   QueryFields query;
     91   query.word_phrase_query.reset(new base::string16);
     92   // No nodes are returned for empty string.
     93   *query.word_phrase_query = ASCIIToUTF16("");
     94   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
     95   EXPECT_TRUE(nodes.empty());
     96   nodes.clear();
     97 
     98   // No nodes are returned for space-only string.
     99   *query.word_phrase_query = ASCIIToUTF16("   ");
    100   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    101   EXPECT_TRUE(nodes.empty());
    102   nodes.clear();
    103 
    104   // Node "foo bar" and folder "foo" are returned in search results.
    105   *query.word_phrase_query = ASCIIToUTF16("foo");
    106   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    107   ASSERT_EQ(2U, nodes.size());
    108   EXPECT_TRUE(nodes[0] == folder1);
    109   EXPECT_TRUE(nodes[1] == node1);
    110   nodes.clear();
    111 
    112   // Ensure url matches return in search results.
    113   *query.word_phrase_query = ASCIIToUTF16("cnn");
    114   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    115   ASSERT_EQ(1U, nodes.size());
    116   EXPECT_TRUE(nodes[0] == node2);
    117   nodes.clear();
    118 
    119   // Ensure folder "foo" is not returned in more specific search.
    120   *query.word_phrase_query = ASCIIToUTF16("foo bar");
    121   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    122   ASSERT_EQ(1U, nodes.size());
    123   EXPECT_TRUE(nodes[0] == node1);
    124   nodes.clear();
    125 
    126   // Bookmark Bar and Other Bookmarks are not returned in search results.
    127   *query.word_phrase_query = ASCIIToUTF16("Bookmark");
    128   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    129   ASSERT_EQ(0U, nodes.size());
    130   nodes.clear();
    131 }
    132 
    133 // Check exact matching against a URL query.
    134 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesUrl) {
    135   TestBookmarkClient client;
    136   scoped_ptr<BookmarkModel> model(client.CreateModel());
    137   const BookmarkNode* node1 = model->AddURL(model->other_node(),
    138                                             0,
    139                                             ASCIIToUTF16("Google"),
    140                                             GURL("https://www.google.com/"));
    141   model->AddURL(model->other_node(),
    142                 0,
    143                 ASCIIToUTF16("Google Calendar"),
    144                 GURL("https://www.google.com/calendar"));
    145 
    146   model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder"));
    147 
    148   std::vector<const BookmarkNode*> nodes;
    149   QueryFields query;
    150   query.url.reset(new base::string16);
    151   *query.url = ASCIIToUTF16("https://www.google.com/");
    152   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    153   ASSERT_EQ(1U, nodes.size());
    154   EXPECT_TRUE(nodes[0] == node1);
    155   nodes.clear();
    156 
    157   *query.url = ASCIIToUTF16("calendar");
    158   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    159   ASSERT_EQ(0U, nodes.size());
    160   nodes.clear();
    161 
    162   // Empty URL should not match folders.
    163   *query.url = ASCIIToUTF16("");
    164   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    165   ASSERT_EQ(0U, nodes.size());
    166   nodes.clear();
    167 }
    168 
    169 // Check exact matching against a title query.
    170 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesTitle) {
    171   TestBookmarkClient client;
    172   scoped_ptr<BookmarkModel> model(client.CreateModel());
    173   const BookmarkNode* node1 = model->AddURL(model->other_node(),
    174                                             0,
    175                                             ASCIIToUTF16("Google"),
    176                                             GURL("https://www.google.com/"));
    177   model->AddURL(model->other_node(),
    178                 0,
    179                 ASCIIToUTF16("Google Calendar"),
    180                 GURL("https://www.google.com/calendar"));
    181 
    182   const BookmarkNode* folder1 =
    183       model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder"));
    184 
    185   std::vector<const BookmarkNode*> nodes;
    186   QueryFields query;
    187   query.title.reset(new base::string16);
    188   *query.title = ASCIIToUTF16("Google");
    189   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    190   ASSERT_EQ(1U, nodes.size());
    191   EXPECT_TRUE(nodes[0] == node1);
    192   nodes.clear();
    193 
    194   *query.title = ASCIIToUTF16("Calendar");
    195   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    196   ASSERT_EQ(0U, nodes.size());
    197   nodes.clear();
    198 
    199   // Title should match folders.
    200   *query.title = ASCIIToUTF16("Folder");
    201   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    202   ASSERT_EQ(1U, nodes.size());
    203   EXPECT_TRUE(nodes[0] == folder1);
    204   nodes.clear();
    205 }
    206 
    207 // Check matching against a query with multiple predicates.
    208 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesConjunction) {
    209   TestBookmarkClient client;
    210   scoped_ptr<BookmarkModel> model(client.CreateModel());
    211   const BookmarkNode* node1 = model->AddURL(model->other_node(),
    212                                             0,
    213                                             ASCIIToUTF16("Google"),
    214                                             GURL("https://www.google.com/"));
    215   model->AddURL(model->other_node(),
    216                 0,
    217                 ASCIIToUTF16("Google Calendar"),
    218                 GURL("https://www.google.com/calendar"));
    219 
    220   model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder"));
    221 
    222   std::vector<const BookmarkNode*> nodes;
    223   QueryFields query;
    224 
    225   // Test all fields matching.
    226   query.word_phrase_query.reset(new base::string16(ASCIIToUTF16("www")));
    227   query.url.reset(new base::string16(ASCIIToUTF16("https://www.google.com/")));
    228   query.title.reset(new base::string16(ASCIIToUTF16("Google")));
    229   GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    230   ASSERT_EQ(1U, nodes.size());
    231   EXPECT_TRUE(nodes[0] == node1);
    232   nodes.clear();
    233 
    234   scoped_ptr<base::string16>* fields[] = {
    235     &query.word_phrase_query, &query.url, &query.title };
    236 
    237   // Test two fields matching.
    238   for (size_t i = 0; i < arraysize(fields); i++) {
    239     scoped_ptr<base::string16> original_value(fields[i]->release());
    240     GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    241     ASSERT_EQ(1U, nodes.size());
    242     EXPECT_TRUE(nodes[0] == node1);
    243     nodes.clear();
    244     fields[i]->reset(original_value.release());
    245   }
    246 
    247   // Test two fields matching with one non-matching field.
    248   for (size_t i = 0; i < arraysize(fields); i++) {
    249     scoped_ptr<base::string16> original_value(fields[i]->release());
    250     fields[i]->reset(new base::string16(ASCIIToUTF16("fjdkslafjkldsa")));
    251     GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes);
    252     ASSERT_EQ(0U, nodes.size());
    253     nodes.clear();
    254     fields[i]->reset(original_value.release());
    255   }
    256 }
    257 
    258 // Copy and paste is not yet supported on iOS. http://crbug.com/228147
    259 #if !defined(OS_IOS)
    260 TEST_F(BookmarkUtilsTest, PasteBookmarkFromURL) {
    261   TestBookmarkClient client;
    262   scoped_ptr<BookmarkModel> model(client.CreateModel());
    263   const base::string16 url_text = ASCIIToUTF16("http://www.google.com/");
    264   const BookmarkNode* new_folder = model->AddFolder(
    265       model->bookmark_bar_node(), 0, ASCIIToUTF16("New_Folder"));
    266 
    267   // Write blank text to clipboard.
    268   {
    269     ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
    270     clipboard_writer.WriteText(base::string16());
    271   }
    272   // Now we shouldn't be able to paste from the clipboard.
    273   EXPECT_FALSE(CanPasteFromClipboard(model.get(), new_folder));
    274 
    275   // Write some valid url to the clipboard.
    276   {
    277     ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
    278     clipboard_writer.WriteText(url_text);
    279   }
    280   // Now we should be able to paste from the clipboard.
    281   EXPECT_TRUE(CanPasteFromClipboard(model.get(), new_folder));
    282 
    283   PasteFromClipboard(model.get(), new_folder, 0);
    284   ASSERT_EQ(1, new_folder->child_count());
    285 
    286   // Url for added node should be same as url_text.
    287   EXPECT_EQ(url_text, ASCIIToUTF16(new_folder->GetChild(0)->url().spec()));
    288 }
    289 
    290 TEST_F(BookmarkUtilsTest, CopyPaste) {
    291   TestBookmarkClient client;
    292   scoped_ptr<BookmarkModel> model(client.CreateModel());
    293   const BookmarkNode* node = model->AddURL(model->other_node(),
    294                                            0,
    295                                            ASCIIToUTF16("foo bar"),
    296                                            GURL("http://www.google.com"));
    297 
    298   // Copy a node to the clipboard.
    299   std::vector<const BookmarkNode*> nodes;
    300   nodes.push_back(node);
    301   CopyToClipboard(model.get(), nodes, false);
    302 
    303   // And make sure we can paste a bookmark from the clipboard.
    304   EXPECT_TRUE(CanPasteFromClipboard(model.get(), model->bookmark_bar_node()));
    305 
    306   // Write some text to the clipboard.
    307   {
    308     ui::ScopedClipboardWriter clipboard_writer(
    309         ui::CLIPBOARD_TYPE_COPY_PASTE);
    310     clipboard_writer.WriteText(ASCIIToUTF16("foo"));
    311   }
    312 
    313   // Now we shouldn't be able to paste from the clipboard.
    314   EXPECT_FALSE(CanPasteFromClipboard(model.get(), model->bookmark_bar_node()));
    315 }
    316 
    317 TEST_F(BookmarkUtilsTest, CopyPasteMetaInfo) {
    318   TestBookmarkClient client;
    319   scoped_ptr<BookmarkModel> model(client.CreateModel());
    320   const BookmarkNode* node = model->AddURL(model->other_node(),
    321                                            0,
    322                                            ASCIIToUTF16("foo bar"),
    323                                            GURL("http://www.google.com"));
    324   model->SetNodeMetaInfo(node, "somekey", "somevalue");
    325   model->SetNodeMetaInfo(node, "someotherkey", "someothervalue");
    326 
    327   // Copy a node to the clipboard.
    328   std::vector<const BookmarkNode*> nodes;
    329   nodes.push_back(node);
    330   CopyToClipboard(model.get(), nodes, false);
    331 
    332   // Paste node to a different folder.
    333   const BookmarkNode* folder =
    334       model->AddFolder(model->bookmark_bar_node(), 0, ASCIIToUTF16("Folder"));
    335   EXPECT_EQ(0, folder->child_count());
    336 
    337   // And make sure we can paste a bookmark from the clipboard.
    338   EXPECT_TRUE(CanPasteFromClipboard(model.get(), folder));
    339 
    340   PasteFromClipboard(model.get(), folder, 0);
    341   ASSERT_EQ(1, folder->child_count());
    342 
    343   // Verify that the pasted node contains the same meta info.
    344   const BookmarkNode* pasted = folder->GetChild(0);
    345   ASSERT_TRUE(pasted->GetMetaInfoMap());
    346   EXPECT_EQ(2u, pasted->GetMetaInfoMap()->size());
    347   std::string value;
    348   EXPECT_TRUE(pasted->GetMetaInfo("somekey", &value));
    349   EXPECT_EQ("somevalue", value);
    350   EXPECT_TRUE(pasted->GetMetaInfo("someotherkey", &value));
    351   EXPECT_EQ("someothervalue", value);
    352 }
    353 
    354 #if defined(OS_LINUX) || defined(OS_MACOSX)
    355 // http://crbug.com/396472
    356 #define MAYBE_CutToClipboard DISABLED_CutToClipboard
    357 #else
    358 #define MAYBE_CutToClipboard CutToClipboard
    359 #endif
    360 TEST_F(BookmarkUtilsTest, MAYBE_CutToClipboard) {
    361   TestBookmarkClient client;
    362   scoped_ptr<BookmarkModel> model(client.CreateModel());
    363   model->AddObserver(this);
    364 
    365   base::string16 title(ASCIIToUTF16("foo"));
    366   GURL url("http://foo.com");
    367   const BookmarkNode* n1 = model->AddURL(model->other_node(), 0, title, url);
    368   const BookmarkNode* n2 = model->AddURL(model->other_node(), 1, title, url);
    369 
    370   // Cut the nodes to the clipboard.
    371   std::vector<const BookmarkNode*> nodes;
    372   nodes.push_back(n1);
    373   nodes.push_back(n2);
    374   CopyToClipboard(model.get(), nodes, true);
    375 
    376   // Make sure the nodes were removed.
    377   EXPECT_EQ(0, model->other_node()->child_count());
    378 
    379   // Make sure observers were notified the set of changes should be grouped.
    380   ExpectGroupedChangeCount(1, 1);
    381 
    382   // And make sure we can paste from the clipboard.
    383   EXPECT_TRUE(CanPasteFromClipboard(model.get(), model->other_node()));
    384 }
    385 
    386 TEST_F(BookmarkUtilsTest, PasteNonEditableNodes) {
    387   TestBookmarkClient client;
    388   // Load a model with an extra node that is not editable.
    389   BookmarkPermanentNode* extra_node = new BookmarkPermanentNode(100);
    390   BookmarkPermanentNodeList extra_nodes;
    391   extra_nodes.push_back(extra_node);
    392   client.SetExtraNodesToLoad(extra_nodes.Pass());
    393 
    394   scoped_ptr<BookmarkModel> model(client.CreateModel());
    395   const BookmarkNode* node = model->AddURL(model->other_node(),
    396                                            0,
    397                                            ASCIIToUTF16("foo bar"),
    398                                            GURL("http://www.google.com"));
    399 
    400   // Copy a node to the clipboard.
    401   std::vector<const BookmarkNode*> nodes;
    402   nodes.push_back(node);
    403   CopyToClipboard(model.get(), nodes, false);
    404 
    405   // And make sure we can paste a bookmark from the clipboard.
    406   EXPECT_TRUE(CanPasteFromClipboard(model.get(), model->bookmark_bar_node()));
    407 
    408   // But it can't be pasted into a non-editable folder.
    409   BookmarkClient* upcast = &client;
    410   EXPECT_FALSE(upcast->CanBeEditedByUser(extra_node));
    411   EXPECT_FALSE(CanPasteFromClipboard(model.get(), extra_node));
    412 }
    413 #endif  // !defined(OS_IOS)
    414 
    415 TEST_F(BookmarkUtilsTest, GetParentForNewNodes) {
    416   TestBookmarkClient client;
    417   scoped_ptr<BookmarkModel> model(client.CreateModel());
    418   // This tests the case where selection contains one item and that item is a
    419   // folder.
    420   std::vector<const BookmarkNode*> nodes;
    421   nodes.push_back(model->bookmark_bar_node());
    422   int index = -1;
    423   const BookmarkNode* real_parent =
    424       GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index);
    425   EXPECT_EQ(real_parent, model->bookmark_bar_node());
    426   EXPECT_EQ(0, index);
    427 
    428   nodes.clear();
    429 
    430   // This tests the case where selection contains one item and that item is an
    431   // url.
    432   const BookmarkNode* page1 = model->AddURL(model->bookmark_bar_node(),
    433                                             0,
    434                                             ASCIIToUTF16("Google"),
    435                                             GURL("http://google.com"));
    436   nodes.push_back(page1);
    437   real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index);
    438   EXPECT_EQ(real_parent, model->bookmark_bar_node());
    439   EXPECT_EQ(1, index);
    440 
    441   // This tests the case where selection has more than one item.
    442   const BookmarkNode* folder1 =
    443       model->AddFolder(model->bookmark_bar_node(), 1, ASCIIToUTF16("Folder 1"));
    444   nodes.push_back(folder1);
    445   real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index);
    446   EXPECT_EQ(real_parent, model->bookmark_bar_node());
    447   EXPECT_EQ(2, index);
    448 
    449   // This tests the case where selection doesn't contain any items.
    450   nodes.clear();
    451   real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index);
    452   EXPECT_EQ(real_parent, model->bookmark_bar_node());
    453   EXPECT_EQ(2, index);
    454 }
    455 
    456 // Verifies that meta info is copied when nodes are cloned.
    457 TEST_F(BookmarkUtilsTest, CloneMetaInfo) {
    458   TestBookmarkClient client;
    459   scoped_ptr<BookmarkModel> model(client.CreateModel());
    460   // Add a node containing meta info.
    461   const BookmarkNode* node = model->AddURL(model->other_node(),
    462                                            0,
    463                                            ASCIIToUTF16("foo bar"),
    464                                            GURL("http://www.google.com"));
    465   model->SetNodeMetaInfo(node, "somekey", "somevalue");
    466   model->SetNodeMetaInfo(node, "someotherkey", "someothervalue");
    467 
    468   // Clone node to a different folder.
    469   const BookmarkNode* folder =
    470       model->AddFolder(model->bookmark_bar_node(), 0, ASCIIToUTF16("Folder"));
    471   std::vector<BookmarkNodeData::Element> elements;
    472   BookmarkNodeData::Element node_data(node);
    473   elements.push_back(node_data);
    474   EXPECT_EQ(0, folder->child_count());
    475   CloneBookmarkNode(model.get(), elements, folder, 0, false);
    476   ASSERT_EQ(1, folder->child_count());
    477 
    478   // Verify that the cloned node contains the same meta info.
    479   const BookmarkNode* clone = folder->GetChild(0);
    480   ASSERT_TRUE(clone->GetMetaInfoMap());
    481   EXPECT_EQ(2u, clone->GetMetaInfoMap()->size());
    482   std::string value;
    483   EXPECT_TRUE(clone->GetMetaInfo("somekey", &value));
    484   EXPECT_EQ("somevalue", value);
    485   EXPECT_TRUE(clone->GetMetaInfo("someotherkey", &value));
    486   EXPECT_EQ("someothervalue", value);
    487 }
    488 
    489 TEST_F(BookmarkUtilsTest, RemoveAllBookmarks) {
    490   TestBookmarkClient client;
    491   // Load a model with an extra node that is not editable.
    492   BookmarkPermanentNode* extra_node = new BookmarkPermanentNode(100);
    493   BookmarkPermanentNodeList extra_nodes;
    494   extra_nodes.push_back(extra_node);
    495   client.SetExtraNodesToLoad(extra_nodes.Pass());
    496 
    497   scoped_ptr<BookmarkModel> model(client.CreateModel());
    498   EXPECT_TRUE(model->bookmark_bar_node()->empty());
    499   EXPECT_TRUE(model->other_node()->empty());
    500   EXPECT_TRUE(model->mobile_node()->empty());
    501   EXPECT_TRUE(extra_node->empty());
    502 
    503   const base::string16 title = base::ASCIIToUTF16("Title");
    504   const GURL url("http://google.com");
    505   model->AddURL(model->bookmark_bar_node(), 0, title, url);
    506   model->AddURL(model->other_node(), 0, title, url);
    507   model->AddURL(model->mobile_node(), 0, title, url);
    508   model->AddURL(extra_node, 0, title, url);
    509 
    510   std::vector<const BookmarkNode*> nodes;
    511   model->GetNodesByURL(url, &nodes);
    512   ASSERT_EQ(4u, nodes.size());
    513 
    514   RemoveAllBookmarks(model.get(), url);
    515 
    516   nodes.clear();
    517   model->GetNodesByURL(url, &nodes);
    518   ASSERT_EQ(1u, nodes.size());
    519   EXPECT_TRUE(model->bookmark_bar_node()->empty());
    520   EXPECT_TRUE(model->other_node()->empty());
    521   EXPECT_TRUE(model->mobile_node()->empty());
    522   EXPECT_EQ(1, extra_node->child_count());
    523 }
    524 
    525 }  // namespace
    526 }  // namespace bookmarks
    527