Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / web_applications / web_app_mac_unittest.mm
blob3b7fa4d309ca0e366322edda0c5fb82e1ee046c2
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 #import "chrome/browser/web_applications/web_app_mac.h"
7 #import <Cocoa/Cocoa.h>
8 #include <errno.h>
9 #include <sys/xattr.h>
11 #include "base/command_line.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/mac/foundation_util.h"
15 #include "base/mac/scoped_nsobject.h"
16 #include "base/path_service.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/chrome_version_info.h"
22 #import "chrome/common/mac/app_mode_common.h"
23 #include "grit/theme_resources.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #import "testing/gtest_mac.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "ui/base/resource/resource_bundle.h"
29 #include "ui/gfx/image/image.h"
31 using ::testing::_;
32 using ::testing::Return;
33 using ::testing::NiceMock;
35 namespace {
37 const char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
39 class WebAppShortcutCreatorMock : public web_app::WebAppShortcutCreator {
40  public:
41   WebAppShortcutCreatorMock(const base::FilePath& app_data_dir,
42                             const web_app::ShortcutInfo& shortcut_info)
43       : WebAppShortcutCreator(app_data_dir,
44                               shortcut_info,
45                               extensions::FileHandlersInfo()) {}
47   WebAppShortcutCreatorMock(
48       const base::FilePath& app_data_dir,
49       const web_app::ShortcutInfo& shortcut_info,
50       const extensions::FileHandlersInfo& file_handlers_info)
51       : WebAppShortcutCreator(app_data_dir, shortcut_info, file_handlers_info) {
52   }
54   MOCK_CONST_METHOD0(GetApplicationsDirname, base::FilePath());
55   MOCK_CONST_METHOD1(GetAppBundleById,
56                      base::FilePath(const std::string& bundle_id));
57   MOCK_CONST_METHOD0(RevealAppShimInFinder, void());
59  private:
60   DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreatorMock);
63 web_app::ShortcutInfo GetShortcutInfo() {
64   web_app::ShortcutInfo info;
65   info.extension_id = "extensionid";
66   info.extension_path = base::FilePath("/fake/extension/path");
67   info.title = base::ASCIIToUTF16("Shortcut Title");
68   info.url = GURL("http://example.com/");
69   info.profile_path = base::FilePath("user_data_dir").Append("Profile 1");
70   info.profile_name = "profile name";
71   info.version_for_display = "stable 1.0";
72   return info;
75 class WebAppShortcutCreatorTest : public testing::Test {
76  protected:
77   WebAppShortcutCreatorTest() {}
79   void SetUp() override {
80     base::mac::SetBaseBundleID(kFakeChromeBundleId);
82     EXPECT_TRUE(temp_app_data_dir_.CreateUniqueTempDir());
83     EXPECT_TRUE(temp_destination_dir_.CreateUniqueTempDir());
84     app_data_dir_ = temp_app_data_dir_.path();
85     destination_dir_ = temp_destination_dir_.path();
87     info_ = GetShortcutInfo();
88     shim_base_name_ = base::FilePath(
89         info_.profile_path.BaseName().value() +
90         " " + info_.extension_id + ".app");
91     internal_shim_path_ = app_data_dir_.Append(shim_base_name_);
92     shim_path_ = destination_dir_.Append(shim_base_name_);
93   }
95   base::ScopedTempDir temp_app_data_dir_;
96   base::ScopedTempDir temp_destination_dir_;
97   base::FilePath app_data_dir_;
98   base::FilePath destination_dir_;
100   web_app::ShortcutInfo info_;
101   base::FilePath shim_base_name_;
102   base::FilePath internal_shim_path_;
103   base::FilePath shim_path_;
105  private:
106   DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreatorTest);
110 }  // namespace
112 namespace web_app {
114 TEST_F(WebAppShortcutCreatorTest, CreateShortcuts) {
115   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
116   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
117       .WillRepeatedly(Return(destination_dir_));
119   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
120       SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations()));
121   EXPECT_TRUE(base::PathExists(shim_path_));
122   EXPECT_TRUE(base::PathExists(destination_dir_));
123   EXPECT_EQ(shim_base_name_, shortcut_creator.GetShortcutBasename());
125   base::FilePath plist_path =
126       shim_path_.Append("Contents").Append("Info.plist");
127   NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:
128       base::mac::FilePathToNSString(plist_path)];
129   EXPECT_NSEQ(base::SysUTF8ToNSString(info_.extension_id),
130               [plist objectForKey:app_mode::kCrAppModeShortcutIDKey]);
131   EXPECT_NSEQ(base::SysUTF16ToNSString(info_.title),
132               [plist objectForKey:app_mode::kCrAppModeShortcutNameKey]);
133   EXPECT_NSEQ(base::SysUTF8ToNSString(info_.url.spec()),
134               [plist objectForKey:app_mode::kCrAppModeShortcutURLKey]);
136   EXPECT_NSEQ(base::SysUTF8ToNSString(chrome::VersionInfo().Version()),
137               [plist objectForKey:app_mode::kCrBundleVersionKey]);
138   EXPECT_NSEQ(base::SysUTF8ToNSString(info_.version_for_display),
139               [plist objectForKey:app_mode::kCFBundleShortVersionStringKey]);
141   // Make sure all values in the plist are actually filled in.
142   for (id key in plist) {
143     id value = [plist valueForKey:key];
144     if (!base::mac::ObjCCast<NSString>(value))
145       continue;
147     EXPECT_EQ([value rangeOfString:@"@APP_"].location, NSNotFound)
148         << [key UTF8String] << ":" << [value UTF8String];
149   }
152 TEST_F(WebAppShortcutCreatorTest, UpdateShortcuts) {
153   base::ScopedTempDir other_folder_temp_dir;
154   EXPECT_TRUE(other_folder_temp_dir.CreateUniqueTempDir());
155   base::FilePath other_folder = other_folder_temp_dir.path();
156   base::FilePath other_shim_path = other_folder.Append(shim_base_name_);
158   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
159   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
160       .WillRepeatedly(Return(destination_dir_));
162   std::string expected_bundle_id = kFakeChromeBundleId;
163   expected_bundle_id += ".app.Profile-1-" + info_.extension_id;
164   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
165       .WillOnce(Return(other_shim_path));
167   EXPECT_TRUE(shortcut_creator.BuildShortcut(other_shim_path));
169   EXPECT_TRUE(base::DeleteFile(other_shim_path.Append("Contents"), true));
171   EXPECT_TRUE(shortcut_creator.UpdateShortcuts());
172   EXPECT_FALSE(base::PathExists(shim_path_));
173   EXPECT_TRUE(base::PathExists(other_shim_path.Append("Contents")));
175   // Also test case where GetAppBundleById fails.
176   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
177       .WillOnce(Return(base::FilePath()));
179   EXPECT_TRUE(shortcut_creator.BuildShortcut(other_shim_path));
181   EXPECT_TRUE(base::DeleteFile(other_shim_path.Append("Contents"), true));
183   EXPECT_FALSE(shortcut_creator.UpdateShortcuts());
184   EXPECT_FALSE(base::PathExists(shim_path_));
185   EXPECT_FALSE(base::PathExists(other_shim_path.Append("Contents")));
188 TEST_F(WebAppShortcutCreatorTest, DeleteShortcuts) {
189   // When using PathService::Override, it calls base::MakeAbsoluteFilePath.
190   // On Mac this prepends "/private" to the path, but points to the same
191   // directory in the file system.
192   app_data_dir_ = base::MakeAbsoluteFilePath(app_data_dir_);
194   base::ScopedTempDir other_folder_temp_dir;
195   EXPECT_TRUE(other_folder_temp_dir.CreateUniqueTempDir());
196   base::FilePath other_folder = other_folder_temp_dir.path();
197   base::FilePath other_shim_path = other_folder.Append(shim_base_name_);
199   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
200   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
201       .WillRepeatedly(Return(destination_dir_));
203   std::string expected_bundle_id = kFakeChromeBundleId;
204   expected_bundle_id += ".app.Profile-1-" + info_.extension_id;
205   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
206       .WillOnce(Return(other_shim_path));
208   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
209       SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations()));
210   EXPECT_TRUE(base::PathExists(internal_shim_path_));
211   EXPECT_TRUE(base::PathExists(shim_path_));
213   // Create an extra shim in another folder. It should be deleted since its
214   // bundle id matches.
215   EXPECT_TRUE(shortcut_creator.BuildShortcut(other_shim_path));
216   EXPECT_TRUE(base::PathExists(other_shim_path));
218   // Change the user_data_dir of the shim at shim_path_. It should not be
219   // deleted since its user_data_dir does not match.
220   NSString* plist_path = base::mac::FilePathToNSString(
221       shim_path_.Append("Contents").Append("Info.plist"));
222   NSMutableDictionary* plist =
223       [NSDictionary dictionaryWithContentsOfFile:plist_path];
224   [plist setObject:@"fake_user_data_dir"
225             forKey:app_mode::kCrAppModeUserDataDirKey];
226   [plist writeToFile:plist_path
227           atomically:YES];
229   EXPECT_TRUE(PathService::Override(chrome::DIR_USER_DATA, app_data_dir_));
230   shortcut_creator.DeleteShortcuts();
231   EXPECT_FALSE(base::PathExists(internal_shim_path_));
232   EXPECT_TRUE(base::PathExists(shim_path_));
233   EXPECT_FALSE(base::PathExists(other_shim_path));
236 TEST_F(WebAppShortcutCreatorTest, CreateAppListShortcut) {
237   // With an empty |profile_name|, the shortcut path should not have the profile
238   // directory prepended to the extension id on the app bundle name.
239   info_.profile_name.clear();
240   base::FilePath dst_path =
241       destination_dir_.Append(info_.extension_id + ".app");
243   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(base::FilePath(), info_);
244   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
245       .WillRepeatedly(Return(destination_dir_));
246   EXPECT_EQ(dst_path.BaseName(), shortcut_creator.GetShortcutBasename());
249 TEST_F(WebAppShortcutCreatorTest, RunShortcut) {
250   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
251   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
252       .WillRepeatedly(Return(destination_dir_));
254   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
255       SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations()));
256   EXPECT_TRUE(base::PathExists(shim_path_));
258   ssize_t status = getxattr(
259       shim_path_.value().c_str(), "com.apple.quarantine", NULL, 0, 0, 0);
260   EXPECT_EQ(-1, status);
261   EXPECT_EQ(ENOATTR, errno);
264 TEST_F(WebAppShortcutCreatorTest, CreateFailure) {
265   base::FilePath non_existent_path =
266       destination_dir_.Append("not-existent").Append("name.app");
268   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
269   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
270       .WillRepeatedly(Return(non_existent_path));
271   EXPECT_FALSE(shortcut_creator.CreateShortcuts(
272       SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations()));
275 TEST_F(WebAppShortcutCreatorTest, UpdateIcon) {
276   gfx::Image product_logo =
277       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
278           IDR_PRODUCT_LOGO_32);
279   info_.favicon.Add(product_logo);
280   WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_);
282   ASSERT_TRUE(shortcut_creator.UpdateIcon(shim_path_));
283   base::FilePath icon_path =
284       shim_path_.Append("Contents").Append("Resources").Append("app.icns");
286   base::scoped_nsobject<NSImage> image([[NSImage alloc]
287       initWithContentsOfFile:base::mac::FilePathToNSString(icon_path)]);
288   EXPECT_TRUE(image);
289   EXPECT_EQ(product_logo.Width(), [image size].width);
290   EXPECT_EQ(product_logo.Height(), [image size].height);
293 TEST_F(WebAppShortcutCreatorTest, RevealAppShimInFinder) {
294   WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_);
295   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
296       .WillRepeatedly(Return(destination_dir_));
298   EXPECT_CALL(shortcut_creator, RevealAppShimInFinder())
299       .Times(0);
300   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
301       SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations()));
303   EXPECT_CALL(shortcut_creator, RevealAppShimInFinder());
304   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
305       SHORTCUT_CREATION_BY_USER, web_app::ShortcutLocations()));
308 TEST_F(WebAppShortcutCreatorTest, FileHandlers) {
309   base::CommandLine::ForCurrentProcess()->AppendSwitch(
310       switches::kEnableAppsFileAssociations);
311   extensions::FileHandlersInfo file_handlers_info;
312   extensions::FileHandlerInfo handler_0;
313   handler_0.extensions.insert("ext0");
314   handler_0.extensions.insert("ext1");
315   handler_0.types.insert("type0");
316   handler_0.types.insert("type1");
317   file_handlers_info.push_back(handler_0);
318   extensions::FileHandlerInfo handler_1;
319   handler_1.extensions.insert("ext2");
320   handler_1.types.insert("type2");
321   file_handlers_info.push_back(handler_1);
323   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(
324       app_data_dir_, info_, file_handlers_info);
325   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
326       .WillRepeatedly(Return(destination_dir_));
327   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
328       SHORTCUT_CREATION_AUTOMATED, web_app::ShortcutLocations()));
330   base::FilePath plist_path =
331       shim_path_.Append("Contents").Append("Info.plist");
332   NSDictionary* plist = [NSDictionary
333       dictionaryWithContentsOfFile:base::mac::FilePathToNSString(plist_path)];
334   NSArray* file_handlers =
335       [plist objectForKey:app_mode::kCFBundleDocumentTypesKey];
337   NSDictionary* file_handler_0 = [file_handlers objectAtIndex:0];
338   EXPECT_NSEQ(app_mode::kBundleTypeRoleViewer,
339               [file_handler_0 objectForKey:app_mode::kCFBundleTypeRoleKey]);
340   NSArray* file_handler_0_extensions =
341       [file_handler_0 objectForKey:app_mode::kCFBundleTypeExtensionsKey];
342   EXPECT_TRUE([file_handler_0_extensions containsObject:@"ext0"]);
343   EXPECT_TRUE([file_handler_0_extensions containsObject:@"ext1"]);
344   NSArray* file_handler_0_types =
345       [file_handler_0 objectForKey:app_mode::kCFBundleTypeMIMETypesKey];
346   EXPECT_TRUE([file_handler_0_types containsObject:@"type0"]);
347   EXPECT_TRUE([file_handler_0_types containsObject:@"type1"]);
349   NSDictionary* file_handler_1 = [file_handlers objectAtIndex:1];
350   EXPECT_NSEQ(app_mode::kBundleTypeRoleViewer,
351               [file_handler_1 objectForKey:app_mode::kCFBundleTypeRoleKey]);
352   NSArray* file_handler_1_extensions =
353       [file_handler_1 objectForKey:app_mode::kCFBundleTypeExtensionsKey];
354   EXPECT_TRUE([file_handler_1_extensions containsObject:@"ext2"]);
355   NSArray* file_handler_1_types =
356       [file_handler_1 objectForKey:app_mode::kCFBundleTypeMIMETypesKey];
357   EXPECT_TRUE([file_handler_1_types containsObject:@"type2"]);
360 }  // namespace web_app