Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / shell_integration_win_unittest.cc
blobf09c11ce7016b2cb0e08fe70abfce9ea50152317
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/browser/shell_integration.h"
7 #include <vector>
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/macros.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/test/test_shortcut_win.h"
17 #include "base/win/scoped_com_initializer.h"
18 #include "base/win/windows_version.h"
19 #include "chrome/browser/web_applications/web_app.h"
20 #include "chrome/common/chrome_constants.h"
21 #include "chrome/common/chrome_paths_internal.h"
22 #include "chrome/installer/util/browser_distribution.h"
23 #include "chrome/installer/util/install_util.h"
24 #include "chrome/installer/util/shell_util.h"
25 #include "chrome/installer/util/util_constants.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 namespace {
30 struct ShortcutTestObject {
31 base::FilePath path;
32 base::win::ShortcutProperties properties;
35 class ShellIntegrationWinMigrateShortcutTest : public testing::Test {
36 protected:
37 ShellIntegrationWinMigrateShortcutTest()
38 : desired_dual_mode_for_os_version(
39 InstallUtil::ShouldInstallMetroProperties()) {}
41 void SetUp() override {
42 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
44 // A path to a random target.
45 base::CreateTemporaryFileInDir(temp_dir_.path(), &other_target_);
47 // This doesn't need to actually have a base name of "chrome.exe".
48 base::CreateTemporaryFileInDir(temp_dir_.path(), &chrome_exe_);
50 chrome_app_id_ =
51 ShellUtil::GetBrowserModelId(BrowserDistribution::GetDistribution(),
52 true);
54 base::FilePath default_user_data_dir;
55 chrome::GetDefaultUserDataDirectory(&default_user_data_dir);
56 base::FilePath default_profile_path =
57 default_user_data_dir.AppendASCII(chrome::kInitialProfile);
58 app_list_app_id_ =
59 ShellIntegration::GetAppListAppModelIdForProfile(default_profile_path);
60 non_default_user_data_dir_ = base::FilePath(FILE_PATH_LITERAL("root"))
61 .Append(FILE_PATH_LITERAL("Non Default Data Dir"));
62 non_default_profile_ = L"NonDefault";
63 non_default_profile_chrome_app_id_ =
64 ShellIntegration::GetChromiumModelIdForProfile(
65 default_user_data_dir.Append(non_default_profile_));
66 non_default_user_data_dir_chrome_app_id_ =
67 ShellIntegration::GetChromiumModelIdForProfile(
68 non_default_user_data_dir_.AppendASCII(chrome::kInitialProfile));
69 non_default_user_data_dir_and_profile_chrome_app_id_ =
70 ShellIntegration::GetChromiumModelIdForProfile(
71 non_default_user_data_dir_.Append(non_default_profile_));
74 extension_id_ = L"chromiumexampleappidforunittests";
75 base::string16 app_name =
76 base::UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId(
77 base::UTF16ToUTF8(extension_id_)));
78 extension_app_id_ =
79 ShellIntegration::GetAppModelIdForProfile(app_name,
80 default_profile_path);
81 non_default_profile_extension_app_id_ =
82 ShellIntegration::GetAppModelIdForProfile(
83 app_name,
84 default_user_data_dir.Append(non_default_profile_));
86 CreateShortcuts();
89 // Creates a test shortcut corresponding to |shortcut_properties| and resets
90 // |shortcut_properties| after copying it to an internal structure for later
91 // verification.
92 void AddTestShortcutAndResetProperties(
93 base::win::ShortcutProperties* shortcut_properties) {
94 ShortcutTestObject shortcut_test_object;
95 base::FilePath shortcut_path =
96 temp_dir_.path().Append(L"Shortcut " +
97 base::IntToString16(shortcuts_.size()) +
98 installer::kLnkExt);
99 shortcut_test_object.path = shortcut_path;
100 shortcut_test_object.properties = *shortcut_properties;
101 shortcuts_.push_back(shortcut_test_object);
102 ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
103 shortcut_path, *shortcut_properties,
104 base::win::SHORTCUT_CREATE_ALWAYS));
105 shortcut_properties->options = 0U;
108 void CreateShortcuts() {
109 // A temporary object to pass properties to
110 // AddTestShortcutAndResetProperties().
111 base::win::ShortcutProperties temp_properties;
113 // Shortcut 0 doesn't point to chrome.exe and thus should never be migrated.
114 temp_properties.set_target(other_target_);
115 temp_properties.set_app_id(L"Dumbo");
116 ASSERT_NO_FATAL_FAILURE(
117 AddTestShortcutAndResetProperties(&temp_properties));
119 // Shortcut 1 points to chrome.exe and thus should be migrated.
120 temp_properties.set_target(chrome_exe_);
121 temp_properties.set_app_id(L"Dumbo");
122 temp_properties.set_dual_mode(false);
123 ASSERT_NO_FATAL_FAILURE(
124 AddTestShortcutAndResetProperties(&temp_properties));
126 // Shortcut 2 points to chrome.exe, but already has the right appid and thus
127 // should only be migrated if dual_mode is desired.
128 temp_properties.set_target(chrome_exe_);
129 temp_properties.set_app_id(chrome_app_id_);
130 ASSERT_NO_FATAL_FAILURE(
131 AddTestShortcutAndResetProperties(&temp_properties));
133 // Shortcut 3 is like shortcut 1, but it's appid is a prefix of the expected
134 // appid instead of being totally different.
135 base::string16 chrome_app_id_is_prefix(chrome_app_id_);
136 chrome_app_id_is_prefix.push_back(L'1');
137 temp_properties.set_target(chrome_exe_);
138 temp_properties.set_app_id(chrome_app_id_is_prefix);
139 ASSERT_NO_FATAL_FAILURE(
140 AddTestShortcutAndResetProperties(&temp_properties));
142 // Shortcut 4 is like shortcut 1, but it's appid is of the same size as the
143 // expected appid.
144 base::string16 same_size_as_chrome_app_id(L'1', chrome_app_id_.size());
145 temp_properties.set_target(chrome_exe_);
146 temp_properties.set_app_id(same_size_as_chrome_app_id);
147 ASSERT_NO_FATAL_FAILURE(
148 AddTestShortcutAndResetProperties(&temp_properties));
150 // Shortcut 5 doesn't have an app_id, nor is dual_mode even set; they should
151 // be set as expected upon migration.
152 temp_properties.set_target(chrome_exe_);
153 ASSERT_NO_FATAL_FAILURE(
154 AddTestShortcutAndResetProperties(&temp_properties));
156 // Shortcut 6 has a non-default profile directory and so should get a non-
157 // default app id.
158 temp_properties.set_target(chrome_exe_);
159 temp_properties.set_app_id(L"Dumbo");
160 temp_properties.set_arguments(
161 L"--profile-directory=" + non_default_profile_);
162 ASSERT_NO_FATAL_FAILURE(
163 AddTestShortcutAndResetProperties(&temp_properties));
165 // Shortcut 7 has a non-default user data directory and so should get a non-
166 // default app id.
167 temp_properties.set_target(chrome_exe_);
168 temp_properties.set_app_id(L"Dumbo");
169 temp_properties.set_arguments(
170 L"--user-data-dir=\"" + non_default_user_data_dir_.value() + L"\"");
171 ASSERT_NO_FATAL_FAILURE(
172 AddTestShortcutAndResetProperties(&temp_properties));
174 // Shortcut 8 has a non-default user data directory as well as a non-default
175 // profile directory and so should get a non-default app id.
176 temp_properties.set_target(chrome_exe_);
177 temp_properties.set_app_id(L"Dumbo");
178 temp_properties.set_arguments(
179 L"--user-data-dir=\"" + non_default_user_data_dir_.value() + L"\" " +
180 L"--profile-directory=" + non_default_profile_);
181 ASSERT_NO_FATAL_FAILURE(
182 AddTestShortcutAndResetProperties(&temp_properties));
184 // Shortcut 9 is a shortcut to an app and should get an app id for that app
185 // rather than the chrome app id.
186 temp_properties.set_target(chrome_exe_);
187 temp_properties.set_app_id(L"Dumbo");
188 temp_properties.set_arguments(
189 L"--app-id=" + extension_id_);
190 ASSERT_NO_FATAL_FAILURE(
191 AddTestShortcutAndResetProperties(&temp_properties));
193 // Shortcut 10 is a shortcut to an app with a non-default profile and should
194 // get an app id for that app with a non-default app id rather than the
195 // chrome app id.
196 temp_properties.set_target(chrome_exe_);
197 temp_properties.set_app_id(L"Dumbo");
198 temp_properties.set_arguments(
199 L"--app-id=" + extension_id_ +
200 L" --profile-directory=" + non_default_profile_);
201 ASSERT_NO_FATAL_FAILURE(
202 AddTestShortcutAndResetProperties(&temp_properties));
204 // Shortcut 11 points to chrome.exe, already has the right appid, and has
205 // dual_mode set and thus should only be migrated if dual_mode is checked
206 // and not desired for this OS version.
207 temp_properties.set_target(chrome_exe_);
208 temp_properties.set_app_id(chrome_app_id_);
209 temp_properties.set_dual_mode(true);
210 ASSERT_NO_FATAL_FAILURE(
211 AddTestShortcutAndResetProperties(&temp_properties));
214 base::win::ScopedCOMInitializer com_initializer_;
216 base::ScopedTempDir temp_dir_;
218 // Test shortcuts.
219 std::vector<ShortcutTestObject> shortcuts_;
221 // The path to a fake chrome.exe.
222 base::FilePath chrome_exe_;
224 // The path to a random target.
225 base::FilePath other_target_;
227 // Chrome's AppUserModelId.
228 base::string16 chrome_app_id_;
230 // A profile that isn't the Default profile.
231 base::string16 non_default_profile_;
233 // A user data dir that isn't the default.
234 base::FilePath non_default_user_data_dir_;
236 // Chrome's AppUserModelId for the non-default profile.
237 base::string16 non_default_profile_chrome_app_id_;
239 // Chrome's AppUserModelId for the non-default user data dir.
240 base::string16 non_default_user_data_dir_chrome_app_id_;
242 // Chrome's AppUserModelId for the non-default user data dir and non-default
243 // profile.
244 base::string16 non_default_user_data_dir_and_profile_chrome_app_id_;
246 // The app launcher's app id.
247 base::string16 app_list_app_id_;
249 // An example extension id of an example app.
250 base::string16 extension_id_;
252 // The app id of the example app for the default profile and user data dir.
253 base::string16 extension_app_id_;
255 // The app id of the example app for the non-default profile.
256 base::string16 non_default_profile_extension_app_id_;
258 // True if the dual mode property should be set for the default chrome
259 // shortcut on the current OS version.
260 const bool desired_dual_mode_for_os_version;
262 private:
263 DISALLOW_COPY_AND_ASSIGN(ShellIntegrationWinMigrateShortcutTest);
266 } // namespace
268 // Test migration when not checking for dual mode.
269 TEST_F(ShellIntegrationWinMigrateShortcutTest, DontCheckDualMode) {
270 if (base::win::GetVersion() < base::win::VERSION_WIN7)
271 return;
273 EXPECT_EQ(9,
274 ShellIntegration::MigrateShortcutsInPathInternal(
275 chrome_exe_, temp_dir_.path(), false));
277 // Only shortcut 1, 3, 4, 5, 6, 7, 8, 9, and 10 should have been migrated.
278 shortcuts_[1].properties.set_app_id(chrome_app_id_);
279 shortcuts_[3].properties.set_app_id(chrome_app_id_);
280 shortcuts_[4].properties.set_app_id(chrome_app_id_);
281 shortcuts_[5].properties.set_app_id(chrome_app_id_);
282 shortcuts_[6].properties.set_app_id(non_default_profile_chrome_app_id_);
283 shortcuts_[7].properties.set_app_id(non_default_user_data_dir_chrome_app_id_);
284 shortcuts_[8].properties.set_app_id(
285 non_default_user_data_dir_and_profile_chrome_app_id_);
286 shortcuts_[9].properties.set_app_id(extension_app_id_);
287 shortcuts_[10].properties.set_app_id(non_default_profile_extension_app_id_);
289 // Dual mode should be false for shortcuts 1 to 10.
290 for (size_t i = 0; i <= 10; ++i)
291 shortcuts_[i].properties.set_dual_mode(false);
293 for (size_t i = 0; i < shortcuts_.size(); ++i) {
294 SCOPED_TRACE(i);
295 base::win::ValidateShortcut(shortcuts_[i].path, shortcuts_[i].properties);
298 // Make sure shortcuts are not re-migrated.
299 EXPECT_EQ(0,
300 ShellIntegration::MigrateShortcutsInPathInternal(
301 chrome_exe_, temp_dir_.path(), false));
304 // Test migration when also checking for dual mode.
305 TEST_F(ShellIntegrationWinMigrateShortcutTest, CheckDualMode) {
306 if (base::win::GetVersion() < base::win::VERSION_WIN7)
307 return;
309 EXPECT_EQ(desired_dual_mode_for_os_version ? 10 : 6,
310 ShellIntegration::MigrateShortcutsInPathInternal(
311 chrome_exe_, temp_dir_.path(), true));
313 // Shortcut 1, 3, 4, 5, 6, 7, 8, 9, and 10 should have had both their app_id
314 // fixed and shortcut 1, 2, 3, 4, and 5 should also have had their dual_mode
315 // property added if it is desired (or 11 should have had it removed if it is
316 // not).
317 shortcuts_[1].properties.set_app_id(chrome_app_id_);
318 shortcuts_[3].properties.set_app_id(chrome_app_id_);
319 shortcuts_[4].properties.set_app_id(chrome_app_id_);
320 shortcuts_[5].properties.set_app_id(chrome_app_id_);
321 shortcuts_[6].properties.set_app_id(non_default_profile_chrome_app_id_);
322 shortcuts_[7].properties.set_app_id(non_default_user_data_dir_chrome_app_id_);
323 shortcuts_[8].properties.set_app_id(
324 non_default_user_data_dir_and_profile_chrome_app_id_);
325 shortcuts_[9].properties.set_app_id(extension_app_id_);
326 shortcuts_[10].properties.set_app_id(non_default_profile_extension_app_id_);
328 if (desired_dual_mode_for_os_version) {
329 shortcuts_[1].properties.set_dual_mode(true);
330 shortcuts_[2].properties.set_dual_mode(true);
331 shortcuts_[3].properties.set_dual_mode(true);
332 shortcuts_[4].properties.set_dual_mode(true);
333 shortcuts_[5].properties.set_dual_mode(true);
334 } else {
335 shortcuts_[11].properties.set_dual_mode(false);
337 shortcuts_[6].properties.set_dual_mode(false);
338 shortcuts_[7].properties.set_dual_mode(false);
339 shortcuts_[8].properties.set_dual_mode(false);
340 shortcuts_[9].properties.set_dual_mode(false);
341 shortcuts_[10].properties.set_dual_mode(false);
343 for (size_t i = 0; i < shortcuts_.size(); ++i) {
344 SCOPED_TRACE(i);
345 base::win::ValidateShortcut(shortcuts_[i].path, shortcuts_[i].properties);
348 // Make sure shortcuts are not re-migrated.
349 EXPECT_EQ(0,
350 ShellIntegration::MigrateShortcutsInPathInternal(
351 chrome_exe_, temp_dir_.path(), false));
354 TEST(ShellIntegrationWinTest, GetAppModelIdForProfileTest) {
355 const base::string16 base_app_id(
356 BrowserDistribution::GetDistribution()->GetBaseAppId());
358 // Empty profile path should get chrome::kBrowserAppID
359 base::FilePath empty_path;
360 EXPECT_EQ(base_app_id,
361 ShellIntegration::GetAppModelIdForProfile(base_app_id, empty_path));
363 // Default profile path should get chrome::kBrowserAppID
364 base::FilePath default_user_data_dir;
365 chrome::GetDefaultUserDataDirectory(&default_user_data_dir);
366 base::FilePath default_profile_path =
367 default_user_data_dir.AppendASCII(chrome::kInitialProfile);
368 EXPECT_EQ(base_app_id,
369 ShellIntegration::GetAppModelIdForProfile(base_app_id,
370 default_profile_path));
372 // Non-default profile path should get chrome::kBrowserAppID joined with
373 // profile info.
374 base::FilePath profile_path(FILE_PATH_LITERAL("root"));
375 profile_path = profile_path.Append(FILE_PATH_LITERAL("udd"));
376 profile_path = profile_path.Append(FILE_PATH_LITERAL("User Data - Test"));
377 EXPECT_EQ(base_app_id + L".udd.UserDataTest",
378 ShellIntegration::GetAppModelIdForProfile(base_app_id,
379 profile_path));
382 TEST(ShellIntegrationWinTest, GetAppListAppModelIdForProfileTest) {
383 base::string16 base_app_id(
384 BrowserDistribution::GetDistribution()->GetBaseAppId());
385 base_app_id.append(L"AppList");
387 // Empty profile path should get chrome::kBrowserAppID + AppList
388 base::FilePath empty_path;
389 EXPECT_EQ(base_app_id,
390 ShellIntegration::GetAppListAppModelIdForProfile(empty_path));
392 // Default profile path should get chrome::kBrowserAppID + AppList
393 base::FilePath default_user_data_dir;
394 chrome::GetDefaultUserDataDirectory(&default_user_data_dir);
395 base::FilePath default_profile_path =
396 default_user_data_dir.AppendASCII(chrome::kInitialProfile);
397 EXPECT_EQ(base_app_id,
398 ShellIntegration::GetAppListAppModelIdForProfile(
399 default_profile_path));
401 // Non-default profile path should get chrome::kBrowserAppID + AppList joined
402 // with profile info.
403 base::FilePath profile_path(FILE_PATH_LITERAL("root"));
404 profile_path = profile_path.Append(FILE_PATH_LITERAL("udd"));
405 profile_path = profile_path.Append(FILE_PATH_LITERAL("User Data - Test"));
406 EXPECT_EQ(base_app_id + L".udd.UserDataTest",
407 ShellIntegration::GetAppListAppModelIdForProfile(profile_path));