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/mac/scoped_nsobject.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/prefs/pref_service_syncable.h"
12 #include "chrome/browser/profiles/avatar_menu.h"
13 #include "chrome/browser/profiles/profile_info_cache.h"
14 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
15 #include "chrome/browser/signin/fake_profile_oauth2_token_service_wrapper.h"
16 #include "chrome/browser/signin/profile_oauth2_token_service.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"
23 const std::string kEmail = "user@gmail.com";
24 const std::string kSecondaryEmail = "user2@gmail.com";
25 const std::string kLoginToken = "oauth2_login_token";
27 class ProfileChooserControllerTest : public CocoaProfileTest {
29 ProfileChooserControllerTest() {
32 virtual void SetUp() OVERRIDE {
33 CocoaProfileTest::SetUp();
34 ASSERT_TRUE(browser()->profile());
36 TestingProfile::TestingFactories factories;
38 std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(),
39 FakeProfileOAuth2TokenServiceWrapper::Build));
40 testing_profile_manager()->
41 CreateTestingProfile("test1", scoped_ptr<PrefServiceSyncable>(),
42 base::ASCIIToUTF16("Test 1"), 0, std::string(),
44 testing_profile_manager()->
45 CreateTestingProfile("test2", scoped_ptr<PrefServiceSyncable>(),
46 base::ASCIIToUTF16("Test 2"), 1, std::string(),
47 TestingProfile::TestingFactories());
49 menu_ = new AvatarMenu(testing_profile_manager()->profile_info_cache(),
53 // There should be the default profile + two profiles we created.
54 EXPECT_EQ(3U, menu_->GetNumberOfItems());
57 virtual void TearDown() OVERRIDE {
60 CocoaProfileTest::TearDown();
63 void StartProfileChooserController() {
64 NSRect frame = [test_window() frame];
65 NSPoint point = NSMakePoint(NSMidX(frame), NSMidY(frame));
67 [[ProfileChooserController alloc] initWithBrowser:browser()
69 [controller_ showWindow:nil];
72 ProfileChooserController* controller() { return controller_; }
73 AvatarMenu* menu() { return menu_; }
76 base::scoped_nsobject<ProfileChooserController> controller_;
78 // Weak; owned by |controller_|.
81 DISALLOW_COPY_AND_ASSIGN(ProfileChooserControllerTest);
84 TEST_F(ProfileChooserControllerTest, InitialLayout) {
85 StartProfileChooserController();
86 NSArray* subviews = [[[controller() window] contentView] subviews];
88 // Three profiles means we should have one active card, two "other" profiles,
89 // one separator and one option buttons view.
90 EXPECT_EQ(5U, [subviews count]);
92 // There should be three buttons in the option buttons view.
93 NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
94 const SEL buttonSelectors[] = { @selector(showUserManager:),
95 @selector(addNewProfile:),
96 @selector(switchToGuestProfile:) };
97 EXPECT_EQ(3U, [buttonSubviews count]);
98 for (NSUInteger i = 0; i < [buttonSubviews count]; ++i) {
99 NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:i]);
100 EXPECT_EQ(buttonSelectors[i], [button action]);
101 EXPECT_EQ(controller(), [button target]);
104 // There should be a separator.
105 EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
107 // There should be two "other profiles" items. The items are drawn from the
108 // bottom up, so in the opposite order of those in the AvatarMenu.
109 int profileIndex = 1;
110 for (NSUInteger i = 3; i >= 2; --i) {
111 NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i]);
112 EXPECT_EQ(menu()->GetItemAt(profileIndex).name,
113 base::SysNSStringToUTF16([button title]));
114 EXPECT_EQ(profileIndex, [button tag]);
115 EXPECT_EQ(@selector(switchToProfile:), [button action]);
116 EXPECT_EQ(controller(), [button target]);
120 // There should be the profile avatar, name and links container in the active
121 // card view. The links displayed in the container are checked separately.
122 NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
123 EXPECT_EQ(3U, [activeCardSubviews count]);
125 NSView* activeProfileImage = [activeCardSubviews objectAtIndex:0];
126 EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
128 // There are some links in between. The profile name is added last.
129 CGFloat index = [activeCardSubviews count] - 1;
130 NSView* activeProfileName = [activeCardSubviews objectAtIndex:index];
131 EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
132 EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
133 [static_cast<NSButton*>(activeProfileName) title]));
136 TEST_F(ProfileChooserControllerTest, OtherProfilesSortedAlphabetically) {
137 // Add two extra profiles, to make sure sorting is alphabetical and not
138 // by order of creation.
139 testing_profile_manager()->
140 CreateTestingProfile("test3", scoped_ptr<PrefServiceSyncable>(),
141 base::ASCIIToUTF16("New Profile"), 1, std::string(),
142 TestingProfile::TestingFactories());
143 testing_profile_manager()->
144 CreateTestingProfile("test4", scoped_ptr<PrefServiceSyncable>(),
145 base::ASCIIToUTF16("Another Test"), 1, std::string(),
146 TestingProfile::TestingFactories());
147 StartProfileChooserController();
149 NSArray* subviews = [[[controller() window] contentView] subviews];
150 NSString* sortedNames[] = { @"Another Test",
154 // There should be three "other profiles" items, sorted alphabetically.
155 // The "other profiles" start at index 2, after the option buttons and
156 // a separator. We need to iterate through the profiles in the order
157 // displayed in the bubble, which is opposite from the drawn order.
158 int sortedNameIndex = 0;
159 for (NSUInteger i = 5; i >= 2; --i) {
160 NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i]);
162 [[button title] isEqualToString:sortedNames[sortedNameIndex++]]);
166 TEST_F(ProfileChooserControllerTest, LocalProfileActiveCardLinks) {
167 StartProfileChooserController();
168 NSArray* subviews = [[[controller() window] contentView] subviews];
169 NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
170 NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:1] subviews];
172 // There should be one "sign in" link.
173 EXPECT_EQ(1U, [activeCardLinks count]);
174 NSButton* signinLink =
175 static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
176 EXPECT_EQ(@selector(showSigninPage:), [signinLink action]);
177 EXPECT_EQ(controller(), [signinLink target]);
180 TEST_F(ProfileChooserControllerTest, SignedInProfileActiveCardLinks) {
181 // Sign in the first profile.
182 ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
183 cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
185 StartProfileChooserController();
186 NSArray* subviews = [[[controller() window] contentView] subviews];
187 NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
188 NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:1] subviews];
190 // There are two links: lock and manage accounts.
191 EXPECT_EQ(2U, [activeCardLinks count]);
192 NSButton* manageAccountsLink =
193 static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
194 EXPECT_EQ(@selector(showAccountManagement:), [manageAccountsLink action]);
195 EXPECT_EQ(controller(), [manageAccountsLink target]);
198 static_cast<NSButton*>([activeCardLinks objectAtIndex:1]);
199 EXPECT_EQ(@selector(lockProfile:), [lockLink action]);
200 EXPECT_EQ(controller(), [lockLink target]);
203 TEST_F(ProfileChooserControllerTest, AccountManagementLayout) {
204 // Sign in the first profile.
205 ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
206 cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
208 // Set up the signin manager and the OAuth2Tokens.
209 Profile* profile = browser()->profile();
210 SigninManagerFactory::GetForProfile(profile)->
211 SetAuthenticatedUsername(kEmail);
212 ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
213 UpdateCredentials(kEmail, kLoginToken);
214 ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
215 UpdateCredentials(kSecondaryEmail, kLoginToken);
217 StartProfileChooserController();
218 [controller() initMenuContentsWithView:ACCOUNT_MANAGEMENT_VIEW];
220 NSArray* subviews = [[[controller() window] contentView] subviews];
222 // There should be one active card, one accounts container, two separators
223 // and one option buttons view.
224 EXPECT_EQ(5U, [subviews count]);
226 // There should be three buttons in the option buttons view.
227 NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
228 const SEL buttonSelectors[] = { @selector(showUserManager:),
229 @selector(addNewProfile:),
230 @selector(switchToGuestProfile:) };
231 EXPECT_EQ(3U, [buttonSubviews count]);
232 for (NSUInteger i = 0; i < [buttonSubviews count]; ++i) {
233 NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:i]);
234 EXPECT_EQ(buttonSelectors[i], [button action]);
235 EXPECT_EQ(controller(), [button target]);
238 // There should be a separator.
239 EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
241 // In the accounts view, there should be the account list container
242 // accounts and one "add accounts" button.
243 NSArray* accountsSubviews = [[subviews objectAtIndex:2] subviews];
244 EXPECT_EQ(2U, [accountsSubviews count]);
246 NSButton* addAccountsButton =
247 static_cast<NSButton*>([accountsSubviews objectAtIndex:0]);
248 EXPECT_EQ(@selector(addAccount:), [addAccountsButton action]);
249 EXPECT_EQ(controller(), [addAccountsButton target]);
251 // There should be two accounts in the account list container.
252 NSArray* accountsListSubviews = [[accountsSubviews objectAtIndex:1] subviews];
253 EXPECT_EQ(2U, [accountsListSubviews count]);
255 NSButton* genericAccount =
256 static_cast<NSButton*>([accountsListSubviews objectAtIndex:0]);
257 EXPECT_EQ(@selector(removeAccount:), [genericAccount action]);
258 EXPECT_EQ(controller(), [genericAccount target]);
260 // Primary accounts are always last and can't be deleted.
261 NSButton* primaryAccount =
262 static_cast<NSButton*>([accountsListSubviews objectAtIndex:1]);
263 EXPECT_EQ(nil, [primaryAccount action]);
264 EXPECT_EQ(nil, [primaryAccount target]);
266 // There should be another separator.
267 EXPECT_TRUE([[subviews objectAtIndex:3] isKindOfClass:[NSBox class]]);
269 // There should be the profile avatar, name and no links container in the
271 NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
272 EXPECT_EQ(2U, [activeCardSubviews count]);
274 NSView* activeProfileImage = [activeCardSubviews objectAtIndex:0];
275 EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
277 NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
278 EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
279 EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
280 [static_cast<NSButton*>(activeProfileName) title]));