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