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 <objbase.h>  // For CoInitialize().
6
7#include "base/base_paths.h"
8#include "base/files/file_util.h"
9#include "base/location.h"
10#include "base/message_loop/message_loop.h"
11#include "base/path_service.h"
12#include "base/strings/string16.h"
13#include "base/test/scoped_path_override.h"
14#include "base/test/test_shortcut_win.h"
15#include "base/win/shortcut.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/profiles/profile_manager.h"
18#include "chrome/browser/profiles/profile_shortcut_manager.h"
19#include "chrome/browser/profiles/profile_shortcut_manager_win.h"
20#include "chrome/browser/shell_integration.h"
21#include "chrome/grit/chromium_strings.h"
22#include "chrome/installer/util/browser_distribution.h"
23#include "chrome/installer/util/product.h"
24#include "chrome/installer/util/shell_util.h"
25#include "chrome/test/base/testing_browser_process.h"
26#include "chrome/test/base/testing_profile.h"
27#include "chrome/test/base/testing_profile_manager.h"
28#include "content/public/test/test_browser_thread.h"
29#include "testing/gtest/include/gtest/gtest.h"
30#include "ui/base/l10n/l10n_util.h"
31
32using content::BrowserThread;
33
34class ProfileShortcutManagerTest : public testing::Test {
35 protected:
36  ProfileShortcutManagerTest()
37      : ui_thread_(BrowserThread::UI, &message_loop_),
38        file_thread_(BrowserThread::FILE, &message_loop_),
39        profile_info_cache_(NULL),
40        fake_user_desktop_(base::DIR_USER_DESKTOP),
41        fake_system_desktop_(base::DIR_COMMON_DESKTOP) {
42  }
43
44  virtual void SetUp() OVERRIDE {
45    CoInitialize(NULL);
46
47    TestingBrowserProcess* browser_process =
48        TestingBrowserProcess::GetGlobal();
49    profile_manager_.reset(new TestingProfileManager(browser_process));
50    ASSERT_TRUE(profile_manager_->SetUp());
51    profile_info_cache_ = profile_manager_->profile_info_cache();
52    profile_shortcut_manager_.reset(
53        ProfileShortcutManager::Create(profile_manager_->profile_manager()));
54    profile_1_name_ = L"My profile";
55    profile_1_path_ = CreateProfileDirectory(profile_1_name_);
56    profile_2_name_ = L"My profile 2";
57    profile_2_path_ = CreateProfileDirectory(profile_2_name_);
58    profile_3_name_ = L"My profile 3";
59    profile_3_path_ = CreateProfileDirectory(profile_3_name_);
60  }
61
62  virtual void TearDown() OVERRIDE {
63    message_loop_.RunUntilIdle();
64
65    // Delete all profiles and ensure their shortcuts got removed.
66    const int num_profiles = profile_info_cache_->GetNumberOfProfiles();
67    for (int i = 0; i < num_profiles; ++i) {
68      const base::FilePath profile_path =
69          profile_info_cache_->GetPathOfProfileAtIndex(0);
70      base::string16 profile_name =
71          profile_info_cache_->GetNameOfProfileAtIndex(0);
72      profile_info_cache_->DeleteProfileFromCache(profile_path);
73      RunPendingTasks();
74      ASSERT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_name));
75      // The icon file is not deleted until the profile directory is deleted.
76      const base::FilePath icon_path =
77          profiles::internal::GetProfileIconPath(profile_path);
78      ASSERT_TRUE(base::PathExists(icon_path));
79    }
80  }
81
82  base::FilePath CreateProfileDirectory(const base::string16& profile_name) {
83    const base::FilePath profile_path =
84        profile_info_cache_->GetUserDataDir().Append(profile_name);
85    base::CreateDirectory(profile_path);
86    return profile_path;
87  }
88
89  void RunPendingTasks() {
90    base::MessageLoop::current()->PostTask(FROM_HERE,
91                                           base::MessageLoop::QuitClosure());
92    base::MessageLoop::current()->Run();
93  }
94
95  void SetupDefaultProfileShortcut(const tracked_objects::Location& location) {
96    ASSERT_EQ(0, profile_info_cache_->GetNumberOfProfiles())
97        << location.ToString();
98    ASSERT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_1_name_))
99        << location.ToString();
100    profile_info_cache_->AddProfileToCache(profile_1_path_, profile_1_name_,
101                                           base::string16(), 0, std::string());
102    // Also create a non-badged shortcut for Chrome, which is conveniently done
103    // by |CreateProfileShortcut()| since there is only one profile.
104    profile_shortcut_manager_->CreateProfileShortcut(profile_1_path_);
105    RunPendingTasks();
106    // Verify that there's now a shortcut with no profile information.
107    ValidateNonProfileShortcut(location);
108  }
109
110  void SetupAndCreateTwoShortcuts(const tracked_objects::Location& location) {
111    SetupDefaultProfileShortcut(location);
112    CreateProfileWithShortcut(location, profile_2_name_, profile_2_path_);
113    ValidateProfileShortcut(location, profile_1_name_, profile_1_path_);
114  }
115
116  // Returns the default shortcut path for this profile.
117  base::FilePath GetDefaultShortcutPathForProfile(
118      const base::string16& profile_name) {
119    return GetUserShortcutsDirectory().Append(
120        profiles::internal::GetShortcutFilenameForProfile(profile_name,
121                                                          GetDistribution()));
122  }
123
124  // Returns true if the shortcut for this profile exists.
125  bool ProfileShortcutExistsAtDefaultPath(const base::string16& profile_name) {
126    return base::PathExists(
127        GetDefaultShortcutPathForProfile(profile_name));
128  }
129
130  // Calls base::win::ValidateShortcut() with expected properties for the
131  // shortcut at |shortcut_path| for the profile at |profile_path|.
132  void ValidateProfileShortcutAtPath(const tracked_objects::Location& location,
133                                     const base::FilePath& shortcut_path,
134                                     const base::FilePath& profile_path) {
135    EXPECT_TRUE(base::PathExists(shortcut_path)) << location.ToString();
136
137    // Ensure that the corresponding icon exists.
138    const base::FilePath icon_path =
139        profiles::internal::GetProfileIconPath(profile_path);
140    EXPECT_TRUE(base::PathExists(icon_path)) << location.ToString();
141
142    base::win::ShortcutProperties expected_properties;
143    expected_properties.set_app_id(
144        ShellIntegration::GetChromiumModelIdForProfile(profile_path));
145    expected_properties.set_target(GetExePath());
146    expected_properties.set_description(GetDistribution()->GetAppDescription());
147    expected_properties.set_dual_mode(false);
148    expected_properties.set_arguments(
149        profiles::internal::CreateProfileShortcutFlags(profile_path));
150    expected_properties.set_icon(icon_path, 0);
151    base::win::ValidateShortcut(shortcut_path, expected_properties);
152  }
153
154  // Calls base::win::ValidateShortcut() with expected properties for
155  // |profile_name|'s shortcut.
156  void ValidateProfileShortcut(const tracked_objects::Location& location,
157                               const base::string16& profile_name,
158                               const base::FilePath& profile_path) {
159    ValidateProfileShortcutAtPath(
160        location, GetDefaultShortcutPathForProfile(profile_name), profile_path);
161  }
162
163  void ValidateNonProfileShortcutAtPath(
164      const tracked_objects::Location& location,
165      const base::FilePath& shortcut_path) {
166    EXPECT_TRUE(base::PathExists(shortcut_path)) << location.ToString();
167
168    base::win::ShortcutProperties expected_properties;
169    expected_properties.set_target(GetExePath());
170    expected_properties.set_arguments(base::string16());
171    expected_properties.set_icon(GetExePath(), 0);
172    expected_properties.set_description(GetDistribution()->GetAppDescription());
173    expected_properties.set_dual_mode(false);
174    base::win::ValidateShortcut(shortcut_path, expected_properties);
175  }
176
177  void ValidateNonProfileShortcut(const tracked_objects::Location& location) {
178    const base::FilePath shortcut_path =
179        GetDefaultShortcutPathForProfile(base::string16());
180    ValidateNonProfileShortcutAtPath(location, shortcut_path);
181  }
182
183  void CreateProfileWithShortcut(const tracked_objects::Location& location,
184                                 const base::string16& profile_name,
185                                 const base::FilePath& profile_path) {
186    ASSERT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_name))
187        << location.ToString();
188    profile_info_cache_->AddProfileToCache(profile_path, profile_name,
189                                           base::string16(), 0, std::string());
190    profile_shortcut_manager_->CreateProfileShortcut(profile_path);
191    RunPendingTasks();
192    ValidateProfileShortcut(location, profile_name, profile_path);
193  }
194
195  // Creates a regular (non-profile) desktop shortcut with the given name and
196  // returns its path. Fails the test if an error occurs.
197  base::FilePath CreateRegularShortcutWithName(
198      const tracked_objects::Location& location,
199      const base::string16& shortcut_name) {
200    const base::FilePath shortcut_path =
201        GetUserShortcutsDirectory().Append(shortcut_name + installer::kLnkExt);
202    EXPECT_FALSE(base::PathExists(shortcut_path)) << location.ToString();
203
204    installer::Product product(GetDistribution());
205    ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
206    product.AddDefaultShortcutProperties(GetExePath(), &properties);
207    properties.set_shortcut_name(shortcut_name);
208    EXPECT_TRUE(ShellUtil::CreateOrUpdateShortcut(
209        ShellUtil::SHORTCUT_LOCATION_DESKTOP, GetDistribution(), properties,
210        ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)) << location.ToString();
211    EXPECT_TRUE(base::PathExists(shortcut_path)) << location.ToString();
212
213    return shortcut_path;
214  }
215
216  base::FilePath CreateRegularSystemLevelShortcut(
217      const tracked_objects::Location& location) {
218    BrowserDistribution* distribution = GetDistribution();
219    installer::Product product(distribution);
220    ShellUtil::ShortcutProperties properties(ShellUtil::SYSTEM_LEVEL);
221    product.AddDefaultShortcutProperties(GetExePath(), &properties);
222    EXPECT_TRUE(ShellUtil::CreateOrUpdateShortcut(
223        ShellUtil::SHORTCUT_LOCATION_DESKTOP, distribution, properties,
224        ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)) << location.ToString();
225    const base::FilePath system_level_shortcut_path =
226        GetSystemShortcutsDirectory().Append(
227            distribution->
228                GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
229                installer::kLnkExt);
230    EXPECT_TRUE(base::PathExists(system_level_shortcut_path))
231        << location.ToString();
232    return system_level_shortcut_path;
233  }
234
235  void RenameProfile(const tracked_objects::Location& location,
236                     const base::FilePath& profile_path,
237                     const base::string16& new_profile_name) {
238    const size_t profile_index =
239        profile_info_cache_->GetIndexOfProfileWithPath(profile_2_path_);
240    ASSERT_NE(std::string::npos, profile_index);
241    ASSERT_NE(profile_info_cache_->GetNameOfProfileAtIndex(profile_index),
242              new_profile_name);
243    profile_info_cache_->SetNameOfProfileAtIndex(profile_index,
244                                                 new_profile_name);
245    RunPendingTasks();
246  }
247
248  BrowserDistribution* GetDistribution() {
249    return BrowserDistribution::GetDistribution();
250  }
251
252  base::FilePath GetExePath() {
253    base::FilePath exe_path;
254    EXPECT_TRUE(PathService::Get(base::FILE_EXE, &exe_path));
255    return exe_path;
256  }
257
258  base::FilePath GetUserShortcutsDirectory() {
259    base::FilePath user_shortcuts_directory;
260    EXPECT_TRUE(ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
261                                           GetDistribution(),
262                                           ShellUtil::CURRENT_USER,
263                                           &user_shortcuts_directory));
264    return user_shortcuts_directory;
265  }
266
267  base::FilePath GetSystemShortcutsDirectory() {
268    base::FilePath system_shortcuts_directory;
269    EXPECT_TRUE(ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
270                                           GetDistribution(),
271                                           ShellUtil::SYSTEM_LEVEL,
272                                           &system_shortcuts_directory));
273    return system_shortcuts_directory;
274  }
275
276  base::MessageLoopForUI message_loop_;
277  content::TestBrowserThread ui_thread_;
278  content::TestBrowserThread file_thread_;
279  scoped_ptr<TestingProfileManager> profile_manager_;
280  scoped_ptr<ProfileShortcutManager> profile_shortcut_manager_;
281  ProfileInfoCache* profile_info_cache_;
282  base::ScopedPathOverride fake_user_desktop_;
283  base::ScopedPathOverride fake_system_desktop_;
284  base::string16 profile_1_name_;
285  base::FilePath profile_1_path_;
286  base::string16 profile_2_name_;
287  base::FilePath profile_2_path_;
288  base::string16 profile_3_name_;
289  base::FilePath profile_3_path_;
290};
291
292TEST_F(ProfileShortcutManagerTest, ShortcutFilename) {
293  const base::string16 kProfileName = L"Harry";
294  BrowserDistribution* distribution = GetDistribution();
295  const base::string16 expected_name = kProfileName + L" - " +
296      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME) + installer::kLnkExt;
297  EXPECT_EQ(expected_name,
298            profiles::internal::GetShortcutFilenameForProfile(kProfileName,
299                                                              distribution));
300}
301
302TEST_F(ProfileShortcutManagerTest, ShortcutLongFilenameIsTrimmed) {
303  const base::string16 kLongProfileName =
304      L"Harry Harry Harry Harry Harry Harry Harry"
305      L"Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry"
306      L"Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry";
307  const base::string16 file_name =
308      profiles::internal::GetShortcutFilenameForProfile(kLongProfileName,
309                                                        GetDistribution());
310  EXPECT_LT(file_name.size(), kLongProfileName.size());
311}
312
313TEST_F(ProfileShortcutManagerTest, ShortcutFilenameStripsReservedCharacters) {
314  const base::string16 kProfileName = L"<Harry/>";
315  const base::string16 kSanitizedProfileName = L"Harry";
316  BrowserDistribution* distribution = GetDistribution();
317  const base::string16 expected_name = kSanitizedProfileName + L" - " +
318      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME) + installer::kLnkExt;
319  EXPECT_EQ(expected_name,
320            profiles::internal::GetShortcutFilenameForProfile(kProfileName,
321                                                              distribution));
322}
323
324TEST_F(ProfileShortcutManagerTest, UnbadgedShortcutFilename) {
325  BrowserDistribution* distribution = GetDistribution();
326  EXPECT_EQ(
327      distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
328          installer::kLnkExt,
329      profiles::internal::GetShortcutFilenameForProfile(base::string16(),
330                                                        distribution));
331}
332
333TEST_F(ProfileShortcutManagerTest, ShortcutFlags) {
334  const base::string16 kProfileName = L"MyProfileX";
335  const base::FilePath profile_path =
336      profile_info_cache_->GetUserDataDir().Append(kProfileName);
337  EXPECT_EQ(L"--profile-directory=\"" + kProfileName + L"\"",
338            profiles::internal::CreateProfileShortcutFlags(profile_path));
339}
340
341TEST_F(ProfileShortcutManagerTest, DesktopShortcutsCreate) {
342  SetupDefaultProfileShortcut(FROM_HERE);
343  // Validation is done by |ValidateProfileShortcutAtPath()| which is called
344  // by |CreateProfileWithShortcut()|.
345  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
346}
347
348TEST_F(ProfileShortcutManagerTest, DesktopShortcutsUpdate) {
349  SetupDefaultProfileShortcut(FROM_HERE);
350  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
351
352  // Cause an update in ProfileShortcutManager by modifying the profile info
353  // cache.
354  const base::string16 new_profile_2_name = L"New Profile Name";
355  RenameProfile(FROM_HERE, profile_2_path_, new_profile_2_name);
356  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_));
357  ValidateProfileShortcut(FROM_HERE, new_profile_2_name, profile_2_path_);
358}
359
360TEST_F(ProfileShortcutManagerTest, CreateSecondProfileBadgesFirstShortcut) {
361  SetupDefaultProfileShortcut(FROM_HERE);
362  // Assert that a shortcut without a profile name exists.
363  ASSERT_TRUE(ProfileShortcutExistsAtDefaultPath(base::string16()));
364
365  // Create a second profile without a shortcut.
366  profile_info_cache_->AddProfileToCache(profile_2_path_, profile_2_name_,
367                                         base::string16(), 0, std::string());
368  RunPendingTasks();
369
370  // Ensure that the second profile doesn't have a shortcut and that the first
371  // profile's shortcut got renamed and badged.
372  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_));
373  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(base::string16()));
374  ValidateProfileShortcut(FROM_HERE, profile_1_name_, profile_1_path_);
375}
376
377TEST_F(ProfileShortcutManagerTest, DesktopShortcutsDeleteSecondToLast) {
378  SetupAndCreateTwoShortcuts(FROM_HERE);
379
380  // Delete one shortcut.
381  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
382  RunPendingTasks();
383  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_));
384
385  // Verify that the profile name has been removed from the remaining shortcut.
386  ValidateNonProfileShortcut(FROM_HERE);
387  // Verify that an additional shortcut, with the default profile's name does
388  // not exist.
389  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_1_name_));
390}
391
392TEST_F(ProfileShortcutManagerTest, DeleteSecondToLastProfileWithoutShortcut) {
393  SetupAndCreateTwoShortcuts(FROM_HERE);
394
395  const base::FilePath profile_1_shortcut_path =
396      GetDefaultShortcutPathForProfile(profile_1_name_);
397  const base::FilePath profile_2_shortcut_path =
398      GetDefaultShortcutPathForProfile(profile_2_name_);
399
400  // Delete the shortcut for the first profile, but keep the one for the 2nd.
401  ASSERT_TRUE(base::DeleteFile(profile_1_shortcut_path, false));
402  ASSERT_FALSE(base::PathExists(profile_1_shortcut_path));
403  ASSERT_TRUE(base::PathExists(profile_2_shortcut_path));
404
405  // Delete the profile that doesn't have a shortcut.
406  profile_info_cache_->DeleteProfileFromCache(profile_1_path_);
407  RunPendingTasks();
408
409  // Verify that the remaining shortcut does not have a profile name.
410  ValidateNonProfileShortcut(FROM_HERE);
411  // Verify that shortcuts with profile names do not exist.
412  EXPECT_FALSE(base::PathExists(profile_1_shortcut_path));
413  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path));
414}
415
416TEST_F(ProfileShortcutManagerTest, DeleteSecondToLastProfileWithShortcut) {
417  SetupAndCreateTwoShortcuts(FROM_HERE);
418
419  const base::FilePath profile_1_shortcut_path =
420      GetDefaultShortcutPathForProfile(profile_1_name_);
421  const base::FilePath profile_2_shortcut_path =
422      GetDefaultShortcutPathForProfile(profile_2_name_);
423
424  // Delete the shortcut for the first profile, but keep the one for the 2nd.
425  ASSERT_TRUE(base::DeleteFile(profile_1_shortcut_path, false));
426  ASSERT_FALSE(base::PathExists(profile_1_shortcut_path));
427  ASSERT_TRUE(base::PathExists(profile_2_shortcut_path));
428
429  // Delete the profile that has a shortcut.
430  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
431  RunPendingTasks();
432
433  // Verify that the remaining shortcut does not have a profile name.
434  ValidateNonProfileShortcut(FROM_HERE);
435  // Verify that shortcuts with profile names do not exist.
436  EXPECT_FALSE(base::PathExists(profile_1_shortcut_path));
437  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path));
438}
439
440TEST_F(ProfileShortcutManagerTest, DeleteOnlyProfileWithShortcuts) {
441  SetupAndCreateTwoShortcuts(FROM_HERE);
442  CreateProfileWithShortcut(FROM_HERE, profile_3_name_, profile_3_path_);
443
444  const base::FilePath non_profile_shortcut_path =
445      GetDefaultShortcutPathForProfile(base::string16());
446  const base::FilePath profile_1_shortcut_path =
447      GetDefaultShortcutPathForProfile(profile_1_name_);
448  const base::FilePath profile_2_shortcut_path =
449      GetDefaultShortcutPathForProfile(profile_2_name_);
450  const base::FilePath profile_3_shortcut_path =
451      GetDefaultShortcutPathForProfile(profile_3_name_);
452
453  // Delete shortcuts for the first two profiles.
454  ASSERT_TRUE(base::DeleteFile(profile_1_shortcut_path, false));
455  ASSERT_TRUE(base::DeleteFile(profile_2_shortcut_path, false));
456
457  // Only the shortcut to the third profile should exist.
458  ASSERT_FALSE(base::PathExists(profile_1_shortcut_path));
459  ASSERT_FALSE(base::PathExists(profile_2_shortcut_path));
460  ASSERT_FALSE(base::PathExists(non_profile_shortcut_path));
461  ASSERT_TRUE(base::PathExists(profile_3_shortcut_path));
462
463  // Delete the third profile and check that its shortcut is gone and no
464  // shortcuts have been re-created.
465  profile_info_cache_->DeleteProfileFromCache(profile_3_path_);
466  RunPendingTasks();
467  ASSERT_FALSE(base::PathExists(profile_1_shortcut_path));
468  ASSERT_FALSE(base::PathExists(profile_2_shortcut_path));
469  ASSERT_FALSE(base::PathExists(profile_3_shortcut_path));
470  ASSERT_FALSE(base::PathExists(non_profile_shortcut_path));
471}
472
473TEST_F(ProfileShortcutManagerTest, DesktopShortcutsCreateSecond) {
474  SetupAndCreateTwoShortcuts(FROM_HERE);
475
476  // Delete one shortcut.
477  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
478  RunPendingTasks();
479
480  // Verify that a default shortcut exists (no profile name/avatar).
481  ValidateNonProfileShortcut(FROM_HERE);
482  // Verify that an additional shortcut, with the first profile's name does
483  // not exist.
484  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_1_name_));
485
486  // Create a second profile and shortcut.
487  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
488
489  // Verify that the original shortcut received the profile's name.
490  ValidateProfileShortcut(FROM_HERE, profile_1_name_, profile_1_path_);
491  // Verify that a default shortcut no longer exists.
492  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(base::string16()));
493}
494
495TEST_F(ProfileShortcutManagerTest, RenamedDesktopShortcuts) {
496  SetupAndCreateTwoShortcuts(FROM_HERE);
497
498  const base::FilePath profile_2_shortcut_path_1 =
499      GetDefaultShortcutPathForProfile(profile_2_name_);
500  const base::FilePath profile_2_shortcut_path_2 =
501      GetUserShortcutsDirectory().Append(L"MyChrome.lnk");
502  ASSERT_TRUE(base::Move(profile_2_shortcut_path_1,
503                              profile_2_shortcut_path_2));
504
505  // Ensure that a new shortcut does not get made if the old one was renamed.
506  profile_shortcut_manager_->CreateProfileShortcut(profile_2_path_);
507  RunPendingTasks();
508  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_));
509  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_2,
510                                profile_2_path_);
511
512  // Delete the renamed shortcut and try to create it again, which should work.
513  ASSERT_TRUE(base::DeleteFile(profile_2_shortcut_path_2, false));
514  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path_2));
515  profile_shortcut_manager_->CreateProfileShortcut(profile_2_path_);
516  RunPendingTasks();
517  ValidateProfileShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
518}
519
520TEST_F(ProfileShortcutManagerTest, RenamedDesktopShortcutsGetDeleted) {
521  SetupAndCreateTwoShortcuts(FROM_HERE);
522
523  const base::FilePath profile_2_shortcut_path_1 =
524      GetDefaultShortcutPathForProfile(profile_2_name_);
525  const base::FilePath profile_2_shortcut_path_2 =
526      GetUserShortcutsDirectory().Append(L"MyChrome.lnk");
527  // Make a copy of the shortcut.
528  ASSERT_TRUE(base::CopyFile(profile_2_shortcut_path_1,
529                                  profile_2_shortcut_path_2));
530  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_1,
531                                profile_2_path_);
532  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_2,
533                                profile_2_path_);
534
535  // Also, copy the shortcut for the first user and ensure it gets preserved.
536  const base::FilePath preserved_profile_1_shortcut_path =
537      GetUserShortcutsDirectory().Append(L"Preserved.lnk");
538  ASSERT_TRUE(base::CopyFile(
539      GetDefaultShortcutPathForProfile(profile_1_name_),
540      preserved_profile_1_shortcut_path));
541  EXPECT_TRUE(base::PathExists(preserved_profile_1_shortcut_path));
542
543  // Delete the profile and ensure both shortcuts were also deleted.
544  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
545  RunPendingTasks();
546  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path_1));
547  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path_2));
548  ValidateNonProfileShortcutAtPath(FROM_HERE,
549                                   preserved_profile_1_shortcut_path);
550}
551
552TEST_F(ProfileShortcutManagerTest, RenamedDesktopShortcutsAfterProfileRename) {
553  SetupAndCreateTwoShortcuts(FROM_HERE);
554
555  const base::FilePath profile_2_shortcut_path_1 =
556      GetDefaultShortcutPathForProfile(profile_2_name_);
557  const base::FilePath profile_2_shortcut_path_2 =
558      GetUserShortcutsDirectory().Append(L"MyChrome.lnk");
559  // Make a copy of the shortcut.
560  ASSERT_TRUE(base::CopyFile(profile_2_shortcut_path_1,
561                                  profile_2_shortcut_path_2));
562  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_1,
563                                profile_2_path_);
564  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_2,
565                                profile_2_path_);
566
567  // Now, rename the profile.
568  const base::string16 new_profile_2_name = L"New profile";
569  RenameProfile(FROM_HERE, profile_2_path_, new_profile_2_name);
570
571  // The original shortcut should be renamed but the copied shortcut should
572  // keep its name.
573  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path_1));
574  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_2,
575                                profile_2_path_);
576  ValidateProfileShortcut(FROM_HERE, new_profile_2_name, profile_2_path_);
577}
578
579TEST_F(ProfileShortcutManagerTest, UpdateShortcutWithNoFlags) {
580  SetupDefaultProfileShortcut(FROM_HERE);
581
582  // Delete the shortcut that got created for this profile and instead make
583  // a new one without any command-line flags.
584  ASSERT_TRUE(base::DeleteFile(
585      GetDefaultShortcutPathForProfile(base::string16()), false));
586  const base::FilePath regular_shortcut_path =
587      CreateRegularShortcutWithName(FROM_HERE,
588                                    GetDistribution()->GetShortcutName(
589                                        BrowserDistribution::SHORTCUT_CHROME));
590
591  // Add another profile and check that the shortcut was replaced with
592  // a badged shortcut with the right command line for the profile
593  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
594  EXPECT_FALSE(base::PathExists(regular_shortcut_path));
595  ValidateProfileShortcut(FROM_HERE, profile_1_name_, profile_1_path_);
596}
597
598TEST_F(ProfileShortcutManagerTest, UpdateTwoShortcutsWithNoFlags) {
599  SetupDefaultProfileShortcut(FROM_HERE);
600
601  // Delete the shortcut that got created for this profile and instead make
602  // two new ones without any command-line flags.
603  ASSERT_TRUE(base::DeleteFile(
604      GetDefaultShortcutPathForProfile(base::string16()), false));
605  const base::FilePath regular_shortcut_path =
606      CreateRegularShortcutWithName(FROM_HERE,
607                                    GetDistribution()->GetShortcutName(
608                                        BrowserDistribution::SHORTCUT_CHROME));
609  const base::FilePath customized_regular_shortcut_path =
610      CreateRegularShortcutWithName(FROM_HERE, L"MyChrome");
611
612  // Add another profile and check that one shortcut was renamed and that the
613  // other shortcut was updated but kept the same name.
614  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
615  EXPECT_FALSE(base::PathExists(regular_shortcut_path));
616  ValidateProfileShortcutAtPath(FROM_HERE, customized_regular_shortcut_path,
617                                profile_1_path_);
618  ValidateProfileShortcut(FROM_HERE, profile_1_name_, profile_1_path_);
619}
620
621TEST_F(ProfileShortcutManagerTest, RemoveProfileShortcuts) {
622  SetupAndCreateTwoShortcuts(FROM_HERE);
623  CreateProfileWithShortcut(FROM_HERE, profile_3_name_, profile_3_path_);
624
625  const base::FilePath profile_1_shortcut_path_1 =
626      GetDefaultShortcutPathForProfile(profile_1_name_);
627  const base::FilePath profile_2_shortcut_path_1 =
628      GetDefaultShortcutPathForProfile(profile_2_name_);
629
630  // Make copies of the shortcuts for both profiles.
631  const base::FilePath profile_1_shortcut_path_2 =
632      GetUserShortcutsDirectory().Append(L"Copied1.lnk");
633  const base::FilePath profile_2_shortcut_path_2 =
634      GetUserShortcutsDirectory().Append(L"Copied2.lnk");
635  ASSERT_TRUE(base::CopyFile(profile_1_shortcut_path_1,
636                                  profile_1_shortcut_path_2));
637  ASSERT_TRUE(base::CopyFile(profile_2_shortcut_path_1,
638                                  profile_2_shortcut_path_2));
639  ValidateProfileShortcutAtPath(FROM_HERE, profile_1_shortcut_path_2,
640                                profile_1_path_);
641  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_2,
642                                profile_2_path_);
643
644  // Delete shortcuts for profile 1 and ensure that they got deleted while the
645  // shortcuts for profile 2 were kept.
646  profile_shortcut_manager_->RemoveProfileShortcuts(profile_1_path_);
647  RunPendingTasks();
648  EXPECT_FALSE(base::PathExists(profile_1_shortcut_path_1));
649  EXPECT_FALSE(base::PathExists(profile_1_shortcut_path_2));
650  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_1,
651                                profile_2_path_);
652  ValidateProfileShortcutAtPath(FROM_HERE, profile_2_shortcut_path_2,
653                                profile_2_path_);
654}
655
656TEST_F(ProfileShortcutManagerTest, HasProfileShortcuts) {
657  SetupAndCreateTwoShortcuts(FROM_HERE);
658
659  struct HasShortcutsResult {
660    bool has_shortcuts;
661    void set_has_shortcuts(bool value) { has_shortcuts = value; }
662  } result = { false };
663
664  const base::Callback<void(bool)> callback =
665      base::Bind(&HasShortcutsResult::set_has_shortcuts,
666                 base::Unretained(&result));
667
668  // Profile 2 should have a shortcut initially.
669  profile_shortcut_manager_->HasProfileShortcuts(profile_2_path_, callback);
670  RunPendingTasks();
671  EXPECT_TRUE(result.has_shortcuts);
672
673  // Delete the shortcut and check that the function returns false.
674  const base::FilePath profile_2_shortcut_path =
675      GetDefaultShortcutPathForProfile(profile_2_name_);
676  ASSERT_TRUE(base::DeleteFile(profile_2_shortcut_path, false));
677  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path));
678  profile_shortcut_manager_->HasProfileShortcuts(profile_2_path_, callback);
679  RunPendingTasks();
680  EXPECT_FALSE(result.has_shortcuts);
681}
682
683TEST_F(ProfileShortcutManagerTest, ProfileShortcutsWithSystemLevelShortcut) {
684  const base::FilePath system_level_shortcut_path =
685      CreateRegularSystemLevelShortcut(FROM_HERE);
686
687  // Create the initial profile.
688  profile_info_cache_->AddProfileToCache(profile_1_path_, profile_1_name_,
689                                         base::string16(), 0, std::string());
690  RunPendingTasks();
691  ASSERT_EQ(1U, profile_info_cache_->GetNumberOfProfiles());
692
693  // Ensure system-level continues to exist and user-level was not created.
694  EXPECT_TRUE(base::PathExists(system_level_shortcut_path));
695  EXPECT_FALSE(base::PathExists(
696                   GetDefaultShortcutPathForProfile(base::string16())));
697
698  // Create another profile with a shortcut and ensure both profiles receive
699  // user-level profile shortcuts and the system-level one still exists.
700  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
701  ValidateProfileShortcut(FROM_HERE, profile_1_name_, profile_1_path_);
702  ValidateProfileShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
703  EXPECT_TRUE(base::PathExists(system_level_shortcut_path));
704
705  // Create a third profile without a shortcut and ensure it doesn't get one.
706  profile_info_cache_->AddProfileToCache(profile_3_path_, profile_3_name_,
707                                         base::string16(), 0, std::string());
708  RunPendingTasks();
709  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_3_name_));
710
711  // Ensure that changing the avatar icon and the name does not result in a
712  // shortcut being created.
713  profile_info_cache_->SetAvatarIconOfProfileAtIndex(
714      profile_info_cache_->GetIndexOfProfileWithPath(profile_3_path_), 3);
715  RunPendingTasks();
716  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_3_name_));
717
718  const base::string16 new_profile_3_name = L"New Name 3";
719  profile_info_cache_->SetNameOfProfileAtIndex(
720      profile_info_cache_->GetIndexOfProfileWithPath(profile_3_path_),
721      new_profile_3_name);
722  RunPendingTasks();
723  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_3_name_));
724  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(new_profile_3_name));
725
726  // Rename the second profile and ensure its shortcut got renamed.
727  const base::string16 new_profile_2_name = L"New Name 2";
728  profile_info_cache_->SetNameOfProfileAtIndex(
729      profile_info_cache_->GetIndexOfProfileWithPath(profile_2_path_),
730      new_profile_2_name);
731  RunPendingTasks();
732  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_));
733  ValidateProfileShortcut(FROM_HERE, new_profile_2_name, profile_2_path_);
734}
735
736TEST_F(ProfileShortcutManagerTest,
737       DeleteSecondToLastProfileWithSystemLevelShortcut) {
738  SetupAndCreateTwoShortcuts(FROM_HERE);
739
740  const base::FilePath system_level_shortcut_path =
741      CreateRegularSystemLevelShortcut(FROM_HERE);
742
743  // Delete a profile and verify that only the system-level shortcut still
744  // exists.
745  profile_info_cache_->DeleteProfileFromCache(profile_1_path_);
746  RunPendingTasks();
747
748  EXPECT_TRUE(base::PathExists(system_level_shortcut_path));
749  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(base::string16()));
750  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_1_name_));
751  EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_));
752}
753
754TEST_F(ProfileShortcutManagerTest,
755       DeleteSecondToLastProfileWithShortcutWhenSystemLevelShortcutExists) {
756  SetupAndCreateTwoShortcuts(FROM_HERE);
757
758  const base::FilePath profile_1_shortcut_path =
759      GetDefaultShortcutPathForProfile(profile_1_name_);
760  const base::FilePath profile_2_shortcut_path =
761      GetDefaultShortcutPathForProfile(profile_2_name_);
762
763  // Delete the shortcut for the first profile, but keep the one for the 2nd.
764  ASSERT_TRUE(base::DeleteFile(profile_1_shortcut_path, false));
765  ASSERT_FALSE(base::PathExists(profile_1_shortcut_path));
766  ASSERT_TRUE(base::PathExists(profile_2_shortcut_path));
767
768  const base::FilePath system_level_shortcut_path =
769      CreateRegularSystemLevelShortcut(FROM_HERE);
770
771  // Delete the profile that has a shortcut, which will exercise the non-profile
772  // shortcut creation path in |DeleteDesktopShortcuts()|, which is
773  // not covered by the |DeleteSecondToLastProfileWithSystemLevelShortcut| test.
774  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
775  RunPendingTasks();
776
777  // Verify that only the system-level shortcut still exists.
778  EXPECT_TRUE(base::PathExists(system_level_shortcut_path));
779  EXPECT_FALSE(base::PathExists(
780                   GetDefaultShortcutPathForProfile(base::string16())));
781  EXPECT_FALSE(base::PathExists(profile_1_shortcut_path));
782  EXPECT_FALSE(base::PathExists(profile_2_shortcut_path));
783}
784
785TEST_F(ProfileShortcutManagerTest, CreateProfileIcon) {
786  SetupDefaultProfileShortcut(FROM_HERE);
787
788  const base::FilePath icon_path =
789      profiles::internal::GetProfileIconPath(profile_1_path_);
790
791  EXPECT_TRUE(base::PathExists(icon_path));
792  EXPECT_TRUE(base::DeleteFile(icon_path, false));
793  EXPECT_FALSE(base::PathExists(icon_path));
794
795  profile_shortcut_manager_->CreateOrUpdateProfileIcon(profile_1_path_);
796  RunPendingTasks();
797  EXPECT_TRUE(base::PathExists(icon_path));
798}
799
800TEST_F(ProfileShortcutManagerTest, UnbadgeProfileIconOnDeletion) {
801  SetupDefaultProfileShortcut(FROM_HERE);
802  const base::FilePath icon_path_1 =
803      profiles::internal::GetProfileIconPath(profile_1_path_);
804  const base::FilePath icon_path_2 =
805      profiles::internal::GetProfileIconPath(profile_2_path_);
806
807  // Default profile has unbadged icon to start.
808  std::string unbadged_icon_1;
809  EXPECT_TRUE(base::ReadFileToString(icon_path_1, &unbadged_icon_1));
810
811  // Creating a new profile adds a badge to both the new profile icon and the
812  // default profile icon. Since they use the same icon index, the icon files
813  // should be the same.
814  CreateProfileWithShortcut(FROM_HERE, profile_2_name_, profile_2_path_);
815
816  std::string badged_icon_1;
817  EXPECT_TRUE(base::ReadFileToString(icon_path_1, &badged_icon_1));
818  std::string badged_icon_2;
819  EXPECT_TRUE(base::ReadFileToString(icon_path_2, &badged_icon_2));
820
821  EXPECT_NE(badged_icon_1, unbadged_icon_1);
822  EXPECT_EQ(badged_icon_1, badged_icon_2);
823
824  // Deleting the default profile will unbadge the new profile's icon and should
825  // result in an icon that is identical to the unbadged default profile icon.
826  profile_info_cache_->DeleteProfileFromCache(profile_1_path_);
827  RunPendingTasks();
828
829  std::string unbadged_icon_2;
830  EXPECT_TRUE(base::ReadFileToString(icon_path_2, &unbadged_icon_2));
831  EXPECT_EQ(unbadged_icon_1, unbadged_icon_2);
832}
833
834TEST_F(ProfileShortcutManagerTest, ProfileIconOnAvatarChange) {
835  SetupAndCreateTwoShortcuts(FROM_HERE);
836  const base::FilePath icon_path_1 =
837      profiles::internal::GetProfileIconPath(profile_1_path_);
838  const base::FilePath icon_path_2 =
839      profiles::internal::GetProfileIconPath(profile_2_path_);
840  const size_t profile_index_1 =
841      profile_info_cache_->GetIndexOfProfileWithPath(profile_1_path_);
842
843  std::string badged_icon_1;
844  EXPECT_TRUE(base::ReadFileToString(icon_path_1, &badged_icon_1));
845  std::string badged_icon_2;
846  EXPECT_TRUE(base::ReadFileToString(icon_path_2, &badged_icon_2));
847
848  // Profile 1 and 2 are created with the same icon.
849  EXPECT_EQ(badged_icon_1, badged_icon_2);
850
851  // Change profile 1's icon.
852  profile_info_cache_->SetAvatarIconOfProfileAtIndex(profile_index_1, 1);
853  RunPendingTasks();
854
855  std::string new_badged_icon_1;
856  EXPECT_TRUE(base::ReadFileToString(icon_path_1, &new_badged_icon_1));
857  EXPECT_NE(new_badged_icon_1, badged_icon_1);
858
859  // Ensure the new icon is not the unbadged icon.
860  profile_info_cache_->DeleteProfileFromCache(profile_2_path_);
861  RunPendingTasks();
862
863  std::string unbadged_icon_1;
864  EXPECT_TRUE(base::ReadFileToString(icon_path_1, &unbadged_icon_1));
865  EXPECT_NE(unbadged_icon_1, new_badged_icon_1);
866
867  // Ensure the icon doesn't change on avatar change without 2 profiles.
868  profile_info_cache_->SetAvatarIconOfProfileAtIndex(profile_index_1, 1);
869  RunPendingTasks();
870
871  std::string unbadged_icon_1_a;
872  EXPECT_TRUE(base::ReadFileToString(icon_path_1, &unbadged_icon_1_a));
873  EXPECT_EQ(unbadged_icon_1, unbadged_icon_1_a);
874}
875