blob: 47090002db02d56a10b09775118d3499b617abba [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h"
#include "base/command_line.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_header_helper.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
#include "chrome/common/chrome_switches.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/common/profile_management_switches.h"
const std::string kEmail = "user@gmail.com";
const std::string kSecondaryEmail = "user2@gmail.com";
const std::string kLoginToken = "oauth2_login_token";
class ProfileChooserControllerTest : public CocoaProfileTest {
public:
ProfileChooserControllerTest() {
}
virtual void SetUp() OVERRIDE {
CocoaProfileTest::SetUp();
ASSERT_TRUE(browser()->profile());
TestingProfile::TestingFactories factories;
factories.push_back(
std::make_pair(ProfileOAuth2TokenServiceFactory::GetInstance(),
BuildFakeProfileOAuth2TokenService));
testing_profile_manager()->
CreateTestingProfile("test1", scoped_ptr<PrefServiceSyncable>(),
base::ASCIIToUTF16("Test 1"), 0, std::string(),
factories);
testing_profile_manager()->
CreateTestingProfile("test2", scoped_ptr<PrefServiceSyncable>(),
base::ASCIIToUTF16("Test 2"), 1, std::string(),
TestingProfile::TestingFactories());
menu_ = new AvatarMenu(testing_profile_manager()->profile_info_cache(),
NULL, NULL);
menu_->RebuildMenu();
// There should be the default profile + two profiles we created.
EXPECT_EQ(3U, menu_->GetNumberOfItems());
}
virtual void TearDown() OVERRIDE {
[controller() close];
controller_.reset();
CocoaProfileTest::TearDown();
}
void StartProfileChooserController() {
NSRect frame = [test_window() frame];
NSPoint point = NSMakePoint(NSMidX(frame), NSMidY(frame));
controller_.reset([[ProfileChooserController alloc]
initWithBrowser:browser()
anchoredAt:point
withMode:profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
withServiceType:signin::GAIA_SERVICE_TYPE_NONE]);
[controller_ showWindow:nil];
}
void EnableNewAvatarMenuOnly() {
CommandLine::ForCurrentProcess()->AppendSwitch(switches::kNewAvatarMenu);
}
void EnableFastUserSwitching() {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kFastUserSwitching);
}
ProfileChooserController* controller() { return controller_; }
AvatarMenu* menu() { return menu_; }
private:
base::scoped_nsobject<ProfileChooserController> controller_;
// Weak; owned by |controller_|.
AvatarMenu* menu_;
DISALLOW_COPY_AND_ASSIGN(ProfileChooserControllerTest);
};
TEST_F(ProfileChooserControllerTest, InitialLayoutWithNewManagement) {
switches::EnableNewProfileManagementForTesting(
CommandLine::ForCurrentProcess());
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
// Three profiles means we should have one active card, one separator and
// one option buttons view.
EXPECT_EQ(3U, [subviews count]);
// For a local profile, there should be one button in the option buttons view.
NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
EXPECT_EQ(1U, [buttonSubviews count]);
NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(showUserManager:), [button action]);
EXPECT_EQ(controller(), [button target]);
// There should be a separator.
EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
// There should be the profile avatar, name and links container in the active
// card view. The links displayed in the container are checked separately.
NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
EXPECT_EQ(3U, [activeCardSubviews count]);
// Profile icon.
NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
// Profile name.
NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
[static_cast<NSButton*>(activeProfileName) title]));
// Profile links. This is a local profile, so there should be a signin button.
NSArray* linksSubviews = [[activeCardSubviews objectAtIndex:0] subviews];
EXPECT_EQ(1U, [linksSubviews count]);
NSButton* link = static_cast<NSButton*>([linksSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(showInlineSigninPage:), [link action]);
EXPECT_EQ(controller(), [link target]);
}
TEST_F(ProfileChooserControllerTest, InitialLayoutWithNewMenu) {
EnableNewAvatarMenuOnly();
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
// Three profiles means we should have one active card and a
// fast user switcher which has two "other" profiles and 2 separators. In
// this flow we also have the tutorial view.
EXPECT_EQ(6U, [subviews count]);
// There should be two "other profiles" items. The items are drawn from the
// bottom up, so in the opposite order of those in the AvatarMenu.
int profileIndex = 1;
for (int i = 3; i >= 0; i -= 2) {
// Each profile button has a separator.
EXPECT_TRUE([[subviews objectAtIndex:i] isKindOfClass:[NSBox class]]);
NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i-1]);
EXPECT_EQ(menu()->GetItemAt(profileIndex).name,
base::SysNSStringToUTF16([button title]));
EXPECT_EQ(profileIndex, [button tag]);
EXPECT_EQ(@selector(switchToProfile:), [button action]);
EXPECT_EQ(controller(), [button target]);
profileIndex++;
}
// There should be the profile avatar, name and links container in the active
// card view. The links displayed in the container are checked separately.
NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
EXPECT_EQ(3U, [activeCardSubviews count]);
// Profile icon.
NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
// Profile name.
NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
[static_cast<NSButton*>(activeProfileName) title]));
// Profile links. This is a local profile, so there should be a signin button.
NSArray* linksSubviews = [[activeCardSubviews objectAtIndex:0] subviews];
EXPECT_EQ(1U, [linksSubviews count]);
NSButton* link = static_cast<NSButton*>([linksSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(showTabbedSigninPage:), [link action]);
EXPECT_EQ(controller(), [link target]);
// There is a tutorial view card at the top.
EXPECT_TRUE([[subviews objectAtIndex:5] isKindOfClass:[NSView class]]);
}
TEST_F(ProfileChooserControllerTest, InitialLayoutWithFastUserSwitcher) {
switches::EnableNewProfileManagementForTesting(
CommandLine::ForCurrentProcess());
EnableFastUserSwitching();
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
// Three profiles means we should have one active card, two "other" profiles,
// each with a separator, and one option buttons view.
EXPECT_EQ(7U, [subviews count]);
// For a local profile, there should be one button in the option buttons view.
NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
EXPECT_EQ(1U, [buttonSubviews count]);
NSButton* button = static_cast<NSButton*>([buttonSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(showUserManager:), [button action]);
EXPECT_EQ(controller(), [button target]);
// There should be a separator.
EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
// There should be two "other profiles" items. The items are drawn from the
// bottom up, so in the opposite order of those in the AvatarMenu.
int profileIndex = 1;
for (int i = 5; i >= 2; i -= 2) {
// Each profile button has a separator.
EXPECT_TRUE([[subviews objectAtIndex:i] isKindOfClass:[NSBox class]]);
NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i-1]);
EXPECT_EQ(menu()->GetItemAt(profileIndex).name,
base::SysNSStringToUTF16([button title]));
EXPECT_EQ(profileIndex, [button tag]);
EXPECT_EQ(@selector(switchToProfile:), [button action]);
EXPECT_EQ(controller(), [button target]);
profileIndex++;
}
// There should be the profile avatar, name and links container in the active
// card view. These have been checked separately.
NSArray* activeCardSubviews = [[subviews objectAtIndex:6] subviews];
EXPECT_EQ(3U, [activeCardSubviews count]);
}
TEST_F(ProfileChooserControllerTest, OtherProfilesSortedAlphabetically) {
EnableNewAvatarMenuOnly();
// Add two extra profiles, to make sure sorting is alphabetical and not
// by order of creation.
testing_profile_manager()->
CreateTestingProfile("test3", scoped_ptr<PrefServiceSyncable>(),
base::ASCIIToUTF16("New Profile"), 1, std::string(),
TestingProfile::TestingFactories());
testing_profile_manager()->
CreateTestingProfile("test4", scoped_ptr<PrefServiceSyncable>(),
base::ASCIIToUTF16("Another Test"), 1, std::string(),
TestingProfile::TestingFactories());
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
NSString* sortedNames[] = { @"Another Test",
@"New Profile",
@"Test 1",
@"Test 2" };
// There are four "other" profiles, each with a button and a separator, an
// active profile card, and a tutorial card.
EXPECT_EQ(10U, [subviews count]);
// There should be four "other profiles" items, sorted alphabetically.
// The "other profiles" start at index 0, and each have a separator. We
// need to iterate through the profiles in the order displayed in the bubble,
// which is opposite from the drawn order.
int sortedNameIndex = 0;
for (int i = 7; i >= 0; i -= 2) {
// The item at index i is the separator.
NSButton* button = static_cast<NSButton*>([subviews objectAtIndex:i-1]);
EXPECT_TRUE(
[[button title] isEqualToString:sortedNames[sortedNameIndex++]]);
}
}
TEST_F(ProfileChooserControllerTest,
LocalProfileActiveCardLinksWithNewManagement) {
switches::EnableNewProfileManagementForTesting(
CommandLine::ForCurrentProcess());
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
// There should be one "sign in" link.
EXPECT_EQ(1U, [activeCardLinks count]);
NSButton* signinLink =
static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
EXPECT_EQ(@selector(showInlineSigninPage:), [signinLink action]);
EXPECT_EQ(controller(), [signinLink target]);
}
TEST_F(ProfileChooserControllerTest,
LocalProfileActiveCardLinksWithNewMenu) {
EnableNewAvatarMenuOnly();
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
// There should be one "sign in" link.
EXPECT_EQ(1U, [activeCardLinks count]);
NSButton* signinLink =
static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
EXPECT_EQ(@selector(showTabbedSigninPage:), [signinLink action]);
EXPECT_EQ(controller(), [signinLink target]);
}
TEST_F(ProfileChooserControllerTest,
SignedInProfileActiveCardLinksWithNewManagement) {
switches::EnableNewProfileManagementForTesting(
CommandLine::ForCurrentProcess());
// Sign in the first profile.
ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
// There is one link: manage accounts.
EXPECT_EQ(1U, [activeCardLinks count]);
NSButton* manageAccountsLink =
static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
EXPECT_EQ(@selector(showAccountManagement:), [manageAccountsLink action]);
EXPECT_EQ(controller(), [manageAccountsLink target]);
}
TEST_F(ProfileChooserControllerTest,
SignedInProfileActiveCardLinksWithNewMenu) {
EnableNewAvatarMenuOnly();
// Sign in the first profile.
ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
StartProfileChooserController();
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
// There is one link, without a target and with the user's email.
EXPECT_EQ(1U, [activeCardLinks count]);
NSButton* emailLink =
static_cast<NSButton*>([activeCardLinks objectAtIndex:0]);
EXPECT_EQ(nil, [emailLink action]);
EXPECT_EQ(kEmail, base::SysNSStringToUTF8([emailLink title]));
EXPECT_EQ(controller(), [emailLink target]);
}
TEST_F(ProfileChooserControllerTest, AccountManagementLayout) {
switches::EnableNewProfileManagementForTesting(
CommandLine::ForCurrentProcess());
// Sign in the first profile.
ProfileInfoCache* cache = testing_profile_manager()->profile_info_cache();
cache->SetUserNameOfProfileAtIndex(0, base::ASCIIToUTF16(kEmail));
// Set up the signin manager and the OAuth2Tokens.
Profile* profile = browser()->profile();
SigninManagerFactory::GetForProfile(profile)->
SetAuthenticatedUsername(kEmail);
ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
UpdateCredentials(kEmail, kLoginToken);
ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
UpdateCredentials(kSecondaryEmail, kLoginToken);
StartProfileChooserController();
[controller() initMenuContentsWithView:
profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
NSArray* subviews = [[[controller() window] contentView] subviews];
EXPECT_EQ(1U, [subviews count]);
subviews = [[subviews objectAtIndex:0] subviews];
// There should be one active card, one accounts container, two separators
// and one option buttons view.
EXPECT_EQ(5U, [subviews count]);
// There should be two buttons and a separator in the option buttons view.
NSArray* buttonSubviews = [[subviews objectAtIndex:0] subviews];
EXPECT_EQ(3U, [buttonSubviews count]);
NSButton* notYouButton =
static_cast<NSButton*>([buttonSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(showUserManager:), [notYouButton action]);
EXPECT_EQ(controller(), [notYouButton target]);
EXPECT_TRUE([[buttonSubviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
NSButton* lockButton =
static_cast<NSButton*>([buttonSubviews objectAtIndex:2]);
EXPECT_EQ(@selector(lockProfile:), [lockButton action]);
EXPECT_EQ(controller(), [lockButton target]);
// There should be a separator.
EXPECT_TRUE([[subviews objectAtIndex:1] isKindOfClass:[NSBox class]]);
// In the accounts view, there should be the account list container
// accounts and one "add accounts" button.
NSArray* accountsSubviews = [[subviews objectAtIndex:2] subviews];
EXPECT_EQ(2U, [accountsSubviews count]);
NSButton* addAccountsButton =
static_cast<NSButton*>([accountsSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(addAccount:), [addAccountsButton action]);
EXPECT_EQ(controller(), [addAccountsButton target]);
// There should be two accounts in the account list container.
NSArray* accountsListSubviews = [[accountsSubviews objectAtIndex:1] subviews];
EXPECT_EQ(2U, [accountsListSubviews count]);
NSButton* genericAccount =
static_cast<NSButton*>([accountsListSubviews objectAtIndex:0]);
NSButton* genericAccountDelete =
static_cast<NSButton*>([[genericAccount subviews] objectAtIndex:0]);
EXPECT_EQ(@selector(showAccountRemovalView:), [genericAccountDelete action]);
EXPECT_EQ(controller(), [genericAccountDelete target]);
EXPECT_NE(-1, [genericAccountDelete tag]);
// Primary accounts are always last.
NSButton* primaryAccount =
static_cast<NSButton*>([accountsListSubviews objectAtIndex:1]);
NSButton* primaryAccountDelete =
static_cast<NSButton*>([[primaryAccount subviews] objectAtIndex:0]);
EXPECT_EQ(@selector(showAccountRemovalView:), [primaryAccountDelete action]);
EXPECT_EQ(controller(), [primaryAccountDelete target]);
EXPECT_EQ(-1, [primaryAccountDelete tag]);
// There should be another separator.
EXPECT_TRUE([[subviews objectAtIndex:3] isKindOfClass:[NSBox class]]);
// There should be the profile avatar, name and a "hide accounts" link
// container in the active card view.
NSArray* activeCardSubviews = [[subviews objectAtIndex:4] subviews];
EXPECT_EQ(3U, [activeCardSubviews count]);
// Profile icon.
NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
// Profile name.
NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
EXPECT_TRUE([activeProfileName isKindOfClass:[NSButton class]]);
EXPECT_EQ(menu()->GetItemAt(0).name, base::SysNSStringToUTF16(
[static_cast<NSButton*>(activeProfileName) title]));
// Profile links. This is a local profile, so there should be a signin button.
NSArray* linksSubviews = [[activeCardSubviews objectAtIndex:0] subviews];
EXPECT_EQ(1U, [linksSubviews count]);
NSButton* link = static_cast<NSButton*>([linksSubviews objectAtIndex:0]);
EXPECT_EQ(@selector(hideAccountManagement:), [link action]);
EXPECT_EQ(controller(), [link target]);
}