blob: dc2a38922b98e1ace87bbf10c5a7254ab0a2980f [file] [log] [blame]
// Copyright 2016 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 "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
#import <Foundation/Foundation.h>
#include "base/mac/scoped_block.h"
#include "base/strings/sys_string_conversions.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.h"
#include "ios/public/provider/chrome/browser/signin/signin_resources_provider.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using ::testing::_;
using ::testing::Invoke;
namespace {
UIImage* FakeGetCachedAvatarForIdentity(ChromeIdentity*) {
ios::SigninResourcesProvider* provider =
ios::GetChromeBrowserProvider()->GetSigninResourcesProvider();
return provider ? provider->GetDefaultAvatar() : nil;
}
void FakeGetAvatarForIdentity(ChromeIdentity* identity,
ios::GetAvatarCallback callback) {
// |GetAvatarForIdentity| is normally an asynchronous operation, this is
// replicated here by dispatching it.
dispatch_async(dispatch_get_main_queue(), ^{
callback(FakeGetCachedAvatarForIdentity(identity));
});
}
void FakeGetHostedDomainForIdentity(ChromeIdentity* identity,
ios::GetHostedDomainCallback callback) {
NSString* domain = base::SysUTF8ToNSString(gaia::ExtractDomainName(
gaia::CanonicalizeEmail(base::SysNSStringToUTF8(identity.userEmail))));
// |GetHostedDomainForIdentity| is normally an asynchronous operation , this
// is replicated here by dispatching it.
dispatch_async(dispatch_get_main_queue(), ^{
callback(domain, nil);
});
}
}
@interface FakeAccountDetailsViewController : UIViewController {
__weak ChromeIdentity* _identity;
UIButton* _removeAccountButton;
}
@end
@implementation FakeAccountDetailsViewController
- (instancetype)initWithIdentity:(ChromeIdentity*)identity {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_identity = identity;
}
return self;
}
- (void)dealloc {
[_removeAccountButton removeTarget:self
action:@selector(didTapRemoveAccount:)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Obnoxious color, this is a test screen.
self.view.backgroundColor = [UIColor orangeColor];
_removeAccountButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_removeAccountButton setTitle:@"Remove account"
forState:UIControlStateNormal];
[_removeAccountButton addTarget:self
action:@selector(didTapRemoveAccount:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_removeAccountButton];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
CGRect bounds = self.view.bounds;
[_removeAccountButton
setCenter:CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))];
[_removeAccountButton sizeToFit];
}
- (void)didTapRemoveAccount:(id)sender {
ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
->ForgetIdentity(_identity, ^(NSError*) {
[self dismissViewControllerAnimated:YES completion:nil];
});
}
@end
namespace ios {
NSString* const kIdentityEmailFormat = @"%@@foo.com";
NSString* const kIdentityGaiaIDFormat = @"%@ID";
FakeChromeIdentityService::FakeChromeIdentityService()
: identities_([[NSMutableArray alloc] init]), _fakeMDMError(false) {}
FakeChromeIdentityService::~FakeChromeIdentityService() {}
// static
FakeChromeIdentityService*
FakeChromeIdentityService::GetInstanceFromChromeProvider() {
return static_cast<ios::FakeChromeIdentityService*>(
ios::GetChromeBrowserProvider()->GetChromeIdentityService());
}
UINavigationController*
FakeChromeIdentityService::CreateAccountDetailsController(
ChromeIdentity* identity,
id<ChromeIdentityBrowserOpener> browser_opener) {
UIViewController* accountDetailsViewController =
[[FakeAccountDetailsViewController alloc] initWithIdentity:identity];
UINavigationController* navigationController = [[UINavigationController alloc]
initWithRootViewController:accountDetailsViewController];
return navigationController;
}
ChromeIdentityInteractionManager*
FakeChromeIdentityService::CreateChromeIdentityInteractionManager(
ios::ChromeBrowserState* browser_state,
id<ChromeIdentityInteractionManagerDelegate> delegate) const {
ChromeIdentityInteractionManager* manager =
[[FakeChromeIdentityInteractionManager alloc] init];
manager.delegate = delegate;
return manager;
}
bool FakeChromeIdentityService::IsValidIdentity(
ChromeIdentity* identity) const {
return [identities_ indexOfObject:identity] != NSNotFound;
}
ChromeIdentity* FakeChromeIdentityService::GetIdentityWithGaiaID(
const std::string& gaia_id) const {
NSString* gaiaID = base::SysUTF8ToNSString(gaia_id);
NSUInteger index =
[identities_ indexOfObjectPassingTest:^BOOL(ChromeIdentity* obj,
NSUInteger, BOOL* stop) {
return [[obj gaiaID] isEqualToString:gaiaID];
}];
if (index == NSNotFound) {
return nil;
}
return [identities_ objectAtIndex:index];
}
bool FakeChromeIdentityService::HasIdentities() const {
return [identities_ count] > 0;
}
NSArray* FakeChromeIdentityService::GetAllIdentities() const {
return identities_;
}
NSArray* FakeChromeIdentityService::GetAllIdentitiesSortedForDisplay() const {
return identities_;
}
void FakeChromeIdentityService::ForgetIdentity(
ChromeIdentity* identity,
ForgetIdentityCallback callback) {
[identities_ removeObject:identity];
FireIdentityListChanged();
if (callback) {
// Forgetting an identity is normally an asynchronous operation (that
// require some network calls), this is replicated here by dispatching
// it.
dispatch_async(dispatch_get_main_queue(), ^{
callback(nil);
});
}
}
void FakeChromeIdentityService::GetAccessToken(
ChromeIdentity* identity,
const std::string& client_id,
const std::string& client_secret,
const std::set<std::string>& scopes,
ios::AccessTokenCallback callback) {
ios::AccessTokenCallback safe_callback = [callback copy];
NSError* error = nil;
NSDictionary* user_info = nil;
if (_fakeMDMError) {
// |GetAccessToken| is normally an asynchronous operation (that requires
// some network calls), this is replicated here by dispatching it.
error =
[NSError errorWithDomain:@"com.google.HTTPStatus" code:-1 userInfo:nil];
user_info = @{};
EXPECT_CALL(*this, HandleMDMNotification(identity, user_info, _))
.WillRepeatedly(testing::Return(true));
}
// |GetAccessToken| is normally an asynchronous operation (that requires some
// network calls), this is replicated here by dispatching it.
dispatch_async(dispatch_get_main_queue(), ^{
if (user_info)
FireAccessTokenRefreshFailed(identity, user_info);
// Token and expiration date. It should be larger than typical test
// execution because tests usually setup mock to expect one token request
// and then rely on access token being served from cache.
NSTimeInterval expiration = 60.0;
NSDate* expiresDate = [NSDate dateWithTimeIntervalSinceNow:expiration];
NSString* token = [expiresDate description];
safe_callback(token, expiresDate, error);
});
}
UIImage* FakeChromeIdentityService::GetCachedAvatarForIdentity(
ChromeIdentity* identity) {
return FakeGetCachedAvatarForIdentity(identity);
}
void FakeChromeIdentityService::GetAvatarForIdentity(
ChromeIdentity* identity,
GetAvatarCallback callback) {
FakeGetAvatarForIdentity(identity, callback);
}
void FakeChromeIdentityService::GetHostedDomainForIdentity(
ChromeIdentity* identity,
GetHostedDomainCallback callback) {
FakeGetHostedDomainForIdentity(identity, callback);
}
void FakeChromeIdentityService::SetUpForIntegrationTests() {}
void FakeChromeIdentityService::AddIdentities(NSArray* identitiesNames) {
for (NSString* name in identitiesNames) {
NSString* email = [NSString stringWithFormat:kIdentityEmailFormat, name];
NSString* gaiaID = [NSString stringWithFormat:kIdentityGaiaIDFormat, name];
[identities_ addObject:[FakeChromeIdentity identityWithEmail:email
gaiaID:gaiaID
name:name]];
}
}
void FakeChromeIdentityService::AddIdentity(ChromeIdentity* identity) {
[identities_ addObject:identity];
FireIdentityListChanged();
}
void FakeChromeIdentityService::RemoveIdentity(ChromeIdentity* identity) {
if ([identities_ indexOfObject:identity] != NSNotFound) {
[identities_ removeObject:identity];
FireIdentityListChanged();
}
}
void FakeChromeIdentityService::SetFakeMDMError(bool fakeMDMError) {
_fakeMDMError = fakeMDMError;
}
} // namespace ios