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.
5 #import "chrome/browser/ui/cocoa/browser/profile_chooser_controller.h"
7 #include "base/command_line.h"
8 #include "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/prefs/pref_service_syncable.h"
13 #include "chrome/browser/profiles/avatar_menu.h"
14 #include "chrome/browser/profiles/profile_info_cache.h"
15 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
16 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/signin_manager.h"
19 #include "chrome/browser/signin/signin_manager_factory.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "components/signin/core/browser/profile_oauth2_token_service.h"
25 const std::string kEmail = "user@gmail.com";
26 const std::string kSecondaryEmail = "user2@gmail.com";
27 const std::string kLoginToken = "oauth2_login_token";
29 class ProfileChooserControllerTest : public CocoaProfileTest {
31 ProfileChooserControllerTest() {
34 virtual void SetUp() OVERRIDE {
35 CocoaProfileTest::SetUp();
36 ASSERT_TRUE(browser()->profile());
38 TestingProfile::TestingFactories factories;
40 std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(),
41 BuildFakeProfileOAuth2TokenService));
42 testing_profile_manager()->
43 CreateTestingProfile("test1", scoped_ptr<PrefServiceSyncable>(),
44 base::ASCIIToUTF16("Test 1"), 0, std::string(),
46 testing_profile_manager()->
47 CreateTestingProfile("test2", scoped_ptr<PrefServiceSyncable>(),
48 base::ASCIIToUTF16("Test 2"), 1, std::string(),
49 TestingProfile::TestingFactories());
51 menu_ = new AvatarMenu(testing_profile_manager()->profile_info_cache(),
55 // There should be the default profile + two profiles we created.
56 EXPECT_EQ(3U, menu_->GetNumberOfItems());
59 virtual void TearDown() OVERRIDE {
62 CocoaProfileTest::TearDown();
65 void StartProfileChooserController() {
66 NSRect frame = [test_window() frame];
67 NSPoint point = NSMakePoint(NSMidX(frame), NSMidY(frame));
68 controller_.reset([[ProfileChooserController alloc]
69 initWithBrowser:browser()
71 withMode:PROFILE_CHOOSER_VIEW]);
72 [controller_ showWindow:nil];
75 ProfileChooserController* controller() { return controller_; }
76 AvatarMenu* menu() { return menu_; }
79 base::scoped_nsobject<ProfileChooserController> controller_;
81 // Weak; owned by |controller_|.
84 DISALLOW_COPY_AND_ASSIGN(ProfileChooserControllerTest);
87 TEST_F(ProfileChooserControllerTest, InitialLayout) {
88 StartProfileChooserController();
89 NSArray* subviews = [[[controller() window] contentView] subviews];
91 // Three profiles means we should have one active card, one separator and
92 // one option buttons view.
93 EXPECT_EQ(3U, [subviews count]);
95 // For a local profile, there should be one button in the option buttons view.
96 NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
97 EXPECT_EQ(1U, [buttonSubviews count]);
98 NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:0]);
99 EXPECT_EQ(@selector(showUserManager:), [button action]);
100 EXPECT_EQ(controller(), [button target]);
102 // There should be a separator.
103 EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
105 // There should be the profile avatar, name and links container in the active
106 // card view. The links displayed in the container are checked separately.
107 NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
108 EXPECT_EQ(3U, [activeCardSubviews count]);
110 NSView* activeProfileImage = [activeCardSubviews objectAtIndex:0];
111 EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
113 // There are some links in between. The profile name is added last.
114 CGFloat index = [activeCardSubviews count] - 1;
115 NSView* activeProfileName = [activeCardSubviews objectAtIndex:index];
116 EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
117 EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
118 [static_cast<NSButton*>(activeProfileName) title]));
121 TEST_F(ProfileChooserControllerTest, InitialLayoutWithFastUserSwitcher) {
122 // The fast user switcher is only availbale behind a flag.
123 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kFastUserSwitching);
125 StartProfileChooserController();
126 NSArray* subviews = [[[controller() window] contentView] subviews];
128 // Three profiles means we should have one active card, two "other" profiles,
129 // one separator and one option buttons view.
130 EXPECT_EQ(5U, [subviews count]);
132 // For a local profile, there should be one button in the option buttons view.
133 NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
134 EXPECT_EQ(1U, [buttonSubviews count]);
135 NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:0]);
136 EXPECT_EQ(@selector(showUserManager:), [button action]);
137 EXPECT_EQ(controller(), [button target]);
139 // There should be a separator.
140 EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
142 // There should be two "other profiles" items. The items are drawn from the
143 // bottom up, so in the opposite order of those in the AvatarMenu.
144 int profileIndex = 1;
145 for (NSUInteger i = 3; i >= 2; --i) {
146 NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i]);
147 EXPECT_EQ(menu()->GetItemAt(profileIndex).name,
148 base::SysNSStringToUTF16([button title]));
149 EXPECT_EQ(profileIndex, [button tag]);
150 EXPECT_EQ(@selector(switchToProfile:), [button action]);
151 EXPECT_EQ(controller(), [button target]);
155 // There should be the profile avatar, name and links container in the active
156 // card view. The links displayed in the container are checked separately.
157 NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
158 EXPECT_EQ(3U, [activeCardSubviews count]);
160 NSView* activeProfileImage = [activeCardSubviews objectAtIndex:0];
161 EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
163 // There are some links in between. The profile name is added last.
164 CGFloat index = [activeCardSubviews count] - 1;
165 NSView* activeProfileName = [activeCardSubviews objectAtIndex:index];
166 EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
167 EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
168 [static_cast<NSButton*>(activeProfileName) title]));
171 TEST_F(ProfileChooserControllerTest, OtherProfilesSortedAlphabetically) {
172 // The fast user switcher is only availbale behind a flag.
173 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kFastUserSwitching);
175 // Add two extra profiles, to make sure sorting is alphabetical and not
176 // by order of creation.
177 testing_profile_manager()->
178 CreateTestingProfile("test3", scoped_ptr<PrefServiceSyncable>(),
179 base::ASCIIToUTF16("New Profile"), 1, std::string(),
180 TestingProfile::TestingFactories());
181 testing_profile_manager()->
182 CreateTestingProfile("test4", scoped_ptr<PrefServiceSyncable>(),
183 base::ASCIIToUTF16("Another Test"), 1, std::string(),
184 TestingProfile::TestingFactories());
185 StartProfileChooserController();
187 NSArray* subviews = [[[controller() window] contentView] subviews];
188 NSString* sortedNames[] = { @"Another Test",
192 // There should be three "other profiles" items, sorted alphabetically.
193 // The "other profiles" start at index 2, after the option buttons and
194 // a separator. We need to iterate through the profiles in the order
195 // displayed in the bubble, which is opposite from the drawn order.
196 int sortedNameIndex = 0;
197 for (NSUInteger i = 5; i >= 2; --i) {
198 NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i]);
200 [[button title] isEqualToString:sortedNames[sortedNameIndex++]]);
204 TEST_F(ProfileChooserControllerTest, LocalProfileActiveCardLinks) {
205 StartProfileChooserController();
206 NSArray* subviews = [[[controller() window] contentView] subviews];
207 NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
208 NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:1] subviews];
210 // There should be one "sign in" link.
211 EXPECT_EQ(1U, [activeCardLinks count]);
212 NSButton* signinLink =
213 static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
214 EXPECT_EQ(@selector(showSigninPage:), [signinLink action]);
215 EXPECT_EQ(controller(), [signinLink target]);
218 TEST_F(ProfileChooserControllerTest, SignedInProfileActiveCardLinks) {
219 // Sign in the first profile.
220 ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
221 cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
223 StartProfileChooserController();
224 NSArray* subviews = [[[controller() window] contentView] subviews];
225 NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
226 NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:1] subviews];
228 // There is one link: manage accounts.
229 EXPECT_EQ(1U, [activeCardLinks count]);
230 NSButton* manageAccountsLink =
231 static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
232 EXPECT_EQ(@selector(showAccountManagement:), [manageAccountsLink action]);
233 EXPECT_EQ(controller(), [manageAccountsLink target]);
236 TEST_F(ProfileChooserControllerTest, AccountManagementLayout) {
237 // Sign in the first profile.
238 ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
239 cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
241 // Set up the signin manager and the OAuth2Tokens.
242 Profile* profile = browser()->profile();
243 SigninManagerFactory::GetForProfile(profile)->
244 SetAuthenticatedUsername(kEmail);
245 ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
246 UpdateCredentials(kEmail, kLoginToken);
247 ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
248 UpdateCredentials(kSecondaryEmail, kLoginToken);
250 StartProfileChooserController();
251 [controller() initMenuContentsWithView:ACCOUNT_MANAGEMENT_VIEW];
253 NSArray* subviews = [[[controller() window] contentView] subviews];
255 // There should be one active card, one accounts container, two separators
256 // and one option buttons view.
257 EXPECT_EQ(5U, [subviews count]);
259 // There should be two buttons in the option buttons view.
260 NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
261 const SEL buttonSelectors[] = { @selector(showUserManager:),
262 @selector(lockProfile:) };
263 EXPECT_EQ(2U, [buttonSubviews count]);
264 for (NSUInteger i = 0; i < [buttonSubviews count]; ++i) {
265 NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:i]);
266 EXPECT_EQ(buttonSelectors[i], [button action]);
267 EXPECT_EQ(controller(), [button target]);
270 // There should be a separator.
271 EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
273 // In the accounts view, there should be the account list container
274 // accounts and one "add accounts" button.
275 NSArray* accountsSubviews = [[subviews objectAtIndex:2] subviews];
276 EXPECT_EQ(2U, [accountsSubviews count]);
278 NSButton* addAccountsButton =
279 static_cast<NSButton*>([accountsSubviews objectAtIndex:0]);
280 EXPECT_EQ(@selector(addAccount:), [addAccountsButton action]);
281 EXPECT_EQ(controller(), [addAccountsButton target]);
283 // There should be two accounts in the account list container.
284 NSArray* accountsListSubviews = [[accountsSubviews objectAtIndex:1] subviews];
285 EXPECT_EQ(2U, [accountsListSubviews count]);
287 NSButton* genericAccount =
288 static_cast<NSButton*>([accountsListSubviews objectAtIndex:0]);
289 EXPECT_EQ(@selector(removeAccount:), [genericAccount action]);
290 EXPECT_EQ(controller(), [genericAccount target]);
292 // Primary accounts are always last and can't be deleted.
293 NSButton* primaryAccount =
294 static_cast<NSButton*>([accountsListSubviews objectAtIndex:1]);
295 EXPECT_EQ(nil, [primaryAccount action]);
296 EXPECT_EQ(nil, [primaryAccount target]);
298 // There should be another separator.
299 EXPECT_TRUE([[subviews objectAtIndex:3] isKindOfClass:[NSBox class]]);
301 // There should be the profile avatar, name and no links container in the
303 NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
304 EXPECT_EQ(2U, [activeCardSubviews count]);
306 NSView* activeProfileImage = [activeCardSubviews objectAtIndex:0];
307 EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
309 NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
310 EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
311 EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
312 [static_cast<NSButton*>(activeProfileName) title]));