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/app/chrome_command_ids.h"
6#include "chrome/browser/bookmarks/bookmark_model_factory.h"
7#include "chrome/browser/chrome_page_zoom.h"
8#include "chrome/browser/ui/browser_command_controller.h"
9#include "chrome/browser/ui/browser_commands.h"
10#include "chrome/browser/ui/browser_finder.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/browser/ui/zoom/zoom_controller.h"
13#include "chrome/common/url_constants.h"
14#include "chrome/test/base/browser_with_test_window_test.h"
15#include "chrome/test/base/testing_profile.h"
16#include "components/bookmarks/browser/bookmark_model.h"
17#include "components/bookmarks/test/bookmark_test_helpers.h"
18#include "content/public/browser/navigation_controller.h"
19#include "content/public/browser/navigation_entry.h"
20#include "content/public/browser/web_contents.h"
21
22typedef BrowserWithTestWindowTest BrowserCommandsTest;
23
24using content::OpenURLParams;
25using content::Referrer;
26using content::WebContents;
27
28// Tests IDC_SELECT_TAB_0, IDC_SELECT_NEXT_TAB, IDC_SELECT_PREVIOUS_TAB and
29// IDC_SELECT_LAST_TAB.
30TEST_F(BrowserCommandsTest, TabNavigationAccelerators) {
31  GURL about_blank(url::kAboutBlankURL);
32
33  // Create three tabs.
34  AddTab(browser(), about_blank);
35  AddTab(browser(), about_blank);
36  AddTab(browser(), about_blank);
37
38  // Select the second tab.
39  browser()->tab_strip_model()->ActivateTabAt(1, false);
40
41  CommandUpdater* updater = browser()->command_controller()->command_updater();
42
43  // Navigate to the first tab using an accelerator.
44  updater->ExecuteCommand(IDC_SELECT_TAB_0);
45  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
46
47  // Navigate to the second tab using the next accelerators.
48  updater->ExecuteCommand(IDC_SELECT_NEXT_TAB);
49  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
50
51  // Navigate back to the first tab using the previous accelerators.
52  updater->ExecuteCommand(IDC_SELECT_PREVIOUS_TAB);
53  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
54
55  // Navigate to the last tab using the select last accelerator.
56  updater->ExecuteCommand(IDC_SELECT_LAST_TAB);
57  ASSERT_EQ(2, browser()->tab_strip_model()->active_index());
58}
59
60// Tests IDC_DUPLICATE_TAB.
61TEST_F(BrowserCommandsTest, DuplicateTab) {
62  GURL url1("http://foo/1");
63  GURL url2("http://foo/2");
64  GURL url3("http://foo/3");
65  GURL url4("http://foo/4");
66
67  // Navigate to three urls, plus a pending URL that hasn't committed.
68  AddTab(browser(), url1);
69  NavigateAndCommitActiveTab(url2);
70  NavigateAndCommitActiveTab(url3);
71  content::NavigationController& orig_controller =
72      browser()->tab_strip_model()->GetWebContentsAt(0)->GetController();
73  orig_controller.LoadURL(
74      url4, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
75  EXPECT_EQ(3, orig_controller.GetEntryCount());
76  EXPECT_TRUE(orig_controller.GetPendingEntry());
77
78  size_t initial_window_count = chrome::GetTotalBrowserCount();
79
80  // Duplicate the tab.
81  chrome::ExecuteCommand(browser(), IDC_DUPLICATE_TAB);
82
83  // The duplicated tab should not end up in a new window.
84  size_t window_count = chrome::GetTotalBrowserCount();
85  ASSERT_EQ(initial_window_count, window_count);
86
87  // And we should have a newly duplicated tab.
88  ASSERT_EQ(2, browser()->tab_strip_model()->count());
89
90  // Verify the stack of urls.
91  content::NavigationController& controller =
92      browser()->tab_strip_model()->GetWebContentsAt(1)->GetController();
93  EXPECT_EQ(3, controller.GetEntryCount());
94  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
95  EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL());
96  EXPECT_EQ(url2, controller.GetEntryAtIndex(1)->GetURL());
97  EXPECT_EQ(url3, controller.GetEntryAtIndex(2)->GetURL());
98  EXPECT_FALSE(controller.GetPendingEntry());
99}
100
101// Tests IDC_VIEW_SOURCE (See http://crbug.com/138140).
102TEST_F(BrowserCommandsTest, ViewSource) {
103  GURL url1("http://foo/1");
104  GURL url2("http://foo/2");
105
106  // Navigate to a URL, plus a pending URL that hasn't committed.
107  AddTab(browser(), url1);
108  content::NavigationController& orig_controller =
109      browser()->tab_strip_model()->GetWebContentsAt(0)->GetController();
110  orig_controller.LoadURL(
111      url2, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
112  EXPECT_EQ(1, orig_controller.GetEntryCount());
113  EXPECT_TRUE(orig_controller.GetPendingEntry());
114
115  size_t initial_window_count = chrome::GetTotalBrowserCount();
116
117  // View Source.
118  chrome::ExecuteCommand(browser(), IDC_VIEW_SOURCE);
119
120  // The view source tab should not end up in a new window.
121  size_t window_count = chrome::GetTotalBrowserCount();
122  ASSERT_EQ(initial_window_count, window_count);
123
124  // And we should have a newly duplicated tab.
125  ASSERT_EQ(2, browser()->tab_strip_model()->count());
126
127  // Verify we are viewing the source of the last committed entry.
128  GURL view_source_url("view-source:http://foo/1");
129  content::NavigationController& controller =
130      browser()->tab_strip_model()->GetWebContentsAt(1)->GetController();
131  EXPECT_EQ(1, controller.GetEntryCount());
132  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
133  EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL());
134  EXPECT_EQ(view_source_url, controller.GetEntryAtIndex(0)->GetVirtualURL());
135  EXPECT_FALSE(controller.GetPendingEntry());
136}
137
138TEST_F(BrowserCommandsTest, BookmarkCurrentPage) {
139  // We use profile() here, since it's a TestingProfile.
140  profile()->CreateBookmarkModel(true);
141
142  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
143  test::WaitForBookmarkModelToLoad(model);
144
145  // Navigate to a url.
146  GURL url1("http://foo/1");
147  AddTab(browser(), url1);
148  browser()->OpenURL(OpenURLParams(
149      url1, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false));
150
151  chrome::BookmarkCurrentPage(browser());
152
153  // It should now be bookmarked in the bookmark model.
154  EXPECT_EQ(profile(), browser()->profile());
155  EXPECT_TRUE(model->IsBookmarked(url1));
156}
157
158// Tests back/forward in new tab (Control + Back/Forward button in the UI).
159TEST_F(BrowserCommandsTest, BackForwardInNewTab) {
160  GURL url1("http://foo/1");
161  GURL url2("http://foo/2");
162
163  // Make a tab with the two pages navigated in it.
164  AddTab(browser(), url1);
165  NavigateAndCommitActiveTab(url2);
166
167  // Go back in a new background tab.
168  chrome::GoBack(browser(), NEW_BACKGROUND_TAB);
169  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
170  ASSERT_EQ(2, browser()->tab_strip_model()->count());
171
172  WebContents* zeroth = browser()->tab_strip_model()->GetWebContentsAt(0);
173  WebContents* first = browser()->tab_strip_model()->GetWebContentsAt(1);
174
175  // The original tab should be unchanged.
176  EXPECT_EQ(url2, zeroth->GetLastCommittedURL());
177  EXPECT_TRUE(zeroth->GetController().CanGoBack());
178  EXPECT_FALSE(zeroth->GetController().CanGoForward());
179
180  // The new tab should be like the first one but navigated back. Since we
181  // didn't wait for the load to complete, we can't use GetLastCommittedURL.
182  EXPECT_EQ(url1, first->GetVisibleURL());
183  EXPECT_FALSE(first->GetController().CanGoBack());
184  EXPECT_TRUE(first->GetController().CanGoForward());
185
186  // Select the second tab and make it go forward in a new background tab.
187  browser()->tab_strip_model()->ActivateTabAt(1, true);
188  // TODO(brettw) bug 11055: It should not be necessary to commit the load here,
189  // but because of this bug, it will assert later if we don't. When the bug is
190  // fixed, one of the three commits here related to this bug should be removed
191  // (to test both codepaths).
192  CommitPendingLoad(&first->GetController());
193  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
194  chrome::GoForward(browser(), NEW_BACKGROUND_TAB);
195
196  // The previous tab should be unchanged and still in the foreground.
197  EXPECT_EQ(url1, first->GetLastCommittedURL());
198  EXPECT_FALSE(first->GetController().CanGoBack());
199  EXPECT_TRUE(first->GetController().CanGoForward());
200  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
201
202  // There should be a new tab navigated forward.
203  ASSERT_EQ(3, browser()->tab_strip_model()->count());
204  WebContents* second = browser()->tab_strip_model()->GetWebContentsAt(2);
205  // Since we didn't wait for load to complete, we can't use
206  // GetLastCommittedURL.
207  EXPECT_EQ(url2, second->GetVisibleURL());
208  EXPECT_TRUE(second->GetController().CanGoBack());
209  EXPECT_FALSE(second->GetController().CanGoForward());
210
211  // Now do back in a new foreground tab. Don't bother re-checking every sngle
212  // thing above, just validate that it's opening properly.
213  browser()->tab_strip_model()->ActivateTabAt(2, true);
214  // TODO(brettw) bug 11055: see the comment above about why we need this.
215  CommitPendingLoad(&second->GetController());
216  chrome::GoBack(browser(), NEW_FOREGROUND_TAB);
217  ASSERT_EQ(3, browser()->tab_strip_model()->active_index());
218  ASSERT_EQ(url1,
219            browser()->tab_strip_model()->GetActiveWebContents()->
220                GetVisibleURL());
221
222  // Same thing again for forward.
223  // TODO(brettw) bug 11055: see the comment above about why we need this.
224  CommitPendingLoad(&
225      browser()->tab_strip_model()->GetActiveWebContents()->GetController());
226  chrome::GoForward(browser(), NEW_FOREGROUND_TAB);
227  ASSERT_EQ(4, browser()->tab_strip_model()->active_index());
228  ASSERT_EQ(url2,
229            browser()->tab_strip_model()->GetActiveWebContents()->
230                GetVisibleURL());
231}
232
233TEST_F(BrowserCommandsTest, OnMaxZoomIn) {
234  TabStripModel* tab_strip_model = browser()->tab_strip_model();
235
236  GURL url("http://www.google.com");
237  AddTab(browser(), url);
238  content::WebContents* contents1 = tab_strip_model->GetWebContentsAt(0);
239
240  // Continue to zoom in until zoom percent reaches 500.
241  for (int i = 0; i < 9; ++i) {
242    chrome_page_zoom::Zoom(contents1, content::PAGE_ZOOM_IN);
243  }
244
245  // TODO(a.sarkar.arun@gmail.com): Figure out why Zoom-In menu item is not
246  // disabled after Max-zoom is reached. Force disable Zoom-In menu item
247  // from the context menu since it breaks try jobs on bots.
248  if (chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS))
249    chrome::UpdateCommandEnabled(browser(), IDC_ZOOM_PLUS, false);
250
251  ZoomController* zoom_controller = ZoomController::FromWebContents(contents1);
252  EXPECT_EQ(zoom_controller->GetZoomPercent(), 500.0f);
253  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS));
254  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL));
255  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_MINUS));
256}
257
258TEST_F(BrowserCommandsTest, OnMaxZoomOut) {
259  TabStripModel* tab_strip_model = browser()->tab_strip_model();
260
261  GURL url("http://www.google.com");
262  AddTab(browser(), url);
263  content::WebContents* contents1 = tab_strip_model->GetWebContentsAt(0);
264
265  // Continue to zoom out until zoom percent reaches 25.
266  for (int i = 0; i < 7; ++i) {
267    chrome_page_zoom::Zoom(contents1, content::PAGE_ZOOM_OUT);
268  }
269
270  ZoomController* zoom_controller = ZoomController::FromWebContents(contents1);
271  EXPECT_EQ(zoom_controller->GetZoomPercent(), 25.0f);
272  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS));
273  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL));
274  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_MINUS));
275}
276
277TEST_F(BrowserCommandsTest, OnZoomReset) {
278  TabStripModel* tab_strip_model = browser()->tab_strip_model();
279
280  GURL url("http://www.google.com");
281  AddTab(browser(), url);
282  content::WebContents* contents1 = tab_strip_model->GetWebContentsAt(0);
283
284  // Change the zoom percentage to 100.
285  chrome_page_zoom::Zoom(contents1, content::PAGE_ZOOM_RESET);
286
287  ZoomController* zoom_controller = ZoomController::FromWebContents(contents1);
288  EXPECT_EQ(zoom_controller->GetZoomPercent(), 100.0f);
289  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS));
290  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL));
291  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_MINUS));
292}
293
294TEST_F(BrowserCommandsTest, OnZoomLevelChanged) {
295  TabStripModel* tab_strip_model = browser()->tab_strip_model();
296
297  GURL url("http://www.google.com");
298  AddTab(browser(), url);
299  content::WebContents* contents1 = tab_strip_model->GetWebContentsAt(0);
300
301  // Changing zoom percentage from default should enable all the zoom
302  // NSMenuItems.
303  chrome_page_zoom::Zoom(contents1, content::PAGE_ZOOM_IN);
304
305  ZoomController* zoom_controller = ZoomController::FromWebContents(contents1);
306  EXPECT_EQ(zoom_controller->GetZoomPercent(), 110.0f);
307  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS));
308  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL));
309  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_MINUS));
310}
311
312TEST_F(BrowserCommandsTest, OnZoomChangedForActiveTab) {
313  TabStripModel* tab_strip_model = browser()->tab_strip_model();
314
315  GURL url("http://www.google.com");
316  GURL url1("http://code.google.com");
317
318  // Add First tab.
319  AddTab(browser(), url);
320  AddTab(browser(), url1);
321  content::WebContents* contents1 = tab_strip_model->GetWebContentsAt(0);
322
323  ZoomController* zoom_controller = ZoomController::FromWebContents(contents1);
324  EXPECT_EQ(zoom_controller->GetZoomPercent(), 100.0f);
325  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS));
326  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL));
327  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_MINUS));
328
329  // Add Second tab.
330  content::WebContents* contents2 = tab_strip_model->GetWebContentsAt(1);
331
332  tab_strip_model->ActivateTabAt(1, true);
333  EXPECT_TRUE(tab_strip_model->IsTabSelected(1));
334  chrome_page_zoom::Zoom(contents2, content::PAGE_ZOOM_OUT);
335
336  zoom_controller = ZoomController::FromWebContents(contents2);
337  EXPECT_EQ(zoom_controller->GetZoomPercent(), 90.0f);
338  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_PLUS));
339  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL));
340  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_MINUS));
341}
342