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