Fix memory leak in app_list_view_unittest.
[chromium-blink-merge.git] / apps / app_shim / extension_app_shim_handler_mac_unittest.cc
blob573a48f292a9019d8ba8d0e50fba867cce60f24d
1 // Copyright 2013 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 "apps/app_shim/extension_app_shim_handler_mac.h"
7 #include <vector>
9 #include "apps/app_shim/app_shim_host_mac.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/test/base/testing_profile.h"
13 #include "content/public/browser/notification_service.h"
14 #include "extensions/common/extension.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 namespace apps {
20 using extensions::Extension;
21 typedef AppWindowRegistry::AppWindowList AppWindowList;
23 using ::testing::_;
24 using ::testing::Invoke;
25 using ::testing::Return;
26 using ::testing::WithArgs;
28 class MockDelegate : public ExtensionAppShimHandler::Delegate {
29 public:
30 virtual ~MockDelegate() {}
32 MOCK_METHOD1(ProfileExistsForPath, bool(const base::FilePath&));
33 MOCK_METHOD1(ProfileForPath, Profile*(const base::FilePath&));
34 MOCK_METHOD2(LoadProfileAsync,
35 void(const base::FilePath&,
36 base::Callback<void(Profile*)>));
38 MOCK_METHOD2(GetWindows, AppWindowList(Profile*, const std::string&));
40 MOCK_METHOD2(GetAppExtension, const Extension*(Profile*, const std::string&));
41 MOCK_METHOD3(EnableExtension, void(Profile*,
42 const std::string&,
43 const base::Callback<void()>&));
44 MOCK_METHOD3(LaunchApp,
45 void(Profile*,
46 const Extension*,
47 const std::vector<base::FilePath>&));
48 MOCK_METHOD2(LaunchShim, void(Profile*, const Extension*));
50 MOCK_METHOD0(MaybeTerminate, void());
52 void CaptureLoadProfileCallback(
53 const base::FilePath& path,
54 base::Callback<void(Profile*)> callback) {
55 callbacks_[path] = callback;
58 bool RunLoadProfileCallback(
59 const base::FilePath& path,
60 Profile* profile) {
61 callbacks_[path].Run(profile);
62 return callbacks_.erase(path);
65 void RunCallback(const base::Callback<void()>& callback) {
66 callback.Run();
69 private:
70 std::map<base::FilePath,
71 base::Callback<void(Profile*)> > callbacks_;
74 class TestingExtensionAppShimHandler : public ExtensionAppShimHandler {
75 public:
76 TestingExtensionAppShimHandler(Delegate* delegate) {
77 set_delegate(delegate);
79 virtual ~TestingExtensionAppShimHandler() {}
81 MOCK_METHOD3(OnShimFocus,
82 void(Host* host,
83 AppShimFocusType,
84 const std::vector<base::FilePath>& files));
86 void RealOnShimFocus(Host* host,
87 AppShimFocusType focus_type,
88 const std::vector<base::FilePath>& files) {
89 ExtensionAppShimHandler::OnShimFocus(host, focus_type, files);
92 AppShimHandler::Host* FindHost(Profile* profile,
93 const std::string& app_id) {
94 HostMap::const_iterator it = hosts().find(make_pair(profile, app_id));
95 return it == hosts().end() ? NULL : it->second;
98 content::NotificationRegistrar& GetRegistrar() { return registrar(); }
100 private:
101 DISALLOW_COPY_AND_ASSIGN(TestingExtensionAppShimHandler);
104 const char kTestAppIdA[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
105 const char kTestAppIdB[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
107 class FakeHost : public apps::AppShimHandler::Host {
108 public:
109 FakeHost(const base::FilePath& profile_path,
110 const std::string& app_id,
111 TestingExtensionAppShimHandler* handler)
112 : profile_path_(profile_path),
113 app_id_(app_id),
114 handler_(handler),
115 close_count_(0) {}
117 MOCK_METHOD1(OnAppLaunchComplete, void(AppShimLaunchResult));
119 virtual void OnAppClosed() OVERRIDE {
120 handler_->OnShimClose(this);
121 ++close_count_;
123 virtual void OnAppHide() OVERRIDE {}
124 virtual void OnAppRequestUserAttention(AppShimAttentionType type) OVERRIDE {}
125 virtual base::FilePath GetProfilePath() const OVERRIDE {
126 return profile_path_;
128 virtual std::string GetAppId() const OVERRIDE { return app_id_; }
130 int close_count() { return close_count_; }
132 private:
133 base::FilePath profile_path_;
134 std::string app_id_;
135 TestingExtensionAppShimHandler* handler_;
136 int close_count_;
138 DISALLOW_COPY_AND_ASSIGN(FakeHost);
141 class ExtensionAppShimHandlerTest : public testing::Test {
142 protected:
143 ExtensionAppShimHandlerTest()
144 : delegate_(new MockDelegate),
145 handler_(new TestingExtensionAppShimHandler(delegate_)),
146 profile_path_a_("Profile A"),
147 profile_path_b_("Profile B"),
148 host_aa_(profile_path_a_, kTestAppIdA, handler_.get()),
149 host_ab_(profile_path_a_, kTestAppIdB, handler_.get()),
150 host_bb_(profile_path_b_, kTestAppIdB, handler_.get()),
151 host_aa_duplicate_(profile_path_a_, kTestAppIdA, handler_.get()) {
152 base::FilePath extension_path("/fake/path");
153 base::DictionaryValue manifest;
154 manifest.SetString("name", "Fake Name");
155 manifest.SetString("version", "1");
156 std::string error;
157 extension_a_ = Extension::Create(
158 extension_path, extensions::Manifest::INTERNAL, manifest,
159 Extension::NO_FLAGS, kTestAppIdA, &error);
160 EXPECT_TRUE(extension_a_.get()) << error;
162 extension_b_ = Extension::Create(
163 extension_path, extensions::Manifest::INTERNAL, manifest,
164 Extension::NO_FLAGS, kTestAppIdB, &error);
165 EXPECT_TRUE(extension_b_.get()) << error;
167 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
168 .WillRepeatedly(Return(true));
169 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
170 .WillRepeatedly(Return(&profile_a_));
171 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_b_))
172 .WillRepeatedly(Return(true));
173 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_b_))
174 .WillRepeatedly(Return(&profile_b_));
176 // In most tests, we don't care about the result of GetWindows, it just
177 // needs to be non-empty.
178 AppWindowList app_window_list;
179 app_window_list.push_back(static_cast<AppWindow*>(NULL));
180 EXPECT_CALL(*delegate_, GetWindows(_, _))
181 .WillRepeatedly(Return(app_window_list));
183 EXPECT_CALL(*delegate_, GetAppExtension(_, kTestAppIdA))
184 .WillRepeatedly(Return(extension_a_.get()));
185 EXPECT_CALL(*delegate_, GetAppExtension(_, kTestAppIdB))
186 .WillRepeatedly(Return(extension_b_.get()));
187 EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
188 .WillRepeatedly(Return());
191 void NormalLaunch(AppShimHandler::Host* host) {
192 handler_->OnShimLaunch(host,
193 APP_SHIM_LAUNCH_NORMAL,
194 std::vector<base::FilePath>());
197 void RegisterOnlyLaunch(AppShimHandler::Host* host) {
198 handler_->OnShimLaunch(host,
199 APP_SHIM_LAUNCH_REGISTER_ONLY,
200 std::vector<base::FilePath>());
203 MockDelegate* delegate_;
204 scoped_ptr<TestingExtensionAppShimHandler> handler_;
205 base::FilePath profile_path_a_;
206 base::FilePath profile_path_b_;
207 TestingProfile profile_a_;
208 TestingProfile profile_b_;
209 FakeHost host_aa_;
210 FakeHost host_ab_;
211 FakeHost host_bb_;
212 FakeHost host_aa_duplicate_;
213 scoped_refptr<Extension> extension_a_;
214 scoped_refptr<Extension> extension_b_;
216 private:
217 DISALLOW_COPY_AND_ASSIGN(ExtensionAppShimHandlerTest);
220 TEST_F(ExtensionAppShimHandlerTest, LaunchProfileNotFound) {
221 // Bad profile path.
222 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
223 .WillOnce(Return(false))
224 .WillRepeatedly(Return(true));
225 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND));
226 NormalLaunch(&host_aa_);
229 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotFound) {
230 // App not found.
231 EXPECT_CALL(*delegate_, GetAppExtension(&profile_a_, kTestAppIdA))
232 .WillRepeatedly(Return(static_cast<const Extension*>(NULL)));
233 EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
234 .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
235 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND));
236 NormalLaunch(&host_aa_);
239 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotEnabled) {
240 // App not found.
241 EXPECT_CALL(*delegate_, GetAppExtension(&profile_a_, kTestAppIdA))
242 .WillOnce(Return(static_cast<const Extension*>(NULL)))
243 .WillRepeatedly(Return(extension_a_.get()));
244 EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
245 .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
246 NormalLaunch(&host_aa_);
249 TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) {
250 // Normal startup.
251 NormalLaunch(&host_aa_);
252 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
254 NormalLaunch(&host_ab_);
255 EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
257 std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
258 EXPECT_CALL(*delegate_,
259 LaunchApp(&profile_b_, extension_b_.get(), some_file));
260 handler_->OnShimLaunch(&host_bb_, APP_SHIM_LAUNCH_NORMAL, some_file);
261 EXPECT_EQ(&host_bb_, handler_->FindHost(&profile_b_, kTestAppIdB));
263 // Activation when there is a registered shim finishes launch with success and
264 // focuses the app.
265 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
266 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _));
267 handler_->OnAppActivated(&profile_a_, kTestAppIdA);
269 // Starting and closing a second host just focuses the app.
270 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_duplicate_,
271 APP_SHIM_FOCUS_REOPEN,
272 some_file));
273 EXPECT_CALL(host_aa_duplicate_,
274 OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST));
275 handler_->OnShimLaunch(&host_aa_duplicate_,
276 APP_SHIM_LAUNCH_NORMAL,
277 some_file);
278 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
279 handler_->OnShimClose(&host_aa_duplicate_);
280 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
282 // Normal close.
283 handler_->OnShimClose(&host_aa_);
284 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
286 // Closing the second host afterward does nothing.
287 handler_->OnShimClose(&host_aa_duplicate_);
288 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
291 TEST_F(ExtensionAppShimHandlerTest, AppLifetime) {
292 // When the app activates, if there is no shim, start one.
293 EXPECT_CALL(*delegate_, LaunchShim(&profile_a_, extension_a_.get()));
294 handler_->OnAppActivated(&profile_a_, kTestAppIdA);
296 // Normal shim launch adds an entry in the map.
297 // App should not be launched here, but return success to the shim.
298 EXPECT_CALL(*delegate_,
299 LaunchApp(&profile_a_, extension_a_.get(), _))
300 .Times(0);
301 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
302 RegisterOnlyLaunch(&host_aa_);
303 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
305 // Return no app windows for OnShimFocus and OnShimQuit.
306 AppWindowList app_window_list;
307 EXPECT_CALL(*delegate_, GetWindows(&profile_a_, kTestAppIdA))
308 .WillRepeatedly(Return(app_window_list));
310 // Non-reopen focus does nothing.
311 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _))
312 .WillOnce(Invoke(handler_.get(),
313 &TestingExtensionAppShimHandler::RealOnShimFocus));
314 EXPECT_CALL(*delegate_,
315 LaunchApp(&profile_a_, extension_a_.get(), _))
316 .Times(0);
317 handler_->OnShimFocus(&host_aa_,
318 APP_SHIM_FOCUS_NORMAL,
319 std::vector<base::FilePath>());
321 // Reopen focus launches the app.
322 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, _))
323 .WillOnce(Invoke(handler_.get(),
324 &TestingExtensionAppShimHandler::RealOnShimFocus));
325 std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
326 EXPECT_CALL(*delegate_,
327 LaunchApp(&profile_a_, extension_a_.get(), some_file));
328 handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, some_file);
330 // Quit just closes all the windows. This tests that it doesn't terminate,
331 // but we expect closing all windows triggers a OnAppDeactivated from
332 // AppLifetimeMonitor.
333 handler_->OnShimQuit(&host_aa_);
335 // Closing all windows closes the shim and checks if Chrome should be
336 // terminated.
337 EXPECT_CALL(*delegate_, MaybeTerminate())
338 .WillOnce(Return());
339 handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
340 EXPECT_EQ(1, host_aa_.close_count());
343 TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) {
344 // Launch shims, adding entries in the map.
345 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
346 RegisterOnlyLaunch(&host_aa_);
347 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
349 EXPECT_CALL(host_ab_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
350 RegisterOnlyLaunch(&host_ab_);
351 EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
353 // Return empty window list.
354 AppWindowList app_window_list;
355 EXPECT_CALL(*delegate_, GetWindows(_, _))
356 .WillRepeatedly(Return(app_window_list));
358 // Quitting when there's another shim should not terminate.
359 EXPECT_CALL(*delegate_, MaybeTerminate())
360 .Times(0);
361 handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
363 // Quitting when it's the last shim should terminate.
364 EXPECT_CALL(*delegate_, MaybeTerminate());
365 handler_->OnAppDeactivated(&profile_a_, kTestAppIdB);
368 TEST_F(ExtensionAppShimHandlerTest, RegisterOnly) {
369 // For an APP_SHIM_LAUNCH_REGISTER_ONLY, don't launch the app.
370 EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
371 .Times(0);
372 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
373 RegisterOnlyLaunch(&host_aa_);
374 EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
376 // Close the shim, removing the entry in the map.
377 handler_->OnShimClose(&host_aa_);
378 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
381 TEST_F(ExtensionAppShimHandlerTest, LoadProfile) {
382 // If the profile is not loaded when an OnShimLaunch arrives, return false
383 // and load the profile asynchronously. Launch the app when the profile is
384 // ready.
385 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
386 .WillOnce(Return(static_cast<Profile*>(NULL)))
387 .WillRepeatedly(Return(&profile_a_));
388 EXPECT_CALL(*delegate_, LoadProfileAsync(profile_path_a_, _))
389 .WillOnce(Invoke(delegate_, &MockDelegate::CaptureLoadProfileCallback));
390 NormalLaunch(&host_aa_);
391 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
392 delegate_->RunLoadProfileCallback(profile_path_a_, &profile_a_);
393 EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
396 } // namespace apps