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.
4
5 #include "chrome/installer/util/shell_util.h"
6
7 #include <cguid.h>
8 #include <stddef.h>
9
10 #include <memory>
11 #include <vector>
12
13 #include "base/base_paths.h"
14 #include "base/base_paths_win.h"
15 #include "base/command_line.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/files/scoped_temp_dir.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string16.h"
22 #include "base/strings/string_util.h"
23 #include "base/synchronization/atomic_flag.h"
24 #include "base/test/scoped_path_override.h"
25 #include "base/test/test_reg_util_win.h"
26 #include "base/test/test_shortcut_win.h"
27 #include "base/win/registry.h"
28 #include "base/win/shortcut.h"
29 #include "base/win/windows_version.h"
30 #include "chrome/install_static/install_util.h"
31 #include "chrome/installer/util/install_util.h"
32 #include "chrome/installer/util/util_constants.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 namespace {
36
37 const wchar_t kManganeseExe[] = L"manganese.exe";
38 const wchar_t kIronExe[] = L"iron.exe";
39 const wchar_t kOtherIco[] = L"other.ico";
40
41 // For registry tests.
42 const wchar_t kTestProgid[] = L"TestApp";
43 const wchar_t kTestOpenCommand[] = L"C:\\test.exe";
44 const wchar_t kTestApplicationName[] = L"Test Application";
45 const wchar_t kTestFileTypeName[] = L"Test File Type";
46 const wchar_t kTestIconPath[] = L"D:\\test.ico";
47 const wchar_t* kTestFileExtensions[] = {
48 L"test1",
49 L"test2",
50 };
51
52 // TODO(huangs): Separate this into generic shortcut tests and Chrome-specific
53 // tests. Specifically, we should not overly rely on getting shortcut properties
54 // from ShellUtil::AddDefaultShortcutProperties().
55 class ShellUtilShortcutTest : public testing::Test {
56 protected:
ShellUtilShortcutTest()57 ShellUtilShortcutTest() : test_properties_(ShellUtil::CURRENT_USER) {}
58
SetUp()59 void SetUp() override {
60 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
61 chrome_exe_ = temp_dir_.GetPath().Append(installer::kChromeExe);
62 EXPECT_EQ(0, base::WriteFile(chrome_exe_, "", 0));
63
64 manganese_exe_ = temp_dir_.GetPath().Append(kManganeseExe);
65 EXPECT_EQ(0, base::WriteFile(manganese_exe_, "", 0));
66
67 iron_exe_ = temp_dir_.GetPath().Append(kIronExe);
68 EXPECT_EQ(0, base::WriteFile(iron_exe_, "", 0));
69
70 other_ico_ = temp_dir_.GetPath().Append(kOtherIco);
71 EXPECT_EQ(0, base::WriteFile(other_ico_, "", 0));
72
73 ASSERT_TRUE(fake_user_desktop_.CreateUniqueTempDir());
74 ASSERT_TRUE(fake_common_desktop_.CreateUniqueTempDir());
75 ASSERT_TRUE(fake_user_quick_launch_.CreateUniqueTempDir());
76 ASSERT_TRUE(fake_default_user_quick_launch_.CreateUniqueTempDir());
77 ASSERT_TRUE(fake_start_menu_.CreateUniqueTempDir());
78 ASSERT_TRUE(fake_common_start_menu_.CreateUniqueTempDir());
79 ASSERT_TRUE(fake_user_startup_.CreateUniqueTempDir());
80 ASSERT_TRUE(fake_common_startup_.CreateUniqueTempDir());
81 user_desktop_override_.reset(new base::ScopedPathOverride(
82 base::DIR_USER_DESKTOP, fake_user_desktop_.GetPath()));
83 common_desktop_override_.reset(new base::ScopedPathOverride(
84 base::DIR_COMMON_DESKTOP, fake_common_desktop_.GetPath()));
85 user_quick_launch_override_.reset(new base::ScopedPathOverride(
86 base::DIR_USER_QUICK_LAUNCH, fake_user_quick_launch_.GetPath()));
87 start_menu_override_.reset(new base::ScopedPathOverride(
88 base::DIR_START_MENU, fake_start_menu_.GetPath()));
89 common_start_menu_override_.reset(new base::ScopedPathOverride(
90 base::DIR_COMMON_START_MENU, fake_common_start_menu_.GetPath()));
91 common_startup_override_.reset(new base::ScopedPathOverride(
92 base::DIR_COMMON_STARTUP, fake_common_startup_.GetPath()));
93 user_startup_override_.reset(new base::ScopedPathOverride(
94 base::DIR_USER_STARTUP, fake_user_startup_.GetPath()));
95
96 base::FilePath icon_path;
97 base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &icon_path);
98 test_properties_.set_target(chrome_exe_);
99 test_properties_.set_arguments(L"--test --chrome");
100 test_properties_.set_description(L"Makes polar bears dance.");
101 test_properties_.set_icon(icon_path, 7);
102 test_properties_.set_app_id(L"Polar.Bear");
103
104 // The CLSID below was randomly selected.
105 static constexpr CLSID toast_activator_clsid = {
106 0xb2a1d927,
107 0xacd1,
108 0x484a,
109 {0x82, 0x82, 0xd5, 0xfc, 0x66, 0x56, 0x26, 0x4b}};
110 test_properties_.set_toast_activator_clsid(toast_activator_clsid);
111 }
112
113 // Returns the expected path of a test shortcut. Returns an empty FilePath on
114 // failure.
GetExpectedShortcutPath(ShellUtil::ShortcutLocation location,const ShellUtil::ShortcutProperties & properties)115 base::FilePath GetExpectedShortcutPath(
116 ShellUtil::ShortcutLocation location,
117 const ShellUtil::ShortcutProperties& properties) {
118 base::FilePath expected_path;
119 switch (location) {
120 case ShellUtil::SHORTCUT_LOCATION_DESKTOP:
121 expected_path = (properties.level == ShellUtil::CURRENT_USER)
122 ? fake_user_desktop_.GetPath()
123 : fake_common_desktop_.GetPath();
124 break;
125 case ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH:
126 expected_path = fake_user_quick_launch_.GetPath();
127 break;
128 case ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT:
129 expected_path = (properties.level == ShellUtil::CURRENT_USER)
130 ? fake_start_menu_.GetPath()
131 : fake_common_start_menu_.GetPath();
132 break;
133 case ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED:
134 expected_path = (properties.level == ShellUtil::CURRENT_USER)
135 ? fake_start_menu_.GetPath()
136 : fake_common_start_menu_.GetPath();
137 expected_path = expected_path.Append(
138 InstallUtil::GetChromeShortcutDirNameDeprecated());
139 break;
140 default:
141 ADD_FAILURE() << "Unknown location";
142 return base::FilePath();
143 }
144
145 base::string16 shortcut_name = properties.has_shortcut_name()
146 ? properties.shortcut_name
147 : InstallUtil::GetShortcutName();
148 shortcut_name.append(installer::kLnkExt);
149 return expected_path.Append(shortcut_name);
150 }
151
152 // Validates that the shortcut at |location| matches |properties| (and
153 // implicit default properties) for |dist|.
154 // Note: This method doesn't verify the |pin_to_taskbar| property as it
155 // implies real (non-mocked) state which is flaky to test.
ValidateChromeShortcut(ShellUtil::ShortcutLocation location,const ShellUtil::ShortcutProperties & properties)156 void ValidateChromeShortcut(ShellUtil::ShortcutLocation location,
157 const ShellUtil::ShortcutProperties& properties) {
158 base::FilePath expected_path(GetExpectedShortcutPath(location, properties));
159
160 base::win::ShortcutProperties expected_properties;
161 if (properties.has_target()) {
162 expected_properties.set_target(properties.target);
163 expected_properties.set_working_dir(properties.target.DirName());
164 } else {
165 expected_properties.set_target(chrome_exe_);
166 expected_properties.set_working_dir(chrome_exe_.DirName());
167 }
168
169 if (properties.has_arguments())
170 expected_properties.set_arguments(properties.arguments);
171 else
172 expected_properties.set_arguments(base::string16());
173
174 if (properties.has_description())
175 expected_properties.set_description(properties.description);
176 else
177 expected_properties.set_description(InstallUtil::GetAppDescription());
178
179 if (properties.has_icon()) {
180 expected_properties.set_icon(properties.icon, properties.icon_index);
181 } else {
182 int icon_index = install_static::GetIconResourceIndex();
183 expected_properties.set_icon(chrome_exe_, icon_index);
184 }
185
186 if (properties.has_app_id()) {
187 expected_properties.set_app_id(properties.app_id);
188 } else {
189 // Tests are always seen as user-level installs in ShellUtil.
190 expected_properties.set_app_id(ShellUtil::GetBrowserModelId(true));
191 }
192
193 if (properties.has_toast_activator_clsid()) {
194 expected_properties.set_toast_activator_clsid(
195 properties.toast_activator_clsid);
196 } else {
197 expected_properties.set_toast_activator_clsid(CLSID_NULL);
198 }
199
200 base::win::ValidateShortcut(expected_path, expected_properties);
201 }
202
203 // A ShellUtil::ShortcutProperties object with common properties set already.
204 ShellUtil::ShortcutProperties test_properties_;
205
206 base::ScopedTempDir temp_dir_;
207 base::ScopedTempDir fake_user_desktop_;
208 base::ScopedTempDir fake_common_desktop_;
209 base::ScopedTempDir fake_user_quick_launch_;
210 base::ScopedTempDir fake_default_user_quick_launch_;
211 base::ScopedTempDir fake_start_menu_;
212 base::ScopedTempDir fake_common_start_menu_;
213 base::ScopedTempDir fake_user_startup_;
214 base::ScopedTempDir fake_common_startup_;
215 std::unique_ptr<base::ScopedPathOverride> user_desktop_override_;
216 std::unique_ptr<base::ScopedPathOverride> common_desktop_override_;
217 std::unique_ptr<base::ScopedPathOverride> user_quick_launch_override_;
218 std::unique_ptr<base::ScopedPathOverride> start_menu_override_;
219 std::unique_ptr<base::ScopedPathOverride> common_start_menu_override_;
220 std::unique_ptr<base::ScopedPathOverride> user_startup_override_;
221 std::unique_ptr<base::ScopedPathOverride> common_startup_override_;
222
223 base::FilePath chrome_exe_;
224 base::FilePath manganese_exe_;
225 base::FilePath iron_exe_;
226 base::FilePath other_ico_;
227 };
228
229 } // namespace
230
TEST_F(ShellUtilShortcutTest,GetShortcutPath)231 TEST_F(ShellUtilShortcutTest, GetShortcutPath) {
232 base::FilePath path;
233
234 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
235 ShellUtil::CURRENT_USER, &path);
236 EXPECT_EQ(fake_user_desktop_.GetPath(), path);
237
238 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
239 ShellUtil::SYSTEM_LEVEL, &path);
240 EXPECT_EQ(fake_common_desktop_.GetPath(), path);
241
242 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
243 ShellUtil::CURRENT_USER, &path);
244 EXPECT_EQ(fake_user_quick_launch_.GetPath(), path);
245
246 base::string16 start_menu_subfolder =
247 InstallUtil::GetChromeShortcutDirNameDeprecated();
248 ShellUtil::GetShortcutPath(
249 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
250 ShellUtil::CURRENT_USER, &path);
251 EXPECT_EQ(fake_start_menu_.GetPath().Append(start_menu_subfolder), path);
252
253 ShellUtil::GetShortcutPath(
254 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
255 ShellUtil::SYSTEM_LEVEL, &path);
256 EXPECT_EQ(fake_common_start_menu_.GetPath().Append(start_menu_subfolder),
257 path);
258
259 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_STARTUP,
260 ShellUtil::SYSTEM_LEVEL, &path);
261 EXPECT_EQ(fake_common_startup_.GetPath(), path);
262
263 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_STARTUP,
264 ShellUtil::CURRENT_USER, &path);
265 EXPECT_EQ(fake_user_startup_.GetPath(), path);
266 }
267
TEST_F(ShellUtilShortcutTest,MoveExistingShortcut)268 TEST_F(ShellUtilShortcutTest, MoveExistingShortcut) {
269 test_properties_.set_shortcut_name(L"Bobo le shortcut");
270 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
271 base::FilePath old_shortcut_path(GetExpectedShortcutPath(
272 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
273 test_properties_));
274
275 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
276 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
277 test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
278 ValidateChromeShortcut(
279 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
280 test_properties_);
281 ASSERT_TRUE(base::PathExists(old_shortcut_path.DirName()));
282 ASSERT_TRUE(base::PathExists(old_shortcut_path));
283
284 ASSERT_TRUE(ShellUtil::MoveExistingShortcut(
285 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
286 ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, test_properties_));
287
288 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
289 test_properties_);
290 ASSERT_FALSE(base::PathExists(old_shortcut_path));
291 ASSERT_FALSE(base::PathExists(old_shortcut_path.DirName()));
292 }
293
TEST_F(ShellUtilShortcutTest,CreateChromeExeShortcutWithDefaultProperties)294 TEST_F(ShellUtilShortcutTest, CreateChromeExeShortcutWithDefaultProperties) {
295 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
296 ShellUtil::AddDefaultShortcutProperties(chrome_exe_, &properties);
297 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
298 ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties,
299 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
300 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties);
301 }
302
TEST_F(ShellUtilShortcutTest,CreateStartMenuShortcutWithAllProperties)303 TEST_F(ShellUtilShortcutTest, CreateStartMenuShortcutWithAllProperties) {
304 test_properties_.set_shortcut_name(L"Bobo le shortcut");
305 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
306 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
307 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
308 test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
309 ValidateChromeShortcut(
310 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
311 test_properties_);
312 }
313
TEST_F(ShellUtilShortcutTest,ReplaceSystemLevelDesktopShortcut)314 TEST_F(ShellUtilShortcutTest, ReplaceSystemLevelDesktopShortcut) {
315 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
316 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
317 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
318 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
319
320 ShellUtil::ShortcutProperties new_properties(ShellUtil::SYSTEM_LEVEL);
321 ShellUtil::AddDefaultShortcutProperties(chrome_exe_, &new_properties);
322 new_properties.set_description(L"New description");
323 new_properties.set_arguments(L"--new-arguments");
324 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
325 ShellUtil::SHORTCUT_LOCATION_DESKTOP, new_properties,
326 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING));
327
328 // Expect the properties set in |new_properties| to be set as above and
329 // properties that don't have a default value to be set back to their default
330 // (as validated in ValidateChromeShortcut()) or unset if they don't .
331 ShellUtil::ShortcutProperties expected_properties(new_properties);
332
333 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
334 expected_properties);
335 }
336
TEST_F(ShellUtilShortcutTest,UpdateQuickLaunchShortcutArguments)337 TEST_F(ShellUtilShortcutTest, UpdateQuickLaunchShortcutArguments) {
338 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
339 ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, test_properties_,
340 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
341
342 // Only changing one property, don't need all the defaults.
343 ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
344 updated_properties.set_arguments(L"--updated --arguments");
345 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
346 ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, updated_properties,
347 ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
348
349 // Expect the properties set in |updated_properties| to be set as above and
350 // all other properties to remain unchanged.
351 ShellUtil::ShortcutProperties expected_properties(test_properties_);
352 expected_properties.set_arguments(updated_properties.arguments);
353
354 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
355 expected_properties);
356 }
357
TEST_F(ShellUtilShortcutTest,CreateIfNoSystemLevel)358 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevel) {
359 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
360 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
361 ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
362 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
363 test_properties_);
364 }
365
TEST_F(ShellUtilShortcutTest,CreateIfNoSystemLevelWithSystemLevelPresent)366 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelWithSystemLevelPresent) {
367 base::string16 shortcut_name(InstallUtil::GetShortcutName() +
368 installer::kLnkExt);
369
370 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
371 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
372 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
373 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
374 ASSERT_TRUE(
375 base::PathExists(fake_common_desktop_.GetPath().Append(shortcut_name)));
376
377 test_properties_.level = ShellUtil::CURRENT_USER;
378 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
379 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
380 ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
381 ASSERT_FALSE(
382 base::PathExists(fake_user_desktop_.GetPath().Append(shortcut_name)));
383 }
384
TEST_F(ShellUtilShortcutTest,CreateIfNoSystemLevelStartMenu)385 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelStartMenu) {
386 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
387 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
388 test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
389 ValidateChromeShortcut(
390 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
391 test_properties_);
392 }
393
TEST_F(ShellUtilShortcutTest,CreateAlwaysUserWithSystemLevelPresent)394 TEST_F(ShellUtilShortcutTest, CreateAlwaysUserWithSystemLevelPresent) {
395 base::string16 shortcut_name(InstallUtil::GetShortcutName() +
396 installer::kLnkExt);
397
398 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
399 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
400 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
401 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
402 ASSERT_TRUE(
403 base::PathExists(fake_common_desktop_.GetPath().Append(shortcut_name)));
404
405 test_properties_.level = ShellUtil::CURRENT_USER;
406 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
407 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
408 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
409 ASSERT_TRUE(
410 base::PathExists(fake_user_desktop_.GetPath().Append(shortcut_name)));
411 }
412
TEST_F(ShellUtilShortcutTest,RemoveChromeShortcut)413 TEST_F(ShellUtilShortcutTest, RemoveChromeShortcut) {
414 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
415 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
416 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
417 base::FilePath shortcut_path = GetExpectedShortcutPath(
418 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
419 ASSERT_TRUE(base::PathExists(shortcut_path));
420
421 ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
422 ShellUtil::CURRENT_USER, chrome_exe_));
423 ASSERT_FALSE(base::PathExists(shortcut_path));
424 ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
425 }
426
TEST_F(ShellUtilShortcutTest,RemoveSystemLevelChromeShortcut)427 TEST_F(ShellUtilShortcutTest, RemoveSystemLevelChromeShortcut) {
428 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
429 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
430 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
431 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
432 base::FilePath shortcut_path = GetExpectedShortcutPath(
433 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
434 ASSERT_TRUE(base::PathExists(shortcut_path));
435
436 ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
437 ShellUtil::SYSTEM_LEVEL, chrome_exe_));
438 ASSERT_FALSE(base::PathExists(shortcut_path));
439 ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
440 }
441
TEST_F(ShellUtilShortcutTest,RemoveMultipleChromeShortcuts)442 TEST_F(ShellUtilShortcutTest, RemoveMultipleChromeShortcuts) {
443 // Shortcut 1: targets "chrome.exe"; no arguments.
444 test_properties_.set_shortcut_name(L"Chrome 1");
445 test_properties_.set_arguments(L"");
446 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
447 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
448 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
449 base::FilePath shortcut1_path = GetExpectedShortcutPath(
450 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
451 ASSERT_TRUE(base::PathExists(shortcut1_path));
452
453 // Shortcut 2: targets "chrome.exe"; has arguments; icon set to "other.ico".
454 test_properties_.set_shortcut_name(L"Chrome 2");
455 test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
456 test_properties_.set_icon(other_ico_, 0);
457 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
458 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
459 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
460 base::FilePath shortcut2_path = GetExpectedShortcutPath(
461 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
462 ASSERT_TRUE(base::PathExists(shortcut2_path));
463
464 // Shortcut 3: targets "iron.exe"; has arguments; icon set to "chrome.exe".
465 test_properties_.set_shortcut_name(L"Iron 3");
466 test_properties_.set_target(iron_exe_);
467 test_properties_.set_icon(chrome_exe_, 3);
468 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
469 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
470 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
471 base::FilePath shortcut3_path = GetExpectedShortcutPath(
472 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
473 ASSERT_TRUE(base::PathExists(shortcut3_path));
474
475 // Remove shortcuts that target "chrome.exe".
476 ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
477 ShellUtil::CURRENT_USER, chrome_exe_));
478 ASSERT_FALSE(base::PathExists(shortcut1_path));
479 ASSERT_FALSE(base::PathExists(shortcut2_path));
480 ASSERT_TRUE(base::PathExists(shortcut3_path));
481 ASSERT_TRUE(base::PathExists(shortcut1_path.DirName()));
482 }
483
TEST_F(ShellUtilShortcutTest,RetargetShortcutsWithArgs)484 TEST_F(ShellUtilShortcutTest, RetargetShortcutsWithArgs) {
485 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
486 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
487 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
488 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
489 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
490
491 base::FilePath new_exe = manganese_exe_;
492 // Relies on the fact that |test_properties_| has non-empty arguments.
493 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
494 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
495 chrome_exe_, new_exe));
496
497 ShellUtil::ShortcutProperties expected_properties(test_properties_);
498 expected_properties.set_target(new_exe);
499 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
500 expected_properties);
501 }
502
TEST_F(ShellUtilShortcutTest,RetargetSystemLevelChromeShortcutsWithArgs)503 TEST_F(ShellUtilShortcutTest, RetargetSystemLevelChromeShortcutsWithArgs) {
504 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
505 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
506 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
507 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
508 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
509 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
510
511 base::FilePath new_exe = manganese_exe_;
512 // Relies on the fact that |test_properties_| has non-empty arguments.
513 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
514 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::SYSTEM_LEVEL,
515 chrome_exe_, new_exe));
516
517 ShellUtil::ShortcutProperties expected_properties(test_properties_);
518 expected_properties.set_target(new_exe);
519 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
520 expected_properties);
521 }
522
TEST_F(ShellUtilShortcutTest,RetargetChromeShortcutsWithArgsEmpty)523 TEST_F(ShellUtilShortcutTest, RetargetChromeShortcutsWithArgsEmpty) {
524 // Shortcut 1: targets "chrome.exe"; no arguments.
525 test_properties_.set_shortcut_name(L"Chrome 1");
526 test_properties_.set_arguments(L"");
527 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
528 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
529 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
530 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
531 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
532 ShellUtil::ShortcutProperties expected_properties1(test_properties_);
533
534 // Shortcut 2: targets "chrome.exe"; has arguments.
535 test_properties_.set_shortcut_name(L"Chrome 2");
536 test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
537 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
538 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
539 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
540 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
541 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
542 ShellUtil::ShortcutProperties expected_properties2(test_properties_);
543
544 // Retarget shortcuts: replace "chrome.exe" with "manganese.exe". Only
545 // shortcuts with non-empty arguments (i.e., shortcut 2) gets updated.
546 base::FilePath new_exe = manganese_exe_;
547 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
548 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
549 chrome_exe_, new_exe));
550
551 // Verify shortcut 1: no change.
552 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
553 expected_properties1);
554
555 // Verify shortcut 2: target => "manganese.exe".
556 expected_properties2.set_target(new_exe);
557 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
558 expected_properties2);
559 }
560
TEST_F(ShellUtilShortcutTest,RetargetChromeShortcutsWithArgsIcon)561 TEST_F(ShellUtilShortcutTest, RetargetChromeShortcutsWithArgsIcon) {
562 const int kTestIconIndex1 = 3;
563 const int kTestIconIndex2 = 5;
564 const int kTestIconIndex3 = 8;
565
566 // Shortcut 1: targets "chrome.exe"; icon same as target.
567 test_properties_.set_shortcut_name(L"Chrome 1");
568 test_properties_.set_icon(test_properties_.target, kTestIconIndex1);
569 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
570 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
571 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
572 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
573 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
574 ShellUtil::ShortcutProperties expected_properties1(test_properties_);
575
576 // Shortcut 2: targets "chrome.exe"; icon set to "other.ico".
577 test_properties_.set_shortcut_name(L"Chrome 2");
578 test_properties_.set_icon(other_ico_, kTestIconIndex2);
579 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
580 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
581 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
582 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
583 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
584 ShellUtil::ShortcutProperties expected_properties2(test_properties_);
585
586 // Shortcut 3: targets "iron.exe"; icon set to "chrome.exe".
587 test_properties_.set_target(iron_exe_);
588 test_properties_.set_shortcut_name(L"Iron 3");
589 test_properties_.set_icon(chrome_exe_, kTestIconIndex3);
590 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
591 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
592 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
593 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
594 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
595 ShellUtil::ShortcutProperties expected_properties3(test_properties_);
596
597 // Retarget shortcuts: replace "chrome.exe" with "manganese.exe".
598 // Relies on the fact that |test_properties_| has non-empty arguments.
599 base::FilePath new_exe = manganese_exe_;
600 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
601 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
602 chrome_exe_, new_exe));
603
604 // Verify shortcut 1: target & icon => "manganese.exe", kept same icon index.
605 expected_properties1.set_target(new_exe);
606 expected_properties1.set_icon(new_exe, kTestIconIndex1);
607 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
608 expected_properties1);
609
610 // Verify shortcut 2: target => "manganese.exe", kept icon.
611 expected_properties2.set_target(new_exe);
612 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
613 expected_properties2);
614
615 // Verify shortcut 3: no change, since target doesn't match.
616 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
617 expected_properties3);
618 }
619
TEST_F(ShellUtilShortcutTest,ClearShortcutArguments)620 TEST_F(ShellUtilShortcutTest, ClearShortcutArguments) {
621 // Shortcut 1: targets "chrome.exe"; no arguments.
622 test_properties_.set_shortcut_name(L"Chrome 1");
623 test_properties_.set_arguments(L"");
624 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
625 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
626 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
627 base::FilePath shortcut1_path = GetExpectedShortcutPath(
628 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
629 ASSERT_TRUE(base::PathExists(shortcut1_path));
630 ShellUtil::ShortcutProperties expected_properties1(test_properties_);
631
632 // Shortcut 2: targets "chrome.exe"; has 1 argument in the allow list.
633 test_properties_.set_shortcut_name(L"Chrome 2");
634 test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
635 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
636 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
637 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
638 base::FilePath shortcut2_path = GetExpectedShortcutPath(
639 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
640 ASSERT_TRUE(base::PathExists(shortcut2_path));
641 ShellUtil::ShortcutProperties expected_properties2(test_properties_);
642
643 // Shortcut 3: targets "chrome.exe"; has an unknown argument.
644 test_properties_.set_shortcut_name(L"Chrome 3");
645 test_properties_.set_arguments(L"foo.com");
646 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
647 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
648 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
649 base::FilePath shortcut3_path = GetExpectedShortcutPath(
650 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
651 ASSERT_TRUE(base::PathExists(shortcut3_path));
652 ShellUtil::ShortcutProperties expected_properties3(test_properties_);
653
654 // Shortcut 4: targets "chrome.exe"; has both unknown and known arguments.
655 const base::string16 kKnownArg = L"--app-id";
656 const base::string16 kExpectedArgs = L"foo.com " + kKnownArg;
657 test_properties_.set_shortcut_name(L"Chrome 4");
658 test_properties_.set_arguments(kExpectedArgs);
659 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
660 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
661 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
662 base::FilePath shortcut4_path = GetExpectedShortcutPath(
663 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
664 ASSERT_TRUE(base::PathExists(shortcut4_path));
665 ShellUtil::ShortcutProperties expected_properties4(test_properties_);
666
667 // List the shortcuts.
668 std::vector<std::pair<base::FilePath, base::string16>> shortcuts;
669 EXPECT_TRUE(ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
670 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
671 chrome_exe_, false, nullptr, &shortcuts));
672 ASSERT_EQ(2u, shortcuts.size());
673 std::pair<base::FilePath, base::string16> shortcut3 =
674 shortcuts[0].first == shortcut3_path ? shortcuts[0] : shortcuts[1];
675 std::pair<base::FilePath, base::string16> shortcut4 =
676 shortcuts[0].first == shortcut4_path ? shortcuts[0] : shortcuts[1];
677 EXPECT_EQ(shortcut3_path, shortcut3.first);
678 EXPECT_EQ(L"foo.com", shortcut3.second);
679 EXPECT_EQ(shortcut4_path, shortcut4.first);
680 EXPECT_EQ(kExpectedArgs, shortcut4.second);
681
682 // Clear shortcuts.
683 shortcuts.clear();
684 EXPECT_TRUE(ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
685 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
686 chrome_exe_, true, nullptr, &shortcuts));
687 ASSERT_EQ(2u, shortcuts.size());
688 shortcut3 =
689 shortcuts[0].first == shortcut3_path ? shortcuts[0] : shortcuts[1];
690 shortcut4 =
691 shortcuts[0].first == shortcut4_path ? shortcuts[0] : shortcuts[1];
692 EXPECT_EQ(shortcut3_path, shortcut3.first);
693 EXPECT_EQ(L"foo.com", shortcut3.second);
694 EXPECT_EQ(shortcut4_path, shortcut4.first);
695 EXPECT_EQ(kExpectedArgs, shortcut4.second);
696
697 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
698 expected_properties1);
699 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
700 expected_properties2);
701 expected_properties3.set_arguments(base::string16());
702 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
703 expected_properties3);
704 expected_properties4.set_arguments(kKnownArg);
705 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
706 expected_properties4);
707 }
708
TEST_F(ShellUtilShortcutTest,ShortcutsAreNotHidden)709 TEST_F(ShellUtilShortcutTest, ShortcutsAreNotHidden) {
710 // Shortcut 1: targets "chrome.exe"; not hidden.
711 test_properties_.set_shortcut_name(L"Chrome Visible");
712 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
713 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
714 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
715 base::FilePath visible_shortcut = GetExpectedShortcutPath(
716 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
717 ASSERT_TRUE(base::PathExists(visible_shortcut));
718
719 // Shortcut 2: targets "chrome.exe"; hidden.
720 test_properties_.set_shortcut_name(L"Chrome Hidden");
721 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
722 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
723 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
724 base::FilePath hidden_shortcut = GetExpectedShortcutPath(
725 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
726 ASSERT_TRUE(base::PathExists(hidden_shortcut));
727 DWORD shortcut_attributes =
728 ::GetFileAttributes(hidden_shortcut.value().c_str());
729 ASSERT_NE(shortcut_attributes, INVALID_FILE_ATTRIBUTES);
730 ASSERT_TRUE(::SetFileAttributes(hidden_shortcut.value().c_str(),
731 shortcut_attributes | FILE_ATTRIBUTE_HIDDEN));
732
733 EXPECT_TRUE(ShellUtil::ResetShortcutFileAttributes(
734 ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
735 chrome_exe_));
736
737 shortcut_attributes = ::GetFileAttributes(visible_shortcut.value().c_str());
738 EXPECT_EQ(shortcut_attributes & FILE_ATTRIBUTE_HIDDEN, 0UL);
739 shortcut_attributes = ::GetFileAttributes(hidden_shortcut.value().c_str());
740 EXPECT_EQ(shortcut_attributes & FILE_ATTRIBUTE_HIDDEN, 0UL);
741 }
742
TEST_F(ShellUtilShortcutTest,CreateMultipleStartMenuShortcutsAndRemoveFolder)743 TEST_F(ShellUtilShortcutTest, CreateMultipleStartMenuShortcutsAndRemoveFolder) {
744 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
745 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
746 test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
747 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
748 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, test_properties_,
749 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
750 test_properties_.set_shortcut_name(L"A second shortcut");
751 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
752 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
753 test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
754 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
755 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, test_properties_,
756 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
757
758 base::FilePath chrome_shortcut_folder(fake_start_menu_.GetPath().Append(
759 InstallUtil::GetChromeShortcutDirNameDeprecated()));
760 base::FilePath chrome_apps_shortcut_folder(fake_start_menu_.GetPath().Append(
761 InstallUtil::GetChromeAppsShortcutDirName()));
762
763 base::FileEnumerator chrome_file_counter(chrome_shortcut_folder, false,
764 base::FileEnumerator::FILES);
765 int count = 0;
766 while (!chrome_file_counter.Next().empty())
767 ++count;
768 EXPECT_EQ(2, count);
769
770 base::FileEnumerator chrome_apps_file_counter(
771 chrome_apps_shortcut_folder, false, base::FileEnumerator::FILES);
772 count = 0;
773 while (!chrome_apps_file_counter.Next().empty())
774 ++count;
775 EXPECT_EQ(2, count);
776
777 ASSERT_TRUE(base::PathExists(chrome_shortcut_folder));
778 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
779 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
780 ShellUtil::CURRENT_USER, chrome_exe_));
781 ASSERT_FALSE(base::PathExists(chrome_shortcut_folder));
782
783 ASSERT_TRUE(base::PathExists(chrome_apps_shortcut_folder));
784 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
785 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
786 ShellUtil::CURRENT_USER, chrome_exe_));
787 ASSERT_FALSE(base::PathExists(chrome_apps_shortcut_folder));
788 }
789
TEST_F(ShellUtilShortcutTest,DeleteStartMenuRootShortcutWithoutRemovingFolder)790 TEST_F(ShellUtilShortcutTest,
791 DeleteStartMenuRootShortcutWithoutRemovingFolder) {
792 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
793 ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, test_properties_,
794 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
795
796 base::string16 shortcut_name(InstallUtil::GetShortcutName() +
797 installer::kLnkExt);
798 base::FilePath shortcut_path(
799 fake_start_menu_.GetPath().Append(shortcut_name));
800
801 ASSERT_TRUE(base::PathExists(fake_start_menu_.GetPath()));
802 ASSERT_TRUE(base::PathExists(shortcut_path));
803 ASSERT_TRUE(
804 ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
805 ShellUtil::CURRENT_USER, chrome_exe_));
806 // The shortcut should be removed but the "Start Menu" root directory should
807 // remain.
808 ASSERT_TRUE(base::PathExists(fake_start_menu_.GetPath()));
809 ASSERT_FALSE(base::PathExists(shortcut_path));
810 }
811
TEST_F(ShellUtilShortcutTest,DontRemoveChromeShortcutIfPointsToAnotherChrome)812 TEST_F(ShellUtilShortcutTest, DontRemoveChromeShortcutIfPointsToAnotherChrome) {
813 base::ScopedTempDir other_exe_dir;
814 ASSERT_TRUE(other_exe_dir.CreateUniqueTempDir());
815 base::FilePath other_chrome_exe =
816 other_exe_dir.GetPath().Append(installer::kChromeExe);
817 EXPECT_EQ(0, base::WriteFile(other_chrome_exe, "", 0));
818
819 test_properties_.set_target(other_chrome_exe);
820 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
821 ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
822 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
823
824 base::string16 shortcut_name(InstallUtil::GetShortcutName() +
825 installer::kLnkExt);
826 base::FilePath shortcut_path(
827 fake_user_desktop_.GetPath().Append(shortcut_name));
828 ASSERT_TRUE(base::PathExists(shortcut_path));
829
830 // The shortcut shouldn't be removed as it was installed pointing to
831 // |other_chrome_exe| and RemoveChromeShortcut() is being told that the
832 // removed shortcut should point to |chrome_exe_|.
833 ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
834 ShellUtil::CURRENT_USER, chrome_exe_));
835 ASSERT_TRUE(base::PathExists(shortcut_path));
836 ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
837 }
838
839 class ShellUtilRegistryTest : public testing::Test {
840 public:
ShellUtilRegistryTest()841 ShellUtilRegistryTest() {}
842
843 protected:
SetUp()844 void SetUp() override {
845 ASSERT_NO_FATAL_FAILURE(
846 registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER));
847
848 // .test2 files already have a default application.
849 base::win::RegKey key;
850 ASSERT_EQ(ERROR_SUCCESS,
851 key.Create(HKEY_CURRENT_USER, L"Software\\Classes\\.test2",
852 KEY_ALL_ACCESS));
853 EXPECT_EQ(ERROR_SUCCESS, key.WriteValue(L"", L"SomeOtherApp"));
854 }
855
OpenCommand()856 static base::CommandLine OpenCommand() {
857 base::FilePath open_command_path(kTestOpenCommand);
858 base::CommandLine open_command(open_command_path);
859 return open_command;
860 }
861
FileExtensions()862 static std::set<base::string16> FileExtensions() {
863 std::set<base::string16> file_extensions;
864 for (size_t i = 0; i < base::size(kTestFileExtensions); ++i)
865 file_extensions.insert(kTestFileExtensions[i]);
866 return file_extensions;
867 }
868
869 private:
870 registry_util::RegistryOverrideManager registry_overrides_;
871
872 DISALLOW_COPY_AND_ASSIGN(ShellUtilRegistryTest);
873 };
874
TEST_F(ShellUtilRegistryTest,AddFileAssociations)875 TEST_F(ShellUtilRegistryTest, AddFileAssociations) {
876 // Create file associations.
877 EXPECT_TRUE(ShellUtil::AddFileAssociations(
878 kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
879 base::FilePath(kTestIconPath), FileExtensions()));
880
881 // Ensure that the registry keys have been correctly set.
882 base::win::RegKey key;
883 std::wstring value;
884 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
885 L"Software\\Classes\\TestApp", KEY_READ));
886 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
887 EXPECT_EQ(L"Test File Type", value);
888 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"FileExtensions", &value));
889 EXPECT_EQ(L".test1;.test2", value);
890 ASSERT_EQ(ERROR_SUCCESS,
891 key.Open(HKEY_CURRENT_USER,
892 L"Software\\Classes\\TestApp\\DefaultIcon", KEY_READ));
893 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
894 EXPECT_EQ(L"D:\\test.ico,0", value);
895 ASSERT_EQ(
896 ERROR_SUCCESS,
897 key.Open(HKEY_CURRENT_USER,
898 L"Software\\Classes\\TestApp\\shell\\open\\command", KEY_READ));
899 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
900 EXPECT_EQ(L"\"C:\\test.exe\" --single-argument %1", value);
901
902 // The Application subkey and values are only required by Windows 8 and later.
903 if (base::win::GetVersion() >= base::win::Version::WIN8) {
904 ASSERT_EQ(ERROR_SUCCESS,
905 key.Open(HKEY_CURRENT_USER,
906 L"Software\\Classes\\TestApp\\Application", KEY_READ));
907 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"ApplicationName", &value));
908 EXPECT_EQ(L"Test Application", value);
909 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"ApplicationIcon", &value));
910 EXPECT_EQ(L"D:\\test.ico,0", value);
911 }
912
913 // .test1 should be default-associated with our test app.
914 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
915 L"Software\\Classes\\.test1", KEY_READ));
916 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
917 EXPECT_EQ(L"TestApp", value);
918 ASSERT_EQ(ERROR_SUCCESS,
919 key.Open(HKEY_CURRENT_USER,
920 L"Software\\Classes\\.test1\\OpenWithProgids", KEY_READ));
921 EXPECT_TRUE(key.HasValue(L"TestApp"));
922 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"TestApp", &value));
923 EXPECT_EQ(L"", value);
924
925 // .test2 should still be associated with the other app (should not have been
926 // overridden). But it should have our app in its Open With list.
927 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
928 L"Software\\Classes\\.test2", KEY_READ));
929 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
930 EXPECT_EQ(L"SomeOtherApp", value);
931 ASSERT_EQ(ERROR_SUCCESS,
932 key.Open(HKEY_CURRENT_USER,
933 L"Software\\Classes\\.test2\\OpenWithProgids", KEY_READ));
934 EXPECT_TRUE(key.HasValue(L"TestApp"));
935 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"TestApp", &value));
936 EXPECT_EQ(L"", value);
937 }
938
TEST_F(ShellUtilRegistryTest,DeleteFileAssociations)939 TEST_F(ShellUtilRegistryTest, DeleteFileAssociations) {
940 // Create file associations.
941 ASSERT_TRUE(ShellUtil::AddFileAssociations(
942 kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
943 base::FilePath(kTestIconPath), FileExtensions()));
944
945 // Delete them.
946 EXPECT_TRUE(ShellUtil::DeleteFileAssociations(kTestProgid));
947
948 // The class key should have been completely deleted.
949 base::win::RegKey key;
950 std::wstring value;
951 ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
952 L"Software\\Classes\\TestApp", KEY_READ));
953
954 // .test1 and .test2 should no longer be associated with the test app.
955 ASSERT_EQ(ERROR_SUCCESS,
956 key.Open(HKEY_CURRENT_USER,
957 L"Software\\Classes\\.test1\\OpenWithProgids", KEY_READ));
958 EXPECT_FALSE(key.HasValue(L"TestApp"));
959 ASSERT_EQ(ERROR_SUCCESS,
960 key.Open(HKEY_CURRENT_USER,
961 L"Software\\Classes\\.test2\\OpenWithProgids", KEY_READ));
962 EXPECT_FALSE(key.HasValue(L"TestApp"));
963
964 // .test1 should no longer have a default handler.
965 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
966 L"Software\\Classes\\.test1", KEY_READ));
967 EXPECT_FALSE(key.HasValue(L""));
968
969 // .test2 should still have the other app as its default handler.
970 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
971 L"Software\\Classes\\.test2", KEY_READ));
972 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
973 EXPECT_EQ(L"SomeOtherApp", value);
974 }
975
TEST_F(ShellUtilRegistryTest,AddApplicationClass)976 TEST_F(ShellUtilRegistryTest, AddApplicationClass) {
977 // Add TestApp application class and verify registry entries.
978 EXPECT_TRUE(ShellUtil::AddApplicationClass(
979 base::string16(kTestProgid), OpenCommand(), kTestApplicationName,
980 kTestFileTypeName, base::FilePath(kTestIconPath)));
981
982 base::win::RegKey key;
983 std::wstring value;
984 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
985 L"Software\\Classes\\TestApp", KEY_READ));
986 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
987 EXPECT_EQ(L"Test File Type", value);
988 ASSERT_EQ(ERROR_SUCCESS,
989 key.Open(HKEY_CURRENT_USER,
990 L"Software\\Classes\\TestApp\\DefaultIcon", KEY_READ));
991 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
992 EXPECT_EQ(L"D:\\test.ico,0", value);
993 ASSERT_EQ(
994 ERROR_SUCCESS,
995 key.Open(HKEY_CURRENT_USER,
996 L"Software\\Classes\\TestApp\\shell\\open\\command", KEY_READ));
997 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
998 EXPECT_EQ(L"\"C:\\test.exe\" --single-argument %1", value);
999
1000 // The Application subkey and values are only required by Windows 8 and later.
1001 if (base::win::GetVersion() >= base::win::Version::WIN8) {
1002 ASSERT_EQ(ERROR_SUCCESS,
1003 key.Open(HKEY_CURRENT_USER,
1004 L"Software\\Classes\\TestApp\\Application", KEY_READ));
1005 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"ApplicationName", &value));
1006 EXPECT_EQ(L"Test Application", value);
1007 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"ApplicationIcon", &value));
1008 EXPECT_EQ(L"D:\\test.ico,0", value);
1009 }
1010 }
1011
TEST_F(ShellUtilRegistryTest,DeleteApplicationClass)1012 TEST_F(ShellUtilRegistryTest, DeleteApplicationClass) {
1013 ASSERT_TRUE(ShellUtil::AddApplicationClass(
1014 kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
1015 base::FilePath(kTestIconPath)));
1016
1017 base::win::RegKey key;
1018 std::wstring value;
1019 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
1020 L"Software\\Classes\\TestApp", KEY_READ));
1021
1022 EXPECT_TRUE(ShellUtil::DeleteApplicationClass(kTestProgid));
1023 EXPECT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
1024 L"Software\\Classes\\TestApp", KEY_READ));
1025 }
1026
TEST_F(ShellUtilRegistryTest,GetFileAssociationsAndAppName)1027 TEST_F(ShellUtilRegistryTest, GetFileAssociationsAndAppName) {
1028 ShellUtil::FileAssociationsAndAppName empty_file_associations_and_app_name(
1029 ShellUtil::GetFileAssociationsAndAppName(kTestProgid));
1030 EXPECT_TRUE(empty_file_associations_and_app_name.app_name.empty());
1031
1032 // Add file associations and test that GetFileAssociationsAndAppName returns
1033 // the registered file associations and app name. Pass kTestApplicationName
1034 // for the open command, to handle the win7 case, which returns the open
1035 // command executable name as the app_name.
1036 ASSERT_TRUE(ShellUtil::AddFileAssociations(
1037 kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
1038 base::FilePath(kTestIconPath), FileExtensions()));
1039 ShellUtil::FileAssociationsAndAppName file_associations_and_app_name(
1040 ShellUtil::GetFileAssociationsAndAppName(kTestProgid));
1041 EXPECT_EQ(file_associations_and_app_name.app_name, kTestApplicationName);
1042 EXPECT_EQ(file_associations_and_app_name.file_associations, FileExtensions());
1043 }
1044
TEST_F(ShellUtilRegistryTest,GetApplicationForProgId)1045 TEST_F(ShellUtilRegistryTest, GetApplicationForProgId) {
1046 // Create file associations.
1047 ASSERT_TRUE(ShellUtil::AddFileAssociations(
1048 kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
1049 base::FilePath(kTestIconPath), FileExtensions()));
1050 base::FilePath exe_path = ShellUtil::GetApplicationPathForProgId(kTestProgid);
1051 EXPECT_EQ(exe_path, base::FilePath(kTestOpenCommand));
1052 }
1053
TEST(ShellUtilTest,BuildAppModelIdBasic)1054 TEST(ShellUtilTest, BuildAppModelIdBasic) {
1055 std::vector<base::string16> components;
1056 const base::string16 base_app_id(install_static::GetBaseAppId());
1057 components.push_back(base_app_id);
1058 ASSERT_EQ(base_app_id, ShellUtil::BuildAppUserModelId(components));
1059 }
1060
TEST(ShellUtilTest,BuildAppModelIdManySmall)1061 TEST(ShellUtilTest, BuildAppModelIdManySmall) {
1062 std::vector<base::string16> components;
1063 const base::string16 suffixed_app_id(install_static::GetBaseAppId() +
1064 base::string16(L".gab"));
1065 components.push_back(suffixed_app_id);
1066 components.push_back(L"Default");
1067 components.push_back(L"Test");
1068 ASSERT_EQ(suffixed_app_id + L".Default.Test",
1069 ShellUtil::BuildAppUserModelId(components));
1070 }
1071
TEST(ShellUtilTest,BuildAppModelIdNullTerminatorInTheMiddle)1072 TEST(ShellUtilTest, BuildAppModelIdNullTerminatorInTheMiddle) {
1073 std::vector<base::string16> components;
1074 base::string16 appname_with_nullTerminator(
1075 L"I_have_null_terminator_in_middle");
1076 appname_with_nullTerminator[5] = '\0';
1077 components.push_back(appname_with_nullTerminator);
1078 components.push_back(L"Default");
1079 components.push_back(L"Test");
1080 base::string16 expected_string(L"I_have_nul_in_middle.Default.Test");
1081 expected_string[5] = '\0';
1082 ASSERT_EQ(expected_string, ShellUtil::BuildAppUserModelId(components));
1083 }
1084
TEST(ShellUtilTest,BuildAppModelIdLongUsernameNormalProfile)1085 TEST(ShellUtilTest, BuildAppModelIdLongUsernameNormalProfile) {
1086 std::vector<base::string16> components;
1087 const base::string16 long_appname(
1088 L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_"
1089 L"that_goes_over_64_characters");
1090 components.push_back(long_appname);
1091 components.push_back(L"Default");
1092 ASSERT_EQ(L"Chrome.a_user_wer_64_characters.Default",
1093 ShellUtil::BuildAppUserModelId(components));
1094 }
1095
TEST(ShellUtilTest,BuildAppModelIdLongEverything)1096 TEST(ShellUtilTest, BuildAppModelIdLongEverything) {
1097 std::vector<base::string16> components;
1098 const base::string16 long_appname(
1099 L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_"
1100 L"that_goes_over_64_characters");
1101 components.push_back(long_appname);
1102 components.push_back(
1103 L"A_crazy_profile_name_not_even_sure_whether_that_is_possible");
1104 const base::string16 constructed_app_id(
1105 ShellUtil::BuildAppUserModelId(components));
1106 ASSERT_LE(constructed_app_id.length(), installer::kMaxAppModelIdLength);
1107 ASSERT_EQ(L"Chrome.a_user_wer_64_characters.A_crazy_profilethat_is_possible",
1108 constructed_app_id);
1109 }
1110
TEST(ShellUtilTest,GetUserSpecificRegistrySuffix)1111 TEST(ShellUtilTest, GetUserSpecificRegistrySuffix) {
1112 base::string16 suffix;
1113 ASSERT_TRUE(ShellUtil::GetUserSpecificRegistrySuffix(&suffix));
1114 ASSERT_TRUE(base::StartsWith(suffix, L".", base::CompareCase::SENSITIVE));
1115 ASSERT_EQ(27u, suffix.length());
1116 ASSERT_TRUE(base::ContainsOnlyChars(suffix.substr(1),
1117 L"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"));
1118 }
1119
TEST(ShellUtilTest,GetOldUserSpecificRegistrySuffix)1120 TEST(ShellUtilTest, GetOldUserSpecificRegistrySuffix) {
1121 base::string16 suffix;
1122 ASSERT_TRUE(ShellUtil::GetOldUserSpecificRegistrySuffix(&suffix));
1123 ASSERT_TRUE(base::StartsWith(suffix, L".", base::CompareCase::SENSITIVE));
1124
1125 wchar_t user_name[256];
1126 DWORD size = base::size(user_name);
1127 ASSERT_NE(0, ::GetUserName(user_name, &size));
1128 ASSERT_GE(size, 1U);
1129 ASSERT_STREQ(user_name, suffix.substr(1).c_str());
1130 }
1131