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/ui/browser_command_controller.h"
8#include "chrome/browser/ui/browser_commands.h"
9#include "chrome/browser/ui/browser_finder.h"
10#include "chrome/browser/ui/tabs/tab_strip_model.h"
11#include "chrome/common/url_constants.h"
12#include "chrome/test/base/browser_with_test_window_test.h"
13#include "chrome/test/base/testing_profile.h"
14#include "components/bookmarks/browser/bookmark_model.h"
15#include "components/bookmarks/test/bookmark_test_helpers.h"
16#include "content/public/browser/navigation_controller.h"
17#include "content/public/browser/navigation_entry.h"
18#include "content/public/browser/web_contents.h"
19
20typedef BrowserWithTestWindowTest BrowserCommandsTest;
21
22using content::OpenURLParams;
23using content::Referrer;
24using content::WebContents;
25
26// Tests IDC_SELECT_TAB_0, IDC_SELECT_NEXT_TAB, IDC_SELECT_PREVIOUS_TAB and
27// IDC_SELECT_LAST_TAB.
28TEST_F(BrowserCommandsTest, TabNavigationAccelerators) {
29  GURL about_blank(url::kAboutBlankURL);
30
31  // Create three tabs.
32  AddTab(browser(), about_blank);
33  AddTab(browser(), about_blank);
34  AddTab(browser(), about_blank);
35
36  // Select the second tab.
37  browser()->tab_strip_model()->ActivateTabAt(1, false);
38
39  CommandUpdater* updater = browser()->command_controller()->command_updater();
40
41  // Navigate to the first tab using an accelerator.
42  updater->ExecuteCommand(IDC_SELECT_TAB_0);
43  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
44
45  // Navigate to the second tab using the next accelerators.
46  updater->ExecuteCommand(IDC_SELECT_NEXT_TAB);
47  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
48
49  // Navigate back to the first tab using the previous accelerators.
50  updater->ExecuteCommand(IDC_SELECT_PREVIOUS_TAB);
51  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
52
53  // Navigate to the last tab using the select last accelerator.
54  updater->ExecuteCommand(IDC_SELECT_LAST_TAB);
55  ASSERT_EQ(2, browser()->tab_strip_model()->active_index());
56}
57
58// Tests IDC_DUPLICATE_TAB.
59TEST_F(BrowserCommandsTest, DuplicateTab) {
60  GURL url1("http://foo/1");
61  GURL url2("http://foo/2");
62  GURL url3("http://foo/3");
63  GURL url4("http://foo/4");
64
65  // Navigate to three urls, plus a pending URL that hasn't committed.
66  AddTab(browser(), url1);
67  NavigateAndCommitActiveTab(url2);
68  NavigateAndCommitActiveTab(url3);
69  content::NavigationController& orig_controller =
70      browser()->tab_strip_model()->GetWebContentsAt(0)->GetController();
71  orig_controller.LoadURL(
72      url4, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
73  EXPECT_EQ(3, orig_controller.GetEntryCount());
74  EXPECT_TRUE(orig_controller.GetPendingEntry());
75
76  size_t initial_window_count = chrome::GetTotalBrowserCount();
77
78  // Duplicate the tab.
79  chrome::ExecuteCommand(browser(), IDC_DUPLICATE_TAB);
80
81  // The duplicated tab should not end up in a new window.
82  size_t window_count = chrome::GetTotalBrowserCount();
83  ASSERT_EQ(initial_window_count, window_count);
84
85  // And we should have a newly duplicated tab.
86  ASSERT_EQ(2, browser()->tab_strip_model()->count());
87
88  // Verify the stack of urls.
89  content::NavigationController& controller =
90      browser()->tab_strip_model()->GetWebContentsAt(1)->GetController();
91  EXPECT_EQ(3, controller.GetEntryCount());
92  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
93  EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL());
94  EXPECT_EQ(url2, controller.GetEntryAtIndex(1)->GetURL());
95  EXPECT_EQ(url3, controller.GetEntryAtIndex(2)->GetURL());
96  EXPECT_FALSE(controller.GetPendingEntry());
97}
98
99// Tests IDC_VIEW_SOURCE (See http://crbug.com/138140).
100TEST_F(BrowserCommandsTest, ViewSource) {
101  GURL url1("http://foo/1");
102  GURL url2("http://foo/2");
103
104  // Navigate to a URL, plus a pending URL that hasn't committed.
105  AddTab(browser(), url1);
106  content::NavigationController& orig_controller =
107      browser()->tab_strip_model()->GetWebContentsAt(0)->GetController();
108  orig_controller.LoadURL(
109      url2, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
110  EXPECT_EQ(1, orig_controller.GetEntryCount());
111  EXPECT_TRUE(orig_controller.GetPendingEntry());
112
113  size_t initial_window_count = chrome::GetTotalBrowserCount();
114
115  // View Source.
116  chrome::ExecuteCommand(browser(), IDC_VIEW_SOURCE);
117
118  // The view source tab should not end up in a new window.
119  size_t window_count = chrome::GetTotalBrowserCount();
120  ASSERT_EQ(initial_window_count, window_count);
121
122  // And we should have a newly duplicated tab.
123  ASSERT_EQ(2, browser()->tab_strip_model()->count());
124
125  // Verify we are viewing the source of the last committed entry.
126  GURL view_source_url("view-source:http://foo/1");
127  content::NavigationController& controller =
128      browser()->tab_strip_model()->GetWebContentsAt(1)->GetController();
129  EXPECT_EQ(1, controller.GetEntryCount());
130  EXPECT_EQ(0, controller.GetCurrentEntryIndex());
131  EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL());
132  EXPECT_EQ(view_source_url, controller.GetEntryAtIndex(0)->GetVirtualURL());
133  EXPECT_FALSE(controller.GetPendingEntry());
134}
135
136TEST_F(BrowserCommandsTest, BookmarkCurrentPage) {
137  // We use profile() here, since it's a TestingProfile.
138  profile()->CreateBookmarkModel(true);
139
140  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile());
141  test::WaitForBookmarkModelToLoad(model);
142
143  // Navigate to a url.
144  GURL url1("http://foo/1");
145  AddTab(browser(), url1);
146  browser()->OpenURL(OpenURLParams(
147      url1, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
148
149  chrome::BookmarkCurrentPage(browser());
150
151  // It should now be bookmarked in the bookmark model.
152  EXPECT_EQ(profile(), browser()->profile());
153  EXPECT_TRUE(model->IsBookmarked(url1));
154}
155
156// Tests back/forward in new tab (Control + Back/Forward button in the UI).
157TEST_F(BrowserCommandsTest, BackForwardInNewTab) {
158  GURL url1("http://foo/1");
159  GURL url2("http://foo/2");
160
161  // Make a tab with the two pages navigated in it.
162  AddTab(browser(), url1);
163  NavigateAndCommitActiveTab(url2);
164
165  // Go back in a new background tab.
166  chrome::GoBack(browser(), NEW_BACKGROUND_TAB);
167  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
168  ASSERT_EQ(2, browser()->tab_strip_model()->count());
169
170  WebContents* zeroth = browser()->tab_strip_model()->GetWebContentsAt(0);
171  WebContents* first = browser()->tab_strip_model()->GetWebContentsAt(1);
172
173  // The original tab should be unchanged.
174  EXPECT_EQ(url2, zeroth->GetLastCommittedURL());
175  EXPECT_TRUE(zeroth->GetController().CanGoBack());
176  EXPECT_FALSE(zeroth->GetController().CanGoForward());
177
178  // The new tab should be like the first one but navigated back. Since we
179  // didn't wait for the load to complete, we can't use GetLastCommittedURL.
180  EXPECT_EQ(url1, first->GetVisibleURL());
181  EXPECT_FALSE(first->GetController().CanGoBack());
182  EXPECT_TRUE(first->GetController().CanGoForward());
183
184  // Select the second tab and make it go forward in a new background tab.
185  browser()->tab_strip_model()->ActivateTabAt(1, true);
186  // TODO(brettw) bug 11055: It should not be necessary to commit the load here,
187  // but because of this bug, it will assert later if we don't. When the bug is
188  // fixed, one of the three commits here related to this bug should be removed
189  // (to test both codepaths).
190  CommitPendingLoad(&first->GetController());
191  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
192  chrome::GoForward(browser(), NEW_BACKGROUND_TAB);
193
194  // The previous tab should be unchanged and still in the foreground.
195  EXPECT_EQ(url1, first->GetLastCommittedURL());
196  EXPECT_FALSE(first->GetController().CanGoBack());
197  EXPECT_TRUE(first->GetController().CanGoForward());
198  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
199
200  // There should be a new tab navigated forward.
201  ASSERT_EQ(3, browser()->tab_strip_model()->count());
202  WebContents* second = browser()->tab_strip_model()->GetWebContentsAt(2);
203  // Since we didn't wait for load to complete, we can't use
204  // GetLastCommittedURL.
205  EXPECT_EQ(url2, second->GetVisibleURL());
206  EXPECT_TRUE(second->GetController().CanGoBack());
207  EXPECT_FALSE(second->GetController().CanGoForward());
208
209  // Now do back in a new foreground tab. Don't bother re-checking every sngle
210  // thing above, just validate that it's opening properly.
211  browser()->tab_strip_model()->ActivateTabAt(2, true);
212  // TODO(brettw) bug 11055: see the comment above about why we need this.
213  CommitPendingLoad(&second->GetController());
214  chrome::GoBack(browser(), NEW_FOREGROUND_TAB);
215  ASSERT_EQ(3, browser()->tab_strip_model()->active_index());
216  ASSERT_EQ(url1,
217            browser()->tab_strip_model()->GetActiveWebContents()->
218                GetVisibleURL());
219
220  // Same thing again for forward.
221  // TODO(brettw) bug 11055: see the comment above about why we need this.
222  CommitPendingLoad(&
223      browser()->tab_strip_model()->GetActiveWebContents()->GetController());
224  chrome::GoForward(browser(), NEW_FOREGROUND_TAB);
225  ASSERT_EQ(4, browser()->tab_strip_model()->active_index());
226  ASSERT_EQ(url2,
227            browser()->tab_strip_model()->GetActiveWebContents()->
228                GetVisibleURL());
229}
230