mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
* Remove one more umbrella header import in Auth Tests * Add -ObjC for Auth Mac * Scheme cleanups * Make sure the FirebaseAuth framework gets linked for tvOS
2609 lines
131 KiB
Objective-C
2609 lines
131 KiB
Objective-C
/*
|
|
* Copyright 2017 Google
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
#import "FIRAdditionalUserInfo_Internal.h"
|
|
#import "FIRAuth_Internal.h"
|
|
#import "FIRAuthErrorUtils.h"
|
|
#import "FIRAuthBackend.h"
|
|
#import "FIRAuthGlobalWorkQueue.h"
|
|
#import "FIRAuthOperationType.h"
|
|
#import "FIRAuthTokenResult.h"
|
|
#import "FIREmailAuthProvider.h"
|
|
#import "FIREmailLinkSignInResponse.h"
|
|
#import "FIRFacebookAuthProvider.h"
|
|
#import "FIRGetAccountInfoRequest.h"
|
|
#import "FIRGetAccountInfoResponse.h"
|
|
#import "FIRGoogleAuthProvider.h"
|
|
#import "FIRSecureTokenService.h"
|
|
#import "FIRSecureTokenRequest.h"
|
|
#import "FIRSecureTokenResponse.h"
|
|
#import "FIRSetAccountInfoRequest.h"
|
|
#import "FIRSetAccountInfoResponse.h"
|
|
#import "FIRSignUpNewUserResponse.h"
|
|
#import "FIRUser_Internal.h"
|
|
#import "FIRUserInfo.h"
|
|
#import "FIRUserMetadata.h"
|
|
#import "FIRVerifyAssertionResponse.h"
|
|
#import "FIRVerifyAssertionRequest.h"
|
|
#import "FIRVerifyPasswordRequest.h"
|
|
#import "FIRVerifyPasswordResponse.h"
|
|
#import "FIRVerifyPhoneNumberRequest.h"
|
|
#import "FIRVerifyPhoneNumberResponse.h"
|
|
#import "FIRApp+FIRAuthUnitTests.h"
|
|
#import "OCMStubRecorder+FIRAuthUnitTests.h"
|
|
#import <OCMock/OCMock.h>
|
|
|
|
#if TARGET_OS_IOS
|
|
#import "Phone/FIRPhoneAuthCredential_Internal.h"
|
|
#import "FIRPhoneAuthProvider.h"
|
|
#endif
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
/** @var kAPIKey
|
|
@brief The fake API key.
|
|
*/
|
|
static NSString *const kAPIKey = @"FAKE_API_KEY";
|
|
|
|
/** @var kAccessToken
|
|
@brief The fake access token.
|
|
*/
|
|
static NSString *const kAccessToken = @"eyJhbGciOimnuzI1NiIsImtpZCI6ImY1YjE4Mjc2YTQ4NjYxZDBhODBiYzh"
|
|
"jM2U5NDM0OTc0ZDFmMWRiNTEifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vZmItc2EtdXBncm"
|
|
"FkZWQiLCJhdWQiOiJ0ZXN0X2F1ZCIsImF1dGhfdGltZSI6MTUyMjM2MDU0OSwidXNlcl9pZCI6InRlc3RfdXNlcl9pZCIs"
|
|
"InN1YiI6InRlc3Rfc3ViIiwiaWF0IjoxNTIyMzYwNTU3LCJleHAiOjE1MjIzNjQxNTcsImVtYWlsIjoiYXVuaXRlc3R1c2"
|
|
"VyQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6"
|
|
"WyJhdW5pdGVzdHVzZXJAZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0=.WFQqSrpVnxx7m"
|
|
"UrdKZA517Sp4ZBt-l2xQzGKNMVE90JB3vuNa-NyWZC-aTYMvND3-4aS3qRnN2kvk9KJAaF3eI_BKkcbZuq8O7iDVpOvqKC"
|
|
"3QcW0PnwqSPChL3XqoDF322FcBEgemwwgaEVZMuo7GhJvHw-XtBt1KRXOoGHcr3P6RsvoulUouKQmqt6TP27eZtrgH7jjN"
|
|
"hHm7gjX_WaRmgTOvYsuDbBBGdE15yIVZ3acI4cFUgwMRhaW-dDV7jTOqZGYJlTsI5oRMehphoVnYnEedJga28r4mqVkPbW"
|
|
"lddL4dVVm85FYmQcRc0b2CLMnSevBDlwu754ZUZmRgnuvDA";
|
|
|
|
/** @var kAccessTokenWithBase64URLCharacters
|
|
@brief The fake access where the AUD value is "??????????>>>>>>>>>>" and the email value is
|
|
">>>>>>>>????????@gmail.com".
|
|
*/
|
|
static NSString *const kAccessTokenWithBase64URLCharacter = @"ey?hbGciOimnuzI1NiIsImtpZCI6ImY1YjE4M"
|
|
"jc2YTQ4NjYxZDBhODBiYzhjM2U5NDM0OTc0ZDFmMWRiNTEifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2ds"
|
|
"ZS5jb20vZmItc2EtdXBncmFkZWQiLCJhdWQiOiI_Pz8_Pz8_Pz8_Pj4-Pj4-Pj4-PiIsImF1dGhfdGltZSI6MTUyMjM2MD"
|
|
"U0OSwidXNlcl9pZCI6InRlc3RfdXNlcl9pZCIsInN1YiI6InRlc3Rfc3ViIiwiaWF0IjoxNTIyMzYwNTU3LCJleHAiOjE1"
|
|
"MjIzNjQxNTcsImVtYWlsIjoiPj4-Pj4-Pj4_Pz8_Pz8_P0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm"
|
|
"ZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiYXVuaXRlc3R1c2VyQGdtYWlsLmNvbSJdfSwic2lnbl9pbl9w"
|
|
"cm92aWRlciI6IlBhc3N3b3JkIn19.WFQqSrpVnxx7mUrdKZA517Sp4ZBt-l2xQzGKNMVE90JB3vuNa-NyWZC-aTYMvND3-"
|
|
"4aS3qRnN2kvk9KJAaF3eI_BKkcbZuq8O7iDVpOvqKC3QcW0PnwqSPChL3XqoDF322FcBEgemwwgaEVZMuo7GhJvHw-XtBt"
|
|
"1KRXOoGHcr3P6RsvoulUouKQmqt6TP27eZtrgH7jjNhHm7gjX_WaRmgTOvYsuDbBBGdE15yIVZ3acI4cFUgwMRhaW-dDV7"
|
|
"jTOqZGYJlTsI5oRMehphoVnYnEedJga28r4mqVkPbWlddL4dVVm85FYmQcRc0b2CLMnSevBDlwu754ZUZmRgnuvDA";
|
|
|
|
/** @var kbase64URLEncodedEmail
|
|
@brief The fake email address with a value containing non-valid base64 encoded characters.
|
|
@remarks This is used to ensure that the token parser is able to handle base64 URL enconded
|
|
strings.
|
|
*/
|
|
static NSString *const kbase64URLEncodedEmail = @">>>>>>>>????????@gmail.com";
|
|
|
|
/** @var kbase64URLEncodedAUD
|
|
@brief The fake AUD with a value containing non-valid base64 encoded characters.
|
|
@remarks This is used to ensure that the token parser is able to handle base64 URL enconded
|
|
strings.
|
|
*/
|
|
static NSString *const kbase64URLEncodedAUD = @"??????????>>>>>>>>>>";
|
|
|
|
/** @var kAccessTokenLength415
|
|
@brief The fake access token with 415 characters in the claims potion of the token.
|
|
*/
|
|
static NSString *const kAccessTokenLength415 = @"eyJhbGciOimnuzI1NiIsImtpZCI6ImY1YjE4Mjc2YTQ4NjYxZD"
|
|
"BhODBiYzhjM2U5NDM0OTc0ZDFmMWRiNTEifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vdGVzd"
|
|
"CIsImF1ZCI6InRlc3RfYXVkIiwiYXV0aF90aW1lIjoxNTIyMzYwNTQ5LCJ1c2VyX2lkIjoidGVzdF91c2VyX2lkIiwic3V"
|
|
"iIjoidGVzdF9zdWIiLCJpYXQiOjE1MjIzNjA1NTcsImV4cCI6MTUyMjM2NDE1NywiZW1haWwiOiJhdW5pdGVzdHVzZXJAZ"
|
|
"21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7ImVtYWlsIjpbImF"
|
|
"1bml0ZXN0dXNlckBnbWFpbC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ=.WFQqSrpVnxx7m"
|
|
"UrdKZA517Sp4ZBt-l2xQzGKNMVE90JB3vuNa-NyWZC-aTYMvND3-4aS3qRnN2kvk9KJAaF3eI_BKkcbZuq8O7iDVpOvqKC"
|
|
"3QcW0PnwqSPChL3XqoDF322FcBEgemwwgaEVZMuo7GhJvHw-XtBt1KRXOoGHcr3P6RsvoulUouKQmqt6TP27eZtrgH7jjN"
|
|
"hHm7gjX_WaRmgTOvYsuDbBBGdE15yIVZ3acI4cFUgwMRhaW-dDV7jTOqZGYJlTsI5oRMehphoVnYnEedJga28r4mqVkPbW"
|
|
"lddL4dVVm85FYmQcRc0b2CLMnSevBDlwu754ZUZmRgnuvDA";
|
|
|
|
/** @var kAccessTokenLength416
|
|
@brief The fake access token with 416 characters in the claims potion of the token.
|
|
*/
|
|
static NSString *const kAccessTokenLength416 = @"eyJhbGciOimnuzI1NiIsImtpZCI6ImY1YjE4Mjc2YTQ4NjYxZD"
|
|
"BhODBiYzhjM2U5NDM0OTc0ZDFmMWRiNTEifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vdGVzd"
|
|
"DIiLCJhdWQiOiJ0ZXN0X2F1ZCIsImF1dGhfdGltZSI6MTUyMjM2MDU0OSwidXNlcl9pZCI6InRlc3RfdXNlcl9pZCIsInN"
|
|
"1YiI6InRlc3Rfc3ViIiwiaWF0IjoxNTIyMzYwNTU3LCJleHAiOjE1MjIzNjQxNTcsImVtYWlsIjoiYXVuaXRlc3R1c2VyQ"
|
|
"GdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJ"
|
|
"hdW5pdGVzdHVzZXJAZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0=.WFQqSrpVnxx7m"
|
|
"UrdKZA517Sp4ZBt-l2xQzGKNMVE90JB3vuNa-NyWZC-aTYMvND3-4aS3qRnN2kvk9KJAaF3eI_BKkcbZuq8O7iDVpOvqKC"
|
|
"3QcW0PnwqSPChL3XqoDF322FcBEgemwwgaEVZMuo7GhJvHw-XtBt1KRXOoGHcr3P6RsvoulUouKQmqt6TP27eZtrgH7jjN"
|
|
"hHm7gjX_WaRmgTOvYsuDbBBGdE15yIVZ3acI4cFUgwMRhaW-dDV7jTOqZGYJlTsI5oRMehphoVnYnEedJga28r4mqVkPbW"
|
|
"lddL4dVVm85FYmQcRc0b2CLMnSevBDlwu754ZUZmRgnuvDA";
|
|
|
|
/** @var kAccessTokenLength4523
|
|
@brief The fake access token with 523 characters in the claims potion of the token.
|
|
*/
|
|
static NSString *const kAccessTokenLength523 = @"eyJhbGciOimnuzI1NiIsImtpZCI6ImY1YjE4Mjc2YTQ4NjYxZD"
|
|
"BhODBiYzhjM2U5NDM0OTc0ZDFmMWRiNTEifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vdGVzd"
|
|
"DQiLCJhdWQiOiJ0ZXN0X2F1ZCIsImF1dGhfdGltZSI6MTUyMjM2MDU0OSwidXNlcl9pZCI6InRlc3RfdXNlcl9pZF81NDM"
|
|
"yIiwic3ViIjoidGVzdF9zdWIiLCJpYXQiOjE1MjIzNjA1NTcsImV4cCI6MTUyMjM2NDE1OSwiZW1haWwiOiJhdW5pdGVzd"
|
|
"HVzZXI0QGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7ImVtYWl"
|
|
"sIjpbImF1bml0ZXN0dXNlckBnbWFpbC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ=.WFQqSrpVn"
|
|
"xx7mUrdKZA517Sp4ZBt-l2xQzGKNMVE90JB3vuNa-NyWZC-aTYMvND3-4aS3qRnN2kvk9KJAaF3eI_BKkcbZuq8O7iDVpO"
|
|
"vqKC3QcW0PnwqSPChL3XqoDF322FcBEgemwwgaEVZMuo7GhJvHw-XtBt1KRXOoGHcr3P6RsvoulUouKQmqt6TP27eZtrgH"
|
|
"7jjNhHm7gjX_WaRmgTOvYsuDbBBGdE15yIVZ3acI4cFUgwMRhaW-dDV7jTOqZGYJlTsI5oRMehphoVnYnEedJga28r4mqV"
|
|
"kPbWlddL4dVVm85FYmQcRc0b2CLMnSevBDlwu754ZUZmRgnuvDA";
|
|
|
|
/** @var kNewAccessToken
|
|
@brief A new value for the fake access token.
|
|
*/
|
|
static NSString *const kNewAccessToken = @"NEW_ACCESS_TOKEN";
|
|
|
|
/** @var kAccessTokenValidInterval
|
|
@brief The time to live for the fake access token.
|
|
*/
|
|
static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
|
|
|
|
/** @var kRefreshToken
|
|
@brief The fake refresh token.
|
|
*/
|
|
static NSString *const kRefreshToken = @"REFRESH_TOKEN";
|
|
|
|
/** @var kLocalID
|
|
@brief The fake local user ID.
|
|
*/
|
|
static NSString *const kLocalID = @"LOCAL_ID";
|
|
|
|
/** @var kAnotherLocalID
|
|
@brief The fake local ID of another user.
|
|
*/
|
|
static NSString *const kAnotherLocalID = @"ANOTHER_LOCAL_ID";
|
|
|
|
/** @var kGoogleIDToken
|
|
@brief The fake ID token from Google Sign-In.
|
|
*/
|
|
static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
|
|
|
|
/** @var kFacebookIDToken
|
|
@brief The fake ID token from Facebook Sign-In. Facebook provider ID token is always nil.
|
|
*/
|
|
static NSString *const kFacebookIDToken = nil;
|
|
|
|
/** @var kGoogleAccessToken
|
|
@brief The fake access token from Google Sign-In.
|
|
*/
|
|
static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
|
|
|
|
/** @var kFacebookAccessToken
|
|
@brief The fake access token from Facebook Sign-In.
|
|
*/
|
|
static NSString *const kFacebookAccessToken = @"FACEBOOK_ACCESS_TOKEN";
|
|
|
|
/** @var kEmail
|
|
@brief The fake user email.
|
|
*/
|
|
static NSString *const kEmail = @"user@company.com";
|
|
|
|
/** @var kPhoneNumber
|
|
@brief The fake user phone number.
|
|
*/
|
|
static NSString *const kPhoneNumber = @"12345658";
|
|
|
|
/** @var kTemporaryProof
|
|
@brief The fake temporary proof.
|
|
*/
|
|
static NSString *const kTemporaryProof = @"12345658";
|
|
|
|
/** @var kNewEmail
|
|
@brief A new value for the fake user email.
|
|
*/
|
|
static NSString *const kNewEmail = @"newuser@company.com";
|
|
|
|
/** @var kUserName
|
|
@brief The fake user name.
|
|
*/
|
|
static NSString *const kUserName = @"User Doe";
|
|
|
|
/** @var kNewDisplayName
|
|
@brief A new value for the fake user display name.
|
|
*/
|
|
static NSString *const kNewDisplayName = @"New User Doe";
|
|
|
|
/** @var kPhotoURL
|
|
@brief The fake user profile image URL string.
|
|
*/
|
|
static NSString *const kPhotoURL = @"https://host.domain/image";
|
|
|
|
/** @var kNewPhotoURL
|
|
@brief A new value for the fake user profile image URL string..
|
|
*/
|
|
static NSString *const kNewPhotoURL = @"https://host.domain/new/image";
|
|
|
|
/** @var kFakePassword
|
|
@brief The fake user password.
|
|
*/
|
|
static NSString *const kFakePassword = @"123456";
|
|
|
|
/** @var kNewPassword
|
|
@brief The fake new user password.
|
|
*/
|
|
static NSString *const kNewPassword = @"1234567";
|
|
|
|
/** @var kPasswordHash
|
|
@brief The fake user password hash.
|
|
*/
|
|
static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
|
|
|
|
/** @var kGoogleUD
|
|
@brief The fake user ID under Google Sign-In.
|
|
*/
|
|
static NSString *const kGoogleID = @"GOOGLE_ID";
|
|
|
|
/** @var kGoogleEmail
|
|
@brief The fake user email under Google Sign-In.
|
|
*/
|
|
static NSString *const kGoogleEmail = @"user@gmail.com";
|
|
|
|
/** @var kGoogleDisplayName
|
|
@brief The fake user display name under Google Sign-In.
|
|
*/
|
|
static NSString *const kGoogleDisplayName = @"Google Doe";
|
|
|
|
/** @var kEmailDisplayName
|
|
@brief The fake user display name for email password user.
|
|
*/
|
|
static NSString *const kEmailDisplayName = @"Email Doe";
|
|
|
|
/** @var kFacebookDisplayName
|
|
@brief The fake user display name under Facebook Sign-In.
|
|
*/
|
|
static NSString *const kFacebookDisplayName = @"Facebook Doe";
|
|
|
|
/** @var kGooglePhotoURL
|
|
@brief The fake user profile image URL string under Google Sign-In.
|
|
*/
|
|
static NSString *const kGooglePhotoURL = @"https://googleusercontents.com/user/profile";
|
|
|
|
/** @var kFacebookID
|
|
@brief The fake user ID under Facebook Login.
|
|
*/
|
|
static NSString *const kFacebookID = @"FACEBOOK_ID";
|
|
|
|
/** @var kFacebookEmail
|
|
@brief The fake user email under Facebook Login.
|
|
*/
|
|
static NSString *const kFacebookEmail = @"user@facebook.com";
|
|
|
|
/** @var kVerificationCode
|
|
@brief Fake verification code used for testing.
|
|
*/
|
|
static NSString *const kVerificationCode = @"12345678";
|
|
|
|
/** @var kVerificationID
|
|
@brief Fake verification ID for testing.
|
|
*/
|
|
static NSString *const kVerificationID = @"55432";
|
|
|
|
/** @var kUserArchiverKey
|
|
@brief The key used to archive and unarchive the user object for test NSSecureCoding.
|
|
*/
|
|
static NSString *const kUserArchiverKey = @"userArchiverKey";
|
|
|
|
/** @var kCreationDateInSeconds
|
|
@brief The fake creation date.
|
|
*/
|
|
static NSTimeInterval const kCreationDateTimeIntervalInSeconds = 1505858500;
|
|
|
|
/** @var kLastSignInDateTimeIntervalInSeconds
|
|
@brief The fake last sign in date date.
|
|
*/
|
|
static NSTimeInterval const kLastSignInDateTimeIntervalInSeconds = 1505858583;
|
|
|
|
/** @var kExpectationTimeout
|
|
@brief The maximum time waiting for expectations to fulfill.
|
|
*/
|
|
static const NSTimeInterval kExpectationTimeout = 2;
|
|
|
|
/** @extention FIRSecureTokenService
|
|
@brief Extends the FIRSecureTokenService class to expose one private method for testing only.
|
|
*/
|
|
@interface FIRSecureTokenService ()
|
|
|
|
/** @fn hasValidAccessToken
|
|
@brief private method exposed so it can be mocked to prevent the fake expiration date from
|
|
affecting the the unit tests.
|
|
*/
|
|
- (BOOL)hasValidAccessToken;
|
|
@end
|
|
|
|
/** @class FIRUserTests
|
|
@brief Tests for @c FIRUser .
|
|
*/
|
|
@interface FIRUserTests : XCTestCase
|
|
@end
|
|
@implementation FIRUserTests {
|
|
|
|
/** @var _mockBackend
|
|
@brief The mock @c FIRAuthBackendImplementation .
|
|
*/
|
|
id _mockBackend;
|
|
}
|
|
|
|
/** @fn googleProfile
|
|
@brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
|
|
*/
|
|
+ (NSDictionary *)googleProfile {
|
|
static NSDictionary *kGoogleProfile = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
kGoogleProfile = @{
|
|
@"email": kGoogleEmail,
|
|
@"given_name": @"User",
|
|
@"family_name": @"Doe"
|
|
};
|
|
});
|
|
return kGoogleProfile;
|
|
}
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
_mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
|
|
[FIRAuthBackend setBackendImplementation:_mockBackend];
|
|
[FIRApp resetAppForAuthUnitTests];
|
|
}
|
|
|
|
- (void)tearDown {
|
|
[FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
|
|
[super tearDown];
|
|
}
|
|
|
|
#pragma mark - Tests
|
|
|
|
/** @fn testUserPropertiesAndNSSecureCoding
|
|
@brief Tests properties of the @c FIRUser instance before and after being
|
|
serialized/deserialized.
|
|
*/
|
|
- (void)testUserPropertiesAndNSSecureCoding {
|
|
// Mock auth provider user info for email/password for GetAccountInfo.
|
|
id mockPasswordUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
|
|
OCMStub([mockPasswordUserInfo providerID]).andReturn(FIREmailAuthProviderID);
|
|
OCMStub([mockPasswordUserInfo federatedID]).andReturn(kEmail);
|
|
OCMStub([mockPasswordUserInfo email]).andReturn(kEmail);
|
|
|
|
// Mock auth provider user info from Google for GetAccountInfo.
|
|
id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
|
|
OCMStub([mockGoogleUserInfo providerID]).andReturn(FIRGoogleAuthProviderID);
|
|
OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGoogleUserInfo photoURL]).andReturn([NSURL URLWithString:kGooglePhotoURL]);
|
|
OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
|
|
OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
|
|
|
|
// Mock auth provider user info from Facebook for GetAccountInfo.
|
|
id mockFacebookUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
|
|
OCMStub([mockFacebookUserInfo providerID]).andReturn(FIRFacebookAuthProviderID);
|
|
OCMStub([mockFacebookUserInfo federatedID]).andReturn(kFacebookID);
|
|
OCMStub([mockFacebookUserInfo email]).andReturn(kFacebookEmail);
|
|
|
|
#if TARGET_OS_IOS
|
|
// Mock auth provider user info from Phone auth provider for GetAccountInfo.
|
|
id mockPhoneUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
|
|
OCMStub([mockPhoneUserInfo providerID]).andReturn(FIRPhoneAuthProviderID);
|
|
OCMStub([mockPhoneUserInfo phoneNumber]).andReturn(kPhoneNumber);
|
|
#endif
|
|
|
|
// Mock the root user info object for GetAccountInfo.
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser emailVerified]).andReturn(YES);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser photoURL]).andReturn([NSURL URLWithString:kPhotoURL]);
|
|
OCMStub([mockGetAccountInfoResponseUser creationDate]).
|
|
andReturn([NSDate dateWithTimeIntervalSince1970:kCreationDateTimeIntervalInSeconds]);
|
|
OCMStub([mockGetAccountInfoResponseUser lastLoginDate]).
|
|
andReturn([NSDate dateWithTimeIntervalSince1970:kLastSignInDateTimeIntervalInSeconds]);
|
|
NSArray *providerUserInfos = @[
|
|
#if TARGET_OS_IOS
|
|
mockPhoneUserInfo,
|
|
#endif
|
|
mockPasswordUserInfo,
|
|
mockGoogleUserInfo,
|
|
mockFacebookUserInfo
|
|
];
|
|
OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(providerUserInfos);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
// Verify FIRUserInfo properties on FIRUser itself.
|
|
XCTAssertEqualObjects(user.providerID, @"Firebase");
|
|
XCTAssertEqualObjects(user.uid, kLocalID);
|
|
XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
|
|
XCTAssertEqualObjects(user.photoURL, [NSURL URLWithString:kPhotoURL]);
|
|
XCTAssertEqualObjects(user.email, kEmail);
|
|
XCTAssertEqualObjects(user.metadata.creationDate,
|
|
[NSDate dateWithTimeIntervalSince1970:kCreationDateTimeIntervalInSeconds]);
|
|
XCTAssertEqualObjects(user.metadata.lastSignInDate,
|
|
[NSDate dateWithTimeIntervalSince1970:kLastSignInDateTimeIntervalInSeconds]);
|
|
|
|
// Verify FIRUser properties besides providerData contents.
|
|
XCTAssertFalse(user.anonymous);
|
|
XCTAssertTrue(user.emailVerified);
|
|
XCTAssertEqualObjects(user.refreshToken, kRefreshToken);
|
|
XCTAssertEqual(user.providerData.count, providerUserInfos.count);
|
|
|
|
NSDictionary<NSString *, id<FIRUserInfo>> *providerMap =
|
|
[self dictionaryWithUserInfoArray:user.providerData];
|
|
|
|
// Verify FIRUserInfo properties from email/password.
|
|
id<FIRUserInfo> passwordUserInfo = providerMap[FIREmailAuthProviderID];
|
|
XCTAssertEqualObjects(passwordUserInfo.uid, kEmail);
|
|
XCTAssertNil(passwordUserInfo.displayName);
|
|
XCTAssertNil(passwordUserInfo.photoURL);
|
|
XCTAssertEqualObjects(passwordUserInfo.email, kEmail);
|
|
|
|
// Verify FIRUserInfo properties from the Google auth provider.
|
|
id<FIRUserInfo> googleUserInfo = providerMap[FIRGoogleAuthProviderID];
|
|
XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
|
|
XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
|
|
XCTAssertEqualObjects(googleUserInfo.photoURL, [NSURL URLWithString:kGooglePhotoURL]);
|
|
XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
|
|
|
|
// Verify FIRUserInfo properties from the Facebook auth provider.
|
|
id<FIRUserInfo> facebookUserInfo = providerMap[FIRFacebookAuthProviderID];
|
|
XCTAssertEqualObjects(facebookUserInfo.uid, kFacebookID);
|
|
XCTAssertNil(facebookUserInfo.displayName);
|
|
XCTAssertNil(facebookUserInfo.photoURL);
|
|
XCTAssertEqualObjects(facebookUserInfo.email, kFacebookEmail);
|
|
|
|
#if TARGET_OS_IOS
|
|
// Verify FIRUserInfo properties from the phone auth provider.
|
|
id<FIRUserInfo> phoneUserInfo = providerMap[FIRPhoneAuthProviderID];
|
|
XCTAssertEqualObjects(phoneUserInfo.phoneNumber, kPhoneNumber);
|
|
#endif
|
|
|
|
// Test NSSecureCoding
|
|
XCTAssertTrue([FIRUser supportsSecureCoding]);
|
|
NSMutableData *data = [NSMutableData data];
|
|
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
|
[archiver encodeObject:user forKey:kUserArchiverKey];
|
|
[archiver finishEncoding];
|
|
|
|
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
|
FIRUser *unarchivedUser = [unarchiver decodeObjectForKey:kUserArchiverKey];
|
|
|
|
// Verify NSSecureCoding for FIRUser
|
|
XCTAssertEqualObjects(unarchivedUser.providerID, user.providerID);
|
|
XCTAssertEqualObjects(unarchivedUser.uid, user.uid);
|
|
XCTAssertEqualObjects(unarchivedUser.email, user.email);
|
|
XCTAssertEqualObjects(unarchivedUser.photoURL, user.photoURL);
|
|
XCTAssertEqualObjects(unarchivedUser.displayName, user.displayName);
|
|
|
|
// Verify NSSecureCoding properties besides providerData contents.
|
|
XCTAssertEqual(unarchivedUser.anonymous, user.anonymous);
|
|
XCTAssertEqual(unarchivedUser.emailVerified, user.emailVerified);
|
|
XCTAssertEqualObjects(unarchivedUser.refreshToken, user.refreshToken);
|
|
XCTAssertEqualObjects(unarchivedUser.metadata.creationDate, user.metadata.creationDate);
|
|
XCTAssertEqualObjects(unarchivedUser.metadata.lastSignInDate, user.metadata.lastSignInDate);
|
|
XCTAssertEqual(unarchivedUser.providerData.count, user.providerData.count);
|
|
|
|
NSDictionary<NSString *, id<FIRUserInfo>> *unarchivedProviderMap =
|
|
[self dictionaryWithUserInfoArray:unarchivedUser.providerData];
|
|
|
|
// Verify NSSecureCoding properties from email/password.
|
|
id<FIRUserInfo> unarchivedPasswordUserInfo = unarchivedProviderMap[FIREmailAuthProviderID];
|
|
XCTAssertEqualObjects(unarchivedPasswordUserInfo.uid, passwordUserInfo.uid);
|
|
XCTAssertEqualObjects(unarchivedPasswordUserInfo.displayName, passwordUserInfo.displayName);
|
|
XCTAssertEqualObjects(unarchivedPasswordUserInfo.photoURL, passwordUserInfo.photoURL);
|
|
XCTAssertEqualObjects(unarchivedPasswordUserInfo.email, passwordUserInfo.email);
|
|
|
|
// Verify NSSecureCoding properties from the Google auth provider.
|
|
id<FIRUserInfo> unarchivedGoogleUserInfo = unarchivedProviderMap[FIRGoogleAuthProviderID];
|
|
XCTAssertEqualObjects(unarchivedGoogleUserInfo.uid, googleUserInfo.uid);
|
|
XCTAssertEqualObjects(unarchivedGoogleUserInfo.displayName, googleUserInfo.displayName);
|
|
XCTAssertEqualObjects(unarchivedGoogleUserInfo.photoURL, googleUserInfo.photoURL);
|
|
XCTAssertEqualObjects(unarchivedGoogleUserInfo.email, googleUserInfo.email);
|
|
|
|
// Verify NSSecureCoding properties from the Facebook auth provider.
|
|
id<FIRUserInfo> unarchivedFacebookUserInfo = unarchivedProviderMap[FIRFacebookAuthProviderID];
|
|
XCTAssertEqualObjects(unarchivedFacebookUserInfo.uid, facebookUserInfo.uid);
|
|
XCTAssertEqualObjects(unarchivedFacebookUserInfo.displayName, facebookUserInfo.displayName);
|
|
XCTAssertEqualObjects(unarchivedFacebookUserInfo.photoURL, facebookUserInfo.photoURL);
|
|
XCTAssertEqualObjects(unarchivedFacebookUserInfo.email, facebookUserInfo.email);
|
|
|
|
#if TARGET_OS_IOS
|
|
// Verify FIRUserInfo properties from the phone auth provider.
|
|
id<FIRUserInfo> unarchivedPhoneUserInfo = unarchivedProviderMap[FIRPhoneAuthProviderID];
|
|
XCTAssertEqualObjects(unarchivedPhoneUserInfo.phoneNumber, phoneUserInfo.phoneNumber);
|
|
#endif
|
|
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdateEmailSuccess
|
|
@brief Tests the flow of a successful @c updateEmail:completion: call.
|
|
*/
|
|
- (void)testUpdateEmailSuccess {
|
|
id (^mockUserInfoWithDisplayName)(NSString *) = ^(NSString *displayName) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithDisplayName(kGoogleDisplayName);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
// Pretend that the display name on the server has been changed since last request.
|
|
[self
|
|
expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoWithDisplayName(kNewDisplayName)];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertEqualObjects(request.email, kNewEmail);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.displayName);
|
|
XCTAssertNil(request.photoURL);
|
|
XCTAssertNil(request.password);
|
|
XCTAssertNil(request.providers);
|
|
XCTAssertNil(request.deleteAttributes);
|
|
XCTAssertNil(request.deleteProviders);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
OCMStub([mockSetAccountInfoResponse email]).andReturn(kNewEmail);
|
|
OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
[user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(user.email, kNewEmail);
|
|
XCTAssertEqualObjects(user.displayName, kNewDisplayName);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdateEmailWithAuthLinkAccountSuccess
|
|
@brief Tests a successful @c updateEmail:completion: call updates provider info.
|
|
*/
|
|
- (void)testUpdateEmailWithAuthLinkAccountSuccess {
|
|
id (^mockUserInfoWithDisplayName)(NSString *) = ^(NSString *displayName) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithDisplayName(kGoogleDisplayName);
|
|
[self signInWithEmailLinkWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
// Pretend that the display name on the server has been changed since last request.
|
|
[self
|
|
expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoWithDisplayName(kNewDisplayName)];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertEqualObjects(request.email, kNewEmail);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.displayName);
|
|
XCTAssertNil(request.photoURL);
|
|
XCTAssertNil(request.password);
|
|
XCTAssertNil(request.providers);
|
|
XCTAssertNil(request.deleteAttributes);
|
|
XCTAssertNil(request.deleteProviders);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
OCMStub([mockSetAccountInfoResponse email]).andReturn(kNewEmail);
|
|
OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
[user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(user.email, kNewEmail);
|
|
XCTAssertEqualObjects(user.displayName, kNewDisplayName);
|
|
XCTAssertFalse(user.isAnonymous);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdateEmailFailure
|
|
@brief Tests the flow of a failed @c updateEmail:completion: call.
|
|
*/
|
|
- (void)testUpdateEmailFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils invalidEmailErrorWithMessage:nil]);
|
|
[user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidEmail);
|
|
// Email should not have changed on the client side.
|
|
XCTAssertEqualObjects(user.email, kEmail);
|
|
// User is still signed in.
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdateEmailAutoSignOut
|
|
@brief Tests the flow of a failed @c updateEmail:completion: call that automatically signs out.
|
|
*/
|
|
- (void)testUpdateEmailAutoSignOut {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]);
|
|
[user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidUserToken);
|
|
// Email should not have changed on the client side.
|
|
XCTAssertEqualObjects(user.email, kEmail);
|
|
// User is no longer signed in.
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
#if TARGET_OS_IOS
|
|
/** @fn testUpdatePhoneSuccess
|
|
@brief Tests the flow of a successful @c updatePhoneNumberCredential:completion: call.
|
|
*/
|
|
- (void)testUpdatePhoneSuccess {
|
|
id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
if (phoneNumber.length) {
|
|
OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
|
|
}
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
[self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber isLinkOperation:NO error:nil];
|
|
id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
|
|
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
[user updatePhoneNumberCredential:credential
|
|
completion:^(NSError * _Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdatePhoneNumberFailure
|
|
@brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call.
|
|
*/
|
|
- (void)testUpdatePhoneNumberFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:nil]);
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
[user updatePhoneNumberCredential:credential completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidPhoneNumber);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdatePhoneNumberFailureAutoSignOut
|
|
@brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call that
|
|
automatically signs out.
|
|
*/
|
|
- (void)testUpdatePhoneNumberFailureAutoSignOut {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]);
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
[user updatePhoneNumberCredential:credential completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserTokenExpired);
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
#endif
|
|
|
|
/** @fn testUpdatePasswordSuccess
|
|
@brief Tests the flow of a successful @c updatePassword:completion: call.
|
|
*/
|
|
- (void)testUpdatePasswordSuccess {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertEqualObjects(request.password, kNewPassword);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.displayName);
|
|
XCTAssertNil(request.photoURL);
|
|
XCTAssertNil(request.email);
|
|
XCTAssertNil(request.providers);
|
|
XCTAssertNil(request.deleteAttributes);
|
|
XCTAssertNil(request.deleteProviders);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
[user updatePassword:kNewPassword completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertFalse(user.isAnonymous);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdatePasswordFailure
|
|
@brief Tests the flow of a failed @c updatePassword:completion: call.
|
|
*/
|
|
- (void)testUpdatePasswordFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils requiresRecentLoginErrorWithMessage:nil]);
|
|
[user updatePassword:kNewPassword completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeRequiresRecentLogin);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUpdateEmptyPasswordFailure
|
|
@brief Tests the flow of a failed @c updatePassword:completion: call due to an empty password.
|
|
*/
|
|
- (void)testUpdateEmptyPasswordFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[user updatePassword:@"" completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
}
|
|
|
|
/** @fn testUpdatePasswordFailureAutoSignOut
|
|
@brief Tests the flow of a failed @c updatePassword:completion: call that automatically signs
|
|
out.
|
|
*/
|
|
- (void)testUpdatePasswordFailureAutoSignOut {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
|
|
[user updatePassword:kNewPassword completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testChangeProfileSuccess
|
|
@brief Tests a successful user profile change flow.
|
|
*/
|
|
- (void)testChangeProfileSuccess {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser photoURL]).andReturn(kPhotoURL);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertEqualObjects(request.displayName, kNewDisplayName);
|
|
XCTAssertEqualObjects(request.photoURL, [NSURL URLWithString:kNewPhotoURL]);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.email);
|
|
XCTAssertNil(request.password);
|
|
XCTAssertNil(request.providers);
|
|
XCTAssertNil(request.deleteAttributes);
|
|
XCTAssertNil(request.deleteProviders);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
FIRUserProfileChangeRequest *profileChange = [user profileChangeRequest];
|
|
profileChange.photoURL = [NSURL URLWithString:kNewPhotoURL];
|
|
profileChange.displayName = kNewDisplayName;
|
|
[profileChange commitChangesWithCompletion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(user.displayName, kNewDisplayName);
|
|
XCTAssertEqualObjects(user.photoURL, [NSURL URLWithString:kNewPhotoURL]);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testChangeProfileFailure
|
|
@brief Tests a failed user profile change flow.
|
|
*/
|
|
- (void)testChangeProfileFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
|
|
FIRUserProfileChangeRequest *profileChange = [user profileChangeRequest];
|
|
profileChange.displayName = kNewDisplayName;
|
|
[profileChange commitChangesWithCompletion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
|
|
XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testChangeProfileFailureAutoSignOut
|
|
@brief Tests a failed user profile change flow that automatically signs out.
|
|
*/
|
|
- (void)testChangeProfileFailureAutoSignOut {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils userNotFoundErrorWithMessage:nil]);
|
|
FIRUserProfileChangeRequest *profileChange = [user profileChangeRequest];
|
|
profileChange.displayName = kNewDisplayName;
|
|
[profileChange commitChangesWithCompletion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserNotFound);
|
|
XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReloadSuccess
|
|
@brief Tests the flow of a successful @c reloadWithCompletion: call.
|
|
*/
|
|
- (void)testReloadSuccess {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
id mockGetAccountInfoResponseUserNew = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUserNew localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUserNew email]).andReturn(kNewEmail);
|
|
OCMStub([mockGetAccountInfoResponseUserNew displayName]).andReturn(kNewDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUserNew passwordHash]).andReturn(kPasswordHash);
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUserNew];
|
|
[user reloadWithCompletion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(user.email, kNewEmail);
|
|
XCTAssertEqualObjects(user.displayName, kNewDisplayName);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testGetIDTokenResultSuccess
|
|
@brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call.
|
|
*/
|
|
- (void)testGetIDTokenResultSuccess {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id mockSecureTokenService = OCMClassMock([FIRSecureTokenService class]);
|
|
OCMStub([mockSecureTokenService hasValidAccessToken]).andReturn(YES);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
[user getIDTokenResultWithCompletion:^(FIRAuthTokenResult *_Nullable tokenResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(tokenResult.token, kAccessToken);
|
|
XCTAssertTrue(tokenResult.issuedAtDate &&
|
|
[tokenResult.issuedAtDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.authDate && [tokenResult.authDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.expirationDate &&
|
|
[tokenResult.expirationDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.claims && [tokenResult.claims isKindOfClass:[NSDictionary class]]);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testGetIDTokenResultForcingRefreshFailure
|
|
@brief Tests the flow successful @c getIDTokenResultForcingRefresh:completion: calls.
|
|
*/
|
|
- (void)testGetIDTokenResultForcingRefreshSuccess {
|
|
[self getIDTokenResultForcingRefreshSuccessWithIDToken:kAccessToken];
|
|
[self getIDTokenResultForcingRefreshSuccessWithIDToken:kAccessTokenLength415];
|
|
[self getIDTokenResultForcingRefreshSuccessWithIDToken:kAccessTokenLength416];
|
|
[self getIDTokenResultForcingRefreshSuccessWithIDToken:kAccessTokenLength523];
|
|
[self getIDTokenResultForcingRefreshSuccessWithIDToken:kAccessTokenWithBase64URLCharacter];
|
|
}
|
|
|
|
/** @fn testGetIDTokenResultSuccessWithBase64EncodedURL
|
|
@brief Tests the flow of a successful @c getIDTokenResultWithCompletion: call using a base64 url
|
|
encoded string.
|
|
*/
|
|
- (void)testGetIDTokenResultSuccessWithBase64EncodedURL {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSecureTokenRequest *_Nullable request,
|
|
FIRSecureTokenResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
|
|
OCMStub([mockSecureTokenResponse accessToken]).andReturn(kAccessTokenWithBase64URLCharacter);
|
|
callback(mockSecureTokenResponse, nil);
|
|
});
|
|
});
|
|
[user getIDTokenResultForcingRefresh:YES
|
|
completion:^(FIRAuthTokenResult *_Nullable tokenResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(tokenResult.token, kAccessTokenWithBase64URLCharacter);
|
|
XCTAssertTrue(tokenResult.issuedAtDate &&
|
|
[tokenResult.issuedAtDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.authDate && [tokenResult.authDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.expirationDate &&
|
|
[tokenResult.expirationDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.claims && [tokenResult.claims isKindOfClass:[NSDictionary class]]);
|
|
NSDictionary *claims = tokenResult.claims;
|
|
XCTAssertEqualObjects(claims[@"email"], kbase64URLEncodedEmail);
|
|
XCTAssertEqualObjects(claims[@"aud"], kbase64URLEncodedAUD);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testGetIDTokenResultForcingRefreshFailure
|
|
@brief Tests the flow of a failed @c getIDTokenResultForcingRefresh:completion: call.
|
|
*/
|
|
- (void)testGetIDTokenResultForcingRefreshFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSecureTokenRequest *_Nullable request,
|
|
FIRSecureTokenResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
NSError *underlying = [NSError errorWithDomain:@"Test Error" code:1 userInfo:nil];
|
|
callback(nil, [FIRAuthErrorUtils networkErrorWithUnderlyingError:underlying]);
|
|
});
|
|
});
|
|
[user getIDTokenResultForcingRefresh:YES
|
|
completion:^(FIRAuthTokenResult *_Nullable tokenResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(tokenResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeNetworkError);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReloadFailure
|
|
@brief Tests the flow of a failed @c reloadWithCompletion: call.
|
|
*/
|
|
- (void)testReloadFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils quotaExceededErrorWithMessage:nil]);
|
|
[user reloadWithCompletion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeQuotaExceeded);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReloadFailureAutoSignOut
|
|
@brief Tests the flow of a failed @c reloadWithCompletion: call that automtatically signs out.
|
|
*/
|
|
- (void)testReloadFailureAutoSignOut {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andDispatchError2([FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]);
|
|
[user reloadWithCompletion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserTokenExpired);
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReauthenticateSuccess
|
|
@brief Tests the flow of a successful @c reauthenticateWithCredential:completion: call.
|
|
*/
|
|
- (void)testReauthenticateSuccess {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
|
|
FIRVerifyPasswordResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
|
|
// New authentication comes back with new access token.
|
|
OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kNewAccessToken);
|
|
OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
|
|
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
|
|
OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
|
|
callback(mockVeriyPasswordResponse, nil);
|
|
});
|
|
});
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
FIRGetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
// Verify that the new access token is being used for subsequent requests.
|
|
XCTAssertEqualObjects(request.accessToken, kNewAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
|
|
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
|
|
callback(mockGetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
FIRAuthCredential *emailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
[user reauthenticateWithCredential:emailCredential completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
// Verify that the current user is unchanged.
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReauthenticateAndRetrieveDataSuccess
|
|
@brief Tests the flow of a successful @c reauthenticateAndRetrieveDataWithCredential:completion:
|
|
call.
|
|
*/
|
|
- (void)testReauthenticateAndRetrieveDataSuccess {
|
|
[self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
|
|
federatedID:kGoogleID
|
|
displayName:kGoogleDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kGoogleIDToken
|
|
providerAccessToken:kGoogleAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *googleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:googleCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserGoogle:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRGoogleAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
[self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
|
|
federatedID:kGoogleID
|
|
displayName:kGoogleDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kGoogleIDToken
|
|
providerAccessToken:kGoogleAccessToken];
|
|
|
|
FIRAuthCredential *reauthenticateGoogleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[authResult.user
|
|
reauthenticateAndRetrieveDataWithCredential:reauthenticateGoogleCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
reauthenticateAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
// Verify that the current user is unchanged.
|
|
XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
|
|
// Verify that the current user and reauthenticated user are not same pointers.
|
|
XCTAssertNotEqualObjects(authResult.user, reauthenticateAuthResult.user);
|
|
// Verify that anyway the current user and reauthenticated user have same IDs.
|
|
XCTAssertEqualObjects(authResult.user.uid, reauthenticateAuthResult.user.uid);
|
|
XCTAssertEqualObjects(authResult.user.displayName, reauthenticateAuthResult.user.displayName);
|
|
XCTAssertEqualObjects(reauthenticateAuthResult.additionalUserInfo.profile,
|
|
[[self class] googleProfile]);
|
|
XCTAssertEqualObjects(reauthenticateAuthResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(reauthenticateAuthResult.additionalUserInfo.providerID,
|
|
FIRGoogleAuthProviderID);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
[self assertUserGoogle:[FIRAuth auth].currentUser];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReauthenticateFailure
|
|
@brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call.
|
|
*/
|
|
- (void)testReauthenticateFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
|
|
FIRVerifyPasswordResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
|
|
OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kNewAccessToken);
|
|
OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
|
|
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
|
|
OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
|
|
callback(mockVeriyPasswordResponse, nil);
|
|
});
|
|
});
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
FIRGetAccountInfoResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockGetAccountInfoResponseUserNew = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
// The newly-signed-in user has a different ID.
|
|
OCMStub([mockGetAccountInfoResponseUserNew localID]).andReturn(kAnotherLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUserNew email]).andReturn(kNewEmail);
|
|
OCMStub([mockGetAccountInfoResponseUserNew displayName]).andReturn(kNewDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUserNew passwordHash]).andReturn(kPasswordHash);
|
|
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
|
|
OCMStub([mockGetAccountInfoResponse users])
|
|
.andReturn(@[ mockGetAccountInfoResponseUserNew ]);
|
|
callback(mockGetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
FIRAuthCredential *emailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
[user reauthenticateWithCredential:emailCredential completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
// Verify user mismatch error.
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserMismatch);
|
|
// Verify that the current user is unchanged.
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testReauthenticateUserMismatchFailure
|
|
@brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call due to trying
|
|
to reauthenticate a user that does not exist.
|
|
*/
|
|
- (void)testReauthenticateUserMismatchFailure {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
|
|
FIRVerifyAssertionResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
callback(nil, [FIRAuthErrorUtils userNotFoundErrorWithMessage:nil]);
|
|
});
|
|
});
|
|
FIRAuthCredential *googleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[user reauthenticateWithCredential:googleCredential completion:^(NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
// Verify user mismatch error.
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserMismatch);
|
|
// Verify that the current user is unchanged.
|
|
XCTAssertEqual([FIRAuth auth].currentUser, user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkAndRetrieveDataSuccess
|
|
@brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
|
|
call.
|
|
*/
|
|
- (void)testlinkAndRetrieveDataSuccess {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
[self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
|
|
federatedID:kGoogleID
|
|
displayName:kGoogleDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kGoogleIDToken
|
|
providerAccessToken:kGoogleAccessToken];
|
|
|
|
FIRAuthCredential *linkGoogleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkGoogleCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
// Verify that the current user is unchanged.
|
|
XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
|
|
// Verify that the current user and reauthenticated user are same pointers.
|
|
XCTAssertEqualObjects(authResult.user, linkAuthResult.user);
|
|
// Verify that anyway the current user and linked user have same IDs.
|
|
XCTAssertEqualObjects(authResult.user.uid, linkAuthResult.user.uid);
|
|
XCTAssertEqualObjects(authResult.user.displayName, linkAuthResult.user.displayName);
|
|
XCTAssertEqualObjects(linkAuthResult.additionalUserInfo.profile,
|
|
[[self class] googleProfile]);
|
|
XCTAssertEqualObjects(linkAuthResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(linkAuthResult.additionalUserInfo.providerID,
|
|
FIRGoogleAuthProviderID);
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
[self assertUserGoogle:[FIRAuth auth].currentUser];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkAndRetrieveDataError
|
|
@brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
|
|
call with an error from the backend.
|
|
*/
|
|
- (void)testlinkAndRetrieveDataError {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
|
|
FIRVerifyAssertionResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
callback(nil,
|
|
[FIRAuthErrorUtils accountExistsWithDifferentCredentialErrorWithEmail:kEmail]);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkGoogleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkGoogleCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeAccountExistsWithDifferentCredential);
|
|
XCTAssertEqual(error.userInfo[FIRAuthErrorUserInfoEmailKey], kEmail);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkAndRetrieveDataProviderAlreadyLinked
|
|
@brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
|
|
call with FIRAuthErrorCodeProviderAlreadyLinked, which is a client side error.
|
|
*/
|
|
- (void)testlinkAndRetrieveDataProviderAlreadyLinked {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
FIRAuthCredential *linkFacebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkFacebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkAndRetrieveDataErrorAutoSignOut
|
|
@brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
|
|
call that automatically signs out.
|
|
*/
|
|
- (void)testlinkAndRetrieveDataErrorAutoSignOut {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
|
|
FIRVerifyAssertionResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
callback(nil, [FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkGoogleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkGoogleCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testLinkingAnonymousAccountsUpdatesIsAnonymous
|
|
@brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
|
|
invocation for email credential.
|
|
*/
|
|
- (void)testLinkingAnonymousAccountsUpdatesIsAnonymous {
|
|
FIRAuthCredential *linkEmailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail
|
|
link:@"https://google.com?oobCode=aCode&mode=signIn"];
|
|
|
|
id (^mockUserInfoWithDisplayName)(NSString *, BOOL) = ^(NSString *displayName,
|
|
BOOL hasProviders) {
|
|
NSArray *providers = hasProviders ? @[ @{
|
|
@"providerId": FIREmailAuthProviderID,
|
|
@"email": kEmail
|
|
} ] : @[];
|
|
FIRGetAccountInfoResponseUser *responseUser =
|
|
[[FIRGetAccountInfoResponseUser alloc] initWithDictionary:@{
|
|
@"providerUserInfo": providers,
|
|
@"localId": kLocalID,
|
|
@"displayName": displayName,
|
|
@"email": kEmail
|
|
}];
|
|
return responseUser;
|
|
};
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithDisplayName(kGoogleDisplayName, NO);
|
|
|
|
[self signInAnonymouslyWithMockGetAccountInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
// Pretend that the display name and providers on the server have been updated.
|
|
// Get account info is expected to be invoked twice.
|
|
id updatedMockUser = mockUserInfoWithDisplayName(kNewDisplayName, YES);
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:updatedMockUser];
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:updatedMockUser];
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
OCMStub([mockSetAccountInfoResponse email]).andReturn(kNewEmail);
|
|
OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
XCTAssertTrue(user.isAnonymous);
|
|
|
|
[user linkAndRetrieveDataWithCredential:linkEmailCredential
|
|
completion:^(FIRAuthDataResult *_Nullable linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(user.email, kEmail);
|
|
XCTAssertFalse(user.isAnonymous);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkEmailAndRetrieveDataSuccess
|
|
@brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
|
|
invocation for email credential.
|
|
*/
|
|
- (void)testlinkEmailAndRetrieveDataSuccess {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kEmailDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
// Get account info is expected to be invoked twice.
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertEqualObjects(request.password, kFakePassword);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.displayName);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkEmailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(linkAuthResult.user.email, kEmail);
|
|
XCTAssertEqualObjects(linkAuthResult.user.displayName, kEmailDisplayName);
|
|
[expectation fulfill];
|
|
}];
|
|
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkEmailProviderAlreadyLinkedError
|
|
@brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
|
|
invocation for email credential and FIRAuthErrorCodeProviderAlreadyLinked which is a client
|
|
side error.
|
|
*/
|
|
- (void)testlinkEmailProviderAlreadyLinkedError {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kEmailDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
// Get account info is expected to be invoked twice.
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
|
|
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertEqualObjects(request.password, kFakePassword);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.displayName);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkEmailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(linkAuthResult.user.email, kEmail);
|
|
XCTAssertEqualObjects(linkAuthResult.user.displayName, kEmailDisplayName);
|
|
|
|
// Try linking same credential a second time to trigger client side error.
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkEmailAndRetrieveDataError
|
|
@brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
|
|
invocation for email credential and an error from the backend.
|
|
*/
|
|
- (void)testlinkEmailAndRetrieveDataError {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
FIRGetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
callback(nil, [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkEmailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkEmailAndRetrieveDataError
|
|
@brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
|
|
invocation that automatically signs out.
|
|
*/
|
|
- (void)testlinkEmailAndRetrieveDataErrorAutoSignOut {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
FIRGetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
callback(nil, [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkEmailCredential =
|
|
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
[authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserTokenExpired);
|
|
XCTAssertNil([FIRAuth auth].currentUser);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkCredentialSuccess
|
|
@brief Tests the flow of a successful @c linkWithCredential:completion: call, without additional
|
|
IDP data.
|
|
*/
|
|
- (void)testlinkCredentialSuccess {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
[self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
|
|
federatedID:kGoogleID
|
|
displayName:kGoogleDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kGoogleIDToken
|
|
providerAccessToken:kGoogleAccessToken];
|
|
|
|
FIRAuthCredential *linkGoogleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[authResult.user linkWithCredential:linkGoogleCredential
|
|
completion:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
id<FIRUserInfo> userInfo = user.providerData.firstObject;
|
|
XCTAssertEqual(userInfo.providerID, FIRGoogleAuthProviderID);
|
|
XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
[self assertUserGoogle:[FIRAuth auth].currentUser];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkCredentialError
|
|
@brief Tests the flow of an unsuccessful @c linkWithCredential:completion: call, with an error
|
|
from the backend.
|
|
*/
|
|
- (void)testlinkCredentialError {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
|
|
FIRVerifyAssertionResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
callback(nil, [FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
|
|
});
|
|
});
|
|
|
|
FIRAuthCredential *linkGoogleCredential =
|
|
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
|
|
[authResult.user linkWithCredential:linkGoogleCredential
|
|
completion:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(user);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkCredentialProviderAlreadyLinkedError
|
|
@brief Tests the flow of an unsuccessful @c linkWithCredential:completion: call, with a client
|
|
side error.
|
|
*/
|
|
- (void)testlinkCredentialProviderAlreadyLinkedError {
|
|
[self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
|
|
federatedID:kFacebookID
|
|
displayName:kFacebookDisplayName
|
|
profile:[[self class] googleProfile]
|
|
providerIDToken:kFacebookIDToken
|
|
providerAccessToken:kFacebookAccessToken];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
FIRAuthCredential *facebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
|
|
[[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserFacebook:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertNil(error);
|
|
|
|
FIRAuthCredential *linkFacebookCredential =
|
|
[FIRFacebookAuthProvider credentialWithAccessToken:kGoogleAccessToken];
|
|
[authResult.user linkWithCredential:linkFacebookCredential
|
|
completion:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(user);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
#if TARGET_OS_IOS
|
|
/** @fn testlinkPhoneAuthCredentialSuccess
|
|
@brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
|
|
call using a phoneAuthCredential.
|
|
*/
|
|
- (void)testlinkPhoneAuthCredentialSuccess {
|
|
id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
if (phoneNumber.length) {
|
|
NSDictionary *userInfoDictionary = @{ @"providerId" : FIRPhoneAuthProviderID };
|
|
FIRGetAccountInfoResponseProviderUserInfo *userInfo =
|
|
[[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:userInfoDictionary];
|
|
OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(@[ userInfo ]);
|
|
OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
|
|
}
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
[self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber isLinkOperation:YES error:nil];
|
|
id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
|
|
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
[user linkAndRetrieveDataWithCredential:credential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects([FIRAuth auth].currentUser.providerData.firstObject.providerID,
|
|
FIRPhoneAuthProviderID);
|
|
XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testUnlinkPhoneAuthCredentialSuccess
|
|
@brief Tests the flow of a successful @c unlinkFromProvider:completion: call using a
|
|
@c FIRPhoneAuthProvider.
|
|
*/
|
|
- (void)testUnlinkPhoneAuthCredentialSuccess {
|
|
id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
if (phoneNumber.length) {
|
|
NSDictionary *userInfoDictionary = @{ @"providerId" : FIRPhoneAuthProviderID };
|
|
FIRGetAccountInfoResponseProviderUserInfo *userInfo =
|
|
[[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:userInfoDictionary];
|
|
OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(@[ userInfo ]);
|
|
OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
|
|
}
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
|
|
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
|
|
FIRSetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
XCTAssertNotNil(request.deleteProviders);
|
|
XCTAssertNil(request.email);
|
|
XCTAssertNil(request.localID);
|
|
XCTAssertNil(request.displayName);
|
|
XCTAssertNil(request.photoURL);
|
|
XCTAssertNil(request.password);
|
|
XCTAssertNil(request.providers);
|
|
XCTAssertNil(request.deleteAttributes);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
|
|
callback(mockSetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
[self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber isLinkOperation:YES error:nil];
|
|
id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
|
|
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
// Link phone credential.
|
|
[user linkAndRetrieveDataWithCredential:credential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects([FIRAuth auth].currentUser.providerData.firstObject.providerID,
|
|
FIRPhoneAuthProviderID);
|
|
XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
|
|
// Immediately unlink the phone auth provider.
|
|
[user unlinkFromProvider:FIRPhoneAuthProviderID
|
|
completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
|
|
XCTAssertNil(error);
|
|
XCTAssertNil([FIRAuth auth].currentUser.phoneNumber);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkPhoneAuthCredentialFailure
|
|
@brief Tests the flow of a failed call to @c linkAndRetrieveDataWithCredential:completion: due
|
|
to a phone provider already being linked.
|
|
*/
|
|
- (void)testlinkPhoneAuthCredentialFailure {
|
|
id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
if (phoneNumber.length) {
|
|
OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
|
|
}
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
NSError *error = [FIRAuthErrorUtils providerAlreadyLinkedError];
|
|
[self expectVerifyPhoneNumberRequestWithPhoneNumber:nil isLinkOperation:YES error:error];
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
[user linkAndRetrieveDataWithCredential:credential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testlinkPhoneCredentialAlreadyExistsError
|
|
@brief Tests the flow of @c linkAndRetrieveDataWithCredential:completion:
|
|
call using a phoneAuthCredential and a credential already exisits error. In this case we
|
|
should get a FIRAuthCredential in the error object.
|
|
*/
|
|
- (void)testlinkPhoneCredentialAlreadyExistsError {
|
|
id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
if (phoneNumber.length) {
|
|
OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
|
|
}
|
|
return mockGetAccountInfoResponseUser;
|
|
};
|
|
|
|
void (^expectVerifyPhoneNumberRequest)(NSString *) = ^(NSString *phoneNumber) {
|
|
OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
|
|
FIRVerifyPhoneNumberResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.verificationID, kVerificationID);
|
|
XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthCredential alloc] initWithTemporaryProof:kTemporaryProof
|
|
phoneNumber:kPhoneNumber
|
|
providerID:FIRPhoneAuthProviderID];
|
|
callback(nil,
|
|
[FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil
|
|
credential:credential]);
|
|
});
|
|
});
|
|
};
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
|
|
completion:^(FIRUser *user) {
|
|
expectVerifyPhoneNumberRequest(kPhoneNumber);
|
|
|
|
FIRPhoneAuthCredential *credential =
|
|
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
|
|
verificationCode:kVerificationCode];
|
|
[user linkAndRetrieveDataWithCredential:credential
|
|
completion:^(FIRAuthDataResult *_Nullable
|
|
linkAuthResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNil(linkAuthResult);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeCredentialAlreadyInUse);
|
|
FIRPhoneAuthCredential *credential = error.userInfo[FIRAuthUpdatedCredentialKey];
|
|
XCTAssertEqual(credential.temporaryProof, kTemporaryProof);
|
|
XCTAssertEqual(credential.phoneNumber, kPhoneNumber);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
#endif
|
|
|
|
#pragma mark - Helpers
|
|
|
|
/** @fn getIDTokenResultForcingRefreshSuccess
|
|
@brief Helper for testing the flow of a successful @c
|
|
getIDTokenResultForcingRefresh:completion: call.
|
|
*/
|
|
- (void)getIDTokenResultForcingRefreshSuccessWithIDToken:(NSString *)idToken {
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
|
|
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
|
|
completion:^(FIRUser *user) {
|
|
OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSecureTokenRequest *_Nullable request,
|
|
FIRSecureTokenResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
|
|
OCMStub([mockSecureTokenResponse accessToken]).andReturn(idToken);
|
|
callback(mockSecureTokenResponse, nil);
|
|
});
|
|
});
|
|
[user getIDTokenResultForcingRefresh:YES
|
|
completion:^(FIRAuthTokenResult *_Nullable tokenResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(error);
|
|
XCTAssertEqualObjects(tokenResult.token, idToken);
|
|
XCTAssertTrue(tokenResult.issuedAtDate &&
|
|
[tokenResult.issuedAtDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.authDate && [tokenResult.authDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.expirationDate &&
|
|
[tokenResult.expirationDate isKindOfClass:[NSDate class]]);
|
|
XCTAssertTrue(tokenResult.claims && [tokenResult.claims isKindOfClass:[NSDictionary class]]);
|
|
[expectation fulfill];
|
|
}];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn signInAnonymouslyWithMockGetAccountInfoResponse:completion:
|
|
@brief Signs in with an anonymous account with mocked backend end calls.
|
|
@param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
|
|
@param completion The completion block that takes the newly signed-in user as the only
|
|
parameter.
|
|
*/
|
|
- (void)signInAnonymouslyWithMockGetAccountInfoResponse:(id)mockUserInfoResponse
|
|
completion:(void (^)(FIRUser *user))completion {
|
|
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
|
|
FIRSignupNewUserCallback callback) {
|
|
id mockSignUpResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
|
|
OCMStub([mockSignUpResponse IDToken]).andReturn(kAccessToken);
|
|
OCMStub([mockSignUpResponse approximateExpirationDate])
|
|
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
|
|
OCMStub([mockSignUpResponse refreshToken]).andReturn(kRefreshToken);
|
|
callback(mockSignUpResponse, nil);
|
|
});
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
[[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
|
|
NSError *_Nullable error) {
|
|
XCTAssertNotNil(result.user);
|
|
XCTAssertNil(error);
|
|
completion(result.user);
|
|
}];
|
|
}
|
|
|
|
/** @fn signInWithEmailPasswordWithMockGetAccountInfoResponse:completion:
|
|
@brief Signs in with an email and password account with mocked backend end calls.
|
|
@param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
|
|
@param completion The completion block that takes the newly signed-in user as the only
|
|
parameter.
|
|
*/
|
|
- (void)signInWithEmailPasswordWithMockUserInfoResponse:(id)mockUserInfoResponse
|
|
completion:(void (^)(FIRUser *user))completion {
|
|
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
|
|
FIRVerifyPasswordResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
|
|
OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kAccessToken);
|
|
OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
|
|
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
|
|
OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
|
|
callback(mockVeriyPasswordResponse, nil);
|
|
});
|
|
});
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
[[FIRAuth auth] signInWithEmail:kEmail
|
|
password:kFakePassword
|
|
completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
|
|
XCTAssertNotNil(result.user);
|
|
XCTAssertNil(error);
|
|
completion(result.user);
|
|
}];
|
|
}
|
|
|
|
/** @fn signInWithEmailLinkWithMockGetAccountInfoResponse:completion:
|
|
@brief Signs in with an email link auth account with mocked backend end calls.
|
|
@param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
|
|
@param completion The completion block that takes the newly signed-in user as the only
|
|
parameter.
|
|
*/
|
|
- (void)signInWithEmailLinkWithMockUserInfoResponse:(id)mockUserInfoResponse
|
|
completion:(void (^)(FIRUser *user))completion {
|
|
OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
|
|
FIREmailLinkSigninResponseCallback callback) {
|
|
id mockVerifyLinkResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
|
|
OCMStub([mockVerifyLinkResponse IDToken]).andReturn(kAccessToken);
|
|
OCMStub([mockVerifyLinkResponse approximateExpirationDate])
|
|
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
|
|
OCMStub([mockVerifyLinkResponse refreshToken]).andReturn(kRefreshToken);
|
|
callback(mockVerifyLinkResponse, nil);
|
|
});
|
|
[self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
|
|
[[FIRAuth auth] signOut:NULL];
|
|
[[FIRAuth auth] signInWithEmail:kEmail
|
|
link:@"https://www.google.com?oobCode=aCode&mode=signIn"
|
|
completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
|
|
XCTAssertNotNil(result.user);
|
|
XCTAssertNil(error);
|
|
completion(result.user);
|
|
}];
|
|
}
|
|
|
|
/** @fn expectGetAccountInfoWithMockUserInfoResponse:
|
|
@brief Expects a GetAccountInfo request on the mock backend and calls back with provided
|
|
fake account data.
|
|
@param mockUserInfoResponse A mock @c FIRGetAccountInfoResponseUser object containing user info.
|
|
*/
|
|
- (void)expectGetAccountInfoWithMockUserInfoResponse:(id)mockUserInfoResponse {
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
FIRGetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
|
|
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockUserInfoResponse ]);
|
|
callback(mockGetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
}
|
|
|
|
/** @fn dictionaryWithUserInfoArray:
|
|
@brief Converts an array of @c FIRUserInfo into a dictionary that indexed by provider IDs.
|
|
@param userInfoArray An array of @c FIRUserInfo objects.
|
|
@return A dictionary contains same values as @c userInfoArray does but keyed by their
|
|
@c providerID .
|
|
*/
|
|
- (NSDictionary<NSString *, id<FIRUserInfo>> *)
|
|
dictionaryWithUserInfoArray:(NSArray<id<FIRUserInfo>> *)userInfoArray {
|
|
NSMutableDictionary<NSString *, id<FIRUserInfo>> *map =
|
|
[NSMutableDictionary dictionaryWithCapacity:userInfoArray.count];
|
|
for (id<FIRUserInfo> userInfo in userInfoArray) {
|
|
XCTAssertNil(map[userInfo.providerID]);
|
|
map[userInfo.providerID] = userInfo;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
/** @fn stubSecureTokensWithMockResponse
|
|
@brief Creates stubs on the mock response object with access and refresh tokens
|
|
@param mockResponse The mock response object.
|
|
*/
|
|
- (void)stubTokensWithMockResponse:(id)mockResponse {
|
|
OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
|
|
OCMStub([mockResponse approximateExpirationDate])
|
|
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
|
|
OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
|
|
}
|
|
|
|
/** @fn assertUserGoogle
|
|
@brief Asserts the given FIRUser matching the fake data returned by
|
|
@c expectGetAccountInfo:federatedID:displayName: .
|
|
@param user The user object to be verified.
|
|
*/
|
|
- (void)assertUserGoogle:(FIRUser *)user {
|
|
XCTAssertNotNil(user);
|
|
XCTAssertEqualObjects(user.uid, kLocalID);
|
|
XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
|
|
XCTAssertEqual(user.providerData.count, 1u);
|
|
id<FIRUserInfo> googleUserInfo = user.providerData[0];
|
|
XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
|
|
XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
|
|
XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
|
|
XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
|
|
}
|
|
|
|
/** @fn assertUserFacebook
|
|
@brief Asserts the given FIRUser matching the fake data returned by
|
|
@c expectGetAccountInfo:federatedID:displayName: .
|
|
@param user The user object to be verified.
|
|
*/
|
|
- (void)assertUserFacebook:(FIRUser *)user {
|
|
XCTAssertNotNil(user);
|
|
XCTAssertEqualObjects(user.uid, kLocalID);
|
|
XCTAssertEqualObjects(user.displayName, kFacebookDisplayName);
|
|
XCTAssertEqual(user.providerData.count, 1u);
|
|
id<FIRUserInfo> googleUserInfo = user.providerData[0];
|
|
XCTAssertEqualObjects(googleUserInfo.providerID, FIRFacebookAuthProviderID);
|
|
XCTAssertEqualObjects(googleUserInfo.uid, kFacebookID);
|
|
XCTAssertEqualObjects(googleUserInfo.displayName, kFacebookDisplayName);
|
|
XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
|
|
}
|
|
|
|
/** @fn expectGetAccountInfo:federatedID:displayName:
|
|
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
|
|
data for a Google Sign-In user.
|
|
*/
|
|
- (void)expectGetAccountInfo:(NSString *)providerId
|
|
federatedID:(NSString *)federatedID
|
|
displayName:(NSString *)displayName {
|
|
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
FIRGetAccountInfoResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
|
|
OCMStub([mockGoogleUserInfo providerID]).andReturn(providerId);
|
|
OCMStub([mockGoogleUserInfo displayName]).andReturn(displayName);
|
|
OCMStub([mockGoogleUserInfo federatedID]).andReturn(federatedID);
|
|
OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
|
|
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
|
|
OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
|
|
.andReturn((@[ mockGoogleUserInfo ]));
|
|
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
|
|
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
|
|
callback(mockGetAccountInfoResponse, nil);
|
|
});
|
|
});
|
|
}
|
|
|
|
/** @fn expectVerifyAssertionRequest:federatedID:displayName:profile:providerAccessToken:
|
|
@brief Expects a Verify Assertion request on the mock backend and calls back with fake account
|
|
data.
|
|
*/
|
|
- (void)expectVerifyAssertionRequest:(NSString *)providerId
|
|
federatedID:(NSString *)federatedID
|
|
displayName:(NSString *)displayName
|
|
profile:(NSDictionary *)profile
|
|
providerIDToken:(nullable NSString *)providerIDToken
|
|
providerAccessToken:(NSString *)providerAccessToken {
|
|
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
|
|
FIRVerifyAssertionResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
XCTAssertEqualObjects(request.providerID, providerId);
|
|
XCTAssertEqualObjects(request.providerIDToken, providerIDToken);
|
|
XCTAssertEqualObjects(request.providerAccessToken, providerAccessToken);
|
|
XCTAssertTrue(request.returnSecureToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
|
|
OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(federatedID);
|
|
OCMStub([mockVeriyAssertionResponse providerID]).andReturn(providerId);
|
|
OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
|
|
OCMStub([mockVeriyAssertionResponse displayName]).andReturn(displayName);
|
|
OCMStub([mockVeriyAssertionResponse profile]).andReturn(profile);
|
|
OCMStub([mockVeriyAssertionResponse username]).andReturn(kUserName);
|
|
[self stubTokensWithMockResponse:mockVeriyAssertionResponse];
|
|
callback(mockVeriyAssertionResponse, nil);
|
|
});
|
|
});
|
|
[self expectGetAccountInfo:providerId federatedID:federatedID displayName:displayName];
|
|
}
|
|
|
|
#if TARGET_OS_IOS
|
|
/** @fn expectVerifyPhoneNumberRequestWithPhoneNumber:error:
|
|
@brief Expects a verify phone numner request on the mock backend and calls back with fake
|
|
account data or an error.
|
|
@param phoneNumber Optionally; The phone number to use in the mocked response.
|
|
@param isLinkOperation Boolean value that indicates whether or not this method is triggered by
|
|
a link operation.
|
|
@param error Optionally; The error to return in the mocked response.
|
|
*/
|
|
- (void)expectVerifyPhoneNumberRequestWithPhoneNumber:(nullable NSString *)phoneNumber
|
|
isLinkOperation:(BOOL)isLinkOperation
|
|
error:(nullable NSError*)error {
|
|
OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
|
|
FIRVerifyPhoneNumberResponseCallback callback) {
|
|
XCTAssertEqualObjects(request.verificationID, kVerificationID);
|
|
XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
|
|
if (isLinkOperation) {
|
|
XCTAssertEqual(request.operation, FIRAuthOperationTypeLink);
|
|
} else {
|
|
XCTAssertEqual(request.operation, FIRAuthOperationTypeUpdate);
|
|
}
|
|
XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
if (error) {
|
|
callback(nil, error);
|
|
return;
|
|
}
|
|
id mockVerifyPhoneNumberResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
|
|
OCMStub([mockVerifyPhoneNumberResponse phoneNumber]).andReturn(phoneNumber);
|
|
callback(mockVerifyPhoneNumberResponse, nil);
|
|
});
|
|
});
|
|
}
|
|
#endif
|
|
|
|
@end
|
|
|
|
NS_ASSUME_NONNULL_END
|