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/test/base/browser_with_test_window_test.h"
6
7 #include "base/run_loop.h"
8 #include "chrome/browser/profiles/profile_destroyer.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_navigator.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/common/render_messages.h"
13 #include "chrome/test/base/testing_profile.h"
14 #include "content/public/browser/navigation_controller.h"
15 #include "content/public/browser/navigation_entry.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/common/page_transition_types.h"
18 #include "content/public/test/test_renderer_host.h"
19
20 #if defined(USE_AURA)
21 #include "ui/aura/test/aura_test_helper.h"
22 #endif
23
24 #if defined(USE_ASH)
25 #include "ash/test/ash_test_helper.h"
26 #endif
27
28 using content::NavigationController;
29 using content::RenderViewHost;
30 using content::RenderViewHostTester;
31 using content::WebContents;
32
BrowserWithTestWindowTest()33 BrowserWithTestWindowTest::BrowserWithTestWindowTest()
34 : host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE) {
35 }
36
~BrowserWithTestWindowTest()37 BrowserWithTestWindowTest::~BrowserWithTestWindowTest() {
38 }
39
SetHostDesktopType(chrome::HostDesktopType host_desktop_type)40 void BrowserWithTestWindowTest::SetHostDesktopType(
41 chrome::HostDesktopType host_desktop_type) {
42 DCHECK(!window_);
43 host_desktop_type_ = host_desktop_type;
44 }
45
SetUp()46 void BrowserWithTestWindowTest::SetUp() {
47 testing::Test::SetUp();
48 #if defined(OS_CHROMEOS)
49 // TODO(jamescook): Windows Ash support. This will require refactoring
50 // AshTestHelper and AuraTestHelper so they can be used at the same time,
51 // perhaps by AshTestHelper owning an AuraTestHelper.
52 ash_test_helper_.reset(new ash::test::AshTestHelper(
53 base::MessageLoopForUI::current()));
54 ash_test_helper_->SetUp(true);
55 #elif defined(USE_AURA)
56 aura_test_helper_.reset(new aura::test::AuraTestHelper(
57 base::MessageLoopForUI::current()));
58 aura_test_helper_->SetUp();
59 #endif // USE_AURA
60
61 // Subclasses can provide their own Profile.
62 profile_ = CreateProfile();
63 // Subclasses can provide their own test BrowserWindow. If they return NULL
64 // then Browser will create the a production BrowserWindow and the subclass
65 // is responsible for cleaning it up (usually by NativeWidget destruction).
66 window_.reset(CreateBrowserWindow());
67
68 browser_.reset(CreateBrowser(profile(), host_desktop_type_, window_.get()));
69 }
70
TearDown()71 void BrowserWithTestWindowTest::TearDown() {
72 // Some tests end up posting tasks to the DB thread that must be completed
73 // before the profile can be destroyed and the test safely shut down.
74 base::RunLoop().RunUntilIdle();
75
76 // Reset the profile here because some profile keyed services (like the
77 // audio service) depend on test stubs that the helpers below will remove.
78 DestroyBrowserAndProfile();
79
80 #if defined(OS_CHROMEOS)
81 ash_test_helper_->TearDown();
82 #elif defined(USE_AURA)
83 aura_test_helper_->TearDown();
84 #endif
85 testing::Test::TearDown();
86
87 // A Task is leaked if we don't destroy everything, then run the message
88 // loop.
89 base::MessageLoop::current()->PostTask(FROM_HERE,
90 base::MessageLoop::QuitClosure());
91 base::MessageLoop::current()->Run();
92 }
93
AddTab(Browser * browser,const GURL & url)94 void BrowserWithTestWindowTest::AddTab(Browser* browser, const GURL& url) {
95 chrome::NavigateParams params(browser, url, content::PAGE_TRANSITION_TYPED);
96 params.tabstrip_index = 0;
97 params.disposition = NEW_FOREGROUND_TAB;
98 chrome::Navigate(¶ms);
99 CommitPendingLoad(¶ms.target_contents->GetController());
100 }
101
CommitPendingLoad(NavigationController * controller)102 void BrowserWithTestWindowTest::CommitPendingLoad(
103 NavigationController* controller) {
104 if (!controller->GetPendingEntry())
105 return; // Nothing to commit.
106
107 RenderViewHost* old_rvh =
108 controller->GetWebContents()->GetRenderViewHost();
109
110 RenderViewHost* pending_rvh = RenderViewHostTester::GetPendingForController(
111 controller);
112 if (pending_rvh) {
113 // Simulate the ShouldClose_ACK that is received from the current renderer
114 // for a cross-site navigation.
115 DCHECK_NE(old_rvh, pending_rvh);
116 RenderViewHostTester::For(old_rvh)->SendShouldCloseACK(true);
117 }
118 // Commit on the pending_rvh, if one exists.
119 RenderViewHost* test_rvh = pending_rvh ? pending_rvh : old_rvh;
120 RenderViewHostTester* test_rvh_tester = RenderViewHostTester::For(test_rvh);
121
122 // Simulate a SwapOut_ACK before the navigation commits.
123 if (pending_rvh)
124 RenderViewHostTester::For(old_rvh)->SimulateSwapOutACK();
125
126 // For new navigations, we need to send a larger page ID. For renavigations,
127 // we need to send the preexisting page ID. We can tell these apart because
128 // renavigations will have a pending_entry_index while new ones won't (they'll
129 // just have a standalong pending_entry that isn't in the list already).
130 if (controller->GetPendingEntryIndex() >= 0) {
131 test_rvh_tester->SendNavigateWithTransition(
132 controller->GetPendingEntry()->GetPageID(),
133 controller->GetPendingEntry()->GetURL(),
134 controller->GetPendingEntry()->GetTransitionType());
135 } else {
136 test_rvh_tester->SendNavigateWithTransition(
137 controller->GetWebContents()->
138 GetMaxPageIDForSiteInstance(test_rvh->GetSiteInstance()) + 1,
139 controller->GetPendingEntry()->GetURL(),
140 controller->GetPendingEntry()->GetTransitionType());
141 }
142 }
143
NavigateAndCommit(NavigationController * controller,const GURL & url)144 void BrowserWithTestWindowTest::NavigateAndCommit(
145 NavigationController* controller,
146 const GURL& url) {
147 controller->LoadURL(
148 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
149 CommitPendingLoad(controller);
150 }
151
NavigateAndCommitActiveTab(const GURL & url)152 void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL& url) {
153 NavigateAndCommit(&browser()->tab_strip_model()->GetActiveWebContents()->
154 GetController(),
155 url);
156 }
157
NavigateAndCommitActiveTabWithTitle(Browser * navigating_browser,const GURL & url,const string16 & title)158 void BrowserWithTestWindowTest::NavigateAndCommitActiveTabWithTitle(
159 Browser* navigating_browser,
160 const GURL& url,
161 const string16& title) {
162 NavigationController* controller = &navigating_browser->tab_strip_model()->
163 GetActiveWebContents()->GetController();
164 NavigateAndCommit(controller, url);
165 controller->GetActiveEntry()->SetTitle(title);
166 }
167
DestroyBrowserAndProfile()168 void BrowserWithTestWindowTest::DestroyBrowserAndProfile() {
169 if (browser_.get()) {
170 // Make sure we close all tabs, otherwise Browser isn't happy in its
171 // destructor.
172 browser()->tab_strip_model()->CloseAllTabs();
173 browser_.reset(NULL);
174 }
175 window_.reset(NULL);
176 // Destroy the profile here - otherwise, if the profile is freed in the
177 // destructor, and a test subclass owns a resource that the profile depends
178 // on (such as g_browser_process()->local_state()) there's no way for the
179 // subclass to free it after the profile.
180 if (profile_)
181 DestroyProfile(profile_);
182 profile_ = NULL;
183 }
184
CreateProfile()185 TestingProfile* BrowserWithTestWindowTest::CreateProfile() {
186 return new TestingProfile();
187 }
188
DestroyProfile(TestingProfile * profile)189 void BrowserWithTestWindowTest::DestroyProfile(TestingProfile* profile) {
190 delete profile;
191 }
192
CreateBrowserWindow()193 BrowserWindow* BrowserWithTestWindowTest::CreateBrowserWindow() {
194 return new TestBrowserWindow();
195 }
196
CreateBrowser(Profile * profile,chrome::HostDesktopType host_desktop_type,BrowserWindow * browser_window)197 Browser* BrowserWithTestWindowTest::CreateBrowser(
198 Profile* profile,
199 chrome::HostDesktopType host_desktop_type,
200 BrowserWindow* browser_window) {
201 Browser::CreateParams params(profile, host_desktop_type);
202 params.window = browser_window;
203 return new Browser(params);
204 }
205