bookmark_context_menu_unittest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 "chrome/browser/ui/views/bookmarks/bookmark_context_menu.h"
6
7#include <string>
8#include <vector>
9
10#include "base/compiler_specific.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/prefs/pref_service.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/threading/sequenced_worker_pool.h"
15#include "base/values.h"
16#include "chrome/app/chrome_command_ids.h"
17#include "chrome/browser/bookmarks/bookmark_model_factory.h"
18#include "chrome/browser/bookmarks/chrome_bookmark_client.h"
19#include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
20#include "chrome/browser/profiles/profile.h"
21#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
22#include "chrome/common/pref_names.h"
23#include "chrome/test/base/testing_profile.h"
24#include "components/bookmarks/browser/bookmark_model.h"
25#include "components/bookmarks/test/bookmark_test_helpers.h"
26#include "content/public/browser/page_navigator.h"
27#include "content/public/test/test_browser_thread.h"
28#include "testing/gtest/include/gtest/gtest.h"
29#include "ui/base/clipboard/clipboard.h"
30#include "ui/events/platform/platform_event_source.h"
31#include "ui/views/controls/menu/menu_item_view.h"
32
33#if defined(OS_WIN)
34#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
35#endif
36
37using base::ASCIIToUTF16;
38using content::BrowserThread;
39using content::OpenURLParams;
40using content::PageNavigator;
41using content::WebContents;
42
43namespace {
44
45// PageNavigator implementation that records the URL.
46class TestingPageNavigator : public PageNavigator {
47 public:
48  virtual WebContents* OpenURL(const OpenURLParams& params) OVERRIDE {
49    urls_.push_back(params.url);
50    return NULL;
51  }
52
53  std::vector<GURL> urls_;
54};
55
56}  // namespace
57
58class BookmarkContextMenuTest : public testing::Test {
59 public:
60  BookmarkContextMenuTest()
61      : ui_thread_(BrowserThread::UI, &message_loop_),
62        file_thread_(BrowserThread::FILE, &message_loop_),
63        model_(NULL) {
64  }
65
66  virtual void SetUp() OVERRIDE {
67    event_source_ = ui::PlatformEventSource::CreateDefault();
68    profile_.reset(new TestingProfile());
69    profile_->CreateBookmarkModel(true);
70
71    model_ = BookmarkModelFactory::GetForProfile(profile_.get());
72    test::WaitForBookmarkModelToLoad(model_);
73
74    AddTestData();
75  }
76
77  virtual void TearDown() OVERRIDE {
78    ui::Clipboard::DestroyClipboardForCurrentThread();
79
80    BrowserThread::GetBlockingPool()->FlushForTesting();
81    // Flush the message loop to make application verifiers happy.
82    message_loop_.RunUntilIdle();
83    event_source_.reset();
84  }
85
86 protected:
87  base::MessageLoopForUI message_loop_;
88  content::TestBrowserThread ui_thread_;
89  content::TestBrowserThread file_thread_;
90  scoped_ptr<ui::PlatformEventSource> event_source_;
91  scoped_ptr<TestingProfile> profile_;
92  BookmarkModel* model_;
93  TestingPageNavigator navigator_;
94
95 private:
96  // Creates the following structure:
97  // a
98  // F1
99  //  f1a
100  // -f1b as "chrome://settings"
101  //  F11
102  //   f11a
103  // F2
104  // F3
105  // F4
106  //   f4a
107  void AddTestData() {
108    const BookmarkNode* bb_node = model_->bookmark_bar_node();
109    std::string test_base = "file:///c:/tmp/";
110    model_->AddURL(bb_node, 0, ASCIIToUTF16("a"), GURL(test_base + "a"));
111    const BookmarkNode* f1 = model_->AddFolder(bb_node, 1, ASCIIToUTF16("F1"));
112    model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
113    model_->AddURL(f1, 1, ASCIIToUTF16("f1b"), GURL("chrome://settings"));
114    const BookmarkNode* f11 = model_->AddFolder(f1, 2, ASCIIToUTF16("F11"));
115    model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
116    model_->AddFolder(bb_node, 2, ASCIIToUTF16("F2"));
117    model_->AddFolder(bb_node, 3, ASCIIToUTF16("F3"));
118    const BookmarkNode* f4 = model_->AddFolder(bb_node, 4, ASCIIToUTF16("F4"));
119    model_->AddURL(f4, 0, ASCIIToUTF16("f4a"), GURL(test_base + "f4a"));
120  }
121};
122
123// Tests Deleting from the menu.
124TEST_F(BookmarkContextMenuTest, DeleteURL) {
125  std::vector<const BookmarkNode*> nodes;
126  nodes.push_back(model_->bookmark_bar_node()->GetChild(0));
127  BookmarkContextMenu controller(
128      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
129  GURL url = model_->bookmark_bar_node()->GetChild(0)->url();
130  ASSERT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
131  // Delete the URL.
132  controller.ExecuteCommand(IDC_BOOKMARK_BAR_REMOVE, 0);
133  // Model shouldn't have URL anymore.
134  ASSERT_FALSE(model_->IsBookmarked(url));
135}
136
137// Tests open all on a folder with a couple of bookmarks.
138TEST_F(BookmarkContextMenuTest, OpenAll) {
139  const BookmarkNode* folder = model_->bookmark_bar_node()->GetChild(1);
140  chrome::OpenAll(NULL, &navigator_, folder, NEW_FOREGROUND_TAB, NULL);
141
142  // Should have navigated to F1's child but not F11's child.
143  ASSERT_EQ(static_cast<size_t>(2), navigator_.urls_.size());
144  ASSERT_TRUE(folder->GetChild(0)->url() == navigator_.urls_[0]);
145}
146
147// Tests open all on a folder with a couple of bookmarks in incognito window.
148TEST_F(BookmarkContextMenuTest, OpenAllIngonito) {
149  const BookmarkNode* folder = model_->bookmark_bar_node()->GetChild(1);
150  chrome::OpenAll(NULL, &navigator_, folder, OFF_THE_RECORD, NULL);
151
152  // Should have navigated to only f1a but not f2a.
153  ASSERT_EQ(static_cast<size_t>(1), navigator_.urls_.size());
154  ASSERT_TRUE(folder->GetChild(0)->url() == navigator_.urls_[0]);
155}
156
157// Tests the enabled state of the menus when supplied an empty vector.
158TEST_F(BookmarkContextMenuTest, EmptyNodes) {
159  BookmarkContextMenu controller(
160      NULL, NULL, profile_.get(), NULL, model_->other_node(),
161      std::vector<const BookmarkNode*>(), false);
162  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
163  EXPECT_FALSE(
164      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
165  EXPECT_FALSE(
166      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
167  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
168  EXPECT_TRUE(
169      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
170  EXPECT_TRUE(
171      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
172}
173
174// Tests the enabled state of the menus when supplied a vector with a single
175// url.
176TEST_F(BookmarkContextMenuTest, SingleURL) {
177  std::vector<const BookmarkNode*> nodes;
178  nodes.push_back(model_->bookmark_bar_node()->GetChild(0));
179  BookmarkContextMenu controller(
180      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
181  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
182  EXPECT_TRUE(
183      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
184  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
185  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
186  EXPECT_TRUE(
187      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
188  EXPECT_TRUE(
189      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
190}
191
192// Tests the enabled state of the menus when supplied a vector with multiple
193// urls.
194TEST_F(BookmarkContextMenuTest, MultipleURLs) {
195  std::vector<const BookmarkNode*> nodes;
196  nodes.push_back(model_->bookmark_bar_node()->GetChild(0));
197  nodes.push_back(model_->bookmark_bar_node()->GetChild(1)->GetChild(0));
198  BookmarkContextMenu controller(
199      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
200  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
201  EXPECT_TRUE(
202      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
203  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
204  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
205  EXPECT_TRUE(
206      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
207  EXPECT_TRUE(
208      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
209}
210
211// Tests the enabled state of the menus when supplied an vector with a single
212// folder.
213TEST_F(BookmarkContextMenuTest, SingleFolder) {
214  std::vector<const BookmarkNode*> nodes;
215  nodes.push_back(model_->bookmark_bar_node()->GetChild(2));
216  BookmarkContextMenu controller(
217      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
218  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
219  EXPECT_FALSE(
220      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
221  EXPECT_FALSE(
222      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
223  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
224  EXPECT_TRUE(
225      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
226  EXPECT_TRUE(
227      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
228}
229
230// Tests the enabled state of the menus when supplied a vector with multiple
231// folders, all of which are empty.
232TEST_F(BookmarkContextMenuTest, MultipleEmptyFolders) {
233  std::vector<const BookmarkNode*> nodes;
234  nodes.push_back(model_->bookmark_bar_node()->GetChild(2));
235  nodes.push_back(model_->bookmark_bar_node()->GetChild(3));
236  BookmarkContextMenu controller(
237      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
238  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
239  EXPECT_FALSE(
240      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
241  EXPECT_FALSE(
242      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
243  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
244  EXPECT_TRUE(
245      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
246  EXPECT_TRUE(
247      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
248}
249
250// Tests the enabled state of the menus when supplied a vector with multiple
251// folders, some of which contain URLs.
252TEST_F(BookmarkContextMenuTest, MultipleFoldersWithURLs) {
253  std::vector<const BookmarkNode*> nodes;
254  nodes.push_back(model_->bookmark_bar_node()->GetChild(3));
255  nodes.push_back(model_->bookmark_bar_node()->GetChild(4));
256  BookmarkContextMenu controller(
257      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
258  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
259  EXPECT_TRUE(
260      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
261  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
262  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
263  EXPECT_TRUE(
264      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
265  EXPECT_TRUE(
266      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
267}
268
269// Tests the enabled state of open incognito.
270TEST_F(BookmarkContextMenuTest, DisableIncognito) {
271  std::vector<const BookmarkNode*> nodes;
272  nodes.push_back(model_->bookmark_bar_node()->GetChild(0));
273  Profile* incognito = profile_->GetOffTheRecordProfile();
274  BookmarkContextMenu controller(
275      NULL, NULL, incognito, NULL, nodes[0]->parent(), nodes, false);
276  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
277  EXPECT_FALSE(
278      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
279}
280
281// Tests that you can't remove/edit when showing the other node.
282TEST_F(BookmarkContextMenuTest, DisabledItemsWithOtherNode) {
283  std::vector<const BookmarkNode*> nodes;
284  nodes.push_back(model_->other_node());
285  BookmarkContextMenu controller(
286      NULL, NULL, profile_.get(), NULL, nodes[0], nodes, false);
287  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_EDIT));
288  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
289}
290
291// Tests the enabled state of the menus when supplied an empty vector and null
292// parent.
293TEST_F(BookmarkContextMenuTest, EmptyNodesNullParent) {
294  BookmarkContextMenu controller(
295      NULL, NULL, profile_.get(), NULL, NULL,
296      std::vector<const BookmarkNode*>(), false);
297  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
298  EXPECT_FALSE(
299      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
300  EXPECT_FALSE(
301      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
302  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
303  EXPECT_FALSE(
304      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
305  EXPECT_FALSE(
306      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
307}
308
309TEST_F(BookmarkContextMenuTest, CutCopyPasteNode) {
310  const BookmarkNode* bb_node = model_->bookmark_bar_node();
311  std::vector<const BookmarkNode*> nodes;
312  nodes.push_back(bb_node->GetChild(0));
313  scoped_ptr<BookmarkContextMenu> controller(new BookmarkContextMenu(
314      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false));
315  EXPECT_TRUE(controller->IsCommandEnabled(IDC_COPY));
316  EXPECT_TRUE(controller->IsCommandEnabled(IDC_CUT));
317
318  // Copy the URL.
319  controller->ExecuteCommand(IDC_COPY, 0);
320
321  controller.reset(new BookmarkContextMenu(
322      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false));
323  int old_count = bb_node->child_count();
324  controller->ExecuteCommand(IDC_PASTE, 0);
325
326  ASSERT_TRUE(bb_node->GetChild(1)->is_url());
327  ASSERT_EQ(old_count + 1, bb_node->child_count());
328  ASSERT_EQ(bb_node->GetChild(0)->url(), bb_node->GetChild(1)->url());
329
330  controller.reset(new BookmarkContextMenu(
331      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false));
332  // Cut the URL.
333  controller->ExecuteCommand(IDC_CUT, 0);
334  ASSERT_TRUE(bb_node->GetChild(0)->is_url());
335  ASSERT_TRUE(bb_node->GetChild(1)->is_folder());
336  ASSERT_EQ(old_count, bb_node->child_count());
337}
338
339// Tests that the "Show managed bookmarks" option in the context menu is only
340// visible if the policy is set.
341TEST_F(BookmarkContextMenuTest, ShowManagedBookmarks) {
342  // Create a BookmarkContextMenu for the bookmarks bar.
343  const BookmarkNode* bb_node = model_->bookmark_bar_node();
344  std::vector<const BookmarkNode*> nodes;
345  nodes.push_back(bb_node->GetChild(0));
346  scoped_ptr<BookmarkContextMenu> controller(new BookmarkContextMenu(
347      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false));
348
349  // Verify that there are no managed nodes yet.
350  ChromeBookmarkClient* client = ChromeBookmarkClientFactory::GetForProfile(
351      profile_.get());
352  EXPECT_TRUE(client->managed_node()->empty());
353
354  // The context menu should not show the option to "Show managed bookmarks".
355  EXPECT_FALSE(
356      controller->IsCommandVisible(IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS));
357  views::MenuItemView* menu = controller->menu();
358  EXPECT_FALSE(menu->GetMenuItemByID(IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS)
359                   ->visible());
360
361  // Other options are not affected.
362  EXPECT_TRUE(controller->IsCommandVisible(IDC_BOOKMARK_BAR_NEW_FOLDER));
363  EXPECT_TRUE(menu->GetMenuItemByID(IDC_BOOKMARK_BAR_NEW_FOLDER)->visible());
364
365  // Now set the managed bookmarks policy.
366  base::DictionaryValue* dict = new base::DictionaryValue;
367  dict->SetString("name", "Google");
368  dict->SetString("url", "http://google.com");
369  base::ListValue list;
370  list.Append(dict);
371  EXPECT_TRUE(client->managed_node()->empty());
372  profile_->GetPrefs()->Set(bookmarks::prefs::kManagedBookmarks, list);
373  EXPECT_FALSE(client->managed_node()->empty());
374
375  // New context menus now show the "Show managed bookmarks" option.
376  controller.reset(new BookmarkContextMenu(
377      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false));
378  EXPECT_TRUE(controller->IsCommandVisible(IDC_BOOKMARK_BAR_NEW_FOLDER));
379  EXPECT_TRUE(
380      controller->IsCommandVisible(IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS));
381  menu = controller->menu();
382  EXPECT_TRUE(menu->GetMenuItemByID(IDC_BOOKMARK_BAR_NEW_FOLDER)->visible());
383  EXPECT_TRUE(menu->GetMenuItemByID(IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS)
384                  ->visible());
385}
386