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.
5 #include "chrome/test/base/browser_with_test_window_test.h"
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"
21 #include "ui/aura/test/aura_test_helper.h"
22 #include "ui/compositor/test/context_factories_for_test.h"
26 #include "ash/test/ash_test_helper.h"
29 #if defined(TOOLKIT_VIEWS)
30 #include "ui/views/test/test_views_delegate.h"
33 using content::NavigationController
;
34 using content::RenderViewHost
;
35 using content::RenderViewHostTester
;
36 using content::WebContents
;
38 BrowserWithTestWindowTest::BrowserWithTestWindowTest()
39 : browser_type_(Browser::TYPE_TABBED
),
40 host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE
),
44 BrowserWithTestWindowTest::BrowserWithTestWindowTest(
45 Browser::Type browser_type
,
46 chrome::HostDesktopType host_desktop_type
,
48 : browser_type_(browser_type
),
49 host_desktop_type_(host_desktop_type
),
50 hosted_app_(hosted_app
) {
53 BrowserWithTestWindowTest::~BrowserWithTestWindowTest() {
56 void BrowserWithTestWindowTest::SetUp() {
57 testing::Test::SetUp();
58 #if defined(OS_CHROMEOS)
59 // TODO(jamescook): Windows Ash support. This will require refactoring
60 // AshTestHelper and AuraTestHelper so they can be used at the same time,
61 // perhaps by AshTestHelper owning an AuraTestHelper.
62 ash_test_helper_
.reset(new ash::test::AshTestHelper(
63 base::MessageLoopForUI::current()));
64 ash_test_helper_
->SetUp(true);
65 #elif defined(USE_AURA)
66 // The ContextFactory must exist before any Compositors are created.
67 bool enable_pixel_output
= false;
68 ui::InitializeContextFactoryForTests(enable_pixel_output
);
70 aura_test_helper_
.reset(new aura::test::AuraTestHelper(
71 base::MessageLoopForUI::current()));
72 aura_test_helper_
->SetUp();
74 #if defined(TOOLKIT_VIEWS)
75 views_delegate_
.reset(CreateViewsDelegate());
76 views::ViewsDelegate::views_delegate
= views_delegate_
.get();
79 // Subclasses can provide their own Profile.
80 profile_
= CreateProfile();
81 // Subclasses can provide their own test BrowserWindow. If they return NULL
82 // then Browser will create the a production BrowserWindow and the subclass
83 // is responsible for cleaning it up (usually by NativeWidget destruction).
84 window_
.reset(CreateBrowserWindow());
86 browser_
.reset(CreateBrowser(profile(), browser_type_
, hosted_app_
,
87 host_desktop_type_
, window_
.get()));
90 void BrowserWithTestWindowTest::TearDown() {
91 // Some tests end up posting tasks to the DB thread that must be completed
92 // before the profile can be destroyed and the test safely shut down.
93 base::RunLoop().RunUntilIdle();
95 // Reset the profile here because some profile keyed services (like the
96 // audio service) depend on test stubs that the helpers below will remove.
97 DestroyBrowserAndProfile();
99 #if defined(OS_CHROMEOS)
100 ash_test_helper_
->TearDown();
101 #elif defined(USE_AURA)
102 aura_test_helper_
->TearDown();
103 ui::TerminateContextFactoryForTests();
105 testing::Test::TearDown();
107 // A Task is leaked if we don't destroy everything, then run the message
109 base::MessageLoop::current()->PostTask(FROM_HERE
,
110 base::MessageLoop::QuitClosure());
111 base::MessageLoop::current()->Run();
113 #if defined(TOOLKIT_VIEWS)
114 views::ViewsDelegate::views_delegate
= NULL
;
115 views_delegate_
.reset(NULL
);
119 void BrowserWithTestWindowTest::AddTab(Browser
* browser
, const GURL
& url
) {
120 chrome::NavigateParams
params(browser
, url
, content::PAGE_TRANSITION_TYPED
);
121 params
.tabstrip_index
= 0;
122 params
.disposition
= NEW_FOREGROUND_TAB
;
123 chrome::Navigate(¶ms
);
124 CommitPendingLoad(¶ms
.target_contents
->GetController());
127 void BrowserWithTestWindowTest::CommitPendingLoad(
128 NavigationController
* controller
) {
129 if (!controller
->GetPendingEntry())
130 return; // Nothing to commit.
132 RenderViewHost
* old_rvh
=
133 controller
->GetWebContents()->GetRenderViewHost();
135 RenderViewHost
* pending_rvh
= RenderViewHostTester::GetPendingForController(
138 // Simulate the ShouldClose_ACK that is received from the current renderer
139 // for a cross-site navigation.
140 DCHECK_NE(old_rvh
, pending_rvh
);
141 RenderViewHostTester::For(old_rvh
)->SendShouldCloseACK(true);
143 // Commit on the pending_rvh, if one exists.
144 RenderViewHost
* test_rvh
= pending_rvh
? pending_rvh
: old_rvh
;
145 RenderViewHostTester
* test_rvh_tester
= RenderViewHostTester::For(test_rvh
);
147 // Simulate a SwapOut_ACK before the navigation commits.
149 RenderViewHostTester::For(old_rvh
)->SimulateSwapOutACK();
151 // For new navigations, we need to send a larger page ID. For renavigations,
152 // we need to send the preexisting page ID. We can tell these apart because
153 // renavigations will have a pending_entry_index while new ones won't (they'll
154 // just have a standalong pending_entry that isn't in the list already).
155 if (controller
->GetPendingEntryIndex() >= 0) {
156 test_rvh_tester
->SendNavigateWithTransition(
157 controller
->GetPendingEntry()->GetPageID(),
158 controller
->GetPendingEntry()->GetURL(),
159 controller
->GetPendingEntry()->GetTransitionType());
161 test_rvh_tester
->SendNavigateWithTransition(
162 controller
->GetWebContents()->
163 GetMaxPageIDForSiteInstance(test_rvh
->GetSiteInstance()) + 1,
164 controller
->GetPendingEntry()->GetURL(),
165 controller
->GetPendingEntry()->GetTransitionType());
169 void BrowserWithTestWindowTest::NavigateAndCommit(
170 NavigationController
* controller
,
173 url
, content::Referrer(), content::PAGE_TRANSITION_LINK
, std::string());
174 CommitPendingLoad(controller
);
177 void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL
& url
) {
178 NavigateAndCommit(&browser()->tab_strip_model()->GetActiveWebContents()->
183 void BrowserWithTestWindowTest::NavigateAndCommitActiveTabWithTitle(
184 Browser
* navigating_browser
,
186 const base::string16
& title
) {
187 NavigationController
* controller
= &navigating_browser
->tab_strip_model()->
188 GetActiveWebContents()->GetController();
189 NavigateAndCommit(controller
, url
);
190 controller
->GetActiveEntry()->SetTitle(title
);
193 void BrowserWithTestWindowTest::DestroyBrowserAndProfile() {
194 if (browser_
.get()) {
195 // Make sure we close all tabs, otherwise Browser isn't happy in its
197 browser()->tab_strip_model()->CloseAllTabs();
198 browser_
.reset(NULL
);
201 // Destroy the profile here - otherwise, if the profile is freed in the
202 // destructor, and a test subclass owns a resource that the profile depends
203 // on (such as g_browser_process()->local_state()) there's no way for the
204 // subclass to free it after the profile.
206 DestroyProfile(profile_
);
210 TestingProfile
* BrowserWithTestWindowTest::CreateProfile() {
211 return new TestingProfile();
214 void BrowserWithTestWindowTest::DestroyProfile(TestingProfile
* profile
) {
218 BrowserWindow
* BrowserWithTestWindowTest::CreateBrowserWindow() {
219 return new TestBrowserWindow();
222 Browser
* BrowserWithTestWindowTest::CreateBrowser(
224 Browser::Type browser_type
,
226 chrome::HostDesktopType host_desktop_type
,
227 BrowserWindow
* browser_window
) {
228 Browser::CreateParams
params(profile
, host_desktop_type
);
229 params
.type
= browser_type
;
230 params
.window
= browser_window
;
232 params
.app_name
= "Test";
233 return new Browser(params
);
236 #if defined(TOOLKIT_VIEWS)
237 views::ViewsDelegate
* BrowserWithTestWindowTest::CreateViewsDelegate() {
238 return new views::TestViewsDelegate
;