1 // Copyright 2013 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 <string> 6 7 #include "ash/ash_switches.h" 8 #include "base/command_line.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/strings/string16.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "chrome/browser/chromeos/login/fake_user_manager.h" 13 #include "chrome/browser/chromeos/profiles/profile_helper.h" 14 #include "chrome/browser/prefs/pref_service_syncable.h" 15 #include "chrome/browser/profiles/avatar_menu.h" 16 #include "chrome/browser/profiles/avatar_menu_observer.h" 17 #include "chrome/browser/profiles/profile_info_cache.h" 18 #include "chrome/browser/ui/ash/chrome_shell_delegate.h" 19 #include "chrome/common/chrome_constants.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "chrome/test/base/testing_browser_process.h" 22 #include "chrome/test/base/testing_profile_manager.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "ui/base/l10n/l10n_util.h" 25 26 namespace { 27 28 // As defined in /chromeos/dbus/cryptohome_client.cc. 29 static const char kUserIdHashSuffix[] = "-hash"; 30 31 class MockObserver : public AvatarMenuObserver { 32 public: 33 MockObserver() : count_(0) {} 34 virtual ~MockObserver() {} 35 36 virtual void OnAvatarMenuChanged( 37 AvatarMenu* avatar_menu) OVERRIDE { 38 ++count_; 39 } 40 41 int change_count() const { return count_; } 42 43 private: 44 int count_; 45 46 DISALLOW_COPY_AND_ASSIGN(MockObserver); 47 }; 48 49 } // namespace 50 51 namespace chromeos { 52 53 class ProfileListChromeOSTest : public testing::Test { 54 public: 55 ProfileListChromeOSTest() 56 : manager_(TestingBrowserProcess::GetGlobal()) { 57 } 58 59 virtual void SetUp() { 60 ASSERT_TRUE(manager_.SetUp()); 61 62 // AvatarMenu and multiple profiles works after user logged in. 63 manager_.SetLoggedIn(true); 64 65 // We only instantiate UserMenuModel if multi-profile mode is enabled. 66 CommandLine* cl = CommandLine::ForCurrentProcess(); 67 cl->AppendSwitch(switches::kMultiProfiles); 68 69 // Initialize the UserManager singleton to a fresh FakeUserManager instance. 70 user_manager_enabler_.reset( 71 new ScopedUserManagerEnabler(new FakeUserManager)); 72 } 73 74 FakeUserManager* GetFakeUserManager() { 75 return static_cast<FakeUserManager*>(UserManager::Get()); 76 } 77 78 void AddProfile(base::string16 name, bool log_in) { 79 std::string email_string = UTF16ToASCII(name) + "@example.com"; 80 81 // Add a user to the fake user manager. 82 GetFakeUserManager()->AddUser(email_string); 83 if (log_in) { 84 GetFakeUserManager()->UserLoggedIn( 85 email_string, 86 email_string + kUserIdHashSuffix, 87 false); 88 } 89 90 // Create a profile for the user. 91 manager()->CreateTestingProfile( 92 chrome::kProfileDirPrefix + email_string + kUserIdHashSuffix, 93 scoped_ptr<PrefServiceSyncable>(), 94 ASCIIToUTF16(email_string), 0, std::string(), 95 TestingProfile::TestingFactories()); 96 } 97 98 AvatarMenu* GetAvatarMenu() { 99 // Reset the MockObserver. 100 mock_observer_.reset(new MockObserver()); 101 EXPECT_EQ(0, change_count()); 102 103 // Reset the menu. 104 avatar_menu_.reset(new AvatarMenu( 105 manager()->profile_info_cache(), 106 mock_observer_.get(), 107 NULL)); 108 avatar_menu_->RebuildMenu(); 109 EXPECT_EQ(0, change_count()); 110 return avatar_menu_.get(); 111 } 112 113 void ActiveUserChanged(ProfileHelper* profile_helper, 114 const std::string& hash) { 115 profile_helper->ActiveUserHashChanged(hash); 116 } 117 118 TestingProfileManager* manager() { return &manager_; } 119 120 int change_count() const { return mock_observer_->change_count(); } 121 122 private: 123 TestingProfileManager manager_; 124 scoped_ptr<MockObserver> mock_observer_; 125 scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_; 126 scoped_ptr<AvatarMenu> avatar_menu_; 127 ChromeShellDelegate chrome_shell_delegate_; 128 129 DISALLOW_COPY_AND_ASSIGN(ProfileListChromeOSTest); 130 }; 131 132 TEST_F(ProfileListChromeOSTest, InitialCreation) { 133 base::string16 name1(ASCIIToUTF16("p1")); 134 135 AddProfile(name1, true); 136 137 AvatarMenu* menu = GetAvatarMenu(); 138 139 ASSERT_EQ(1U, menu->GetNumberOfItems()); 140 141 const AvatarMenu::Item& item1 = menu->GetItemAt(0); 142 EXPECT_EQ(0U, item1.menu_index); 143 EXPECT_EQ(name1, item1.name); 144 } 145 146 TEST_F(ProfileListChromeOSTest, ShowLoggedInUsers) { 147 base::string16 name1(ASCIIToUTF16("p1")); 148 base::string16 name2(ASCIIToUTF16("p2")); 149 base::string16 name3(ASCIIToUTF16("p3")); 150 base::string16 name4(ASCIIToUTF16("p4")); 151 152 AddProfile(name1, true); 153 AddProfile(name2, false); 154 AddProfile(name3, true); 155 AddProfile(name4, false); 156 157 AvatarMenu* menu = GetAvatarMenu(); 158 159 ASSERT_EQ(2U, menu->GetNumberOfItems()); 160 161 const AvatarMenu::Item& item1 = menu->GetItemAt(0); 162 EXPECT_EQ(0U, item1.menu_index); 163 EXPECT_EQ(name1, item1.name); 164 165 const AvatarMenu::Item& item3 = menu->GetItemAt(1); 166 EXPECT_EQ(1U, item3.menu_index); 167 EXPECT_EQ(name3, item3.name); 168 } 169 170 TEST_F(ProfileListChromeOSTest, DontShowManagedUsers) { 171 base::string16 name1(ASCIIToUTF16("p1")); 172 base::string16 managed_name(ASCIIToUTF16("p2 (at) example.com")); 173 174 AddProfile(name1, true); 175 176 // Add a managed user profile. 177 ProfileInfoCache* cache = manager()->profile_info_cache(); 178 manager()->profile_info_cache()->AddProfileToCache( 179 cache->GetUserDataDir().AppendASCII("p2"), managed_name, 180 base::string16(), 0, "TEST_ID"); 181 182 GetFakeUserManager()->AddUser(UTF16ToASCII(managed_name)); 183 184 AvatarMenu* menu = GetAvatarMenu(); 185 ASSERT_EQ(1U, menu->GetNumberOfItems()); 186 187 const AvatarMenu::Item& item1 = menu->GetItemAt(0); 188 EXPECT_EQ(0U, item1.menu_index); 189 EXPECT_EQ(name1, item1.name); 190 } 191 192 TEST_F(ProfileListChromeOSTest, ShowAddProfileLink) { 193 base::string16 name1(ASCIIToUTF16("p1.com")); 194 base::string16 name2(ASCIIToUTF16("p2.com")); 195 196 AddProfile(name1, true); 197 AddProfile(name2, false); 198 199 AvatarMenu* menu = GetAvatarMenu(); 200 201 ASSERT_EQ(1U, menu->GetNumberOfItems()); 202 EXPECT_TRUE(menu->ShouldShowAddNewProfileLink()); 203 } 204 205 TEST_F(ProfileListChromeOSTest, DontShowAddProfileLink) { 206 base::string16 name1(ASCIIToUTF16("p1.com")); 207 base::string16 name2(ASCIIToUTF16("p2.com")); 208 209 AddProfile(name1, true); 210 AddProfile(name2, true); 211 212 AvatarMenu* menu = GetAvatarMenu(); 213 214 ASSERT_EQ(2U, menu->GetNumberOfItems()); 215 EXPECT_FALSE(menu->ShouldShowAddNewProfileLink()); 216 } 217 218 TEST_F(ProfileListChromeOSTest, ActiveItem) { 219 base::string16 name1(ASCIIToUTF16("p1.com")); 220 base::string16 name2(ASCIIToUTF16("p2.com")); 221 222 AddProfile(name1, true); 223 AddProfile(name2, true); 224 225 // Initialize ProfileHelper, it will be accessed from GetActiveProfileIndex. 226 std::string email_string = UTF16ToASCII(name1) + "@example.com"; 227 std::string hash = email_string + kUserIdHashSuffix; 228 ActiveUserChanged( 229 g_browser_process->platform_part()->profile_helper(), hash); 230 231 AvatarMenu* menu = GetAvatarMenu(); 232 233 ASSERT_EQ(2U, menu->GetNumberOfItems()); 234 // TODO(jeremy): Expand test to verify active profile index other than 0 235 // crbug.com/100871 236 ASSERT_EQ(0U, menu->GetActiveProfileIndex()); 237 } 238 239 TEST_F(ProfileListChromeOSTest, ModifyingNameResortsCorrectly) { 240 base::string16 name1(ASCIIToUTF16("Alpha")); 241 base::string16 name2(ASCIIToUTF16("Beta")); 242 base::string16 newname1(ASCIIToUTF16("Gamma")); 243 244 AddProfile(name1, true); 245 AddProfile(name2, true); 246 247 AvatarMenu* menu = GetAvatarMenu(); 248 249 ASSERT_EQ(2U, menu->GetNumberOfItems()); 250 251 const AvatarMenu::Item& item1 = menu->GetItemAt(0); 252 EXPECT_EQ(0U, item1.menu_index); 253 EXPECT_EQ(name1, item1.name); 254 255 const AvatarMenu::Item& item2 = menu->GetItemAt(1); 256 EXPECT_EQ(1U, item2.menu_index); 257 EXPECT_EQ(name2, item2.name); 258 259 // Change name of the first profile, to trigger resorting of the profiles: 260 // now the first menu item should be named "beta", and the second be "gamma". 261 GetFakeUserManager()->SaveUserDisplayName( 262 UTF16ToASCII(name1) + "@example.com", newname1); 263 manager()->profile_info_cache()->SetNameOfProfileAtIndex(0, newname1); 264 265 const AvatarMenu::Item& item1next = menu->GetItemAt(0); 266 EXPECT_GT(change_count(), 1); 267 EXPECT_EQ(0U, item1next.menu_index); 268 EXPECT_EQ(name2, item1next.name); 269 270 const AvatarMenu::Item& item2next = menu->GetItemAt(1); 271 EXPECT_EQ(1U, item2next.menu_index); 272 EXPECT_EQ(newname1, item2next.name); 273 } 274 275 TEST_F(ProfileListChromeOSTest, ChangeOnNotify) { 276 base::string16 name1(ASCIIToUTF16("p1.com")); 277 base::string16 name2(ASCIIToUTF16("p2.com")); 278 279 AddProfile(name1, true); 280 AddProfile(name2, true); 281 282 AvatarMenu* menu = GetAvatarMenu(); 283 EXPECT_EQ(2U, menu->GetNumberOfItems()); 284 285 base::string16 name3(ASCIIToUTF16("p3.com")); 286 AddProfile(name3, true); 287 288 // Four changes happened via the call to CreateTestingProfile: adding the 289 // profile to the cache, setting the user name, rebuilding the list of 290 // profiles after the name change, and changing the avatar. 291 // TODO(michaelpg): Determine why actual change number does not match comment. 292 EXPECT_GE(change_count(), 4); 293 ASSERT_EQ(3U, menu->GetNumberOfItems()); 294 295 const AvatarMenu::Item& item1 = menu->GetItemAt(0); 296 EXPECT_EQ(0U, item1.menu_index); 297 EXPECT_EQ(name1, item1.name); 298 299 const AvatarMenu::Item& item2 = menu->GetItemAt(1); 300 EXPECT_EQ(1U, item2.menu_index); 301 EXPECT_EQ(name2, item2.name); 302 303 const AvatarMenu::Item& item3 = menu->GetItemAt(2); 304 EXPECT_EQ(2U, item3.menu_index); 305 EXPECT_EQ(name3, item3.name); 306 } 307 308 TEST_F(ProfileListChromeOSTest, DontShowAvatarMenu) { 309 // If in the new M-32 UX mode the icon gets shown, the menu will not. 310 base::string16 name1(ASCIIToUTF16("p1")); 311 base::string16 name2(ASCIIToUTF16("p2")); 312 313 AddProfile(name1, true); 314 315 // Should only show avatar menu with multiple users. 316 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 317 318 AddProfile(name2, false); 319 320 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 321 } 322 323 TEST_F(ProfileListChromeOSTest, ShowAvatarMenuInM31) { 324 // In M-31 mode, the menu will get shown. 325 CommandLine* cl = CommandLine::ForCurrentProcess(); 326 cl->AppendSwitch(ash::switches::kAshEnableFullMultiProfileMode); 327 328 base::string16 name1(ASCIIToUTF16("p1")); 329 base::string16 name2(ASCIIToUTF16("p2")); 330 331 AddProfile(name1, true); 332 333 // Should only show avatar menu with multiple users. 334 EXPECT_FALSE(AvatarMenu::ShouldShowAvatarMenu()); 335 336 AddProfile(name2, false); 337 338 EXPECT_TRUE(AvatarMenu::ShouldShowAvatarMenu()); 339 } 340 341 } // namespace chromeos 342