| // 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 |