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/browser/profiles/profile_list_desktop.h" 6 7 #include <string> 8 9 #include "base/command_line.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/metrics/field_trial.h" 12 #include "base/strings/string16.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "chrome/browser/prefs/pref_service_syncable.h" 15 #include "chrome/browser/profiles/avatar_menu_observer.h" 16 #include "chrome/browser/profiles/profile_info_cache.h" 17 #include "chrome/browser/profiles/profiles_state.h" 18 #include "chrome/grit/generated_resources.h" 19 #include "chrome/test/base/testing_browser_process.h" 20 #include "chrome/test/base/testing_profile_manager.h" 21 #include "components/signin/core/common/profile_management_switches.h" 22 #include "content/public/test/test_browser_thread_bundle.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "ui/base/l10n/l10n_util.h" 25 26 using base::ASCIIToUTF16; 27 28 namespace { 29 30 class MockObserver : public AvatarMenuObserver { 31 public: 32 MockObserver() : count_(0) {} 33 virtual ~MockObserver() {} 34 35 virtual void OnAvatarMenuChanged( 36 AvatarMenu* avatar_menu) OVERRIDE { 37 ++count_; 38 } 39 40 int change_count() const { return count_; } 41 42 private: 43 int count_; 44 45 DISALLOW_COPY_AND_ASSIGN(MockObserver); 46 }; 47 48 class ProfileListDesktopTest : public testing::Test { 49 public: 50 ProfileListDesktopTest() 51 : manager_(TestingBrowserProcess::GetGlobal()) { 52 } 53 54 virtual void SetUp() { 55 ASSERT_TRUE(manager_.SetUp()); 56 #if defined(OS_CHROMEOS) 57 // AvatarMenu and multiple profiles works after user logged in. 58 manager_.SetLoggedIn(true); 59 #endif 60 } 61 62 AvatarMenu* GetAvatarMenu() { 63 // Reset the MockObserver. 64 mock_observer_.reset(new MockObserver()); 65 EXPECT_EQ(0, change_count()); 66 67 // Reset the model. 68 avatar_menu_.reset(new AvatarMenu( 69 manager()->profile_info_cache(), 70 mock_observer_.get(), 71 NULL)); 72 avatar_menu_->RebuildMenu(); 73 EXPECT_EQ(0, change_count()); 74 return avatar_menu_.get(); 75 } 76 77 TestingProfileManager* manager() { return &manager_; } 78 79 void AddOmittedProfile(std::string name) { 80 ProfileInfoCache* cache = manager()->profile_info_cache(); 81 cache->AddProfileToCache( 82 cache->GetUserDataDir().AppendASCII(name), ASCIIToUTF16(name), 83 base::string16(), 0, "TEST_ID"); 84 } 85 86 int change_count() const { return mock_observer_->change_count(); } 87 88 private: 89 TestingProfileManager manager_; 90 scoped_ptr<MockObserver> mock_observer_; 91 scoped_ptr<AvatarMenu> avatar_menu_; 92 content::TestBrowserThreadBundle thread_bundle_; 93 94 DISALLOW_COPY_AND_ASSIGN(ProfileListDesktopTest); 95 }; 96 97 TEST_F(ProfileListDesktopTest, InitialCreation) { 98 manager()->CreateTestingProfile("Test 1"); 99 manager()->CreateTestingProfile("Test 2"); 100 101 AvatarMenu* model = GetAvatarMenu(); 102 EXPECT_EQ(0, change_count()); 103 104 ASSERT_EQ(2U, model->GetNumberOfItems()); 105 106 const AvatarMenu::Item& item1 = model->GetItemAt(0); 107 EXPECT_EQ(0U, item1.menu_index); 108 EXPECT_EQ(ASCIIToUTF16("Test 1"), item1.name); 109 110 const AvatarMenu::Item& item2 = model->GetItemAt(1); 111 EXPECT_EQ(1U, item2.menu_index); 112 EXPECT_EQ(ASCIIToUTF16("Test 2"), item2.name); 113 } 114 115 TEST_F(ProfileListDesktopTest, NoOmittedProfiles) { 116 ProfileListDesktop profile_list(manager()->profile_info_cache()); 117 118 // Profiles are stored and listed alphabetically. 119 manager()->CreateTestingProfile("1 included"); 120 manager()->CreateTestingProfile("2 included"); 121 manager()->CreateTestingProfile("3 included"); 122 manager()->CreateTestingProfile("4 included"); 123 124 profile_list.RebuildMenu(); 125 ASSERT_EQ(4u, profile_list.GetNumberOfItems()); 126 127 const AvatarMenu::Item& item1 = profile_list.GetItemAt(0); 128 EXPECT_EQ(0u, item1.menu_index); 129 EXPECT_EQ(0u, item1.profile_index); 130 EXPECT_EQ(ASCIIToUTF16("1 included"), item1.name); 131 132 const AvatarMenu::Item& item2 = profile_list.GetItemAt(1); 133 EXPECT_EQ(1u, item2.menu_index); 134 EXPECT_EQ(1u, item2.profile_index); 135 EXPECT_EQ(ASCIIToUTF16("2 included"), item2.name); 136 137 const AvatarMenu::Item& item3 = profile_list.GetItemAt(2); 138 EXPECT_EQ(2u, item3.menu_index); 139 EXPECT_EQ(2u, item3.profile_index); 140 EXPECT_EQ(ASCIIToUTF16("3 included"), item3.name); 141 142 const AvatarMenu::Item& item4 = profile_list.GetItemAt(3); 143 EXPECT_EQ(3u, item4.menu_index); 144 EXPECT_EQ(3u, item4.profile_index); 145 EXPECT_EQ(ASCIIToUTF16("4 included"), item4.name); 146 147 EXPECT_EQ(0u, profile_list.MenuIndexFromProfileIndex(0)); 148 EXPECT_EQ(1u, profile_list.MenuIndexFromProfileIndex(1)); 149 EXPECT_EQ(2u, profile_list.MenuIndexFromProfileIndex(2)); 150 EXPECT_EQ(3u, profile_list.MenuIndexFromProfileIndex(3)); 151 } 152 153 TEST_F(ProfileListDesktopTest, WithOmittedProfiles) { 154 ProfileListDesktop profile_list(manager()->profile_info_cache()); 155 156 // Profiles are stored and listed alphabetically. 157 AddOmittedProfile("0 omitted"); 158 manager()->CreateTestingProfile("1 included"); 159 AddOmittedProfile("2 omitted"); 160 manager()->CreateTestingProfile("3 included"); 161 manager()->CreateTestingProfile("4 included"); 162 AddOmittedProfile("5 omitted"); 163 manager()->CreateTestingProfile("6 included"); 164 AddOmittedProfile("7 omitted"); 165 166 profile_list.RebuildMenu(); 167 ASSERT_EQ(4u, profile_list.GetNumberOfItems()); 168 169 const AvatarMenu::Item& item1 = profile_list.GetItemAt(0); 170 EXPECT_EQ(0u, item1.menu_index); 171 EXPECT_EQ(1u, item1.profile_index); 172 EXPECT_EQ(ASCIIToUTF16("1 included"), item1.name); 173 174 const AvatarMenu::Item& item2 = profile_list.GetItemAt(1); 175 EXPECT_EQ(1u, item2.menu_index); 176 EXPECT_EQ(3u, item2.profile_index); 177 EXPECT_EQ(ASCIIToUTF16("3 included"), item2.name); 178 179 const AvatarMenu::Item& item3 = profile_list.GetItemAt(2); 180 EXPECT_EQ(2u, item3.menu_index); 181 EXPECT_EQ(4u, item3.profile_index); 182 EXPECT_EQ(ASCIIToUTF16("4 included"), item3.name); 183 184 const AvatarMenu::Item& item4 = profile_list.GetItemAt(3); 185 EXPECT_EQ(3u, item4.menu_index); 186 EXPECT_EQ(6u, item4.profile_index); 187 EXPECT_EQ(ASCIIToUTF16("6 included"), item4.name); 188 189 EXPECT_EQ(0u, profile_list.MenuIndexFromProfileIndex(1)); 190 EXPECT_EQ(1u, profile_list.MenuIndexFromProfileIndex(3)); 191 EXPECT_EQ(2u, profile_list.MenuIndexFromProfileIndex(4)); 192 EXPECT_EQ(3u, profile_list.MenuIndexFromProfileIndex(6)); 193 } 194 195 TEST_F(ProfileListDesktopTest, ActiveItem) { 196 manager()->CreateTestingProfile("Test 1"); 197 manager()->CreateTestingProfile("Test 2"); 198 199 AvatarMenu* model = GetAvatarMenu(); 200 ASSERT_EQ(2U, model->GetNumberOfItems()); 201 // TODO(jeremy): Expand test to verify active profile index other than 0 202 // crbug.com/100871 203 ASSERT_EQ(0U, model->GetActiveProfileIndex()); 204 } 205 206 TEST_F(ProfileListDesktopTest, ModifyingNameResortsCorrectly) { 207 std::string name1("Alpha"); 208 std::string name2("Beta"); 209 std::string newname1("Gamma"); 210 211 manager()->CreateTestingProfile(name1); 212 manager()->CreateTestingProfile(name2); 213 214 AvatarMenu* model = GetAvatarMenu(); 215 EXPECT_EQ(0, change_count()); 216 217 ASSERT_EQ(2U, model->GetNumberOfItems()); 218 219 const AvatarMenu::Item& item1 = model->GetItemAt(0); 220 EXPECT_EQ(0U, item1.menu_index); 221 EXPECT_EQ(ASCIIToUTF16(name1), item1.name); 222 223 const AvatarMenu::Item& item2 = model->GetItemAt(1); 224 EXPECT_EQ(1U, item2.menu_index); 225 EXPECT_EQ(ASCIIToUTF16(name2), item2.name); 226 227 // Change name of the first profile, to trigger resorting of the profiles: 228 // now the first model should be named "beta", and the second be "gamma". 229 manager()->profile_info_cache()->SetNameOfProfileAtIndex(0, 230 ASCIIToUTF16(newname1)); 231 const AvatarMenu::Item& item1next = model->GetItemAt(0); 232 EXPECT_GT(change_count(), 1); 233 EXPECT_EQ(0U, item1next.menu_index); 234 EXPECT_EQ(ASCIIToUTF16(name2), item1next.name); 235 236 const AvatarMenu::Item& item2next = model->GetItemAt(1); 237 EXPECT_EQ(1U, item2next.menu_index); 238 EXPECT_EQ(ASCIIToUTF16(newname1), item2next.name); 239 } 240 241 TEST_F(ProfileListDesktopTest, ChangeOnNotify) { 242 manager()->CreateTestingProfile("Test 1"); 243 manager()->CreateTestingProfile("Test 2"); 244 245 AvatarMenu* model = GetAvatarMenu(); 246 EXPECT_EQ(0, change_count()); 247 EXPECT_EQ(2U, model->GetNumberOfItems()); 248 249 manager()->CreateTestingProfile("Test 3"); 250 251 // Four changes happened via the call to CreateTestingProfile: adding the 252 // profile to the cache, setting the user name, rebuilding the list of 253 // profiles after the name change, and changing the avatar. 254 // On Windows, an extra change happens to set the shortcut name for the 255 // profile. 256 // TODO(michaelpg): Determine why five changes happen on ChromeOS and 257 // investigate other platforms. 258 EXPECT_GE(change_count(), 4); 259 ASSERT_EQ(3U, model->GetNumberOfItems()); 260 261 const AvatarMenu::Item& item1 = model->GetItemAt(0); 262 EXPECT_EQ(0U, item1.menu_index); 263 EXPECT_EQ(ASCIIToUTF16("Test 1"), item1.name); 264 265 const AvatarMenu::Item& item2 = model->GetItemAt(1); 266 EXPECT_EQ(1U, item2.menu_index); 267 EXPECT_EQ(ASCIIToUTF16("Test 2"), item2.name); 268 269 const AvatarMenu::Item& item3 = model->GetItemAt(2); 270 EXPECT_EQ(2U, item3.menu_index); 271 EXPECT_EQ(ASCIIToUTF16("Test 3"), item3.name); 272 } 273 274 TEST_F(ProfileListDesktopTest, ShowAvatarMenuInTrial) { 275 // If multiprofile mode is not enabled, the trial will not be enabled, so it 276 // isn't tested. 277 if (!profiles::IsMultipleProfilesEnabled()) 278 return; 279 280 base::FieldTrialList field_trial_list_(NULL); 281 base::FieldTrialList::CreateFieldTrial("ShowProfileSwitcher", "AlwaysShow"); 282 283 #if defined(OS_CHROMEOS) 284 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 285 #else 286 EXPECT_TRUE(AvatarMenu::ShouldShowAvatarMenu()); 287 #endif 288 } 289 290 TEST_F(ProfileListDesktopTest, DontShowOldAvatarMenuForSingleProfile) { 291 switches::DisableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess()); 292 293 manager()->CreateTestingProfile("Test 1"); 294 295 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 296 297 // If multiprofile mode is enabled, there are no other cases when we wouldn't 298 // show the menu. 299 if (profiles::IsMultipleProfilesEnabled()) 300 return; 301 302 manager()->CreateTestingProfile("Test 2"); 303 304 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 305 } 306 307 TEST_F(ProfileListDesktopTest, AlwaysShowNewAvatarMenu) { 308 // If multiprofile mode is not enabled then the menu is never shown. 309 if (!profiles::IsMultipleProfilesEnabled()) 310 return; 311 312 switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess()); 313 314 manager()->CreateTestingProfile("Test 1"); 315 316 EXPECT_TRUE(AvatarMenu::ShouldShowAvatarMenu()); 317 } 318 319 TEST_F(ProfileListDesktopTest, ShowAvatarMenu) { 320 // If multiprofile mode is not enabled then the menu is never shown. 321 if (!profiles::IsMultipleProfilesEnabled()) 322 return; 323 324 manager()->CreateTestingProfile("Test 1"); 325 manager()->CreateTestingProfile("Test 2"); 326 327 #if defined(OS_CHROMEOS) 328 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 329 #else 330 EXPECT_TRUE(AvatarMenu::ShouldShowAvatarMenu()); 331 #endif 332 } 333 334 TEST_F(ProfileListDesktopTest, SyncState) { 335 // If multiprofile mode is not enabled then the menu is never shown. 336 if (!profiles::IsMultipleProfilesEnabled()) 337 return; 338 339 manager()->CreateTestingProfile("Test 1"); 340 341 // Add a managed user profile. 342 ProfileInfoCache* cache = manager()->profile_info_cache(); 343 base::FilePath path = cache->GetUserDataDir().AppendASCII("p2"); 344 cache->AddProfileToCache(path, ASCIIToUTF16("Test 2"), base::string16(), 0, 345 "TEST_ID"); 346 cache->SetIsOmittedProfileAtIndex(cache->GetIndexOfProfileWithPath(path), 347 false); 348 349 AvatarMenu* model = GetAvatarMenu(); 350 model->RebuildMenu(); 351 EXPECT_EQ(2U, model->GetNumberOfItems()); 352 353 // Now check that the sync_state of a supervised user shows the supervised 354 // user avatar label instead. 355 base::string16 supervised_user_label = 356 l10n_util::GetStringUTF16(IDS_SUPERVISED_USER_AVATAR_LABEL); 357 const AvatarMenu::Item& item1 = model->GetItemAt(0); 358 EXPECT_NE(item1.sync_state, supervised_user_label); 359 360 const AvatarMenu::Item& item2 = model->GetItemAt(1); 361 EXPECT_EQ(item2.sync_state, supervised_user_label); 362 } 363 364 } // namespace 365