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 "base/command_line.h"
6 #include "base/file_path.h"
7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/extensions/extension_browsertest.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_init.h"
13 #include "chrome/browser/ui/browser_list.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/test/in_process_browser_test.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 class BrowserInitTest : public ExtensionBrowserTest {
20 protected:
21 // Helper functions return void so that we can ASSERT*().
22 // Use ASSERT_FALSE(HasFatalFailure()) after calling these functions
23 // to stop the test if an assert fails.
LoadApp(const std::string & app_name,const Extension ** out_app_extension)24 void LoadApp(const std::string& app_name,
25 const Extension** out_app_extension) {
26 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(app_name.c_str())));
27
28 ExtensionService* service = browser()->profile()->GetExtensionService();
29 *out_app_extension = service->GetExtensionById(
30 last_loaded_extension_id_, false);
31 ASSERT_TRUE(*out_app_extension);
32
33 // Code that opens a new browser assumes we start with exactly one.
34 ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
35 }
36
SetAppLaunchPref(const std::string & app_id,ExtensionPrefs::LaunchType launch_type)37 void SetAppLaunchPref(const std::string& app_id,
38 ExtensionPrefs::LaunchType launch_type) {
39 ExtensionService* service = browser()->profile()->GetExtensionService();
40 service->extension_prefs()->SetLaunchType(app_id, launch_type);
41 }
42
43 // Check that there are two browsers. Find the one that is not |browser()|.
FindOneOtherBrowser(Browser ** out_other_browser)44 void FindOneOtherBrowser(Browser** out_other_browser) {
45 // There should only be one other browser.
46 ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile()));
47
48 // Find the new browser.
49 Browser* other_browser = NULL;
50 for (BrowserList::const_iterator i = BrowserList::begin();
51 i != BrowserList::end() && !other_browser; ++i) {
52 if (*i != browser())
53 other_browser = *i;
54 }
55 ASSERT_TRUE(other_browser);
56 ASSERT_TRUE(other_browser != browser());
57 *out_other_browser = other_browser;
58 }
59 };
60
61 class OpenURLsPopupObserver : public BrowserList::Observer {
62 public:
OpenURLsPopupObserver()63 OpenURLsPopupObserver() : added_browser_(NULL) { }
64
OnBrowserAdded(const Browser * browser)65 virtual void OnBrowserAdded(const Browser* browser) {
66 added_browser_ = browser;
67 }
68
OnBrowserRemoved(const Browser * browser)69 virtual void OnBrowserRemoved(const Browser* browser) { }
70
71 const Browser* added_browser_;
72 };
73
74 // Test that when there is a popup as the active browser any requests to
75 // BrowserInit::LaunchWithProfile::OpenURLsInBrowser don't crash because
76 // there's no explicit profile given.
IN_PROC_BROWSER_TEST_F(BrowserInitTest,OpenURLsPopup)77 IN_PROC_BROWSER_TEST_F(BrowserInitTest, OpenURLsPopup) {
78 std::vector<GURL> urls;
79 urls.push_back(GURL("http://localhost"));
80
81 // Note that in our testing we do not ever query the BrowserList for the "last
82 // active" browser. That's because the browsers are set as "active" by
83 // platform UI toolkit messages, and those messages are not sent during unit
84 // testing sessions.
85
86 OpenURLsPopupObserver observer;
87 BrowserList::AddObserver(&observer);
88
89 Browser* popup = Browser::CreateForType(Browser::TYPE_POPUP,
90 browser()->profile());
91 ASSERT_EQ(popup->type(), Browser::TYPE_POPUP);
92 ASSERT_EQ(popup, observer.added_browser_);
93
94 CommandLine dummy(CommandLine::NO_PROGRAM);
95 BrowserInit::LaunchWithProfile launch(FilePath(), dummy);
96 // This should create a new window, but re-use the profile from |popup|. If
97 // it used a NULL or invalid profile, it would crash.
98 launch.OpenURLsInBrowser(popup, false, urls);
99 ASSERT_NE(popup, observer.added_browser_);
100 BrowserList::RemoveObserver(&observer);
101 }
102
103 // App shortcuts are not implemented on mac os.
104 #if !defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(BrowserInitTest,OpenAppShortcutNoPref)105 IN_PROC_BROWSER_TEST_F(BrowserInitTest, OpenAppShortcutNoPref) {
106 // Load an app with launch.container = 'tab'.
107 const Extension* extension_app = NULL;
108 LoadApp("app_with_tab_container", &extension_app);
109 ASSERT_FALSE(HasFatalFailure()); // Check for ASSERT failures in LoadApp().
110
111 // Add --app-id=<extension->id()> to the command line.
112 CommandLine command_line(CommandLine::NO_PROGRAM);
113 command_line.AppendSwitchASCII(switches::kAppId, extension_app->id());
114
115 BrowserInit::LaunchWithProfile launch(FilePath(), command_line);
116 ASSERT_TRUE(launch.Launch(browser()->profile(), std::vector<GURL>(), false));
117
118 // No pref was set, so the app should have opened in a window.
119 // The launch should have created a new browser.
120 Browser* new_browser = NULL;
121 FindOneOtherBrowser(&new_browser);
122 ASSERT_FALSE(HasFatalFailure());
123
124 // Expect an app window.
125 EXPECT_EQ(Browser::TYPE_APP, new_browser->type());
126
127 // The browser's app_name should include the app's ID.
128 EXPECT_NE(
129 new_browser->app_name_.find(extension_app->id()),
130 std::string::npos) << new_browser->app_name_;
131 }
132
IN_PROC_BROWSER_TEST_F(BrowserInitTest,OpenAppShortcutWindowPref)133 IN_PROC_BROWSER_TEST_F(BrowserInitTest, OpenAppShortcutWindowPref) {
134 const Extension* extension_app = NULL;
135 LoadApp("app_with_tab_container", &extension_app);
136 ASSERT_FALSE(HasFatalFailure()); // Check for ASSERT failures in LoadApp().
137
138 // Set a pref indicating that the user wants to open this app in a window.
139 SetAppLaunchPref(extension_app->id(), ExtensionPrefs::LAUNCH_WINDOW);
140
141 CommandLine command_line(CommandLine::NO_PROGRAM);
142 command_line.AppendSwitchASCII(switches::kAppId, extension_app->id());
143 BrowserInit::LaunchWithProfile launch(FilePath(), command_line);
144 ASSERT_TRUE(launch.Launch(browser()->profile(), std::vector<GURL>(), false));
145
146 // Pref was set to open in a window, so the app should have opened in a
147 // window. The launch should have created a new browser. Find the new
148 // browser.
149 Browser* new_browser = NULL;
150 FindOneOtherBrowser(&new_browser);
151 ASSERT_FALSE(HasFatalFailure());
152
153 // Expect an app window.
154 EXPECT_EQ(Browser::TYPE_APP, new_browser->type());
155
156 // The browser's app_name should include the app's ID.
157 EXPECT_NE(
158 new_browser->app_name_.find(extension_app->id()),
159 std::string::npos) << new_browser->app_name_;
160 }
161
IN_PROC_BROWSER_TEST_F(BrowserInitTest,OpenAppShortcutTabPref)162 IN_PROC_BROWSER_TEST_F(BrowserInitTest, OpenAppShortcutTabPref) {
163 // Load an app with launch.container = 'tab'.
164 const Extension* extension_app = NULL;
165 LoadApp("app_with_tab_container", &extension_app);
166 ASSERT_FALSE(HasFatalFailure()); // Check for ASSERT failures in LoadApp().
167
168 // Set a pref indicating that the user wants to open this app in a window.
169 SetAppLaunchPref(extension_app->id(), ExtensionPrefs::LAUNCH_REGULAR);
170
171 CommandLine command_line(CommandLine::NO_PROGRAM);
172 command_line.AppendSwitchASCII(switches::kAppId, extension_app->id());
173 BrowserInit::LaunchWithProfile launch(FilePath(), command_line);
174 ASSERT_TRUE(launch.Launch(browser()->profile(), std::vector<GURL>(), false));
175
176 // When an app shortcut is open and the pref indicates a tab should
177 // open, the tab is open in a new browser window. Expect a new window.
178 ASSERT_EQ(2u, BrowserList::GetBrowserCount(browser()->profile()));
179
180 Browser* new_browser = NULL;
181 FindOneOtherBrowser(&new_browser);
182 ASSERT_FALSE(HasFatalFailure());
183
184 // The tab should be in a normal window.
185 EXPECT_EQ(Browser::TYPE_NORMAL, new_browser->type());
186
187 // The browser's app_name should not include the app's ID: It is in a
188 // normal browser.
189 EXPECT_EQ(
190 new_browser->app_name_.find(extension_app->id()),
191 std::string::npos) << new_browser->app_name_;
192 }
193
IN_PROC_BROWSER_TEST_F(BrowserInitTest,OpenAppShortcutPanel)194 IN_PROC_BROWSER_TEST_F(BrowserInitTest, OpenAppShortcutPanel) {
195 // Load an app with launch.container = 'panel'.
196 const Extension* extension_app = NULL;
197 LoadApp("app_with_panel_container", &extension_app);
198 ASSERT_FALSE(HasFatalFailure()); // Check for ASSERT failures in LoadApp().
199
200 CommandLine command_line(CommandLine::NO_PROGRAM);
201 command_line.AppendSwitchASCII(switches::kAppId, extension_app->id());
202 BrowserInit::LaunchWithProfile launch(FilePath(), command_line);
203 ASSERT_TRUE(launch.Launch(browser()->profile(), std::vector<GURL>(), false));
204
205 // The launch should have created a new browser, with a panel type.
206 Browser* new_browser = NULL;
207 FindOneOtherBrowser(&new_browser);
208 ASSERT_FALSE(HasFatalFailure());
209
210 // Expect an app panel.
211 EXPECT_EQ(Browser::TYPE_APP_POPUP, new_browser->type());
212
213 // The new browser's app_name should include the app's ID.
214 EXPECT_NE(
215 new_browser->app_name_.find(extension_app->id()),
216 std::string::npos) << new_browser->app_name_;
217 }
218
219 #endif // !defined(OS_MACOSX)
220