shell_util_unittest.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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 <vector>
8
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"
14#include "base/md5.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/strings/string16.h"
17#include "base/strings/string_util.h"
18#include "base/test/scoped_path_override.h"
19#include "base/test/test_shortcut_win.h"
20#include "base/win/shortcut.h"
21#include "base/win/windows_version.h"
22#include "chrome/installer/util/browser_distribution.h"
23#include "chrome/installer/util/product.h"
24#include "chrome/installer/util/util_constants.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27namespace {
28
29const wchar_t kManganeseExe[] = L"manganese.exe";
30
31// TODO(huangs): Separate this into generic shortcut tests and Chrome-specific
32// tests. Specifically, we should not overly rely on getting shortcut properties
33// from product_->AddDefaultShortcutProperties().
34class ShellUtilShortcutTest : public testing::Test {
35 protected:
36  ShellUtilShortcutTest() : test_properties_(ShellUtil::CURRENT_USER) {}
37
38  virtual void SetUp() OVERRIDE {
39    dist_ = BrowserDistribution::GetDistribution();
40    ASSERT_TRUE(dist_ != NULL);
41    product_.reset(new installer::Product(dist_));
42
43    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
44    chrome_exe_ = temp_dir_.path().Append(installer::kChromeExe);
45    EXPECT_EQ(0, file_util::WriteFile(chrome_exe_, "", 0));
46
47    manganese_exe_ = temp_dir_.path().Append(kManganeseExe);
48    EXPECT_EQ(0, file_util::WriteFile(manganese_exe_, "", 0));
49
50    ASSERT_TRUE(fake_user_desktop_.CreateUniqueTempDir());
51    ASSERT_TRUE(fake_common_desktop_.CreateUniqueTempDir());
52    ASSERT_TRUE(fake_user_quick_launch_.CreateUniqueTempDir());
53    ASSERT_TRUE(fake_default_user_quick_launch_.CreateUniqueTempDir());
54    ASSERT_TRUE(fake_start_menu_.CreateUniqueTempDir());
55    ASSERT_TRUE(fake_common_start_menu_.CreateUniqueTempDir());
56    user_desktop_override_.reset(
57        new base::ScopedPathOverride(base::DIR_USER_DESKTOP,
58                                     fake_user_desktop_.path()));
59    common_desktop_override_.reset(
60        new base::ScopedPathOverride(base::DIR_COMMON_DESKTOP,
61                                     fake_common_desktop_.path()));
62    user_quick_launch_override_.reset(
63        new base::ScopedPathOverride(base::DIR_USER_QUICK_LAUNCH,
64                                     fake_user_quick_launch_.path()));
65    default_user_quick_launch_override_.reset(
66        new base::ScopedPathOverride(base::DIR_DEFAULT_USER_QUICK_LAUNCH,
67                                     fake_default_user_quick_launch_.path()));
68    start_menu_override_.reset(
69        new base::ScopedPathOverride(base::DIR_START_MENU,
70                                     fake_start_menu_.path()));
71    common_start_menu_override_.reset(
72        new base::ScopedPathOverride(base::DIR_COMMON_START_MENU,
73                                     fake_common_start_menu_.path()));
74
75    base::FilePath icon_path;
76    file_util::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path);
77    test_properties_.set_target(chrome_exe_);
78    test_properties_.set_arguments(L"--test --chrome");
79    test_properties_.set_description(L"Makes polar bears dance.");
80    test_properties_.set_icon(icon_path, 0);
81    test_properties_.set_app_id(L"Polar.Bear");
82    test_properties_.set_dual_mode(true);
83  }
84
85  // Validates that the shortcut at |location| matches |properties| (and
86  // implicit default properties) for |dist|.
87  // Note: This method doesn't verify the |pin_to_taskbar| property as it
88  // implies real (non-mocked) state which is flaky to test.
89  void ValidateChromeShortcut(
90      ShellUtil::ShortcutLocation location,
91      BrowserDistribution* dist,
92      const ShellUtil::ShortcutProperties& properties) {
93    base::FilePath expected_path;
94    switch (location) {
95      case ShellUtil::SHORTCUT_LOCATION_DESKTOP:
96        expected_path = (properties.level == ShellUtil::CURRENT_USER) ?
97            fake_user_desktop_.path() : fake_common_desktop_.path();
98        break;
99      case ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH:
100        expected_path = (properties.level == ShellUtil::CURRENT_USER) ?
101            fake_user_quick_launch_.path() :
102            fake_default_user_quick_launch_.path();
103        break;
104      case ShellUtil::SHORTCUT_LOCATION_START_MENU:
105        expected_path = (properties.level == ShellUtil::CURRENT_USER) ?
106            fake_start_menu_.path() : fake_common_start_menu_.path();
107        expected_path = expected_path.Append(
108            dist_->GetStartMenuShortcutSubfolder(
109                BrowserDistribution::SUBFOLDER_CHROME));
110        break;
111      default:
112        ADD_FAILURE() << "Unknown location";
113        return;
114    }
115
116    string16 shortcut_name;
117    if (properties.has_shortcut_name()) {
118      shortcut_name = properties.shortcut_name;
119    } else {
120      shortcut_name =
121          dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME);
122    }
123    shortcut_name.append(installer::kLnkExt);
124    expected_path = expected_path.Append(shortcut_name);
125
126    base::win::ShortcutProperties expected_properties;
127    if (properties.has_target()) {
128      expected_properties.set_target(properties.target);
129      expected_properties.set_working_dir(properties.target.DirName());
130    } else {
131      expected_properties.set_target(chrome_exe_);
132      expected_properties.set_working_dir(chrome_exe_.DirName());
133    }
134
135    if (properties.has_arguments())
136      expected_properties.set_arguments(properties.arguments);
137    else
138      expected_properties.set_arguments(string16());
139
140    if (properties.has_description())
141      expected_properties.set_description(properties.description);
142    else
143      expected_properties.set_description(dist->GetAppDescription());
144
145    if (properties.has_icon()) {
146      expected_properties.set_icon(properties.icon, 0);
147    } else {
148      int icon_index = dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
149      expected_properties.set_icon(chrome_exe_, icon_index);
150    }
151
152    if (properties.has_app_id()) {
153      expected_properties.set_app_id(properties.app_id);
154    } else {
155      // Tests are always seen as user-level installs in ShellUtil.
156      expected_properties.set_app_id(ShellUtil::GetBrowserModelId(dist, true));
157    }
158
159    if (properties.has_dual_mode())
160      expected_properties.set_dual_mode(properties.dual_mode);
161    else
162      expected_properties.set_dual_mode(false);
163
164    base::win::ValidateShortcut(expected_path, expected_properties);
165  }
166
167  BrowserDistribution* dist_;
168  scoped_ptr<installer::Product> product_;
169
170  // A ShellUtil::ShortcutProperties object with common properties set already.
171  ShellUtil::ShortcutProperties test_properties_;
172
173  base::ScopedTempDir temp_dir_;
174  base::ScopedTempDir fake_user_desktop_;
175  base::ScopedTempDir fake_common_desktop_;
176  base::ScopedTempDir fake_user_quick_launch_;
177  base::ScopedTempDir fake_default_user_quick_launch_;
178  base::ScopedTempDir fake_start_menu_;
179  base::ScopedTempDir fake_common_start_menu_;
180  scoped_ptr<base::ScopedPathOverride> user_desktop_override_;
181  scoped_ptr<base::ScopedPathOverride> common_desktop_override_;
182  scoped_ptr<base::ScopedPathOverride> user_quick_launch_override_;
183  scoped_ptr<base::ScopedPathOverride> default_user_quick_launch_override_;
184  scoped_ptr<base::ScopedPathOverride> start_menu_override_;
185  scoped_ptr<base::ScopedPathOverride> common_start_menu_override_;
186
187  base::FilePath chrome_exe_;
188  base::FilePath manganese_exe_;
189};
190
191}  // namespace
192
193TEST_F(ShellUtilShortcutTest, GetShortcutPath) {
194  base::FilePath path;
195  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
196                             ShellUtil::CURRENT_USER, &path);
197  EXPECT_EQ(fake_user_desktop_.path(), path);
198  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
199                             ShellUtil::SYSTEM_LEVEL, &path);
200  EXPECT_EQ(fake_common_desktop_.path(), path);
201  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
202                             ShellUtil::CURRENT_USER, &path);
203  EXPECT_EQ(fake_user_quick_launch_.path(), path);
204  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
205                             ShellUtil::SYSTEM_LEVEL, &path);
206  EXPECT_EQ(fake_default_user_quick_launch_.path(), path);
207  string16 start_menu_subfolder =
208      dist_->GetStartMenuShortcutSubfolder(
209          BrowserDistribution::SUBFOLDER_CHROME);
210  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
211                             ShellUtil::CURRENT_USER, &path);
212  EXPECT_EQ(fake_start_menu_.path().Append(start_menu_subfolder),
213            path);
214  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
215                             ShellUtil::SYSTEM_LEVEL, &path);
216  EXPECT_EQ(fake_common_start_menu_.path().Append(start_menu_subfolder),
217            path);
218}
219
220TEST_F(ShellUtilShortcutTest, CreateChromeExeShortcutWithDefaultProperties) {
221  ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
222  product_->AddDefaultShortcutProperties(chrome_exe_, &properties);
223  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
224                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, properties,
225                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
226  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
227                         properties);
228}
229
230TEST_F(ShellUtilShortcutTest, CreateStartMenuShortcutWithAllProperties) {
231  test_properties_.set_shortcut_name(L"Bobo le shortcut");
232  test_properties_.level = ShellUtil::SYSTEM_LEVEL;
233  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
234                  ShellUtil::SHORTCUT_LOCATION_START_MENU,
235                  dist_, test_properties_,
236                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
237  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
238                         test_properties_);
239}
240
241TEST_F(ShellUtilShortcutTest, ReplaceSystemLevelQuickLaunchShortcut) {
242  test_properties_.level = ShellUtil::SYSTEM_LEVEL;
243  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
244                  ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
245                  dist_, test_properties_,
246                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
247
248  ShellUtil::ShortcutProperties new_properties(ShellUtil::SYSTEM_LEVEL);
249  product_->AddDefaultShortcutProperties(chrome_exe_, &new_properties);
250  new_properties.set_description(L"New description");
251  new_properties.set_arguments(L"--new-arguments");
252  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
253                  ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
254                  dist_, new_properties,
255                  ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING));
256
257  // Expect the properties set in |new_properties| to be set as above and
258  // properties that don't have a default value to be set back to their default
259  // (as validated in ValidateChromeShortcut()) or unset if they don't .
260  ShellUtil::ShortcutProperties expected_properties(new_properties);
261  expected_properties.set_dual_mode(false);
262
263  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
264                         expected_properties);
265}
266
267TEST_F(ShellUtilShortcutTest, UpdateQuickLaunchShortcutArguments) {
268  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
269                  ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
270                  dist_, test_properties_,
271                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
272
273  // Only changing one property, don't need all the defaults.
274  ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
275  updated_properties.set_arguments(L"--updated --arguments");
276  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
277                  ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
278                  dist_, updated_properties,
279                  ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
280
281  // Expect the properties set in |updated_properties| to be set as above and
282  // all other properties to remain unchanged.
283  ShellUtil::ShortcutProperties expected_properties(test_properties_);
284  expected_properties.set_arguments(updated_properties.arguments);
285
286  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
287                         expected_properties);
288}
289
290TEST_F(ShellUtilShortcutTest, UpdateAddDualModeToStartMenuShortcut) {
291  ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
292  product_->AddDefaultShortcutProperties(chrome_exe_, &properties);
293  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
294                  ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_, properties,
295                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
296
297  ShellUtil::ShortcutProperties added_properties(ShellUtil::CURRENT_USER);
298  added_properties.set_dual_mode(true);
299  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
300                  ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
301                  added_properties, ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
302
303  ShellUtil::ShortcutProperties expected_properties(properties);
304  expected_properties.set_dual_mode(true);
305
306  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
307                         expected_properties);
308}
309
310TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevel) {
311  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
312                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
313                  ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
314  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
315                         test_properties_);
316}
317
318TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelWithSystemLevelPresent) {
319  string16 shortcut_name(
320      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
321      installer::kLnkExt);
322
323  test_properties_.level = ShellUtil::SYSTEM_LEVEL;
324  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
325                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
326                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
327  ASSERT_TRUE(base::PathExists(
328      fake_common_desktop_.path().Append(shortcut_name)));
329
330  test_properties_.level = ShellUtil::CURRENT_USER;
331  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
332                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
333                  ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
334  ASSERT_FALSE(base::PathExists(
335      fake_user_desktop_.path().Append(shortcut_name)));
336}
337
338TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelStartMenu) {
339  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
340                  ShellUtil::SHORTCUT_LOCATION_START_MENU,
341                  dist_, test_properties_,
342                  ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
343  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
344                         test_properties_);
345}
346
347TEST_F(ShellUtilShortcutTest, CreateAlwaysUserWithSystemLevelPresent) {
348  string16 shortcut_name(
349      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
350      installer::kLnkExt);
351
352  test_properties_.level = ShellUtil::SYSTEM_LEVEL;
353  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
354                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
355                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
356  ASSERT_TRUE(base::PathExists(
357      fake_common_desktop_.path().Append(shortcut_name)));
358
359  test_properties_.level = ShellUtil::CURRENT_USER;
360  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
361                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
362                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
363  ASSERT_TRUE(base::PathExists(
364      fake_user_desktop_.path().Append(shortcut_name)));
365}
366
367TEST_F(ShellUtilShortcutTest, RemoveChromeShortcut) {
368  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
369                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
370                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
371
372  string16 shortcut_name(
373      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
374      installer::kLnkExt);
375  base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
376  ASSERT_TRUE(base::PathExists(shortcut_path));
377
378  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
379      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
380      chrome_exe_));
381  ASSERT_FALSE(base::PathExists(shortcut_path));
382  ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
383}
384
385TEST_F(ShellUtilShortcutTest, RemoveSystemLevelChromeShortcut) {
386  test_properties_.level = ShellUtil::SYSTEM_LEVEL;
387  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
388                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
389                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
390
391  string16 shortcut_name(
392      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
393      installer::kLnkExt);
394  base::FilePath shortcut_path(
395      fake_common_desktop_.path().Append(shortcut_name));
396  ASSERT_TRUE(base::PathExists(shortcut_path));
397
398  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
399      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL,
400      chrome_exe_));
401  ASSERT_FALSE(base::PathExists(shortcut_path));
402  ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
403}
404
405TEST_F(ShellUtilShortcutTest, RemoveMultipleChromeShortcuts) {
406  const wchar_t kShortcutName1[] = L"Chrome 1";
407  const wchar_t kShortcutName2[] = L"Chrome 2";
408
409  test_properties_.set_shortcut_name(kShortcutName1);
410  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
411                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
412                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
413  string16 shortcut1_name(
414      string16(kShortcutName1).append(installer::kLnkExt));
415  base::FilePath shortcut1_path(
416      fake_user_desktop_.path().Append(shortcut1_name));
417  ASSERT_TRUE(base::PathExists(shortcut1_path));
418
419  test_properties_.set_shortcut_name(kShortcutName2);
420  test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
421  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
422                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
423                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
424  string16 shortcut2_name(string16(kShortcutName2).append(installer::kLnkExt));
425  base::FilePath shortcut2_path(
426      fake_user_desktop_.path().Append(shortcut2_name));
427  ASSERT_TRUE(base::PathExists(shortcut2_path));
428
429  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
430      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
431      chrome_exe_));
432  ASSERT_FALSE(base::PathExists(shortcut1_path));
433  ASSERT_FALSE(base::PathExists(shortcut2_path));
434  ASSERT_TRUE(base::PathExists(shortcut1_path.DirName()));
435}
436
437TEST_F(ShellUtilShortcutTest, UpdateChromeShortcutsWithArgs) {
438  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
439                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
440                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
441
442  string16 shortcut_name(
443      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
444      installer::kLnkExt);
445  base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
446  ASSERT_TRUE(base::PathExists(shortcut_path));
447
448  base::FilePath new_exe = temp_dir_.path().Append(kManganeseExe);
449  ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
450  updated_properties.set_target(new_exe);
451  // |updated_properties| has arguments.
452  ASSERT_TRUE(ShellUtil::UpdateShortcutsWithArgs(
453      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
454      chrome_exe_, updated_properties));
455
456  ShellUtil::ShortcutProperties expected_properties(test_properties_);
457  expected_properties.set_target(new_exe);
458  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
459                         expected_properties);
460}
461
462TEST_F(ShellUtilShortcutTest, UpdateSystemLevelChromeShortcutsWithArgs) {
463  test_properties_.level = ShellUtil::SYSTEM_LEVEL;
464  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
465                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
466                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
467
468  string16 shortcut_name(
469      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
470      installer::kLnkExt);
471  base::FilePath shortcut_path(
472      fake_common_desktop_.path().Append(shortcut_name));
473  ASSERT_TRUE(base::PathExists(shortcut_path));
474
475  base::FilePath new_exe = temp_dir_.path().Append(kManganeseExe);
476  ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
477  updated_properties.set_target(new_exe);
478  // |updated_properties| has arguments.
479  ASSERT_TRUE(ShellUtil::UpdateShortcutsWithArgs(
480      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL,
481      chrome_exe_, updated_properties));
482
483  ShellUtil::ShortcutProperties expected_properties(test_properties_);
484  expected_properties.set_target(new_exe);
485  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
486                         expected_properties);
487}
488
489TEST_F(ShellUtilShortcutTest, UpdateMultipleChromeShortcutsWithArgs) {
490  const wchar_t kShortcutName1[] = L"Chrome 1";
491  const wchar_t kShortcutName2[] = L"Chrome 2";
492
493  // Setup shortcut 1, which has empty arguments.
494  test_properties_.set_shortcut_name(kShortcutName1);
495  test_properties_.set_arguments(L"");
496  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
497                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
498                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
499  string16 shortcut1_name(string16(kShortcutName1).append(installer::kLnkExt));
500  base::FilePath shortcut1_path(
501      fake_user_desktop_.path().Append(shortcut1_name));
502  ShellUtil::ShortcutProperties expected_properties1(test_properties_);
503
504  // Setup shortcut 2, which has non-empty arguments.
505  string16 shortcut2_args = L"--profile-directory=\"Profile 2\"";
506  test_properties_.set_shortcut_name(kShortcutName2);
507  test_properties_.set_arguments(shortcut2_args);
508  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
509                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
510                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
511  string16 shortcut2_name(string16(kShortcutName2).append(installer::kLnkExt));
512  base::FilePath shortcut2_path(
513      fake_user_desktop_.path().Append(shortcut2_name));
514  ASSERT_TRUE(base::PathExists(shortcut2_path));
515  ShellUtil::ShortcutProperties expected_properties2(test_properties_);
516
517  // Update shortcuts: target "manganese.exe" instead of "chrome.exe".
518  base::FilePath new_exe = temp_dir_.path().Append(kManganeseExe);
519  ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
520  updated_properties.set_target(new_exe);
521
522  // Only changing shrotcuts that have non-empty arguments, i.e., shortcut 2.
523  ASSERT_TRUE(ShellUtil::UpdateShortcutsWithArgs(
524      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
525      chrome_exe_, updated_properties));
526  // Verify shortcut 1.
527  // |expected_properties1| was unchanged and still targets "chrome.exe", since
528  // it has empty target, yet we passed |require_args| = true.
529  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
530                         expected_properties1);
531  // Verify shortcut 2.
532  expected_properties2.set_target(new_exe);
533  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
534                         expected_properties2);
535}
536
537TEST_F(ShellUtilShortcutTest, CreateMultipleStartMenuShortcutsAndRemoveFolder) {
538  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
539                  ShellUtil::SHORTCUT_LOCATION_START_MENU,
540                  dist_, test_properties_,
541                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
542  test_properties_.set_shortcut_name(L"A second shortcut");
543  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
544                  ShellUtil::SHORTCUT_LOCATION_START_MENU,
545                  dist_, test_properties_,
546                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
547
548  base::FilePath shortcut_folder(
549      fake_start_menu_.path().Append(
550          dist_->GetStartMenuShortcutSubfolder(
551              BrowserDistribution::SUBFOLDER_CHROME)));
552  base::FileEnumerator file_counter(shortcut_folder, false,
553                                    base::FileEnumerator::FILES);
554  int count = 0;
555  while (!file_counter.Next().empty())
556    ++count;
557  EXPECT_EQ(2, count);
558
559  ASSERT_TRUE(base::PathExists(shortcut_folder));
560  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
561      ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_, ShellUtil::CURRENT_USER,
562      chrome_exe_));
563  ASSERT_FALSE(base::PathExists(shortcut_folder));
564}
565
566TEST_F(ShellUtilShortcutTest, DontRemoveChromeShortcutIfPointsToAnotherChrome) {
567  base::ScopedTempDir other_exe_dir;
568  ASSERT_TRUE(other_exe_dir.CreateUniqueTempDir());
569  base::FilePath other_chrome_exe =
570      other_exe_dir.path().Append(installer::kChromeExe);
571  EXPECT_EQ(0, file_util::WriteFile(other_chrome_exe, "", 0));
572
573  test_properties_.set_target(other_chrome_exe);
574  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
575                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
576                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
577
578  string16 shortcut_name(
579      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
580      installer::kLnkExt);
581  base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
582  ASSERT_TRUE(base::PathExists(shortcut_path));
583
584  // The shortcut shouldn't be removed as it was installed pointing to
585  // |other_chrome_exe| and RemoveChromeShortcut() is being told that the
586  // removed shortcut should point to |chrome_exe_|.
587  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
588      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
589      chrome_exe_));
590  ASSERT_TRUE(base::PathExists(shortcut_path));
591  ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
592}
593
594TEST(ShellUtilTest, BuildAppModelIdBasic) {
595  std::vector<string16> components;
596  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
597  const string16 base_app_id(dist->GetBaseAppId());
598  components.push_back(base_app_id);
599  ASSERT_EQ(base_app_id, ShellUtil::BuildAppModelId(components));
600}
601
602TEST(ShellUtilTest, BuildAppModelIdManySmall) {
603  std::vector<string16> components;
604  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
605  const string16 suffixed_app_id(dist->GetBaseAppId().append(L".gab"));
606  components.push_back(suffixed_app_id);
607  components.push_back(L"Default");
608  components.push_back(L"Test");
609  ASSERT_EQ(suffixed_app_id + L".Default.Test",
610            ShellUtil::BuildAppModelId(components));
611}
612
613TEST(ShellUtilTest, BuildAppModelIdLongUsernameNormalProfile) {
614  std::vector<string16> components;
615  const string16 long_appname(
616      L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_"
617      L"that_goes_over_64_characters");
618  components.push_back(long_appname);
619  components.push_back(L"Default");
620  ASSERT_EQ(L"Chrome.a_user_wer_64_characters.Default",
621            ShellUtil::BuildAppModelId(components));
622}
623
624TEST(ShellUtilTest, BuildAppModelIdLongEverything) {
625  std::vector<string16> components;
626  const string16 long_appname(
627      L"Chrome.a_user_who_has_a_crazy_long_name_with_some_weird@symbols_in_it_"
628      L"that_goes_over_64_characters");
629  components.push_back(long_appname);
630  components.push_back(
631      L"A_crazy_profile_name_not_even_sure_whether_that_is_possible");
632  const string16 constructed_app_id(ShellUtil::BuildAppModelId(components));
633  ASSERT_LE(constructed_app_id.length(), installer::kMaxAppModelIdLength);
634  ASSERT_EQ(L"Chrome.a_user_wer_64_characters.A_crazy_profilethat_is_possible",
635            constructed_app_id);
636}
637
638TEST(ShellUtilTest, GetUserSpecificRegistrySuffix) {
639  string16 suffix;
640  ASSERT_TRUE(ShellUtil::GetUserSpecificRegistrySuffix(&suffix));
641  ASSERT_TRUE(StartsWith(suffix, L".", true));
642  ASSERT_EQ(27, suffix.length());
643  ASSERT_TRUE(ContainsOnlyChars(suffix.substr(1),
644                                L"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"));
645}
646
647TEST(ShellUtilTest, GetOldUserSpecificRegistrySuffix) {
648  string16 suffix;
649  ASSERT_TRUE(ShellUtil::GetOldUserSpecificRegistrySuffix(&suffix));
650  ASSERT_TRUE(StartsWith(suffix, L".", true));
651
652  wchar_t user_name[256];
653  DWORD size = arraysize(user_name);
654  ASSERT_NE(0, ::GetUserName(user_name, &size));
655  ASSERT_GE(size, 1U);
656  ASSERT_STREQ(user_name, suffix.substr(1).c_str());
657}
658
659TEST(ShellUtilTest, ByteArrayToBase32) {
660  // Tests from http://tools.ietf.org/html/rfc4648#section-10.
661  const unsigned char test_array[] = { 'f', 'o', 'o', 'b', 'a', 'r' };
662
663  const string16 expected[] = { L"", L"MY", L"MZXQ", L"MZXW6", L"MZXW6YQ",
664                                L"MZXW6YTB", L"MZXW6YTBOI"};
665
666  // Run the tests, with one more letter in the input every pass.
667  for (int i = 0; i < arraysize(expected); ++i) {
668    ASSERT_EQ(expected[i],
669              ShellUtil::ByteArrayToBase32(test_array, i));
670  }
671}
672