Home | History | Annotate | Download | only in bookmarks
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
      9 #include "chrome/browser/bookmarks/bookmark_stats.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "chrome/test/base/browser_with_test_window_test.h"
     12 #include "chrome/test/base/testing_profile.h"
     13 #include "components/bookmarks/browser/bookmark_model.h"
     14 #include "components/bookmarks/test/bookmark_test_helpers.h"
     15 #include "ui/views/controls/menu/menu_item_view.h"
     16 #include "ui/views/controls/menu/menu_runner.h"
     17 #include "ui/views/controls/menu/submenu_view.h"
     18 
     19 using base::ASCIIToUTF16;
     20 
     21 class BookmarkMenuDelegateTest : public BrowserWithTestWindowTest {
     22  public:
     23   BookmarkMenuDelegateTest() : model_(NULL) {}
     24 
     25   virtual void SetUp() OVERRIDE {
     26     BrowserWithTestWindowTest::SetUp();
     27 
     28     profile()->CreateBookmarkModel(true);
     29 
     30     model_ = BookmarkModelFactory::GetForProfile(profile());
     31     test::WaitForBookmarkModelToLoad(model_);
     32 
     33     AddTestData();
     34   }
     35 
     36   virtual void TearDown() OVERRIDE {
     37     if (bookmark_menu_delegate_.get()) {
     38       // Since we never show the menu we need to pass the MenuItemView to
     39       // MenuRunner so that the MenuItemView is destroyed.
     40       views::MenuRunner menu_runner(bookmark_menu_delegate_->menu());
     41       bookmark_menu_delegate_.reset();
     42     }
     43     BrowserWithTestWindowTest::TearDown();
     44   }
     45 
     46  protected:
     47   void NewDelegate(int min_menu_id, int max_menu_id) {
     48     // Destroy current menu if available, see comments in TearDown().
     49     if (bookmark_menu_delegate_.get())
     50       views::MenuRunner menu_runner(bookmark_menu_delegate_->menu());
     51 
     52     bookmark_menu_delegate_.reset(
     53         new BookmarkMenuDelegate(browser(), NULL, NULL,
     54                                  min_menu_id, max_menu_id));
     55   }
     56 
     57   void NewAndInitDelegateForPermanent(int min_menu_id,
     58                                       int max_menu_id) {
     59     const BookmarkNode* node = model_->bookmark_bar_node();
     60     NewDelegate(min_menu_id, max_menu_id);
     61     bookmark_menu_delegate_->Init(&test_delegate_, NULL, node, 0,
     62                                   BookmarkMenuDelegate::SHOW_PERMANENT_FOLDERS,
     63                                   BOOKMARK_LAUNCH_LOCATION_NONE);
     64   }
     65 
     66   BookmarkModel* model_;
     67 
     68   scoped_ptr<BookmarkMenuDelegate> bookmark_menu_delegate_;
     69 
     70  private:
     71   std::string base_path() const { return "file:///c:/tmp/"; }
     72 
     73   // Creates the following structure:
     74   // bookmark bar node
     75   //   a
     76   //   F1
     77   //    f1a
     78   //    F11
     79   //     f11a
     80   //   F2
     81   // other node
     82   //   oa
     83   //   OF1
     84   //     of1a
     85   void AddTestData() {
     86     const BookmarkNode* bb_node = model_->bookmark_bar_node();
     87     std::string test_base = base_path();
     88     model_->AddURL(bb_node, 0, ASCIIToUTF16("a"), GURL(test_base + "a"));
     89     const BookmarkNode* f1 = model_->AddFolder(bb_node, 1, ASCIIToUTF16("F1"));
     90     model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
     91     const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11"));
     92     model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
     93     model_->AddFolder(bb_node, 2, ASCIIToUTF16("F2"));
     94 
     95     // Children of the other node.
     96     model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
     97                    GURL(test_base + "oa"));
     98     const BookmarkNode* of1 =
     99         model_->AddFolder(model_->other_node(), 1, ASCIIToUTF16("OF1"));
    100     model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a"));
    101   }
    102 
    103   views::MenuDelegate test_delegate_;
    104 
    105   DISALLOW_COPY_AND_ASSIGN(BookmarkMenuDelegateTest);
    106 };
    107 
    108 // Verifies WillRemoveBookmarks() doesn't attempt to access MenuItemViews that
    109 // have since been deleted.
    110 TEST_F(BookmarkMenuDelegateTest, RemoveBookmarks) {
    111   views::MenuDelegate test_delegate;
    112   const BookmarkNode* node = model_->bookmark_bar_node()->GetChild(1);
    113   NewDelegate(0, kint32max);
    114   bookmark_menu_delegate_->Init(&test_delegate, NULL, node, 0,
    115                                 BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
    116                                 BOOKMARK_LAUNCH_LOCATION_NONE);
    117   std::vector<const BookmarkNode*> nodes_to_remove;
    118   nodes_to_remove.push_back(node->GetChild(1));
    119   bookmark_menu_delegate_->WillRemoveBookmarks(nodes_to_remove);
    120   nodes_to_remove.clear();
    121   bookmark_menu_delegate_->DidRemoveBookmarks();
    122 }
    123 
    124 // Verifies menu ID's of items in menu fall within the specified range.
    125 TEST_F(BookmarkMenuDelegateTest, MenuIdRange) {
    126   // Start with maximum menu Id of 10 - the number of items that AddTestData()
    127   // populated.  Everything should be created.
    128   NewAndInitDelegateForPermanent(0, 10);
    129   views::MenuItemView* root_item = bookmark_menu_delegate_->menu();
    130   ASSERT_TRUE(root_item->HasSubmenu());
    131   EXPECT_EQ(4, root_item->GetSubmenu()->GetMenuItemCount());
    132   EXPECT_EQ(5, root_item->GetSubmenu()->child_count());  // Includes separator.
    133   views::MenuItemView* F1_item = root_item->GetSubmenu()->GetMenuItemAt(1);
    134   ASSERT_TRUE(F1_item->HasSubmenu());
    135   EXPECT_EQ(2, F1_item->GetSubmenu()->GetMenuItemCount());
    136   views::MenuItemView* F11_item = F1_item->GetSubmenu()->GetMenuItemAt(1);
    137   ASSERT_TRUE(F11_item->HasSubmenu());
    138   EXPECT_EQ(1, F11_item->GetSubmenu()->GetMenuItemCount());
    139   views::MenuItemView* other_item = root_item->GetSubmenu()->GetMenuItemAt(3);
    140   ASSERT_TRUE(other_item->HasSubmenu());
    141   EXPECT_EQ(2, other_item->GetSubmenu()->GetMenuItemCount());
    142   views::MenuItemView* OF1_item = other_item->GetSubmenu()->GetMenuItemAt(1);
    143   ASSERT_TRUE(OF1_item->HasSubmenu());
    144   EXPECT_EQ(1, OF1_item->GetSubmenu()->GetMenuItemCount());
    145 
    146   // Reduce maximum 9.  "of1a" item should not be created.
    147   NewAndInitDelegateForPermanent(0, 9);
    148   root_item = bookmark_menu_delegate_->menu();
    149   EXPECT_EQ(4, root_item->GetSubmenu()->GetMenuItemCount());
    150   EXPECT_EQ(5, root_item->GetSubmenu()->child_count());  // Includes separator.
    151   other_item = root_item->GetSubmenu()->GetMenuItemAt(3);
    152   OF1_item = other_item->GetSubmenu()->GetMenuItemAt(1);
    153   EXPECT_EQ(0, OF1_item->GetSubmenu()->GetMenuItemCount());
    154 
    155   // Reduce maximum 8.  "OF1" submenu should not be created.
    156   NewAndInitDelegateForPermanent(0, 8);
    157   root_item = bookmark_menu_delegate_->menu();
    158   EXPECT_EQ(4, root_item->GetSubmenu()->GetMenuItemCount());
    159   EXPECT_EQ(5, root_item->GetSubmenu()->child_count());  // Includes separator.
    160   other_item = root_item->GetSubmenu()->GetMenuItemAt(3);
    161   EXPECT_EQ(1, other_item->GetSubmenu()->GetMenuItemCount());
    162 
    163   // Reduce maximum 7.  "Other" submenu should be empty.
    164   NewAndInitDelegateForPermanent(0, 7);
    165   root_item = bookmark_menu_delegate_->menu();
    166   EXPECT_EQ(4, root_item->GetSubmenu()->GetMenuItemCount());
    167   EXPECT_EQ(5, root_item->GetSubmenu()->child_count());  // Includes separator.
    168   other_item = root_item->GetSubmenu()->GetMenuItemAt(3);
    169   EXPECT_EQ(0, other_item->GetSubmenu()->GetMenuItemCount());
    170 
    171   // Reduce maximum to 6.  "Other" submenu should not be created, and no
    172   // separator.
    173   NewAndInitDelegateForPermanent(0, 6);
    174   root_item = bookmark_menu_delegate_->menu();
    175   EXPECT_EQ(3, root_item->GetSubmenu()->GetMenuItemCount());
    176   EXPECT_EQ(3, root_item->GetSubmenu()->child_count());  // No separator.
    177 
    178   // Reduce maximum 5.  "F2" and "Other" submenus shouldn't be created.
    179   NewAndInitDelegateForPermanent(0, 5);
    180   root_item = bookmark_menu_delegate_->menu();
    181   EXPECT_EQ(2, root_item->GetSubmenu()->GetMenuItemCount());
    182   EXPECT_EQ(2, root_item->GetSubmenu()->child_count());  // No separator.
    183   F1_item = root_item->GetSubmenu()->GetMenuItemAt(1);
    184   F11_item = F1_item->GetSubmenu()->GetMenuItemAt(1);
    185   EXPECT_EQ(1, F11_item->GetSubmenu()->GetMenuItemCount());
    186 
    187   // Reduce maximum to 4.  "f11a" item and "F2" and "Other" submenus should
    188   // not be created.
    189   NewAndInitDelegateForPermanent(0, 4);
    190   root_item = bookmark_menu_delegate_->menu();
    191   EXPECT_EQ(2, root_item->GetSubmenu()->GetMenuItemCount());
    192   EXPECT_EQ(2, root_item->GetSubmenu()->child_count());  // No separator.
    193   F1_item = root_item->GetSubmenu()->GetMenuItemAt(1);
    194   F11_item = F1_item->GetSubmenu()->GetMenuItemAt(1);
    195   EXPECT_EQ(0, F11_item->GetSubmenu()->GetMenuItemCount());
    196 
    197   // Reduce maximum to 3.  "F11", "F2" and "Other" submenus should not be
    198   // created.
    199   NewAndInitDelegateForPermanent(0, 3);
    200   root_item = bookmark_menu_delegate_->menu();
    201   EXPECT_EQ(2, root_item->GetSubmenu()->GetMenuItemCount());
    202   EXPECT_EQ(2, root_item->GetSubmenu()->child_count());  // No separator.
    203   F1_item = root_item->GetSubmenu()->GetMenuItemAt(1);
    204   EXPECT_EQ(views::MenuItemView::SUBMENU, F1_item->GetType());
    205   EXPECT_EQ(1, F1_item->GetSubmenu()->GetMenuItemCount());
    206 
    207   // Reduce maximum 2.  Only "a" item and empty "F1" submenu should be created.
    208   NewAndInitDelegateForPermanent(0, 2);
    209   root_item = bookmark_menu_delegate_->menu();
    210   EXPECT_EQ(2, root_item->GetSubmenu()->GetMenuItemCount());
    211   EXPECT_EQ(2, root_item->GetSubmenu()->child_count());  // No separator.
    212   F1_item = root_item->GetSubmenu()->GetMenuItemAt(1);
    213   EXPECT_EQ(views::MenuItemView::SUBMENU, F1_item->GetType());
    214   EXPECT_EQ(0, F1_item->GetSubmenu()->GetMenuItemCount());
    215 
    216   // Reduce maximum to 1.  Only "a" item should be created.
    217   NewAndInitDelegateForPermanent(0, 1);
    218   root_item = bookmark_menu_delegate_->menu();
    219   EXPECT_EQ(1, root_item->GetSubmenu()->GetMenuItemCount());
    220   EXPECT_EQ(1, root_item->GetSubmenu()->child_count());  // No separator.
    221 
    222   // Verify correct handling of integer overflow with range, set kint32max as
    223   // maximum and 1 less as minimum.  Only "a" item should be created.
    224   NewAndInitDelegateForPermanent(kint32max - 1, kint32max);
    225   root_item = bookmark_menu_delegate_->menu();
    226   EXPECT_EQ(1, root_item->GetSubmenu()->GetMenuItemCount());
    227   EXPECT_EQ(1, root_item->GetSubmenu()->child_count());  // No separator.
    228 }
    229