Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / profiles / profile_chooser_controller_unittest.mm
1 // Copyright 2014 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 #import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h"
6
7 #include "base/command_line.h"
8 #import "base/mac/foundation_util.h"
9 #include "base/mac/scoped_nsobject.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/prefs/pref_service_syncable.h"
14 #include "chrome/browser/profiles/avatar_menu.h"
15 #include "chrome/browser/profiles/profile_info_cache.h"
16 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
17 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/signin/signin_header_helper.h"
20 #include "chrome/browser/signin/signin_manager_factory.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "components/signin/core/browser/profile_oauth2_token_service.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "components/signin/core/common/profile_management_switches.h"
27
28 const std::string kEmail = "user@gmail.com";
29 const std::string kSecondaryEmail = "user2@gmail.com";
30 const std::string kLoginToken = "oauth2_login_token";
31
32 class ProfileChooserControllerTest : public CocoaProfileTest {
33  public:
34   ProfileChooserControllerTest() {
35   }
36
37   virtual void SetUp() OVERRIDE {
38     CocoaProfileTest::SetUp();
39     ASSERT_TRUE(browser()->profile());
40
41     TestingProfile::TestingFactories factories;
42     factories.push_back(
43         std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(),
44                        BuildFakeProfileOAuth2TokenService));
45     testing_profile_manager()->
46         CreateTestingProfile("test1", scoped_ptr<PrefServiceSyncable>(),
47                              base::ASCIIToUTF16("Test 1"), 0, std::string(),
48                              factories);
49     testing_profile_manager()->
50         CreateTestingProfile("test2", scoped_ptr<PrefServiceSyncable>(),
51                              base::ASCIIToUTF16("Test 2"), 1, std::string(),
52                              TestingProfile::TestingFactories());
53
54     menu_ = new AvatarMenu(testing_profile_manager()->profile_info_cache(),
55                            NULL, NULL);
56     menu_->RebuildMenu();
57
58     // There should be the default profile + two profiles we created.
59     EXPECT_EQ(3U, menu_->GetNumberOfItems());
60   }
61
62   virtual void TearDown() OVERRIDE {
63     [controller() close];
64     controller_.reset();
65     CocoaProfileTest::TearDown();
66   }
67
68   void StartProfileChooserController() {
69     NSRect frame = [test_window() frame];
70     NSPoint point = NSMakePoint(NSMidX(frame), NSMidY(frame));
71     controller_.reset([[ProfileChooserController alloc]
72         initWithBrowser:browser()
73              anchoredAt:point
74                viewMode:profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
75            tutorialMode:profiles::TUTORIAL_MODE_NONE
76             serviceType:signin::GAIA_SERVICE_TYPE_NONE]);
77     [controller_ showWindow:nil];
78   }
79
80   void EnableFastUserSwitching() {
81     CommandLine::ForCurrentProcess()->AppendSwitch(
82         switches::kFastUserSwitching);
83   }
84
85   ProfileChooserController* controller() { return controller_; }
86   AvatarMenu* menu() { return menu_; }
87
88  private:
89   base::scoped_nsobject<ProfileChooserController> controller_;
90
91   // Weak; owned by |controller_|.
92   AvatarMenu* menu_;
93
94   DISALLOW_COPY_AND_ASSIGN(ProfileChooserControllerTest);
95 };
96
97 TEST_F(ProfileChooserControllerTest, InitialLayoutWithNewMenu) {
98   switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
99   StartProfileChooserController();
100
101   NSArray* subviews = [[[controller() window] contentView] subviews];
102   ASSERT_EQ(1U, [subviews count]);
103   subviews = [[subviews objectAtIndex:0] subviews];
104
105   // Three profiles means we should have one active card, one separator and
106   // one option buttons view. We also have an update promo for the new avatar
107   // menu.
108   // TODO(noms): Enforcing 4U fails on the waterfall debug bots, but it's not
109   // reproducible anywhere else.
110   ASSERT_GE([subviews count], 3U);
111
112   // There should be two buttons and a separator in the option buttons view.
113   NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
114   ASSERT_EQ(3U, [buttonSubviews count]);
115
116   // There should be an incognito button.
117   NSButton* incognitoButton =
118       base::mac::ObjCCast<NSButton>([buttonSubviews objectAtIndex:0]);
119   EXPECT_EQ(@selector(goIncognito:), [incognitoButton action]);
120   EXPECT_EQ(controller(), [incognitoButton target]);
121
122   // There should be a separator.
123   EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
124
125   // There should be a user switcher button.
126   NSButton* userSwitcherButton =
127       base::mac::ObjCCast<NSButton>([buttonSubviews objectAtIndex:2]);
128   EXPECT_EQ(@selector(showUserManager:), [userSwitcherButton action]);
129   EXPECT_EQ(controller(), [userSwitcherButton target]);
130
131   // There should be a separator.
132   EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
133
134   // There should be the profile avatar, name and links container in the active
135   // card view. The links displayed in the container are checked separately.
136   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
137   ASSERT_EQ(3U, [activeCardSubviews count]);
138
139   // Profile icon.
140   NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
141   EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
142
143   // Profile name.
144   NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
145   EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
146   EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
147       [base::mac::ObjCCast<NSButton>(activeProfileName) title]));
148
149   // Profile links. This is a local profile, so there should be a signin button
150   // and a signin promo.
151   NSArray* linksSubviews = [[activeCardSubviews objectAtIndex:0] subviews];
152   ASSERT_EQ(2U, [linksSubviews count]);
153   NSButton* link = base::mac::ObjCCast<NSButton>(
154       [linksSubviews objectAtIndex:0]);
155   EXPECT_EQ(@selector(showInlineSigninPage:), [link action]);
156   EXPECT_EQ(controller(), [link target]);
157
158   NSTextField* promo = base::mac::ObjCCast<NSTextField>(
159       [linksSubviews objectAtIndex:1]);
160   EXPECT_GT([[promo stringValue] length], 0U);
161 }
162
163 TEST_F(ProfileChooserControllerTest, InitialLayoutWithFastUserSwitcher) {
164   switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
165   EnableFastUserSwitching();
166   StartProfileChooserController();
167
168   NSArray* subviews = [[[controller() window] contentView] subviews];
169   ASSERT_EQ(1U, [subviews count]);
170   subviews = [[subviews objectAtIndex:0] subviews];
171
172   // Three profiles means we should have one active card and a
173   // fast user switcher which has two "other" profiles and 2 separators, and
174   // an option buttons view with its separator. We also have a promo for
175   // the new avatar menu.
176   // TODO(noms): Enforcing 8U fails on the waterfall debug bots, but it's not
177   // reproducible anywhere else.
178   ASSERT_GE([subviews count], 7U);
179
180   // There should be two buttons and a separator in the option buttons view.
181   // These buttons are tested in InitialLayoutWithNewMenu.
182   NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
183   ASSERT_EQ(3U, [buttonSubviews count]);
184
185   // There should be a separator.
186   EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
187
188   // There should be two "other profiles" items. The items are drawn from the
189   // bottom up, so in the opposite order of those in the AvatarMenu.
190   int profileIndex = 1;
191   for (int i = 5; i >= 2; i -= 2) {
192     // Each profile button has a separator.
193     EXPECT_TRUE([[subviews objectAtIndex:i] isKindOfClass:[NSBox class]]);
194
195     NSButton* button = base::mac::ObjCCast<NSButton>(
196         [subviews objectAtIndex:i-1]);
197     EXPECT_EQ(menu()->GetItemAt(profileIndex).name,
198               base::SysNSStringToUTF16([button title]));
199     EXPECT_EQ(profileIndex, [button tag]);
200     EXPECT_EQ(@selector(switchToProfile:), [button action]);
201     EXPECT_EQ(controller(), [button target]);
202     profileIndex++;
203   }
204
205   // There should be the profile avatar, name and links container in the active
206   // card view. The links displayed in the container are checked separately.
207   NSArray* activeCardSubviews = [[subviews objectAtIndex:6] subviews];
208   ASSERT_EQ(3U, [activeCardSubviews count]);
209
210   // Profile icon.
211   NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
212   EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
213
214   // Profile name.
215   NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
216   EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
217   EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
218       [base::mac::ObjCCast<NSButton>(activeProfileName) title]));
219
220   // Profile links. This is a local profile, so there should be a signin button
221   // and a signin promo. These are also tested in InitialLayoutWithNewMenu.
222   NSArray* linksSubviews = [[activeCardSubviews objectAtIndex:0] subviews];
223   EXPECT_EQ(2U, [linksSubviews count]);
224 }
225
226 TEST_F(ProfileChooserControllerTest, OtherProfilesSortedAlphabetically) {
227   switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
228   EnableFastUserSwitching();
229
230   // Add two extra profiles, to make sure sorting is alphabetical and not
231   // by order of creation.
232   testing_profile_manager()->
233       CreateTestingProfile("test3", scoped_ptr<PrefServiceSyncable>(),
234                            base::ASCIIToUTF16("New Profile"), 1, std::string(),
235                            TestingProfile::TestingFactories());
236   testing_profile_manager()->
237       CreateTestingProfile("test4", scoped_ptr<PrefServiceSyncable>(),
238                            base::ASCIIToUTF16("Another Test"), 1, std::string(),
239                            TestingProfile::TestingFactories());
240   StartProfileChooserController();
241
242   NSArray* subviews = [[[controller() window] contentView] subviews];
243   ASSERT_EQ(1U, [subviews count]);
244   subviews = [[subviews objectAtIndex:0] subviews];
245   NSString* sortedNames[] = { @"Another Test",
246                               @"New Profile",
247                               @"Test 1",
248                               @"Test 2" };
249   // There are four "other" profiles, each with a button and a separator, an
250   // active profile card, and an option buttons view with a separator. We
251   // also have an update promo for the new avatar menu.
252   // TODO(noms): Enforcing 12U fails on the waterfall debug bots, but it's not
253   // reproducible anywhere else.
254   ASSERT_GE([subviews count], 11U);
255   // There should be four "other profiles" items, sorted alphabetically. The
256   // "other profiles" start at index 2 (after the option buttons view and its
257   // separator), and each have a separator. We need to iterate through the
258   // profiles in the order displayed in the bubble, which is opposite from the
259   // drawn order.
260   int sortedNameIndex = 0;
261   for (int i = 9; i >= 2; i -= 2) {
262     // The item at index i is the separator.
263     NSButton* button = base::mac::ObjCCast<NSButton>(
264         [subviews objectAtIndex:i-1]);
265     EXPECT_TRUE(
266         [[button title] isEqualToString:sortedNames[sortedNameIndex++]]);
267   }
268 }
269
270 TEST_F(ProfileChooserControllerTest,
271     LocalProfileActiveCardLinksWithNewMenu) {
272   switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
273   StartProfileChooserController();
274   NSArray* subviews = [[[controller() window] contentView] subviews];
275   ASSERT_EQ(1U, [subviews count]);
276   subviews = [[subviews objectAtIndex:0] subviews];
277   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
278   NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
279
280   ASSERT_EQ(2U, [activeCardLinks count]);
281
282   // There should be a sign in button.
283   NSButton* link = base::mac::ObjCCast<NSButton>(
284       [activeCardLinks objectAtIndex:0]);
285   EXPECT_EQ(@selector(showInlineSigninPage:), [link action]);
286   EXPECT_EQ(controller(), [link target]);
287
288   // Local profiles have a signin promo.
289   NSTextField* promo = base::mac::ObjCCast<NSTextField>(
290       [activeCardLinks objectAtIndex:1]);
291   EXPECT_GT([[promo stringValue] length], 0U);
292 }
293
294 TEST_F(ProfileChooserControllerTest,
295        SignedInProfileActiveCardLinksWithAccountConsistency) {
296   switches::EnableAccountConsistencyForTesting(
297       CommandLine::ForCurrentProcess());
298   // Sign in the first profile.
299   ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
300   cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
301
302   StartProfileChooserController();
303   NSArray* subviews = [[[controller() window] contentView] subviews];
304   ASSERT_EQ(1U, [subviews count]);
305   subviews = [[subviews objectAtIndex:0] subviews];
306   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
307   NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
308
309   // There is one link: manage accounts.
310   ASSERT_EQ(1U, [activeCardLinks count]);
311   NSButton* manageAccountsLink =
312       base::mac::ObjCCast<NSButton>([activeCardLinks objectAtIndex:0]);
313   EXPECT_EQ(@selector(showAccountManagement:), [manageAccountsLink action]);
314   EXPECT_EQ(controller(), [manageAccountsLink target]);
315 }
316
317 TEST_F(ProfileChooserControllerTest,
318     SignedInProfileActiveCardLinksWithNewMenu) {
319   switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
320   // Sign in the first profile.
321   ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
322   cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
323
324   StartProfileChooserController();
325   NSArray* subviews = [[[controller() window] contentView] subviews];
326   ASSERT_EQ(1U, [subviews count]);
327   subviews = [[subviews objectAtIndex:0] subviews];
328   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
329   NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
330
331   // There is one disabled button with the user's email.
332   ASSERT_EQ(1U, [activeCardLinks count]);
333   NSButton* emailButton =
334       base::mac::ObjCCast<NSButton>([activeCardLinks objectAtIndex:0]);
335   EXPECT_EQ(kEmail, base::SysNSStringToUTF8([emailButton title]));
336   EXPECT_EQ(nil, [emailButton action]);
337   EXPECT_FALSE([emailButton isEnabled]);
338 }
339
340 TEST_F(ProfileChooserControllerTest, AccountManagementLayout) {
341   switches::EnableAccountConsistencyForTesting(
342       CommandLine::ForCurrentProcess());
343   // Sign in the first profile.
344   ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
345   cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
346
347   // Set up the signin manager and the OAuth2Tokens.
348   Profile* profile = browser()->profile();
349   SigninManagerFactory::GetForProfile(profile)->
350       SetAuthenticatedUsername(kEmail);
351   ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
352       UpdateCredentials(kEmail, kLoginToken);
353   ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
354       UpdateCredentials(kSecondaryEmail, kLoginToken);
355
356   StartProfileChooserController();
357   [controller() initMenuContentsWithView:
358       profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
359
360   NSArray* subviews = [[[controller() window] contentView] subviews];
361   ASSERT_EQ(1U, [subviews count]);
362   subviews = [[subviews objectAtIndex:0] subviews];
363
364   // There should be one active card, one accounts container, two separators
365   // and one option buttons view.
366   ASSERT_EQ(5U, [subviews count]);
367
368   // There should be three buttons and two separators in the option
369   // buttons view.
370   NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
371   ASSERT_EQ(5U, [buttonSubviews count]);
372
373   // There should be a lock button.
374   NSButton* lockButton =
375       base::mac::ObjCCast<NSButton>([buttonSubviews objectAtIndex:0]);
376   EXPECT_EQ(@selector(lockProfile:), [lockButton action]);
377   EXPECT_EQ(controller(), [lockButton target]);
378
379   // There should be a separator.
380   EXPECT_TRUE([[buttonSubviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
381
382   // There should be an incognito button.
383   NSButton* incognitoButton =
384       base::mac::ObjCCast<NSButton>([buttonSubviews objectAtIndex:2]);
385   EXPECT_EQ(@selector(goIncognito:), [incognitoButton action]);
386   EXPECT_EQ(controller(), [incognitoButton target]);
387
388   // There should be a separator.
389   EXPECT_TRUE([[subviews objectAtIndex:3] isKindOfClass:[NSBox class]]);
390
391   // There should be a user switcher button.
392   NSButton* userSwitcherButton =
393       base::mac::ObjCCast<NSButton>([buttonSubviews objectAtIndex:4]);
394   EXPECT_EQ(@selector(showUserManager:), [userSwitcherButton action]);
395   EXPECT_EQ(controller(), [userSwitcherButton target]);
396
397   // In the accounts view, there should be the account list container
398   // accounts and one "add accounts" button.
399   NSArray* accountsSubviews = [[subviews objectAtIndex:2] subviews];
400   ASSERT_EQ(2U, [accountsSubviews count]);
401
402   NSButton* addAccountsButton =
403       base::mac::ObjCCast<NSButton>([accountsSubviews objectAtIndex:0]);
404   EXPECT_EQ(@selector(addAccount:), [addAccountsButton action]);
405   EXPECT_EQ(controller(), [addAccountsButton target]);
406
407   // There should be two accounts in the account list container.
408   NSArray* accountsListSubviews = [[accountsSubviews objectAtIndex:1] subviews];
409   ASSERT_EQ(2U, [accountsListSubviews count]);
410
411   NSButton* genericAccount =
412       base::mac::ObjCCast<NSButton>([accountsListSubviews objectAtIndex:0]);
413   NSButton* genericAccountDelete = base::mac::ObjCCast<NSButton>(
414   [[genericAccount subviews] objectAtIndex:0]);
415   EXPECT_EQ(@selector(showAccountRemovalView:), [genericAccountDelete action]);
416   EXPECT_EQ(controller(), [genericAccountDelete target]);
417   EXPECT_NE(-1, [genericAccountDelete tag]);
418
419   // Primary accounts are always last.
420   NSButton* primaryAccount =
421       base::mac::ObjCCast<NSButton>([accountsListSubviews objectAtIndex:1]);
422   NSButton* primaryAccountDelete = base::mac::ObjCCast<NSButton>(
423       [[primaryAccount subviews] objectAtIndex:0]);
424   EXPECT_EQ(@selector(showAccountRemovalView:), [primaryAccountDelete action]);
425   EXPECT_EQ(controller(), [primaryAccountDelete target]);
426   EXPECT_EQ(-1, [primaryAccountDelete tag]);
427
428   // There should be another separator.
429   EXPECT_TRUE([[subviews objectAtIndex:3] isKindOfClass:[NSBox class]]);
430
431   // There should be the profile avatar, name and a "hide accounts" link
432   // container in the active card view.
433   NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
434   ASSERT_EQ(3U, [activeCardSubviews count]);
435
436   // Profile icon.
437   NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
438   EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
439
440   // Profile name.
441   NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
442   EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
443   EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
444       [base::mac::ObjCCast<NSButton>(activeProfileName) title]));
445
446   // Profile links. This is a local profile, so there should be a signin button.
447   NSArray* linksSubviews = [[activeCardSubviews objectAtIndex:0] subviews];
448   ASSERT_EQ(1U, [linksSubviews count]);
449   NSButton* link = base::mac::ObjCCast<NSButton>(
450       [linksSubviews objectAtIndex:0]);
451   EXPECT_EQ(@selector(hideAccountManagement:), [link action]);
452   EXPECT_EQ(controller(), [link target]);
453 }