1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/bookmarks/bookmark_context_menu_controller.h" 6 7#include <string> 8 9#include "base/memory/scoped_ptr.h" 10#include "base/message_loop/message_loop.h" 11#include "base/strings/utf_string_conversions.h" 12#include "base/values.h" 13#include "chrome/app/chrome_command_ids.h" 14#include "chrome/browser/bookmarks/bookmark_model_factory.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 17#include "chrome/common/pref_names.h" 18#include "chrome/test/base/testing_pref_service_syncable.h" 19#include "chrome/test/base/testing_profile.h" 20#include "components/bookmarks/browser/bookmark_model.h" 21#include "components/bookmarks/browser/bookmark_node.h" 22#include "components/bookmarks/test/bookmark_test_helpers.h" 23#include "content/public/browser/page_navigator.h" 24#include "content/public/test/test_browser_thread.h" 25#include "testing/gtest/include/gtest/gtest.h" 26#include "ui/base/clipboard/clipboard.h" 27 28using base::ASCIIToUTF16; 29using content::BrowserThread; 30using content::OpenURLParams; 31using content::PageNavigator; 32using content::WebContents; 33 34// PageNavigator implementation that records the URL. 35class TestingPageNavigator : public PageNavigator { 36 public: 37 virtual WebContents* OpenURL(const OpenURLParams& params) OVERRIDE { 38 urls_.push_back(params.url); 39 return NULL; 40 } 41 42 std::vector<GURL> urls_; 43}; 44 45class BookmarkContextMenuControllerTest : public testing::Test { 46 public: 47 BookmarkContextMenuControllerTest() 48 : ui_thread_(BrowserThread::UI, &message_loop_), 49 file_thread_(BrowserThread::FILE, &message_loop_), 50 model_(NULL) { 51 } 52 53 virtual void SetUp() OVERRIDE { 54 TestingProfile::Builder builder; 55 profile_ = builder.Build(); 56 profile_->CreateBookmarkModel(true); 57 model_ = BookmarkModelFactory::GetForProfile(profile_.get()); 58 test::WaitForBookmarkModelToLoad(model_); 59 AddTestData(model_); 60 } 61 62 virtual void TearDown() OVERRIDE { 63 ui::Clipboard::DestroyClipboardForCurrentThread(); 64 65 // Flush the message loop to make application verifiers happy. 66 message_loop_.RunUntilIdle(); 67 } 68 69 // Creates the following structure: 70 // a 71 // F1 72 // f1a 73 // F11 74 // f11a 75 // F2 76 // F3 77 // F4 78 // f4a 79 static void AddTestData(BookmarkModel* model) { 80 const BookmarkNode* bb_node = model->bookmark_bar_node(); 81 std::string test_base = "file:///c:/tmp/"; 82 model->AddURL(bb_node, 0, ASCIIToUTF16("a"), GURL(test_base + "a")); 83 const BookmarkNode* f1 = model->AddFolder(bb_node, 1, ASCIIToUTF16("F1")); 84 model->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a")); 85 const BookmarkNode* f11 = model->AddFolder(f1, 1, ASCIIToUTF16("F11")); 86 model->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a")); 87 model->AddFolder(bb_node, 2, ASCIIToUTF16("F2")); 88 model->AddFolder(bb_node, 3, ASCIIToUTF16("F3")); 89 const BookmarkNode* f4 = model->AddFolder(bb_node, 4, ASCIIToUTF16("F4")); 90 model->AddURL(f4, 0, ASCIIToUTF16("f4a"), GURL(test_base + "f4a")); 91 } 92 93 protected: 94 base::MessageLoopForUI message_loop_; 95 content::TestBrowserThread ui_thread_; 96 content::TestBrowserThread file_thread_; 97 scoped_ptr<TestingProfile> profile_; 98 BookmarkModel* model_; 99 TestingPageNavigator navigator_; 100}; 101 102// Tests Deleting from the menu. 103TEST_F(BookmarkContextMenuControllerTest, DeleteURL) { 104 std::vector<const BookmarkNode*> nodes; 105 nodes.push_back(model_->bookmark_bar_node()->GetChild(0)); 106 BookmarkContextMenuController controller( 107 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 108 GURL url = model_->bookmark_bar_node()->GetChild(0)->url(); 109 ASSERT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 110 // Delete the URL. 111 controller.ExecuteCommand(IDC_BOOKMARK_BAR_REMOVE, 0); 112 // Model shouldn't have URL anymore. 113 ASSERT_FALSE(model_->IsBookmarked(url)); 114} 115 116// Tests open all on a folder with a couple of bookmarks. 117TEST_F(BookmarkContextMenuControllerTest, OpenAll) { 118 const BookmarkNode* folder = model_->bookmark_bar_node()->GetChild(1); 119 chrome::OpenAll(NULL, &navigator_, folder, NEW_FOREGROUND_TAB, NULL); 120 121 // Should have navigated to F1's child, but not F11's child. 122 ASSERT_EQ(static_cast<size_t>(1), navigator_.urls_.size()); 123 ASSERT_TRUE(folder->GetChild(0)->url() == navigator_.urls_[0]); 124} 125 126// Tests the enabled state of the menus when supplied an empty vector. 127TEST_F(BookmarkContextMenuControllerTest, EmptyNodes) { 128 BookmarkContextMenuController controller( 129 NULL, NULL, NULL, profile_.get(), NULL, model_->other_node(), 130 std::vector<const BookmarkNode*>()); 131 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 132 EXPECT_FALSE( 133 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 134 EXPECT_FALSE( 135 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 136 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 137 EXPECT_TRUE( 138 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 139 EXPECT_TRUE( 140 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 141} 142 143// Tests the enabled state of the menus when supplied a vector with a single 144// url. 145TEST_F(BookmarkContextMenuControllerTest, SingleURL) { 146 std::vector<const BookmarkNode*> nodes; 147 nodes.push_back(model_->bookmark_bar_node()->GetChild(0)); 148 BookmarkContextMenuController controller( 149 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 150 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 151 EXPECT_TRUE( 152 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 153 EXPECT_TRUE( 154 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 155 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 156 EXPECT_TRUE( 157 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 158 EXPECT_TRUE( 159 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 160} 161 162// Tests the enabled state of the menus when supplied a vector with multiple 163// urls. 164TEST_F(BookmarkContextMenuControllerTest, MultipleURLs) { 165 std::vector<const BookmarkNode*> nodes; 166 nodes.push_back(model_->bookmark_bar_node()->GetChild(0)); 167 nodes.push_back(model_->bookmark_bar_node()->GetChild(1)->GetChild(0)); 168 BookmarkContextMenuController controller( 169 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 170 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 171 EXPECT_TRUE( 172 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 173 EXPECT_TRUE( 174 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 175 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 176 EXPECT_TRUE( 177 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 178 EXPECT_TRUE( 179 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 180} 181 182// Tests the enabled state of the menus when supplied an vector with a single 183// folder. 184TEST_F(BookmarkContextMenuControllerTest, SingleFolder) { 185 std::vector<const BookmarkNode*> nodes; 186 nodes.push_back(model_->bookmark_bar_node()->GetChild(2)); 187 BookmarkContextMenuController controller( 188 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 189 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 190 EXPECT_FALSE( 191 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 192 EXPECT_FALSE( 193 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 194 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 195 EXPECT_TRUE( 196 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 197 EXPECT_TRUE( 198 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 199} 200 201// Tests the enabled state of the menus when supplied a vector with multiple 202// folders, all of which are empty. 203TEST_F(BookmarkContextMenuControllerTest, MultipleEmptyFolders) { 204 std::vector<const BookmarkNode*> nodes; 205 nodes.push_back(model_->bookmark_bar_node()->GetChild(2)); 206 nodes.push_back(model_->bookmark_bar_node()->GetChild(3)); 207 BookmarkContextMenuController controller( 208 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 209 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 210 EXPECT_FALSE( 211 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 212 EXPECT_FALSE( 213 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 214 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 215 EXPECT_TRUE( 216 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 217 EXPECT_TRUE( 218 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 219} 220 221// Tests the enabled state of the menus when supplied a vector with multiple 222// folders, some of which contain URLs. 223TEST_F(BookmarkContextMenuControllerTest, MultipleFoldersWithURLs) { 224 std::vector<const BookmarkNode*> nodes; 225 nodes.push_back(model_->bookmark_bar_node()->GetChild(3)); 226 nodes.push_back(model_->bookmark_bar_node()->GetChild(4)); 227 BookmarkContextMenuController controller( 228 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 229 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 230 EXPECT_TRUE( 231 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 232 EXPECT_TRUE( 233 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 234 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 235 EXPECT_TRUE( 236 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 237 EXPECT_TRUE( 238 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 239} 240 241// Tests the enabled state of open incognito. 242TEST_F(BookmarkContextMenuControllerTest, DisableIncognito) { 243 TestingProfile* incognito = 244 TestingProfile::Builder().BuildIncognito(profile_.get()); 245 246 incognito->CreateBookmarkModel(true); 247 BookmarkModel* model = BookmarkModelFactory::GetForProfile(incognito); 248 test::WaitForBookmarkModelToLoad(model); 249 AddTestData(model); 250 251 std::vector<const BookmarkNode*> nodes; 252 nodes.push_back(model->bookmark_bar_node()->GetChild(0)); 253 BookmarkContextMenuController controller( 254 NULL, NULL, NULL, incognito, NULL, nodes[0]->parent(), nodes); 255 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO)); 256 EXPECT_FALSE( 257 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 258} 259 260// Tests that you can't remove/edit when showing the other node. 261TEST_F(BookmarkContextMenuControllerTest, DisabledItemsWithOtherNode) { 262 std::vector<const BookmarkNode*> nodes; 263 nodes.push_back(model_->other_node()); 264 BookmarkContextMenuController controller( 265 NULL, NULL, NULL, profile_.get(), NULL, nodes[0], nodes); 266 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_EDIT)); 267 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 268} 269 270// Tests the enabled state of the menus when supplied an empty vector and null 271// parent. 272TEST_F(BookmarkContextMenuControllerTest, EmptyNodesNullParent) { 273 BookmarkContextMenuController controller( 274 NULL, NULL, NULL, profile_.get(), NULL, NULL, 275 std::vector<const BookmarkNode*>()); 276 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 277 EXPECT_FALSE( 278 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 279 EXPECT_FALSE( 280 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 281 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 282 EXPECT_FALSE( 283 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 284 EXPECT_FALSE( 285 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 286} 287 288// Tests the enabled state of the menus when supplied a vector containing just 289// the top-level bookmark bar node. 290TEST_F(BookmarkContextMenuControllerTest, BookmarkBar) { 291 std::vector<const BookmarkNode*> nodes; 292 nodes.push_back(model_->bookmark_bar_node()); 293 BookmarkContextMenuController controller( 294 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes); 295 EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL)); 296 EXPECT_TRUE( 297 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW)); 298 EXPECT_TRUE( 299 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO)); 300 EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE)); 301 EXPECT_TRUE( 302 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK)); 303 EXPECT_TRUE( 304 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER)); 305} 306 307TEST_F(BookmarkContextMenuControllerTest, CutCopyPasteNode) { 308 const BookmarkNode* bb_node = model_->bookmark_bar_node(); 309 std::vector<const BookmarkNode*> nodes; 310 nodes.push_back(bb_node->GetChild(0)); 311 scoped_ptr<BookmarkContextMenuController> controller( 312 new BookmarkContextMenuController( 313 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes)); 314 EXPECT_TRUE(controller->IsCommandIdEnabled(IDC_COPY)); 315 EXPECT_TRUE(controller->IsCommandIdEnabled(IDC_CUT)); 316 317 // Copy the URL. 318 controller->ExecuteCommand(IDC_COPY, 0); 319 320 controller.reset(new BookmarkContextMenuController( 321 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes)); 322 int old_count = bb_node->child_count(); 323 controller->ExecuteCommand(IDC_PASTE, 0); 324 325 ASSERT_TRUE(bb_node->GetChild(1)->is_url()); 326 ASSERT_EQ(old_count + 1, bb_node->child_count()); 327 ASSERT_EQ(bb_node->GetChild(0)->url(), bb_node->GetChild(1)->url()); 328 329 controller.reset(new BookmarkContextMenuController( 330 NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes)); 331 // Cut the URL. 332 controller->ExecuteCommand(IDC_CUT, 0); 333 ASSERT_TRUE(bb_node->GetChild(0)->is_url()); 334 ASSERT_TRUE(bb_node->GetChild(1)->is_folder()); 335 ASSERT_EQ(old_count, bb_node->child_count()); 336} 337 338TEST_F(BookmarkContextMenuControllerTest, 339 ManagedShowAppsShortcutInBookmarksBar) { 340 BookmarkContextMenuController controller( 341 NULL, NULL, NULL, profile_.get(), NULL, model_->bookmark_bar_node(), 342 std::vector<const BookmarkNode*>()); 343 344 // By default, the pref is not managed and the command is enabled. 345 TestingPrefServiceSyncable* prefs = profile_->GetTestingPrefService(); 346 EXPECT_FALSE(prefs->IsManagedPreference( 347 bookmarks::prefs::kShowAppsShortcutInBookmarkBar)); 348 EXPECT_TRUE( 349 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT)); 350 351 // Disabling the shorcut by policy disables the command. 352 prefs->SetManagedPref(bookmarks::prefs::kShowAppsShortcutInBookmarkBar, 353 new base::FundamentalValue(false)); 354 EXPECT_FALSE( 355 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT)); 356 357 // And enabling the shortcut by policy disables the command too. 358 prefs->SetManagedPref(bookmarks::prefs::kShowAppsShortcutInBookmarkBar, 359 new base::FundamentalValue(true)); 360 EXPECT_FALSE( 361 controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT)); 362} 363