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/installer/util/shell_util.h"
9 #include "base/base_paths.h"
10 #include "base/base_paths_win.h"
11 #include "base/file_util.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/scoped_temp_dir.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/string_util.h"
18 #include "base/synchronization/cancellation_flag.h"
19 #include "base/test/scoped_path_override.h"
20 #include "base/test/test_shortcut_win.h"
21 #include "base/win/shortcut.h"
22 #include "base/win/windows_version.h"
23 #include "chrome/installer/util/browser_distribution.h"
24 #include "chrome/installer/util/product.h"
25 #include "chrome/installer/util/util_constants.h"
26 #include "testing/gtest/include/gtest/gtest.h"
30 const wchar_t kManganeseExe[] = L"manganese.exe";
31 const wchar_t kIronExe[] = L"iron.exe";
32 const wchar_t kOtherIco[] = L"other.ico";
34 // TODO(huangs): Separate this into generic shortcut tests and Chrome-specific
35 // tests. Specifically, we should not overly rely on getting shortcut properties
36 // from product_->AddDefaultShortcutProperties().
37 class ShellUtilShortcutTest : public testing::Test {
39 ShellUtilShortcutTest() : test_properties_(ShellUtil::CURRENT_USER) {}
41 virtual void SetUp() OVERRIDE {
42 dist_ = BrowserDistribution::GetDistribution();
43 ASSERT_TRUE(dist_ != NULL);
44 product_.reset(new installer::Product(dist_));
46 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
47 chrome_exe_ = temp_dir_.path().Append(installer::kChromeExe);
48 EXPECT_EQ(0, base::WriteFile(chrome_exe_, "", 0));
50 manganese_exe_ = temp_dir_.path().Append(kManganeseExe);
51 EXPECT_EQ(0, base::WriteFile(manganese_exe_, "", 0));
53 iron_exe_ = temp_dir_.path().Append(kIronExe);
54 EXPECT_EQ(0, base::WriteFile(iron_exe_, "", 0));
56 other_ico_ = temp_dir_.path().Append(kOtherIco);
57 EXPECT_EQ(0, base::WriteFile(other_ico_, "", 0));
59 ASSERT_TRUE(fake_user_desktop_.CreateUniqueTempDir());
60 ASSERT_TRUE(fake_common_desktop_.CreateUniqueTempDir());
61 ASSERT_TRUE(fake_user_quick_launch_.CreateUniqueTempDir());
62 ASSERT_TRUE(fake_default_user_quick_launch_.CreateUniqueTempDir());
63 ASSERT_TRUE(fake_start_menu_.CreateUniqueTempDir());
64 ASSERT_TRUE(fake_common_start_menu_.CreateUniqueTempDir());
65 user_desktop_override_.reset(
66 new base::ScopedPathOverride(base::DIR_USER_DESKTOP,
67 fake_user_desktop_.path()));
68 common_desktop_override_.reset(
69 new base::ScopedPathOverride(base::DIR_COMMON_DESKTOP,
70 fake_common_desktop_.path()));
71 user_quick_launch_override_.reset(
72 new base::ScopedPathOverride(base::DIR_USER_QUICK_LAUNCH,
73 fake_user_quick_launch_.path()));
74 start_menu_override_.reset(
75 new base::ScopedPathOverride(base::DIR_START_MENU,
76 fake_start_menu_.path()));
77 common_start_menu_override_.reset(
78 new base::ScopedPathOverride(base::DIR_COMMON_START_MENU,
79 fake_common_start_menu_.path()));
81 base::FilePath icon_path;
82 base::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path);
83 test_properties_.set_target(chrome_exe_);
84 test_properties_.set_arguments(L"--test --chrome");
85 test_properties_.set_description(L"Makes polar bears dance.");
86 test_properties_.set_icon(icon_path, 7);
87 test_properties_.set_app_id(L"Polar.Bear");
88 test_properties_.set_dual_mode(true);
91 // Returns the expected path of a test shortcut. Returns an empty FilePath on
93 base::FilePath GetExpectedShortcutPath(
94 ShellUtil::ShortcutLocation location,
95 BrowserDistribution* dist,
96 const ShellUtil::ShortcutProperties& properties) {
97 base::FilePath expected_path;
99 case ShellUtil::SHORTCUT_LOCATION_DESKTOP:
100 expected_path = (properties.level == ShellUtil::CURRENT_USER) ?
101 fake_user_desktop_.path() : fake_common_desktop_.path();
103 case ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH:
104 expected_path = fake_user_quick_launch_.path();
106 case ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR:
107 expected_path = (properties.level == ShellUtil::CURRENT_USER) ?
108 fake_start_menu_.path() : fake_common_start_menu_.path();
109 expected_path = expected_path.Append(
110 dist_->GetStartMenuShortcutSubfolder(
111 BrowserDistribution::SUBFOLDER_CHROME));
114 ADD_FAILURE() << "Unknown location";
115 return base::FilePath();
118 base::string16 shortcut_name = properties.has_shortcut_name() ?
119 properties.shortcut_name :
120 dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME);
121 shortcut_name.append(installer::kLnkExt);
122 return expected_path.Append(shortcut_name);
125 // Validates that the shortcut at |location| matches |properties| (and
126 // implicit default properties) for |dist|.
127 // Note: This method doesn't verify the |pin_to_taskbar| property as it
128 // implies real (non-mocked) state which is flaky to test.
129 void ValidateChromeShortcut(
130 ShellUtil::ShortcutLocation location,
131 BrowserDistribution* dist,
132 const ShellUtil::ShortcutProperties& properties) {
133 base::FilePath expected_path(
134 GetExpectedShortcutPath(location, dist, properties));
136 base::win::ShortcutProperties expected_properties;
137 if (properties.has_target()) {
138 expected_properties.set_target(properties.target);
139 expected_properties.set_working_dir(properties.target.DirName());
141 expected_properties.set_target(chrome_exe_);
142 expected_properties.set_working_dir(chrome_exe_.DirName());
145 if (properties.has_arguments())
146 expected_properties.set_arguments(properties.arguments);
148 expected_properties.set_arguments(base::string16());
150 if (properties.has_description())
151 expected_properties.set_description(properties.description);
153 expected_properties.set_description(dist->GetAppDescription());
155 if (properties.has_icon()) {
156 expected_properties.set_icon(properties.icon, properties.icon_index);
158 int icon_index = dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
159 expected_properties.set_icon(chrome_exe_, icon_index);
162 if (properties.has_app_id()) {
163 expected_properties.set_app_id(properties.app_id);
165 // Tests are always seen as user-level installs in ShellUtil.
166 expected_properties.set_app_id(ShellUtil::GetBrowserModelId(dist, true));
169 if (properties.has_dual_mode())
170 expected_properties.set_dual_mode(properties.dual_mode);
172 expected_properties.set_dual_mode(false);
174 base::win::ValidateShortcut(expected_path, expected_properties);
177 BrowserDistribution* dist_;
178 scoped_ptr<installer::Product> product_;
180 // A ShellUtil::ShortcutProperties object with common properties set already.
181 ShellUtil::ShortcutProperties test_properties_;
183 base::ScopedTempDir temp_dir_;
184 base::ScopedTempDir fake_user_desktop_;
185 base::ScopedTempDir fake_common_desktop_;
186 base::ScopedTempDir fake_user_quick_launch_;
187 base::ScopedTempDir fake_default_user_quick_launch_;
188 base::ScopedTempDir fake_start_menu_;
189 base::ScopedTempDir fake_common_start_menu_;
190 scoped_ptr<base::ScopedPathOverride> user_desktop_override_;
191 scoped_ptr<base::ScopedPathOverride> common_desktop_override_;
192 scoped_ptr<base::ScopedPathOverride> user_quick_launch_override_;
193 scoped_ptr<base::ScopedPathOverride> start_menu_override_;
194 scoped_ptr<base::ScopedPathOverride> common_start_menu_override_;
196 base::FilePath chrome_exe_;
197 base::FilePath manganese_exe_;
198 base::FilePath iron_exe_;
199 base::FilePath other_ico_;
204 TEST_F(ShellUtilShortcutTest, GetShortcutPath) {
207 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
208 ShellUtil::CURRENT_USER, &path);
209 EXPECT_EQ(fake_user_desktop_.path(), path);
211 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
212 ShellUtil::SYSTEM_LEVEL, &path);
213 EXPECT_EQ(fake_common_desktop_.path(), path);
215 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
216 ShellUtil::CURRENT_USER, &path);
217 EXPECT_EQ(fake_user_quick_launch_.path(), path);
219 base::string16 start_menu_subfolder =
220 dist_->GetStartMenuShortcutSubfolder(
221 BrowserDistribution::SUBFOLDER_CHROME);
222 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
223 dist_, ShellUtil::CURRENT_USER, &path);
224 EXPECT_EQ(fake_start_menu_.path().Append(start_menu_subfolder),
227 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
228 dist_, ShellUtil::SYSTEM_LEVEL, &path);
229 EXPECT_EQ(fake_common_start_menu_.path().Append(start_menu_subfolder),
233 TEST_F(ShellUtilShortcutTest, CreateChromeExeShortcutWithDefaultProperties) {
234 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
235 product_->AddDefaultShortcutProperties(chrome_exe_, &properties);
236 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
237 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, properties,
238 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
239 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
243 TEST_F(ShellUtilShortcutTest, CreateStartMenuShortcutWithAllProperties) {
244 test_properties_.set_shortcut_name(L"Bobo le shortcut");
245 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
246 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
247 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
248 dist_, test_properties_,
249 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
250 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
251 dist_, test_properties_);
254 TEST_F(ShellUtilShortcutTest, ReplaceSystemLevelDesktopShortcut) {
255 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
256 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
257 ShellUtil::SHORTCUT_LOCATION_DESKTOP,
258 dist_, test_properties_,
259 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
261 ShellUtil::ShortcutProperties new_properties(ShellUtil::SYSTEM_LEVEL);
262 product_->AddDefaultShortcutProperties(chrome_exe_, &new_properties);
263 new_properties.set_description(L"New description");
264 new_properties.set_arguments(L"--new-arguments");
265 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
266 ShellUtil::SHORTCUT_LOCATION_DESKTOP,
267 dist_, new_properties,
268 ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING));
270 // Expect the properties set in |new_properties| to be set as above and
271 // properties that don't have a default value to be set back to their default
272 // (as validated in ValidateChromeShortcut()) or unset if they don't .
273 ShellUtil::ShortcutProperties expected_properties(new_properties);
274 expected_properties.set_dual_mode(false);
276 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
277 expected_properties);
280 TEST_F(ShellUtilShortcutTest, UpdateQuickLaunchShortcutArguments) {
281 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
282 ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
283 dist_, test_properties_,
284 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
286 // Only changing one property, don't need all the defaults.
287 ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
288 updated_properties.set_arguments(L"--updated --arguments");
289 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
290 ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
291 dist_, updated_properties,
292 ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
294 // Expect the properties set in |updated_properties| to be set as above and
295 // all other properties to remain unchanged.
296 ShellUtil::ShortcutProperties expected_properties(test_properties_);
297 expected_properties.set_arguments(updated_properties.arguments);
299 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
300 expected_properties);
303 TEST_F(ShellUtilShortcutTest, UpdateAddDualModeToStartMenuShortcut) {
304 ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
305 product_->AddDefaultShortcutProperties(chrome_exe_, &properties);
306 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
307 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_,
308 properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
310 ShellUtil::ShortcutProperties added_properties(ShellUtil::CURRENT_USER);
311 added_properties.set_dual_mode(true);
312 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
313 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_,
314 added_properties, ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
316 ShellUtil::ShortcutProperties expected_properties(properties);
317 expected_properties.set_dual_mode(true);
319 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
320 dist_, expected_properties);
323 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevel) {
324 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
325 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
326 ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
327 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
331 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelWithSystemLevelPresent) {
332 base::string16 shortcut_name(
333 dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
336 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
337 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
338 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
339 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
340 ASSERT_TRUE(base::PathExists(
341 fake_common_desktop_.path().Append(shortcut_name)));
343 test_properties_.level = ShellUtil::CURRENT_USER;
344 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
345 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
346 ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
347 ASSERT_FALSE(base::PathExists(
348 fake_user_desktop_.path().Append(shortcut_name)));
351 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelStartMenu) {
352 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
353 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
354 dist_, test_properties_,
355 ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
356 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
357 dist_, test_properties_);
360 TEST_F(ShellUtilShortcutTest, CreateAlwaysUserWithSystemLevelPresent) {
361 base::string16 shortcut_name(
362 dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
365 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
366 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
367 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
368 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
369 ASSERT_TRUE(base::PathExists(
370 fake_common_desktop_.path().Append(shortcut_name)));
372 test_properties_.level = ShellUtil::CURRENT_USER;
373 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
374 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
375 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
376 ASSERT_TRUE(base::PathExists(
377 fake_user_desktop_.path().Append(shortcut_name)));
380 TEST_F(ShellUtilShortcutTest, RemoveChromeShortcut) {
381 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
382 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
383 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
384 base::FilePath shortcut_path = GetExpectedShortcutPath(
385 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
386 ASSERT_TRUE(base::PathExists(shortcut_path));
388 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
389 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
391 ASSERT_FALSE(base::PathExists(shortcut_path));
392 ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
395 TEST_F(ShellUtilShortcutTest, RemoveSystemLevelChromeShortcut) {
396 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
397 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
398 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
399 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
400 base::FilePath shortcut_path = GetExpectedShortcutPath(
401 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
402 ASSERT_TRUE(base::PathExists(shortcut_path));
404 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
405 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL,
407 ASSERT_FALSE(base::PathExists(shortcut_path));
408 ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
411 TEST_F(ShellUtilShortcutTest, RemoveMultipleChromeShortcuts) {
412 // Shortcut 1: targets "chrome.exe"; no arguments.
413 test_properties_.set_shortcut_name(L"Chrome 1");
414 test_properties_.set_arguments(L"");
415 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
416 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
417 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
418 base::FilePath shortcut1_path = GetExpectedShortcutPath(
419 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
420 ASSERT_TRUE(base::PathExists(shortcut1_path));
422 // Shortcut 2: targets "chrome.exe"; has arguments; icon set to "other.ico".
423 test_properties_.set_shortcut_name(L"Chrome 2");
424 test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
425 test_properties_.set_icon(other_ico_, 0);
426 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
427 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
428 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
429 base::FilePath shortcut2_path = GetExpectedShortcutPath(
430 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
431 ASSERT_TRUE(base::PathExists(shortcut2_path));
433 // Shortcut 3: targets "iron.exe"; has arguments; icon set to "chrome.exe".
434 test_properties_.set_shortcut_name(L"Iron 3");
435 test_properties_.set_target(iron_exe_);
436 test_properties_.set_icon(chrome_exe_, 3);
437 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
438 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
439 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
440 base::FilePath shortcut3_path = GetExpectedShortcutPath(
441 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
442 ASSERT_TRUE(base::PathExists(shortcut3_path));
444 // Remove shortcuts that target "chrome.exe".
445 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
446 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
448 ASSERT_FALSE(base::PathExists(shortcut1_path));
449 ASSERT_FALSE(base::PathExists(shortcut2_path));
450 ASSERT_TRUE(base::PathExists(shortcut3_path));
451 ASSERT_TRUE(base::PathExists(shortcut1_path.DirName()));
454 TEST_F(ShellUtilShortcutTest, RetargetShortcutsWithArgs) {
455 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
456 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
457 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
458 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
459 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
461 base::FilePath new_exe = manganese_exe_;
462 // Relies on the fact that |test_properties_| has non-empty arguments.
463 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
464 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
465 chrome_exe_, new_exe));
467 ShellUtil::ShortcutProperties expected_properties(test_properties_);
468 expected_properties.set_target(new_exe);
469 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
470 expected_properties);
473 TEST_F(ShellUtilShortcutTest, RetargetSystemLevelChromeShortcutsWithArgs) {
474 test_properties_.level = ShellUtil::SYSTEM_LEVEL;
475 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
476 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
477 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
478 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
479 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
481 base::FilePath new_exe = manganese_exe_;
482 // Relies on the fact that |test_properties_| has non-empty arguments.
483 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
484 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL,
485 chrome_exe_, new_exe));
487 ShellUtil::ShortcutProperties expected_properties(test_properties_);
488 expected_properties.set_target(new_exe);
489 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
490 expected_properties);
493 TEST_F(ShellUtilShortcutTest, RetargetChromeShortcutsWithArgsEmpty) {
494 // Shortcut 1: targets "chrome.exe"; no arguments.
495 test_properties_.set_shortcut_name(L"Chrome 1");
496 test_properties_.set_arguments(L"");
497 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
498 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
499 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
500 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
501 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
502 ShellUtil::ShortcutProperties expected_properties1(test_properties_);
504 // Shortcut 2: targets "chrome.exe"; has arguments.
505 test_properties_.set_shortcut_name(L"Chrome 2");
506 test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
507 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
508 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
509 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
510 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
511 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
512 ShellUtil::ShortcutProperties expected_properties2(test_properties_);
514 // Retarget shortcuts: replace "chrome.exe" with "manganese.exe". Only
515 // shortcuts with non-empty arguments (i.e., shortcut 2) gets updated.
516 base::FilePath new_exe = manganese_exe_;
517 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
518 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
519 chrome_exe_, new_exe));
521 // Verify shortcut 1: no change.
522 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
523 expected_properties1);
525 // Verify shortcut 2: target => "manganese.exe".
526 expected_properties2.set_target(new_exe);
527 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
528 expected_properties2);
531 TEST_F(ShellUtilShortcutTest, RetargetChromeShortcutsWithArgsIcon) {
532 const int kTestIconIndex1 = 3;
533 const int kTestIconIndex2 = 5;
534 const int kTestIconIndex3 = 8;
536 // Shortcut 1: targets "chrome.exe"; icon same as target.
537 test_properties_.set_shortcut_name(L"Chrome 1");
538 test_properties_.set_icon(test_properties_.target, kTestIconIndex1);
539 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
540 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
541 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
542 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
543 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
544 ShellUtil::ShortcutProperties expected_properties1(test_properties_);
546 // Shortcut 2: targets "chrome.exe"; icon set to "other.ico".
547 test_properties_.set_shortcut_name(L"Chrome 2");
548 test_properties_.set_icon(other_ico_, kTestIconIndex2);
549 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
550 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
551 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
552 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
553 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
554 ShellUtil::ShortcutProperties expected_properties2(test_properties_);
556 // Shortcut 3: targets "iron.exe"; icon set to "chrome.exe".
557 test_properties_.set_target(iron_exe_);
558 test_properties_.set_shortcut_name(L"Iron 3");
559 test_properties_.set_icon(chrome_exe_, kTestIconIndex3);
560 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
561 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
562 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
563 ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
564 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
565 ShellUtil::ShortcutProperties expected_properties3(test_properties_);
567 // Retarget shortcuts: replace "chrome.exe" with "manganese.exe".
568 // Relies on the fact that |test_properties_| has non-empty arguments.
569 base::FilePath new_exe = manganese_exe_;
570 ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
571 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
572 chrome_exe_, new_exe));
574 // Verify shortcut 1: target & icon => "manganese.exe", kept same icon index.
575 expected_properties1.set_target(new_exe);
576 expected_properties1.set_icon(new_exe, kTestIconIndex1);
577 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
578 expected_properties1);
580 // Verify shortcut 2: target => "manganese.exe", kept icon.
581 expected_properties2.set_target(new_exe);
582 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
583 expected_properties2);
585 // Verify shortcut 3: no change, since target doesn't match.
586 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
587 expected_properties3);
590 TEST_F(ShellUtilShortcutTest, ClearShortcutArguments) {
591 // Shortcut 1: targets "chrome.exe"; no arguments.
592 test_properties_.set_shortcut_name(L"Chrome 1");
593 test_properties_.set_arguments(L"");
594 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
595 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
596 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
597 base::FilePath shortcut1_path = GetExpectedShortcutPath(
598 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
599 ASSERT_TRUE(base::PathExists(shortcut1_path));
600 ShellUtil::ShortcutProperties expected_properties1(test_properties_);
602 // Shortcut 2: targets "chrome.exe"; has 1 whitelisted argument.
603 test_properties_.set_shortcut_name(L"Chrome 2");
604 test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
605 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
606 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
607 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
608 base::FilePath shortcut2_path = GetExpectedShortcutPath(
609 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
610 ASSERT_TRUE(base::PathExists(shortcut2_path));
611 ShellUtil::ShortcutProperties expected_properties2(test_properties_);
613 // Shortcut 3: targets "chrome.exe"; has an unknown argument.
614 test_properties_.set_shortcut_name(L"Chrome 3");
615 test_properties_.set_arguments(L"foo.com");
616 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
617 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
618 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
619 base::FilePath shortcut3_path = GetExpectedShortcutPath(
620 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
621 ASSERT_TRUE(base::PathExists(shortcut3_path));
622 ShellUtil::ShortcutProperties expected_properties3(test_properties_);
624 // Shortcut 4: targets "chrome.exe"; has both unknown and known arguments.
625 test_properties_.set_shortcut_name(L"Chrome 4");
626 test_properties_.set_arguments(L"foo.com --show-app-list");
627 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
628 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
629 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
630 base::FilePath shortcut4_path = GetExpectedShortcutPath(
631 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
632 ASSERT_TRUE(base::PathExists(shortcut4_path));
633 ShellUtil::ShortcutProperties expected_properties4(test_properties_);
635 // List the shortcuts.
636 std::vector<std::pair<base::FilePath, base::string16> > shortcuts;
637 EXPECT_TRUE(ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
638 ShellUtil::SHORTCUT_LOCATION_DESKTOP,
640 ShellUtil::CURRENT_USER,
645 ASSERT_EQ(2u, shortcuts.size());
646 std::pair<base::FilePath, base::string16> shortcut3 =
647 shortcuts[0].first == shortcut3_path ? shortcuts[0] : shortcuts[1];
648 std::pair<base::FilePath, base::string16> shortcut4 =
649 shortcuts[0].first == shortcut4_path ? shortcuts[0] : shortcuts[1];
650 EXPECT_EQ(shortcut3_path, shortcut3.first);
651 EXPECT_EQ(L"foo.com", shortcut3.second);
652 EXPECT_EQ(shortcut4_path, shortcut4.first);
653 EXPECT_EQ(L"foo.com --show-app-list", shortcut4.second);
657 EXPECT_TRUE(ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
658 ShellUtil::SHORTCUT_LOCATION_DESKTOP,
660 ShellUtil::CURRENT_USER,
665 ASSERT_EQ(2u, shortcuts.size());
666 shortcut3 = shortcuts[0].first == shortcut3_path ? shortcuts[0] :
668 shortcut4 = shortcuts[0].first == shortcut4_path ? shortcuts[0] :
670 EXPECT_EQ(shortcut3_path, shortcut3.first);
671 EXPECT_EQ(L"foo.com", shortcut3.second);
672 EXPECT_EQ(shortcut4_path, shortcut4.first);
673 EXPECT_EQ(L"foo.com --show-app-list", shortcut4.second);
675 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
676 expected_properties1);
677 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
678 expected_properties2);
679 expected_properties3.set_arguments(base::string16());
680 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
681 expected_properties3);
682 expected_properties4.set_arguments(L"--show-app-list");
683 ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
684 expected_properties4);
687 TEST_F(ShellUtilShortcutTest, CreateMultipleStartMenuShortcutsAndRemoveFolder) {
688 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
689 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
690 dist_, test_properties_,
691 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
692 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
693 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
694 dist_, test_properties_,
695 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
696 test_properties_.set_shortcut_name(L"A second shortcut");
697 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
698 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR,
699 dist_, test_properties_,
700 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
701 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
702 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
703 dist_, test_properties_,
704 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
706 base::FilePath chrome_shortcut_folder(
707 fake_start_menu_.path().Append(
708 dist_->GetStartMenuShortcutSubfolder(
709 BrowserDistribution::SUBFOLDER_CHROME)));
710 base::FilePath chrome_apps_shortcut_folder(
711 fake_start_menu_.path().Append(
712 dist_->GetStartMenuShortcutSubfolder(
713 BrowserDistribution::SUBFOLDER_APPS)));
715 base::FileEnumerator chrome_file_counter(chrome_shortcut_folder, false,
716 base::FileEnumerator::FILES);
718 while (!chrome_file_counter.Next().empty())
722 base::FileEnumerator chrome_apps_file_counter(chrome_apps_shortcut_folder,
724 base::FileEnumerator::FILES);
726 while (!chrome_apps_file_counter.Next().empty())
730 ASSERT_TRUE(base::PathExists(chrome_shortcut_folder));
731 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
732 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, dist_,
733 ShellUtil::CURRENT_USER, chrome_exe_));
734 ASSERT_FALSE(base::PathExists(chrome_shortcut_folder));
736 ASSERT_TRUE(base::PathExists(chrome_apps_shortcut_folder));
737 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
738 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, dist_,
739 ShellUtil::CURRENT_USER, chrome_exe_));
740 ASSERT_FALSE(base::PathExists(chrome_apps_shortcut_folder));
743 TEST_F(ShellUtilShortcutTest,
744 DeleteStartMenuRootShortcutWithoutRemovingFolder) {
745 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
746 ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
747 dist_, test_properties_,
748 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
750 base::string16 shortcut_name(
751 dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
753 base::FilePath shortcut_path(
754 fake_start_menu_.path().Append(shortcut_name));
756 ASSERT_TRUE(base::PathExists(fake_start_menu_.path()));
757 ASSERT_TRUE(base::PathExists(shortcut_path));
758 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
759 ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, dist_,
760 ShellUtil::CURRENT_USER, chrome_exe_));
761 // The shortcut should be removed but the "Start Menu" root directory should
763 ASSERT_TRUE(base::PathExists(fake_start_menu_.path()));
764 ASSERT_FALSE(base::PathExists(shortcut_path));
767 TEST_F(ShellUtilShortcutTest, DontRemoveChromeShortcutIfPointsToAnotherChrome) {
768 base::ScopedTempDir other_exe_dir;
769 ASSERT_TRUE(other_exe_dir.CreateUniqueTempDir());
770 base::FilePath other_chrome_exe =
771 other_exe_dir.path().Append(installer::kChromeExe);
772 EXPECT_EQ(0, base::WriteFile(other_chrome_exe, "", 0));
774 test_properties_.set_target(other_chrome_exe);
775 ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
776 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
777 ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
779 base::string16 shortcut_name(
780 dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
782 base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
783 ASSERT_TRUE(base::PathExists(shortcut_path));
785 // The shortcut shouldn't be removed as it was installed pointing to
786 // |other_chrome_exe| and RemoveChromeShortcut() is being told that the
787 // removed shortcut should point to |chrome_exe_|.
788 ASSERT_TRUE(ShellUtil::RemoveShortcuts(
789 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
791 ASSERT_TRUE(base::PathExists(shortcut_path));
792 ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
795 TEST(ShellUtilTest, BuildAppModelIdBasic) {
796 std::vector<base::string16> components;
797 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
798 const base::string16 base_app_id(dist->GetBaseAppId());
799 components.push_back(base_app_id);
800 ASSERT_EQ(base_app_id, ShellUtil::BuildAppModelId(components));
803 TEST(ShellUtilTest, BuildAppModelIdManySmall) {
804 std::vector<base::string16> components;
805 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
806 const base::string16 suffixed_app_id(dist->GetBaseAppId().append(L".gab"));
807 components.push_back(suffixed_app_id);
808 components.push_back(L"Default");
809 components.push_back(L"Test");
810 ASSERT_EQ(suffixed_app_id + L".Default.Test",
811 ShellUtil::BuildAppModelId(components));
814 TEST(ShellUtilTest, BuildAppModelIdLongUsernameNormalProfile) {
815 std::vector<base::string16> components;
816 const base::string16 long_appname(
817 L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_"
818 L"that_goes_over_64_characters");
819 components.push_back(long_appname);
820 components.push_back(L"Default");
821 ASSERT_EQ(L"Chrome.a_user_wer_64_characters.Default",
822 ShellUtil::BuildAppModelId(components));
825 TEST(ShellUtilTest, BuildAppModelIdLongEverything) {
826 std::vector<base::string16> components;
827 const base::string16 long_appname(L"Chrome.a_user_who_has_a_crazy_long_name_"
828 L"with_some_weird@symbols_in_"
829 L"it_" L"that_goes_over_64_characters");
830 components.push_back(long_appname);
831 components.push_back(
832 L"A_crazy_profile_name_not_even_sure_whether_that_is_possible");
833 const base::string16 constructed_app_id(
834 ShellUtil::BuildAppModelId(components));
835 ASSERT_LE(constructed_app_id.length(), installer::kMaxAppModelIdLength);
836 ASSERT_EQ(L"Chrome.a_user_wer_64_characters.A_crazy_profilethat_is_possible",
840 TEST(ShellUtilTest, GetUserSpecificRegistrySuffix) {
841 base::string16 suffix;
842 ASSERT_TRUE(ShellUtil::GetUserSpecificRegistrySuffix(&suffix));
843 ASSERT_TRUE(StartsWith(suffix, L".", true));
844 ASSERT_EQ(27, suffix.length());
845 ASSERT_TRUE(base::ContainsOnlyChars(suffix.substr(1),
846 L"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"));
849 TEST(ShellUtilTest, GetOldUserSpecificRegistrySuffix) {
850 base::string16 suffix;
851 ASSERT_TRUE(ShellUtil::GetOldUserSpecificRegistrySuffix(&suffix));
852 ASSERT_TRUE(StartsWith(suffix, L".", true));
854 wchar_t user_name[256];
855 DWORD size = arraysize(user_name);
856 ASSERT_NE(0, ::GetUserName(user_name, &size));
858 ASSERT_STREQ(user_name, suffix.substr(1).c_str());
861 TEST(ShellUtilTest, ByteArrayToBase32) {
862 // Tests from http://tools.ietf.org/html/rfc4648#section-10.
863 const unsigned char test_array[] = { 'f', 'o', 'o', 'b', 'a', 'r' };
865 const base::string16 expected[] = { L"", L"MY", L"MZXQ", L"MZXW6", L"MZXW6YQ",
866 L"MZXW6YTB", L"MZXW6YTBOI"};
868 // Run the tests, with one more letter in the input every pass.
869 for (int i = 0; i < arraysize(expected); ++i) {
870 ASSERT_EQ(expected[i],
871 ShellUtil::ByteArrayToBase32(test_array, i));