Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / web_applications / web_app_mac_unittest.mm
blob463383770b8baedb14348a2b14f13576517fcce7
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/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/mac/foundation_util.h"
14 #include "base/mac/scoped_nsobject.h"
15 #include "base/path_service.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "chrome/common/chrome_paths.h"
19 #import "chrome/common/mac/app_mode_common.h"
20 #include "grit/theme_resources.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #import "testing/gtest_mac.h"
24 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/gfx/image/image.h"
28 using ::testing::_;
29 using ::testing::Return;
30 using ::testing::NiceMock;
32 namespace {
34 const char kFakeChromeBundleId[] = "fake.cfbundleidentifier";
36 class WebAppShortcutCreatorMock : public web_app::WebAppShortcutCreator {
37  public:
38   explicit WebAppShortcutCreatorMock(
39       const base::FilePath& app_data_dir,
40       const ShellIntegration::ShortcutInfo& shortcut_info)
41       : WebAppShortcutCreator(app_data_dir,
42                               shortcut_info) {
43   }
45   MOCK_CONST_METHOD0(GetApplicationsDirname, base::FilePath());
46   MOCK_CONST_METHOD1(GetAppBundleById,
47                      base::FilePath(const std::string& bundle_id));
48   MOCK_CONST_METHOD0(RevealAppShimInFinder, void());
50  private:
51   DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreatorMock);
54 ShellIntegration::ShortcutInfo GetShortcutInfo() {
55   ShellIntegration::ShortcutInfo info;
56   info.extension_id = "extensionid";
57   info.extension_path = base::FilePath("/fake/extension/path");
58   info.title = base::ASCIIToUTF16("Shortcut Title");
59   info.url = GURL("http://example.com/");
60   info.profile_path = base::FilePath("user_data_dir").Append("Profile 1");
61   info.profile_name = "profile name";
62   return info;
65 class WebAppShortcutCreatorTest : public testing::Test {
66  protected:
67   WebAppShortcutCreatorTest() {}
69   virtual void SetUp() {
70     base::mac::SetBaseBundleID(kFakeChromeBundleId);
72     EXPECT_TRUE(temp_app_data_dir_.CreateUniqueTempDir());
73     EXPECT_TRUE(temp_destination_dir_.CreateUniqueTempDir());
74     app_data_dir_ = temp_app_data_dir_.path();
75     destination_dir_ = temp_destination_dir_.path();
77     info_ = GetShortcutInfo();
78     shim_base_name_ = base::FilePath(
79         info_.profile_path.BaseName().value() +
80         " " + info_.extension_id + ".app");
81     internal_shim_path_ = app_data_dir_.Append(shim_base_name_);
82     shim_path_ = destination_dir_.Append(shim_base_name_);
83   }
85   base::ScopedTempDir temp_app_data_dir_;
86   base::ScopedTempDir temp_destination_dir_;
87   base::FilePath app_data_dir_;
88   base::FilePath destination_dir_;
90   ShellIntegration::ShortcutInfo info_;
91   base::FilePath shim_base_name_;
92   base::FilePath internal_shim_path_;
93   base::FilePath shim_path_;
95  private:
96   DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreatorTest);
100 }  // namespace
102 namespace web_app {
104 TEST_F(WebAppShortcutCreatorTest, CreateShortcuts) {
105   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
106   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
107       .WillRepeatedly(Return(destination_dir_));
109   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
110       SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
111   EXPECT_TRUE(base::PathExists(shim_path_));
112   EXPECT_TRUE(base::PathExists(destination_dir_));
113   EXPECT_EQ(shim_base_name_, shortcut_creator.GetShortcutBasename());
115   base::FilePath plist_path =
116       shim_path_.Append("Contents").Append("Info.plist");
117   NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:
118       base::mac::FilePathToNSString(plist_path)];
119   EXPECT_NSEQ(base::SysUTF8ToNSString(info_.extension_id),
120               [plist objectForKey:app_mode::kCrAppModeShortcutIDKey]);
121   EXPECT_NSEQ(base::SysUTF16ToNSString(info_.title),
122               [plist objectForKey:app_mode::kCrAppModeShortcutNameKey]);
123   EXPECT_NSEQ(base::SysUTF8ToNSString(info_.url.spec()),
124               [plist objectForKey:app_mode::kCrAppModeShortcutURLKey]);
126   // Make sure all values in the plist are actually filled in.
127   for (id key in plist) {
128     id value = [plist valueForKey:key];
129     if (!base::mac::ObjCCast<NSString>(value))
130       continue;
132     EXPECT_EQ([value rangeOfString:@"@APP_"].location, NSNotFound)
133         << [key UTF8String] << ":" << [value UTF8String];
134   }
137 TEST_F(WebAppShortcutCreatorTest, UpdateShortcuts) {
138   base::ScopedTempDir other_folder_temp_dir;
139   EXPECT_TRUE(other_folder_temp_dir.CreateUniqueTempDir());
140   base::FilePath other_folder = other_folder_temp_dir.path();
141   base::FilePath other_shim_path = other_folder.Append(shim_base_name_);
143   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
144   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
145       .WillRepeatedly(Return(destination_dir_));
147   std::string expected_bundle_id = kFakeChromeBundleId;
148   expected_bundle_id += ".app.Profile-1-" + info_.extension_id;
149   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
150       .WillOnce(Return(other_shim_path));
152   EXPECT_TRUE(shortcut_creator.BuildShortcut(other_shim_path));
154   EXPECT_TRUE(base::DeleteFile(other_shim_path.Append("Contents"), true));
156   EXPECT_TRUE(shortcut_creator.UpdateShortcuts());
157   EXPECT_FALSE(base::PathExists(shim_path_));
158   EXPECT_TRUE(base::PathExists(other_shim_path.Append("Contents")));
160   // Also test case where GetAppBundleById fails.
161   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
162       .WillOnce(Return(base::FilePath()));
164   EXPECT_TRUE(shortcut_creator.BuildShortcut(other_shim_path));
166   EXPECT_TRUE(base::DeleteFile(other_shim_path.Append("Contents"), true));
168   EXPECT_FALSE(shortcut_creator.UpdateShortcuts());
169   EXPECT_FALSE(base::PathExists(shim_path_));
170   EXPECT_FALSE(base::PathExists(other_shim_path.Append("Contents")));
173 TEST_F(WebAppShortcutCreatorTest, DeleteShortcuts) {
174   // When using PathService::Override, it calls base::MakeAbsoluteFilePath.
175   // On Mac this prepends "/private" to the path, but points to the same
176   // directory in the file system.
177   app_data_dir_ = base::MakeAbsoluteFilePath(app_data_dir_);
179   base::ScopedTempDir other_folder_temp_dir;
180   EXPECT_TRUE(other_folder_temp_dir.CreateUniqueTempDir());
181   base::FilePath other_folder = other_folder_temp_dir.path();
182   base::FilePath other_shim_path = other_folder.Append(shim_base_name_);
184   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
185   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
186       .WillRepeatedly(Return(destination_dir_));
188   std::string expected_bundle_id = kFakeChromeBundleId;
189   expected_bundle_id += ".app.Profile-1-" + info_.extension_id;
190   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
191       .WillOnce(Return(other_shim_path));
193   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
194       SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
195   EXPECT_TRUE(base::PathExists(internal_shim_path_));
196   EXPECT_TRUE(base::PathExists(shim_path_));
198   // Create an extra shim in another folder. It should be deleted since its
199   // bundle id matches.
200   EXPECT_TRUE(shortcut_creator.BuildShortcut(other_shim_path));
201   EXPECT_TRUE(base::PathExists(other_shim_path));
203   // Change the user_data_dir of the shim at shim_path_. It should not be
204   // deleted since its user_data_dir does not match.
205   NSString* plist_path = base::mac::FilePathToNSString(
206       shim_path_.Append("Contents").Append("Info.plist"));
207   NSMutableDictionary* plist =
208       [NSDictionary dictionaryWithContentsOfFile:plist_path];
209   [plist setObject:@"fake_user_data_dir"
210             forKey:app_mode::kCrAppModeUserDataDirKey];
211   [plist writeToFile:plist_path
212           atomically:YES];
214   EXPECT_TRUE(PathService::Override(chrome::DIR_USER_DATA, app_data_dir_));
215   shortcut_creator.DeleteShortcuts();
216   EXPECT_FALSE(base::PathExists(internal_shim_path_));
217   EXPECT_TRUE(base::PathExists(shim_path_));
218   EXPECT_FALSE(base::PathExists(other_shim_path));
221 TEST_F(WebAppShortcutCreatorTest, CreateAppListShortcut) {
222   // With an empty |profile_name|, the shortcut path should not have the profile
223   // directory prepended to the extension id on the app bundle name.
224   info_.profile_name.clear();
225   base::FilePath dst_path =
226       destination_dir_.Append(info_.extension_id + ".app");
228   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(base::FilePath(), info_);
229   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
230       .WillRepeatedly(Return(destination_dir_));
231   EXPECT_EQ(dst_path.BaseName(), shortcut_creator.GetShortcutBasename());
234 TEST_F(WebAppShortcutCreatorTest, RunShortcut) {
235   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
236   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
237       .WillRepeatedly(Return(destination_dir_));
239   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
240       SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
241   EXPECT_TRUE(base::PathExists(shim_path_));
243   ssize_t status = getxattr(
244       shim_path_.value().c_str(), "com.apple.quarantine", NULL, 0, 0, 0);
245   EXPECT_EQ(-1, status);
246   EXPECT_EQ(ENOATTR, errno);
249 TEST_F(WebAppShortcutCreatorTest, CreateFailure) {
250   base::FilePath non_existent_path =
251       destination_dir_.Append("not-existent").Append("name.app");
253   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
254   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
255       .WillRepeatedly(Return(non_existent_path));
256   EXPECT_FALSE(shortcut_creator.CreateShortcuts(
257       SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
260 TEST_F(WebAppShortcutCreatorTest, UpdateIcon) {
261   gfx::Image product_logo =
262       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
263           IDR_PRODUCT_LOGO_32);
264   info_.favicon.Add(product_logo);
265   WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_);
267   ASSERT_TRUE(shortcut_creator.UpdateIcon(shim_path_));
268   base::FilePath icon_path =
269       shim_path_.Append("Contents").Append("Resources").Append("app.icns");
271   base::scoped_nsobject<NSImage> image([[NSImage alloc]
272       initWithContentsOfFile:base::mac::FilePathToNSString(icon_path)]);
273   EXPECT_TRUE(image);
274   EXPECT_EQ(product_logo.Width(), [image size].width);
275   EXPECT_EQ(product_logo.Height(), [image size].height);
278 TEST_F(WebAppShortcutCreatorTest, RevealAppShimInFinder) {
279   WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_);
280   EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
281       .WillRepeatedly(Return(destination_dir_));
283   EXPECT_CALL(shortcut_creator, RevealAppShimInFinder())
284       .Times(0);
285   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
286       SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
288   EXPECT_CALL(shortcut_creator, RevealAppShimInFinder());
289   EXPECT_TRUE(shortcut_creator.CreateShortcuts(
290       SHORTCUT_CREATION_BY_USER, ShellIntegration::ShortcutLocations()));
293 }  // namespace web_app