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 <objbase.h> // For CoInitialize().
7 #include "base/base_paths.h"
8 #include "base/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/installer/util/browser_distribution.h"
22 #include "chrome/installer/util/product.h"
23 #include "chrome/installer/util/shell_util.h"
24 #include "chrome/test/base/testing_browser_process.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "chrome/test/base/testing_profile_manager.h"
27 #include "content/public/test/test_browser_thread.h"
28 #include "grit/chromium_strings.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "ui/base/l10n/l10n_util.h"
32 using content::BrowserThread
;
34 class ProfileShortcutManagerTest
: public testing::Test
{
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
) {
44 virtual void SetUp() OVERRIDE
{
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_
);
62 virtual void TearDown() OVERRIDE
{
63 message_loop_
.RunUntilIdle();
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
);
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
));
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
);
89 void RunPendingTasks() {
90 base::MessageLoop::current()->PostTask(FROM_HERE
,
91 base::MessageLoop::QuitClosure());
92 base::MessageLoop::current()->Run();
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_
);
106 // Verify that there's now a shortcut with no profile information.
107 ValidateNonProfileShortcut(location
);
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_
);
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
,
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
));
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();
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();
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
);
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
);
163 void ValidateNonProfileShortcutAtPath(
164 const tracked_objects::Location
& location
,
165 const base::FilePath
& shortcut_path
) {
166 EXPECT_TRUE(base::PathExists(shortcut_path
)) << location
.ToString();
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
);
177 void ValidateNonProfileShortcut(const tracked_objects::Location
& location
) {
178 const base::FilePath shortcut_path
=
179 GetDefaultShortcutPathForProfile(base::string16());
180 ValidateNonProfileShortcutAtPath(location
, shortcut_path
);
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
);
192 ValidateProfileShortcut(location
, profile_name
, profile_path
);
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();
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();
213 return shortcut_path
;
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(
228 GetShortcutName(BrowserDistribution::SHORTCUT_CHROME
) +
230 EXPECT_TRUE(base::PathExists(system_level_shortcut_path
))
231 << location
.ToString();
232 return system_level_shortcut_path
;
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
),
243 profile_info_cache_
->SetNameOfProfileAtIndex(profile_index
,
248 BrowserDistribution
* GetDistribution() {
249 return BrowserDistribution::GetDistribution();
252 base::FilePath
GetExePath() {
253 base::FilePath exe_path
;
254 EXPECT_TRUE(PathService::Get(base::FILE_EXE
, &exe_path
));
258 base::FilePath
GetUserShortcutsDirectory() {
259 base::FilePath user_shortcuts_directory
;
260 EXPECT_TRUE(ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP
,
262 ShellUtil::CURRENT_USER
,
263 &user_shortcuts_directory
));
264 return user_shortcuts_directory
;
267 base::FilePath
GetSystemShortcutsDirectory() {
268 base::FilePath system_shortcuts_directory
;
269 EXPECT_TRUE(ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP
,
271 ShellUtil::SYSTEM_LEVEL
,
272 &system_shortcuts_directory
));
273 return system_shortcuts_directory
;
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_
;
292 TEST_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
,
302 TEST_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
,
310 EXPECT_LT(file_name
.size(), kLongProfileName
.size());
313 TEST_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
,
324 TEST_F(ProfileShortcutManagerTest
, UnbadgedShortcutFilename
) {
325 BrowserDistribution
* distribution
= GetDistribution();
327 distribution
->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME
) +
329 profiles::internal::GetShortcutFilenameForProfile(base::string16(),
333 TEST_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
));
341 TEST_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_
);
348 TEST_F(ProfileShortcutManagerTest
, DesktopShortcutsUpdate
) {
349 SetupDefaultProfileShortcut(FROM_HERE
);
350 CreateProfileWithShortcut(FROM_HERE
, profile_2_name_
, profile_2_path_
);
352 // Cause an update in ProfileShortcutManager by modifying the profile info
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_
);
360 TEST_F(ProfileShortcutManagerTest
, CreateSecondProfileBadgesFirstShortcut
) {
361 SetupDefaultProfileShortcut(FROM_HERE
);
362 // Assert that a shortcut without a profile name exists.
363 ASSERT_TRUE(ProfileShortcutExistsAtDefaultPath(base::string16()));
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());
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_
);
377 TEST_F(ProfileShortcutManagerTest
, DesktopShortcutsDeleteSecondToLast
) {
378 SetupAndCreateTwoShortcuts(FROM_HERE
);
380 // Delete one shortcut.
381 profile_info_cache_
->DeleteProfileFromCache(profile_2_path_
);
383 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_
));
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
389 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_1_name_
));
392 TEST_F(ProfileShortcutManagerTest
, DeleteSecondToLastProfileWithoutShortcut
) {
393 SetupAndCreateTwoShortcuts(FROM_HERE
);
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_
);
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
));
405 // Delete the profile that doesn't have a shortcut.
406 profile_info_cache_
->DeleteProfileFromCache(profile_1_path_
);
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
));
416 TEST_F(ProfileShortcutManagerTest
, DeleteSecondToLastProfileWithShortcut
) {
417 SetupAndCreateTwoShortcuts(FROM_HERE
);
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_
);
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
));
429 // Delete the profile that has a shortcut.
430 profile_info_cache_
->DeleteProfileFromCache(profile_2_path_
);
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
));
440 TEST_F(ProfileShortcutManagerTest
, DeleteOnlyProfileWithShortcuts
) {
441 SetupAndCreateTwoShortcuts(FROM_HERE
);
442 CreateProfileWithShortcut(FROM_HERE
, profile_3_name_
, profile_3_path_
);
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_
);
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));
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
));
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_
);
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
));
473 TEST_F(ProfileShortcutManagerTest
, DesktopShortcutsCreateSecond
) {
474 SetupAndCreateTwoShortcuts(FROM_HERE
);
476 // Delete one shortcut.
477 profile_info_cache_
->DeleteProfileFromCache(profile_2_path_
);
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
484 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_1_name_
));
486 // Create a second profile and shortcut.
487 CreateProfileWithShortcut(FROM_HERE
, profile_2_name_
, profile_2_path_
);
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()));
495 TEST_F(ProfileShortcutManagerTest
, RenamedDesktopShortcuts
) {
496 SetupAndCreateTwoShortcuts(FROM_HERE
);
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
));
505 // Ensure that a new shortcut does not get made if the old one was renamed.
506 profile_shortcut_manager_
->CreateProfileShortcut(profile_2_path_
);
508 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_
));
509 ValidateProfileShortcutAtPath(FROM_HERE
, profile_2_shortcut_path_2
,
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_
);
517 ValidateProfileShortcut(FROM_HERE
, profile_2_name_
, profile_2_path_
);
520 TEST_F(ProfileShortcutManagerTest
, RenamedDesktopShortcutsGetDeleted
) {
521 SetupAndCreateTwoShortcuts(FROM_HERE
);
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
,
532 ValidateProfileShortcutAtPath(FROM_HERE
, profile_2_shortcut_path_2
,
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
));
543 // Delete the profile and ensure both shortcuts were also deleted.
544 profile_info_cache_
->DeleteProfileFromCache(profile_2_path_
);
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
);
552 TEST_F(ProfileShortcutManagerTest
, RenamedDesktopShortcutsAfterProfileRename
) {
553 SetupAndCreateTwoShortcuts(FROM_HERE
);
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
,
564 ValidateProfileShortcutAtPath(FROM_HERE
, profile_2_shortcut_path_2
,
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
);
571 // The original shortcut should be renamed but the copied shortcut should
573 EXPECT_FALSE(base::PathExists(profile_2_shortcut_path_1
));
574 ValidateProfileShortcutAtPath(FROM_HERE
, profile_2_shortcut_path_2
,
576 ValidateProfileShortcut(FROM_HERE
, new_profile_2_name
, profile_2_path_
);
579 TEST_F(ProfileShortcutManagerTest
, UpdateShortcutWithNoFlags
) {
580 SetupDefaultProfileShortcut(FROM_HERE
);
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
));
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_
);
598 TEST_F(ProfileShortcutManagerTest
, UpdateTwoShortcutsWithNoFlags
) {
599 SetupDefaultProfileShortcut(FROM_HERE
);
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");
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
,
618 ValidateProfileShortcut(FROM_HERE
, profile_1_name_
, profile_1_path_
);
621 TEST_F(ProfileShortcutManagerTest
, RemoveProfileShortcuts
) {
622 SetupAndCreateTwoShortcuts(FROM_HERE
);
623 CreateProfileWithShortcut(FROM_HERE
, profile_3_name_
, profile_3_path_
);
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_
);
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
,
641 ValidateProfileShortcutAtPath(FROM_HERE
, profile_2_shortcut_path_2
,
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_
);
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
,
652 ValidateProfileShortcutAtPath(FROM_HERE
, profile_2_shortcut_path_2
,
656 TEST_F(ProfileShortcutManagerTest
, HasProfileShortcuts
) {
657 SetupAndCreateTwoShortcuts(FROM_HERE
);
659 struct HasShortcutsResult
{
661 void set_has_shortcuts(bool value
) { has_shortcuts
= value
; }
662 } result
= { false };
664 const base::Callback
<void(bool)> callback
=
665 base::Bind(&HasShortcutsResult::set_has_shortcuts
,
666 base::Unretained(&result
));
668 // Profile 2 should have a shortcut initially.
669 profile_shortcut_manager_
->HasProfileShortcuts(profile_2_path_
, callback
);
671 EXPECT_TRUE(result
.has_shortcuts
);
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
);
680 EXPECT_FALSE(result
.has_shortcuts
);
683 TEST_F(ProfileShortcutManagerTest
, ProfileShortcutsWithSystemLevelShortcut
) {
684 const base::FilePath system_level_shortcut_path
=
685 CreateRegularSystemLevelShortcut(FROM_HERE
);
687 // Create the initial profile.
688 profile_info_cache_
->AddProfileToCache(profile_1_path_
, profile_1_name_
,
689 base::string16(), 0, std::string());
691 ASSERT_EQ(1U, profile_info_cache_
->GetNumberOfProfiles());
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())));
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
));
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());
709 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_3_name_
));
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);
716 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_3_name_
));
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_
),
723 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_3_name_
));
724 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(new_profile_3_name
));
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_
),
732 EXPECT_FALSE(ProfileShortcutExistsAtDefaultPath(profile_2_name_
));
733 ValidateProfileShortcut(FROM_HERE
, new_profile_2_name
, profile_2_path_
);
736 TEST_F(ProfileShortcutManagerTest
,
737 DeleteSecondToLastProfileWithSystemLevelShortcut
) {
738 SetupAndCreateTwoShortcuts(FROM_HERE
);
740 const base::FilePath system_level_shortcut_path
=
741 CreateRegularSystemLevelShortcut(FROM_HERE
);
743 // Delete a profile and verify that only the system-level shortcut still
745 profile_info_cache_
->DeleteProfileFromCache(profile_1_path_
);
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_
));
754 TEST_F(ProfileShortcutManagerTest
,
755 DeleteSecondToLastProfileWithShortcutWhenSystemLevelShortcutExists
) {
756 SetupAndCreateTwoShortcuts(FROM_HERE
);
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_
);
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
));
768 const base::FilePath system_level_shortcut_path
=
769 CreateRegularSystemLevelShortcut(FROM_HERE
);
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_
);
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
));
785 TEST_F(ProfileShortcutManagerTest
, CreateProfileIcon
) {
786 SetupDefaultProfileShortcut(FROM_HERE
);
788 const base::FilePath icon_path
=
789 profiles::internal::GetProfileIconPath(profile_1_path_
);
791 EXPECT_TRUE(base::PathExists(icon_path
));
792 EXPECT_TRUE(base::DeleteFile(icon_path
, false));
793 EXPECT_FALSE(base::PathExists(icon_path
));
795 profile_shortcut_manager_
->CreateOrUpdateProfileIcon(profile_1_path_
);
797 EXPECT_TRUE(base::PathExists(icon_path
));
800 TEST_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_
);
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
));
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_
);
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
));
821 EXPECT_NE(badged_icon_1
, unbadged_icon_1
);
822 EXPECT_EQ(badged_icon_1
, badged_icon_2
);
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_
);
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
);
834 TEST_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_
);
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
));
848 // Profile 1 and 2 are created with the same icon.
849 EXPECT_EQ(badged_icon_1
, badged_icon_2
);
851 // Change profile 1's icon.
852 profile_info_cache_
->SetAvatarIconOfProfileAtIndex(profile_index_1
, 1);
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
);
859 // Ensure the new icon is not the unbadged icon.
860 profile_info_cache_
->DeleteProfileFromCache(profile_2_path_
);
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
);
867 // Ensure the icon doesn't change on avatar change without 2 profiles.
868 profile_info_cache_
->SetAvatarIconOfProfileAtIndex(profile_index_1
, 1);
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
);