1// Copyright (c) 2011 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 <string>
6#include <vector>
7
8#include "base/memory/scoped_ptr.h"
9#include "base/utf_string_conversions.h"
10#include "chrome/app/chrome_command_ids.h"
11#include "chrome/browser/bookmarks/bookmark_model.h"
12#include "chrome/browser/bookmarks/bookmark_utils.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/ui/views/bookmarks/bookmark_context_menu.h"
15#include "chrome/test/testing_profile.h"
16#include "content/browser/browser_thread.h"
17#include "content/browser/tab_contents/page_navigator.h"
18#include "grit/generated_resources.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21#if defined(OS_WIN)
22#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
23#endif
24
25namespace {
26
27// PageNavigator implementation that records the URL.
28class TestingPageNavigator : public PageNavigator {
29 public:
30  virtual void OpenURL(const GURL& url,
31                       const GURL& referrer,
32                       WindowOpenDisposition disposition,
33                       PageTransition::Type transition) {
34    urls_.push_back(url);
35  }
36
37  std::vector<GURL> urls_;
38};
39
40}  // namespace
41
42class BookmarkContextMenuTest : public testing::Test {
43 public:
44  BookmarkContextMenuTest()
45      : ui_thread_(BrowserThread::UI, &message_loop_),
46        file_thread_(BrowserThread::FILE, &message_loop_),
47        model_(NULL) {
48  }
49
50  virtual void SetUp() {
51#if defined(OS_WIN)
52    BookmarkBarView::testing_ = true;
53#endif
54
55    profile_.reset(new TestingProfile());
56    profile_->CreateBookmarkModel(true);
57    profile_->BlockUntilBookmarkModelLoaded();
58
59    model_ = profile_->GetBookmarkModel();
60
61    AddTestData();
62  }
63
64  virtual void TearDown() {
65#if defined(OS_WIN)
66    BookmarkBarView::testing_ = false;
67#endif
68
69    // Flush the message loop to make Purify happy.
70    message_loop_.RunAllPending();
71  }
72
73 protected:
74  MessageLoopForUI message_loop_;
75  BrowserThread ui_thread_;
76  BrowserThread file_thread_;
77  scoped_ptr<TestingProfile> profile_;
78  BookmarkModel* model_;
79  TestingPageNavigator navigator_;
80
81 private:
82  // Creates the following structure:
83  // a
84  // F1
85  //  f1a
86  //  F11
87  //   f11a
88  // F2
89  // F3
90  // F4
91  //   f4a
92  void AddTestData() {
93    std::string test_base = "file:///c:/tmp/";
94
95    model_->AddURL(model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("a"),
96                   GURL(test_base + "a"));
97    const BookmarkNode* f1 =
98        model_->AddFolder(model_->GetBookmarkBarNode(), 1, ASCIIToUTF16("F1"));
99    model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
100    const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11"));
101    model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
102    model_->AddFolder(model_->GetBookmarkBarNode(), 2, ASCIIToUTF16("F2"));
103    model_->AddFolder(model_->GetBookmarkBarNode(), 3, ASCIIToUTF16("F3"));
104    const BookmarkNode* f4 =
105        model_->AddFolder(model_->GetBookmarkBarNode(), 4, ASCIIToUTF16("F4"));
106    model_->AddURL(f4, 0, ASCIIToUTF16("f4a"), GURL(test_base + "f4a"));
107  }
108};
109
110// Tests Deleting from the menu.
111TEST_F(BookmarkContextMenuTest, DeleteURL) {
112  std::vector<const BookmarkNode*> nodes;
113  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
114  BookmarkContextMenu controller(
115      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
116  GURL url = model_->GetBookmarkBarNode()->GetChild(0)->GetURL();
117  ASSERT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
118  // Delete the URL.
119  controller.ExecuteCommand(IDC_BOOKMARK_BAR_REMOVE);
120  // Model shouldn't have URL anymore.
121  ASSERT_FALSE(model_->IsBookmarked(url));
122}
123
124// Tests open all on a folder with a couple of bookmarks.
125TEST_F(BookmarkContextMenuTest, OpenAll) {
126  const BookmarkNode* folder = model_->GetBookmarkBarNode()->GetChild(1);
127  bookmark_utils::OpenAll(
128      NULL, profile_.get(), &navigator_, folder, NEW_FOREGROUND_TAB);
129
130  // Should have navigated to F1's child but not F11's child.
131  ASSERT_EQ(static_cast<size_t>(1), navigator_.urls_.size());
132  ASSERT_TRUE(folder->GetChild(0)->GetURL() == navigator_.urls_[0]);
133}
134
135// Tests the enabled state of the menus when supplied an empty vector.
136TEST_F(BookmarkContextMenuTest, EmptyNodes) {
137  BookmarkContextMenu controller(
138      NULL, profile_.get(), NULL, model_->other_node(),
139      std::vector<const BookmarkNode*>());
140  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
141  EXPECT_FALSE(
142      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
143  EXPECT_FALSE(
144      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
145  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
146  EXPECT_TRUE(
147      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
148  EXPECT_TRUE(
149      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
150}
151
152// Tests the enabled state of the menus when supplied a vector with a single
153// url.
154TEST_F(BookmarkContextMenuTest, SingleURL) {
155  std::vector<const BookmarkNode*> nodes;
156  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
157  BookmarkContextMenu controller(
158      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
159  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
160  EXPECT_TRUE(
161      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
162  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
163  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
164  EXPECT_TRUE(
165      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
166  EXPECT_TRUE(
167      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
168}
169
170// Tests the enabled state of the menus when supplied a vector with multiple
171// urls.
172TEST_F(BookmarkContextMenuTest, MultipleURLs) {
173  std::vector<const BookmarkNode*> nodes;
174  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
175  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(1)->GetChild(0));
176  BookmarkContextMenu controller(
177      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
178  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
179  EXPECT_TRUE(
180      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
181  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
182  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
183  EXPECT_TRUE(
184      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
185  EXPECT_TRUE(
186      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
187}
188
189// Tests the enabled state of the menus when supplied an vector with a single
190// folder.
191TEST_F(BookmarkContextMenuTest, SingleFolder) {
192  std::vector<const BookmarkNode*> nodes;
193  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(2));
194  BookmarkContextMenu controller(
195      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
196  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
197  EXPECT_FALSE(
198      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
199  EXPECT_FALSE(
200      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
201  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
202  EXPECT_TRUE(
203      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
204  EXPECT_TRUE(
205      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
206}
207
208// Tests the enabled state of the menus when supplied a vector with multiple
209// folders, all of which are empty.
210TEST_F(BookmarkContextMenuTest, MultipleEmptyFolders) {
211  std::vector<const BookmarkNode*> nodes;
212  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(2));
213  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(3));
214  BookmarkContextMenu controller(
215      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
216  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
217  EXPECT_FALSE(
218      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
219  EXPECT_FALSE(
220      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
221  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
222  EXPECT_TRUE(
223      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
224  EXPECT_TRUE(
225      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
226}
227
228// Tests the enabled state of the menus when supplied a vector with multiple
229// folders, some of which contain URLs.
230TEST_F(BookmarkContextMenuTest, MultipleFoldersWithURLs) {
231  std::vector<const BookmarkNode*> nodes;
232  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(3));
233  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(4));
234  BookmarkContextMenu controller(
235      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
236  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
237  EXPECT_TRUE(
238      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
239  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
240  EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
241  EXPECT_TRUE(
242      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
243  EXPECT_TRUE(
244      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
245}
246
247// Tests the enabled state of open incognito.
248TEST_F(BookmarkContextMenuTest, DisableIncognito) {
249  std::vector<const BookmarkNode*> nodes;
250  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
251  BookmarkContextMenu controller(
252      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
253  profile_->set_incognito(true);
254  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
255  EXPECT_FALSE(
256      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
257}
258
259// Tests that you can't remove/edit when showing the other node.
260TEST_F(BookmarkContextMenuTest, DisabledItemsWithOtherNode) {
261  std::vector<const BookmarkNode*> nodes;
262  nodes.push_back(model_->other_node());
263  BookmarkContextMenu controller(
264      NULL, profile_.get(), NULL, nodes[0], nodes);
265  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_EDIT));
266  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
267}
268
269// Tests the enabled state of the menus when supplied an empty vector and null
270// parent.
271TEST_F(BookmarkContextMenuTest, EmptyNodesNullParent) {
272  BookmarkContextMenu controller(
273      NULL, profile_.get(), NULL, NULL, std::vector<const BookmarkNode*>());
274  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
275  EXPECT_FALSE(
276      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
277  EXPECT_FALSE(
278      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
279  EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
280  EXPECT_FALSE(
281      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
282  EXPECT_FALSE(
283      controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
284}
285
286TEST_F(BookmarkContextMenuTest, CutCopyPasteNode) {
287  std::vector<const BookmarkNode*> nodes;
288  nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
289  scoped_ptr<BookmarkContextMenu> controller(new BookmarkContextMenu(
290      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes));
291  EXPECT_TRUE(controller->IsCommandEnabled(IDC_COPY));
292  EXPECT_TRUE(controller->IsCommandEnabled(IDC_CUT));
293
294  // Copy the URL.
295  controller->ExecuteCommand(IDC_COPY);
296
297  controller.reset(new BookmarkContextMenu(
298      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes));
299  int old_count = model_->GetBookmarkBarNode()->child_count();
300  controller->ExecuteCommand(IDC_PASTE);
301
302  ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(1)->is_url());
303  ASSERT_EQ(old_count + 1, model_->GetBookmarkBarNode()->child_count());
304  ASSERT_EQ(model_->GetBookmarkBarNode()->GetChild(0)->GetURL(),
305            model_->GetBookmarkBarNode()->GetChild(1)->GetURL());
306
307  controller.reset(new BookmarkContextMenu(
308      NULL, profile_.get(), NULL, nodes[0]->parent(), nodes));
309  // Cut the URL.
310  controller->ExecuteCommand(IDC_CUT);
311  ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(0)->is_url());
312  ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(1)->is_folder());
313  ASSERT_EQ(old_count, model_->GetBookmarkBarNode()->child_count());
314}
315