Files
firebase-ios-sdk/Example/Auth/Tests/FIRAuthTests.m
T
2019-07-29 11:18:45 -07:00

2669 lines
114 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 <FirebaseAuthInterop/FIRAuthInterop.h>
#import <FirebaseCore/FIRAppInternal.h>
#import <FirebaseAuth/FIREmailAuthProvider.h>
#import <FirebaseAuth/FIRGoogleAuthProvider.h>
#import <FirebaseAuth/FIRAdditionalUserInfo.h>
#import <FirebaseCore/FIRComponent.h>
#import <FirebaseCore/FIRLibrary.h>
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
#import "FIRAdditionalUserInfo.h"
#import "FIRAuth_Internal.h"
#import "FIRAuthOperationType.h"
#import "FIRAuthErrorUtils.h"
#import "FIRAuthDispatcher.h"
#import "FIRAuthGlobalWorkQueue.h"
#import "FIRUser_Internal.h"
#import "FIRAuthBackend.h"
#import "FIRCreateAuthURIRequest.h"
#import "FIRCreateAuthURIResponse.h"
#import "FIREmailAuthProvider.h"
#import "FIREmailLinkSignInRequest.h"
#import "FIREmailLinkSignInResponse.h"
#import "FIRFacebookAuthProvider.h"
#import "FIRGetAccountInfoRequest.h"
#import "FIRGetAccountInfoResponse.h"
#import "FIRGetOOBConfirmationCodeRequest.h"
#import "FIRGetOOBConfirmationCodeResponse.h"
#import "FIROAuthProvider.h"
#import "FIRSecureTokenRequest.h"
#import "FIRSecureTokenResponse.h"
#import "FIRResetPasswordRequest.h"
#import "FIRResetPasswordResponse.h"
#import "FIRSetAccountInfoRequest.h"
#import "FIRSetAccountInfoResponse.h"
#import "FIRSignUpNewUserRequest.h"
#import "FIRSignUpNewUserResponse.h"
#import "FIRVerifyCustomTokenRequest.h"
#import "FIRVerifyCustomTokenResponse.h"
#import "FIRVerifyAssertionRequest.h"
#import "FIRVerifyAssertionResponse.h"
#import "FIRVerifyPasswordRequest.h"
#import "FIRVerifyPasswordResponse.h"
#import "FIRVerifyPhoneNumberRequest.h"
#import "FIRVerifyPhoneNumberResponse.h"
#import "FIRApp+FIRAuthUnitTests.h"
#import "OAuth/FIROAuthCredential_Internal.h"
#import "OCMStubRecorder+FIRAuthUnitTests.h"
#import <OCMock/OCMock.h>
#import "FIRActionCodeSettings.h"
#if TARGET_OS_IOS
#import "FIRAuthAPNSToken.h"
#import "FIRAuthAPNSTokenManager.h"
#import "FIRAuthNotificationManager.h"
#import "FIRAuthUIDelegate.h"
#import "FIRAuthURLPresenter.h"
#import "FIRPhoneAuthCredential.h"
#import "FIRPhoneAuthProvider.h"
#endif // TARGET_OS_IOS
/** @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 = @"ACCESS_TOKEN";
/** @var kNewAccessToken
@brief Another fake access token used to simulate token refreshed via automatic token refresh.
*/
NSString *kNewAccessToken = @"NewAccessToken";
/** @var kAccessTokenValidInterval
@brief The time to live for the fake access token.
*/
static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
/** @var kTestTokenExpirationTimeInterval
@brief The fake time interval that it takes a token to expire.
*/
static const NSTimeInterval kTestTokenExpirationTimeInterval = 55 * 60;
/** @var kRefreshToken
@brief The fake refresh token.
*/
static NSString *const kRefreshToken = @"REFRESH_TOKEN";
/** @var kEmail
@brief The fake user email.
*/
static NSString *const kEmail = @"user@company.com";
/** @var kFakePassword
@brief The fake user password.
*/
static NSString *const kFakePassword = @"!@#$%^";
/** @var kPasswordHash
@brief The fake user password hash.
*/
static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
/** @var kLocalID
@brief The fake local user ID.
*/
static NSString *const kLocalID = @"LOCAL_ID";
/** @var kDisplayName
@brief The fake user display name.
*/
static NSString *const kDisplayName = @"User Doe";
/** @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 kGoogleAccessToken
@brief The fake access token from Google Sign-In.
*/
static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
/** @var kGoogleIDToken
@brief The fake ID token from Google Sign-In.
*/
static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
/** @var kCustomToken
@brief The fake custom token to sign in.
*/
static NSString *const kCustomToken = @"CUSTOM_TOKEN";
/** @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 kOAuthRequestURI
@brief Fake OAuthRequest URI for testing.
*/
static NSString *const kOAuthRequestURI = @"requestURI";
/** @var kOAuthSessionID
@brief Fake session ID for testing.
*/
static NSString *const kOAuthSessionID = @"sessionID";
/** @var kFakeWebSignInUserInteractionFailureReason
@brief Fake reason for FIRAuthErrorCodeWebSignInUserInteractionFailure error while testing.
*/
static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reason";
/** @var kContinueURL
@brief Fake string value of continue url.
*/
static NSString *const kContinueURL = @"continueURL";
/** @var kCanHandleCodeInAppKey
@brief The key for the request parameter indicating whether the action code can be handled in
the app or not.
*/
static NSString *const kCanHandleCodeInAppKey = @"canHandleCodeInApp";
/** @var kFIREmailLinkAuthSignInMethod
@brief Fake email link sign-in method for testing.
*/
static NSString *const kFIREmailLinkAuthSignInMethod = @"emailLink";
/** @var kFIRFacebookAuthSignInMethod
@brief Fake Facebook sign-in method for testing.
*/
static NSString *const kFIRFacebookAuthSignInMethod = @"facebook.com";
/** @var kBadSignInEmailLink
@brief Bad sign-in link to test email link sign-in
*/
static NSString *const kBadSignInEmailLink = @"http://www.facebook.com";
/** @var kFakeEmailSignInDeeplink
@brief Fake email sign-in link
*/
static NSString *const kFakeEmailSignInDeeplink =
@"https://example.domain.com/?apiKey=testAPIKey&oobCode=testoobcode&mode=signIn";
/** @var kFakeEmailSignInlink
@brief Fake email sign-in link
*/
static NSString *const kFakeEmailSignInlink = @"https://test.app.goo.gl/?link=https://test.firebase"
"app.com/__/auth/action?apiKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueU"
"rl%3Dhttps://test.apps.com&ibi=com.test.com&ifl=https://test.firebaseapp.com/__/auth/action?ap"
"iKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueUrl%3Dhttps://test.apps.co"
"m";
/** @var kExpectationTimeout
@brief The maximum time waiting for expectations to fulfill.
*/
static const NSTimeInterval kExpectationTimeout = 2;
/** @var kWaitInterval
@brief The time waiting for background tasks to finish before continue when necessary.
*/
static const NSTimeInterval kWaitInterval = .5;
#if TARGET_OS_IOS
/** @class FIRAuthAppDelegate
@brief Application delegate implementation to test the app delegate proxying
*/
@interface FIRAuthAppDelegate : NSObject <UIApplicationDelegate>
@end
@implementation FIRAuthAppDelegate
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return NO;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(nullable NSString *)sourceApplication
annotation:(id)annotation {
return NO;
}
@end
#endif // TARGET_OS_IOS
@interface GULAppDelegateSwizzler (FIRMessagingRemoteNotificationsProxyTest)
+ (void)resetProxyOriginalDelegateOnceToken;
@end
/** Category for FIRAuth to expose FIRComponentRegistrant conformance. */
@interface FIRAuth () <FIRLibrary>
@end
/** @class FIRAuthTests
@brief Tests for @c FIRAuth.
*/
@interface FIRAuthTests : XCTestCase
#if TARGET_OS_IOS
/// A partial mock of `[FIRAuth auth].tokenManager`
@property(nonatomic, strong) id mockTokenManager;
/// A partial mock of `[FIRAuth auth].notificationManager`
@property(nonatomic, strong) id mockNotificationManager;
/// A partial mock of `[FIRAuth auth].authURLPresenter`
@property(nonatomic, strong) id mockAuthURLPresenter;
/// An application delegate instance returned by `self.mockApplication.delegate`
@property(nonatomic, strong) FIRAuthAppDelegate *fakeApplicationDelegate;
#endif // TARGET_OS_IOS
@end
@implementation FIRAuthTests {
/** @var _mockBackend
@brief The mock @c FIRAuthBackendImplementation .
*/
id _mockBackend;
/** @var _FIRAuthDispatcherCallback
@brief Used to save a task from FIRAuthDispatcher to be executed later.
*/
__block void (^_Nonnull _FIRAuthDispatcherCallback)(void);
}
/** @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 = @{
@"iss": @"https://accounts.google.com\\",
@"email": kGoogleEmail,
@"given_name": @"User",
@"family_name": @"Doe"
};
});
return kGoogleProfile;
}
- (void)setUp {
[super setUp];
#if TARGET_OS_IOS
// Make sure the `self.fakeApplicationDelegate` will be swizzled on FIRAuth init.
[GULAppDelegateSwizzler resetProxyOriginalDelegateOnceToken];
self.fakeApplicationDelegate = [[FIRAuthAppDelegate alloc] init];
[[GULAppDelegateSwizzler sharedApplication]
setDelegate:(id<UIApplicationDelegate>)self.fakeApplicationDelegate];
#endif // TARGET_OS_IOS
_mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
[FIRAuthBackend setBackendImplementation:_mockBackend];
[FIRApp resetAppForAuthUnitTests];
// Set FIRAuthDispatcher implementation in order to save the token refresh task for later
// execution.
[[FIRAuthDispatcher sharedInstance]
setDispatchAfterImplementation:^(NSTimeInterval delay,
dispatch_queue_t _Nonnull queue,
void (^task)(void)) {
XCTAssertNotNil(task);
XCTAssert(delay > 0);
XCTAssertEqualObjects(FIRAuthGlobalWorkQueue(), queue);
self->_FIRAuthDispatcherCallback = task;
}];
#if TARGET_OS_IOS
// Wait until FIRAuth initialization completes
[self waitForAuthGlobalWorkQueueDrain];
self.mockTokenManager = OCMPartialMock([FIRAuth auth].tokenManager);
self.mockNotificationManager = OCMPartialMock([FIRAuth auth].notificationManager);
self.mockAuthURLPresenter = OCMPartialMock([FIRAuth auth].authURLPresenter);
#endif // TARGET_OS_IOS
}
- (void)tearDown {
[FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
[[FIRAuthDispatcher sharedInstance] setDispatchAfterImplementation:nil];
#if TARGET_OS_IOS
[self.mockAuthURLPresenter stopMocking];
self.mockAuthURLPresenter = nil;
[self.mockNotificationManager stopMocking];
self.mockNotificationManager = nil;
[self.mockTokenManager stopMocking];
self.mockTokenManager = nil;
self.fakeApplicationDelegate = nil;
#endif // TARGET_OS_IOS
[super tearDown];
}
#pragma mark - Server API Tests
/** @fn testFetchProvidersForEmailSuccess
@brief Tests the flow of a successful @c fetchProvidersForEmail:completion: call.
*/
- (void)testFetchProvidersForEmailSuccess {
NSArray<NSString *> *allProviders =
@[ FIRGoogleAuthProviderID, FIREmailAuthProviderID ];
OCMExpect([_mockBackend createAuthURI:[OCMArg any]
callback:[OCMArg any]])
.andCallBlock2(^(FIRCreateAuthURIRequest *_Nullable request,
FIRCreateAuthURIResponseCallback callback) {
XCTAssertEqualObjects(request.identifier, kEmail);
XCTAssertNotNil(request.endpoint);
XCTAssertEqualObjects(request.APIKey, kAPIKey);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
OCMStub([mockCreateAuthURIResponse allProviders]).andReturn(allProviders);
callback(mockCreateAuthURIResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[FIRAuth auth] fetchProvidersForEmail:kEmail
completion:^(NSArray<NSString *> *_Nullable providers,
NSError *_Nullable error) {
#pragma clang diagnostic pop
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqualObjects(providers, allProviders);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testFetchSignInMethodsForEmailSuccess
@brief Tests the flow of a successful @c fetchSignInMethodsForEmail:completion: call.
*/
- (void)testFetchSignInMethodsForEmailSuccess {
NSArray<NSString *> *allSignInMethods =
@[ kFIREmailLinkAuthSignInMethod, kFIRFacebookAuthSignInMethod ];
OCMExpect([_mockBackend createAuthURI:[OCMArg any]
callback:[OCMArg any]])
.andCallBlock2(^(FIRCreateAuthURIRequest *_Nullable request,
FIRCreateAuthURIResponseCallback callback) {
XCTAssertEqualObjects(request.identifier, kEmail);
XCTAssertNotNil(request.endpoint);
XCTAssertEqualObjects(request.APIKey, kAPIKey);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
OCMStub([mockCreateAuthURIResponse signinMethods]).andReturn(allSignInMethods);
callback(mockCreateAuthURIResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
completion:^(NSArray<NSString *> *_Nullable signInMethods,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqualObjects(signInMethods, allSignInMethods);
XCTAssertTrue([allSignInMethods isKindOfClass:[NSArray class]]);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testFetchProvidersForEmailFailure
@brief Tests the flow of a failed @c fetchProvidersForEmail:completion: call.
*/
- (void)testFetchProvidersForEmailFailure {
OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[FIRAuth auth] fetchProvidersForEmail:kEmail
completion:^(NSArray<NSString *> *_Nullable providers,
NSError *_Nullable error) {
#pragma clang pop
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(providers);
XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testFetchSignInMethodsForEmailFailure
@brief Tests the flow of a failed @c fetchSignInMethodsForEmail:completion: call.
*/
- (void)testFetchSignInMethodsForEmailFailure {
OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
completion:^(NSArray<NSString *> *_Nullable signInMethods,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(signInMethods);
XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
#if TARGET_OS_IOS
/** @fn testPhoneAuthSuccess
@brief Tests the flow of a successful @c signInWithCredential:completion for phone auth.
*/
- (void)testPhoneAuthSuccess {
OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
FIRVerifyPhoneNumberResponseCallback callback) {
XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
XCTAssertEqualObjects(request.verificationID, kVerificationID);
XCTAssertEqual(request.operation, FIRAuthOperationTypeSignUpOrSignIn);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
[self stubTokensWithMockResponse:mockVerifyPhoneResponse];
// Stub isNewUser flag in the response.
OCMStub([mockVerifyPhoneResponse isNewUser]).andReturn(YES);
callback(mockVerifyPhoneResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *credential =
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
verificationCode:kVerificationCode];
[[FIRAuth auth] signInWithCredential:credential
completion:^(FIRAuthDataResult *_Nullable authDataResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:authDataResult.user];
XCTAssertTrue(authDataResult.additionalUserInfo.isNewUser);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testPhoneAuthMissingVerificationCode
@brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
to an empty verification code
*/
- (void)testPhoneAuthMissingVerificationCode {
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *credential =
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
verificationCode:@""];
[[FIRAuth auth] signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationCode);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
}
/** @fn testPhoneAuthMissingVerificationID
@brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
to an empty verification ID.
*/
- (void)testPhoneAuthMissingVerificationID {
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *credential =
[[FIRPhoneAuthProvider provider] credentialWithVerificationID:@""
verificationCode:kVerificationCode];
[[FIRAuth auth] signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationID);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
}
#endif
/** @fn testSignInWithEmailLinkSuccess
@brief Tests the flow of a successful @c signInWithEmail:link:completion: call.
*/
- (void)testSignInWithEmailLinkSuccess {
NSString *fakeCode = @"testoobcode";
OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
FIREmailLinkSigninResponseCallback callback) {
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.oobCode, fakeCode);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockEmailLinkSignInResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
[self stubTokensWithMockResponse:mockEmailLinkSignInResponse];
callback(mockEmailLinkSignInResponse, nil);
OCMStub([mockEmailLinkSignInResponse refreshToken]).andReturn(kRefreshToken);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
link:kFakeEmailSignInlink
completion:^(FIRAuthDataResult *_Nullable authResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNotNil(authResult.user);
XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
XCTAssertFalse(authResult.user.anonymous);
XCTAssertEqualObjects(authResult.user.email, kEmail);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailLinkSuccessDeeplink
@brief Tests the flow of a successful @c signInWithEmail:link:completion: call using a deep
link.
*/
- (void)testSignInWithEmailLinkSuccessDeeplink {
NSString *fakeCode = @"testoobcode";
OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
FIREmailLinkSigninResponseCallback callback) {
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.oobCode, fakeCode);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockEmailLinkSignInResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
[self stubTokensWithMockResponse:mockEmailLinkSignInResponse];
callback(mockEmailLinkSignInResponse, nil);
OCMStub([mockEmailLinkSignInResponse refreshToken]).andReturn(kRefreshToken);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
link:kFakeEmailSignInDeeplink
completion:^(FIRAuthDataResult *_Nullable authResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNotNil(authResult.user);
XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
XCTAssertFalse(authResult.user.anonymous);
XCTAssertEqualObjects(authResult.user.email, kEmail);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailLinkFailure
@brief Tests the flow of a failed @c signInWithEmail:link:completion: call.
*/
- (void)testSignInWithEmailLinkFailure {
OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
link:kFakeEmailSignInlink
completion:^(FIRAuthDataResult *_Nullable authResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailPasswordSuccess
@brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
*/
- (void)testSignInWithEmailPasswordSuccess {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
FIRVerifyPasswordResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.password, kFakePassword);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
[self stubTokensWithMockResponse:mockVerifyPasswordResponse];
callback(mockVerifyPasswordResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailPasswordFailure
@brief Tests the flow of a failed @c signInWithEmail:password:completion: call.
*/
- (void)testSignInWithEmailPasswordFailure {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result.user);
XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAndRetrieveDataWithEmailPasswordSuccess
@brief Tests the flow of a successful @c signInAndRetrieveDataWithEmail:password:completion:
call.
*/
- (void)testSignInAndRetrieveDataWithEmailPasswordSuccess {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
FIRVerifyPasswordResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.password, kFakePassword);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
[self stubTokensWithMockResponse:mockVerifyPasswordResponse];
callback(mockVerifyPasswordResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertFalse(result.additionalUserInfo.isNewUser);
XCTAssertEqualObjects(result.additionalUserInfo.providerID, FIREmailAuthProviderID);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAndRetrieveDataWithEmailPasswordFailure
@brief Tests the flow of a failed @c signInAndRetrieveDataWithEmail:password:completion: call.
*/
- (void)testSignInAndRetrieveDataWithEmailPasswordFailure {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testResetPasswordSuccess
@brief Tests the flow of a successful @c confirmPasswordResetWithCode:newPassword:completion:
call.
*/
- (void)testResetPasswordSuccess {
NSString *fakeEmail = @"fakeEmail";
NSString *fakeCode = @"fakeCode";
NSString *fakeNewPassword = @"fakeNewPassword";
OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
FIRResetPasswordCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.oobCode, fakeCode);
XCTAssertEqualObjects(request.updatedPassword, fakeNewPassword);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
callback(mockResetPasswordResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
newPassword:fakeNewPassword
completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testResetPasswordFailure
@brief Tests the flow of a failed @c confirmPasswordResetWithCode:newPassword:completion:
call.
*/
- (void)testResetPasswordFailure {
NSString *fakeCode = @"fakeCode";
NSString *fakeNewPassword = @"fakeNewPassword";
OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
newPassword:fakeNewPassword
completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testCheckActionCodeSuccess
@brief Tests the flow of a successful @c checkActionCode:completion call.
*/
- (void)testCheckActionCodeSuccess {
NSString *verifyEmailRequestType = @"VERIFY_EMAIL";
NSString *fakeEmail = @"fakeEmail";
NSString *fakeNewEmail = @"fakeNewEmail";
NSString *fakeCode = @"fakeCode";
OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
FIRResetPasswordCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.oobCode, fakeCode);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
OCMStub([mockResetPasswordResponse verifiedEmail]).andReturn(fakeNewEmail);
OCMStubRecorder *stub =
OCMStub([(FIRResetPasswordResponse *) mockResetPasswordResponse requestType]);
stub.andReturn(verifyEmailRequestType);
callback(mockResetPasswordResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] checkActionCode:fakeCode completion:^(FIRActionCodeInfo *_Nullable info,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(error);
XCTAssertEqual(info.operation, FIRActionCodeOperationVerifyEmail);
XCTAssert([fakeNewEmail isEqualToString:[info dataForKey:FIRActionCodeEmailKey]]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testCheckActionCodeFailure
@brief Tests the flow of a failed @c checkActionCode:completion call.
*/
- (void)testCheckActionCodeFailure {
NSString *fakeCode = @"fakeCode";
OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
._andDispatchError2([FIRAuthErrorUtils expiredActionCodeErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] checkActionCode:fakeCode completion:^(FIRActionCodeInfo *_Nullable info,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, FIRAuthErrorCodeExpiredActionCode);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testApplyActionCodeSuccess
@brief Tests the flow of a successful @c applyActionCode:completion call.
*/
- (void)testApplyActionCodeSuccess {
NSString *fakeCode = @"fakeCode";
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
FIRSetAccountInfoResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.OOBCode, fakeCode);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
callback(mockSetAccountInfoResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] applyActionCode:fakeCode completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testApplyActionCodeFailure
@brief Tests the flow of a failed @c checkActionCode:completion call.
*/
- (void)testApplyActionCodeFailure {
NSString *fakeCode = @"fakeCode";
OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] applyActionCode:fakeCode completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testVerifyPasswordResetCodeSuccess
@brief Tests the flow of a successful @c verifyPasswordResetCode:completion call.
*/
- (void)testVerifyPasswordResetCodeSuccess {
NSString *passwordResetRequestType = @"PASSWORD_RESET";
NSString *fakeEmail = @"fakeEmail";
NSString *fakeCode = @"fakeCode";
OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
FIRResetPasswordCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.oobCode, fakeCode);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
OCMStubRecorder *stub =
OCMStub([(FIRResetPasswordResponse *) mockResetPasswordResponse requestType]);
stub.andReturn(passwordResetRequestType);
callback(mockResetPasswordResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] verifyPasswordResetCode:fakeCode completion:^(NSString *_Nullable email,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(error);
XCTAssertEqual(email, fakeEmail);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testVerifyPasswordResetCodeFailure
@brief Tests the flow of a failed @c verifyPasswordResetCode:completion call.
*/
- (void)testVeridyPasswordResetCodeFailure {
NSString *fakeCode = @"fakeCode";
OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] verifyPasswordResetCode:fakeCode completion:^(NSString *_Nullable email,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailLinkCredentialSuccess
@brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
email sign-in link credential using FIREmailAuthProvider.
*/
- (void)testSignInWithEmailLinkCredentialSuccess {
NSString *fakeCode = @"testoobcode";
OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
FIREmailLinkSigninResponseCallback callback) {
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.oobCode, fakeCode);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockEmailLinkSigninResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
[self stubTokensWithMockResponse:mockEmailLinkSigninResponse];
callback(mockEmailLinkSigninResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *emailCredential =
[FIREmailAuthProvider credentialWithEmail:kEmail link:kFakeEmailSignInlink];
[[FIRAuth auth] signInWithCredential:emailCredential
completion:^(FIRAuthDataResult *_Nullable authResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNotNil(authResult.user);
XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
XCTAssertFalse(authResult.user.anonymous);
XCTAssertEqualObjects(authResult.user.email, kEmail);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailLinkCredentialFailure
@brief Tests the flow of a failed @c signInWithCredential:completion: call with an
email-email sign-in link credential using FIREmailAuthProvider.
*/
- (void)testSignInWithEmailLinkCredentialFailure {
OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *emailCredential =
[FIREmailAuthProvider credentialWithEmail:kEmail link:kFakeEmailSignInlink];
[[FIRAuth auth] signInWithCredential:emailCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailCredentialSuccess
@brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
email-password credential.
*/
- (void)testSignInWithEmailCredentialSuccess {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
FIRVerifyPasswordResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.password, kFakePassword);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
[self stubTokensWithMockResponse:mockVeriyPasswordResponse];
callback(mockVeriyPasswordResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *emailCredential =
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
[[FIRAuth auth] signInWithCredential:emailCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailCredentialFailure
@brief Tests the flow of a failed @c signInWithCredential:completion: call with an
email-password credential.
*/
- (void)testSignInWithEmailCredentialFailure {
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *emailCredential =
[FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
[[FIRAuth auth] signInWithCredential:emailCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithEmailCredentialEmptyPassword
@brief Tests the flow of a failed @c signInWithCredential:completion: call with an
email-password credential using an empty password. This error occurs on the client side,
so there is no need to fake an RPC response.
*/
- (void)testSignInWithEmailCredentialEmptyPassword {
NSString *emptyString = @"";
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *emailCredential =
[FIREmailAuthProvider credentialWithEmail:kEmail password:emptyString];
[[FIRAuth auth] signInWithCredential:emailCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
}
#if TARGET_OS_IOS
/** @fn testSignInWithProviderSuccess
@brief Tests a successful @c signInWithProvider:UIDelegate:completion: call with an OAuth
provider configured for Google.
*/
- (void)testSignInWithProviderSuccess {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
FIRVerifyAssertionResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
[self stubTokensWithMockResponse:mockVerifyAssertionResponse];
callback(mockVerifyAssertionResponse, nil);
});
});
[self expectGetAccountInfoGoogle];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
id mockProvider = OCMClassMock([FIROAuthProvider class]);
OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
.andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
dispatch_async(FIRAuthGlobalWorkQueue(), ^(){
FIROAuthCredential *credential =
[[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
sessionID:kOAuthSessionID
OAuthResponseURLString:kOAuthRequestURI];
callback(credential, nil);
});
});
[[FIRAuth auth] signInWithProvider:mockProvider
UIDelegate:nil
completion:^(FIRAuthDataResult *_Nullable authResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUserGoogle:authResult.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithProviderFailure
@brief Tests a failed @c signInWithProvider:UIDelegate:completion: call with the error code
FIRAuthErrorCodeWebSignInUserInteractionFailure.
*/
- (void)testSignInWithProviderFailure {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils webSignInUserInteractionFailureWithReason:
kFakeWebSignInUserInteractionFailureReason]);
[[FIRAuth auth] signOut:NULL];
id mockProvider = OCMClassMock([FIROAuthProvider class]);
OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
.andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
dispatch_async(FIRAuthGlobalWorkQueue(), ^(){
FIROAuthCredential *credential =
[[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
sessionID:kOAuthSessionID
OAuthResponseURLString:kOAuthRequestURI];
callback(credential, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signInWithProvider:mockProvider
UIDelegate:nil
completion:^(FIRAuthDataResult *_Nullable authResult,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(authResult);
XCTAssertEqual(error.code, FIRAuthErrorCodeWebSignInUserInteractionFailure);
XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey],
kFakeWebSignInUserInteractionFailureReason);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithGoogleAccountExistsError
@brief Tests the flow of a failed @c signInWithCredential:completion: with a Google credential
where the backend returns a needs @needConfirmation equal to true. An
FIRAuthErrorCodeAccountExistsWithDifferentCredential error should be thrown.
*/
- (void)testSignInWithGoogleAccountExistsError {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
FIRVerifyAssertionResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
OCMStub([mockVeriyAssertionResponse needConfirmation]).andReturn(YES);
OCMStub([mockVeriyAssertionResponse email]).andReturn(kEmail);
[self stubTokensWithMockResponse:mockVeriyAssertionResponse];
callback(mockVeriyAssertionResponse, nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *googleCredential =
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
[[FIRAuth auth] signInWithCredential:googleCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeAccountExistsWithDifferentCredential);
XCTAssertEqualObjects(error.userInfo[FIRAuthErrorUserInfoEmailKey], kEmail);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithGoogleCredentialSuccess
@brief Tests the flow of a successful @c signInWithCredential:completion: call with an
Google Sign-In credential.
*/
- (void)testSignInWithGoogleCredentialSuccess {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
FIRVerifyAssertionResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
[self stubTokensWithMockResponse:mockVeriyAssertionResponse];
callback(mockVeriyAssertionResponse, nil);
});
});
[self expectGetAccountInfoGoogle];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *googleCredential =
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
[[FIRAuth auth] signInWithCredential:googleCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUserGoogle:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUserGoogle:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithOAuthCredentialSuccess
@brief Tests the flow of a successful @c signInWithCredential:completion: call with a generic
OAuth credential (In this case, configured for the Google IDP).
*/
- (void)testSignInWithOAuthCredentialSuccess {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
FIRVerifyAssertionResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
XCTAssertEqualObjects(request.requestURI, kOAuthRequestURI);
XCTAssertEqualObjects(request.sessionID, kOAuthSessionID);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
[self stubTokensWithMockResponse:mockVeriyAssertionResponse];
callback(mockVeriyAssertionResponse, nil);
});
});
[self expectGetAccountInfoGoogle];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
id mockProvider = OCMClassMock([FIROAuthProvider class]);
OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
.andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
dispatch_async(FIRAuthGlobalWorkQueue(), ^(){
FIROAuthCredential *credential =
[[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
sessionID:kOAuthSessionID
OAuthResponseURLString:kOAuthRequestURI];
callback(credential, nil);
});
});
[mockProvider getCredentialWithUIDelegate:nil
completion:^(FIRAuthCredential *_Nullable credential,
NSError *_Nullable error) {
XCTAssertTrue([credential isKindOfClass:[FIROAuthCredential class]]);
FIROAuthCredential *OAuthCredential = (FIROAuthCredential *)credential;
XCTAssertEqualObjects(OAuthCredential.OAuthResponseURLString, kOAuthRequestURI);
XCTAssertEqualObjects(OAuthCredential.sessionID, kOAuthSessionID);
[[FIRAuth auth] signInWithCredential:OAuthCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUserGoogle:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUserGoogle:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
#endif // TARGET_OS_IOS
/** @fn testSignInAndRetrieveDataWithCredentialSuccess
@brief Tests the flow of a successful @c signInAndRetrieveDataWithCredential:completion: call
with an Google Sign-In credential.
*/
- (void)testSignInAndRetrieveDataWithCredentialSuccess {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
FIRVerifyAssertionResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
OCMStub([mockVeriyAssertionResponse profile]).andReturn([[self class] googleProfile]);
OCMStub([mockVeriyAssertionResponse username]).andReturn(kDisplayName);
[self stubTokensWithMockResponse:mockVeriyAssertionResponse];
callback(mockVeriyAssertionResponse, nil);
});
});
[self expectGetAccountInfoGoogle];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *googleCredential =
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
[[FIRAuth auth] signInWithCredential: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, kDisplayName);
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRGoogleAuthProviderID);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUserGoogle:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithGoogleCredentialFailure
@brief Tests the flow of a failed @c signInWithCredential:completion: call with an
Google Sign-In credential.
*/
- (void)testSignInWithGoogleCredentialFailure {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:kGoogleEmail]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *googleCredential =
[FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
[[FIRAuth auth] signInWithCredential:googleCredential
completion:^(FIRAuthDataResult * _Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result.user);
XCTAssertEqual(error.code, FIRAuthErrorCodeEmailAlreadyInUse);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAnonymouslySuccess
@brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
*/
- (void)testSignInAnonymouslySuccess {
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
FIRSignupNewUserCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertNil(request.email);
XCTAssertNil(request.password);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
[self stubTokensWithMockResponse:mockSignUpNewUserResponse];
callback(mockSignUpNewUserResponse, nil);
});
});
[self expectGetAccountInfoAnonymous];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUserAnonymous:result.user];
XCTAssertNil(error);
FIRAdditionalUserInfo *userInfo = result.additionalUserInfo;
XCTAssertNotNil(userInfo);
XCTAssertTrue(userInfo.isNewUser);
XCTAssertNil(userInfo.username);
XCTAssertNil(userInfo.profile);
XCTAssertNil(userInfo.providerID);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUserAnonymous:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAnonymouslyFailure
@brief Tests the flow of a failed @c signInAnonymouslyWithCompletion: call.
*/
- (void)testSignInAnonymouslyFailure {
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result.user);
XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAnonymouslyAndRetrieveDataSuccess
@brief Tests the flow of a successful @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
*/
- (void)testSignInAnonymouslyAndRetrieveDataSuccess {
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
FIRSignupNewUserCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertNil(request.email);
XCTAssertNil(request.password);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
[self stubTokensWithMockResponse:mockSignUpNewUserResponse];
callback(mockSignUpNewUserResponse, nil);
});
});
[self expectGetAccountInfoAnonymous];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInAnonymouslyWithCompletion:
^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUserAnonymous:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUserAnonymous:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAnonymouslyAndRetrieveDataFailure
@brief Tests the flow of a failed @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
*/
- (void)testSignInAnonymouslyAndRetrieveDataFailure {
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInAnonymouslyWithCompletion:
^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithCustomTokenSuccess
@brief Tests the flow of a successful @c signInWithCustomToken:completion: call.
*/
- (void)testSignInWithCustomTokenSuccess {
OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
FIRVerifyCustomTokenResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.token, kCustomToken);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
[self stubTokensWithMockResponse:mockVeriyCustomTokenResponse];
callback(mockVeriyCustomTokenResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithCustomToken:kCustomToken completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInWithCustomTokenFailure
@brief Tests the flow of a failed @c signInWithCustomToken:completion: call.
*/
- (void)testSignInWithCustomTokenFailure {
OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithCustomToken:kCustomToken
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result.user);
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAndRetrieveDataWithCustomTokenSuccess
@brief Tests the flow of a successful @c signInAndRetrieveDataWithCustomToken:completion: call.
*/
- (void)testSignInAndRetrieveDataWithCustomTokenSuccess {
OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
FIRVerifyCustomTokenResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.token, kCustomToken);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVeriyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
[self stubTokensWithMockResponse:mockVeriyCustomTokenResponse];
callback(mockVeriyCustomTokenResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithCustomToken:kCustomToken
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertFalse(result.additionalUserInfo.isNewUser);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignInAndRetrieveDataWithCustomTokenFailure
@brief Tests the flow of a failed @c signInAndRetrieveDataWithCustomToken:completion: call.
*/
- (void)testSignInAndRetrieveDataWithCustomTokenFailure {
OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] signInWithCustomToken:kCustomToken
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testCreateUserWithEmailPasswordSuccess
@brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
*/
- (void)testCreateUserWithEmailPasswordSuccess {
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
FIRSignupNewUserCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.password, kFakePassword);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
[self stubTokensWithMockResponse:mockSignUpNewUserResponse];
callback(mockSignUpNewUserResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] createUserWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testCreateUserWithEmailPasswordFailure
@brief Tests the flow of a failed @c createUserWithEmail:password:completion: call.
*/
- (void)testCreateUserWithEmailPasswordFailure {
NSString *reason = @"Password shouldn't be a common word.";
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] createUserWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result.user);
XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testCreateUserAndRetrieveDataWithEmailPasswordSuccess
@brief Tests the flow of a successful @c createUserAndRetrieveDataWithEmail:password:completion:
call.
*/
- (void)testCreateUserAndRetrieveDataWithEmailPasswordSuccess {
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
FIRSignupNewUserCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.password, kFakePassword);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
[self stubTokensWithMockResponse:mockSignUpNewUserResponse];
callback(mockSignUpNewUserResponse, nil);
});
});
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] createUserWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUser:result.user];
XCTAssertTrue(result.additionalUserInfo.isNewUser);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUser:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}
/** @fn testCreateUserAndRetrieveDataWithEmailPasswordFailure
@brief Tests the flow of a failed @c createUserAndRetrieveDataWithEmail:password:completion:
call.
*/
- (void)testCreateUserAndRetrieveDataWithEmailPasswordFailure {
NSString *reason = @"Password shouldn't be a common word.";
OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] createUserWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(result);
XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testCreateUserEmptyPasswordFailure
@brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
empty password. This error occurs on the client side, so there is no need to fake an RPC
response.
*/
- (void)testCreateUserEmptyPasswordFailure {
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] createUserWithEmail:kEmail
password:@""
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
}
/** @fn testCreateUserEmptyEmailFailure
@brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
empty email adress. This error occurs on the client side, so there is no need to fake an RPC
response.
*/
- (void)testCreateUserEmptyEmailFailure {
[self expectGetAccountInfo];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
[[FIRAuth auth] createUserWithEmail:@""
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result,
NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeMissingEmail);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
}
/** @fn testSendPasswordResetEmailSuccess
@brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
*/
- (void)testSendPasswordResetEmailSuccess {
OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
FIRGetOOBConfirmationCodeResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] sendPasswordResetWithEmail:kEmail completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSendPasswordResetEmailFailure
@brief Tests the flow of a failed @c sendPasswordResetWithEmail:completion: call.
*/
- (void)testSendPasswordResetEmailFailure {
OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] sendPasswordResetWithEmail:kEmail completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSendSignInLinkToEmailSuccess
@brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings:completion:
call.
*/
- (void)testSendSignInLinkToEmailSuccess {
OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
FIRGetOOBConfirmationCodeResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.email, kEmail);
XCTAssertEqualObjects(request.continueURL, kContinueURL);
XCTAssertTrue(request.handleCodeInApp);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
});
});
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] sendSignInLinkToEmail:kEmail
actionCodeSettings:[self fakeActionCodeSettings]
completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSendSignInLinkToEmailFailure
@brief Tests the flow of a failed @c sendSignInLinkToEmail:actionCodeSettings:completion:
call.
*/
- (void)testSendSignInLinkToEmailFailure {
OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] sendSignInLinkToEmail:kEmail
actionCodeSettings:[self fakeActionCodeSettings]
completion:^(NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn fakeActionCodeSettings
@brief Constructs and returns a fake instance of @c FIRActionCodeSettings for testing.
@return An instance of @c FIRActionCodeSettings for testing.
*/
- (FIRActionCodeSettings *)fakeActionCodeSettings {
FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc]init];
actionCodeSettings.URL = [NSURL URLWithString:kContinueURL];
actionCodeSettings.handleCodeInApp = YES;
return actionCodeSettings;
}
/** @fn testUpdateCurrentUserFailure
@brief Tests the flow of a failed @c updateCurrentUser:completion:
call.
*/
- (void)testUpdateCurrentUserFailure {
NSString *kTestAccessToken = @"fakeAccessToken";
NSString *kTestAPIKey = @"fakeAPIKey";
[self waitForSignInWithAccessToken:kTestAccessToken
APIKey:kTestAPIKey
completion:nil];
NSString *kTestAPIKey2 = @"fakeAPIKey2";
FIRUser *user2 = [FIRAuth auth].currentUser;
user2.requestConfiguration = [[FIRAuthRequestConfiguration alloc]initWithAPIKey:kTestAPIKey2];
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils invalidAPIKeyError]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] updateCurrentUser:user2 completion:^(NSError *_Nullable error) {
XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidAPIKey);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testUpdateCurrentUserFailureNetworkError
@brief Tests the flow of a failed @c updateCurrentUser:completion:
call with a network error.
*/
- (void)testUpdateCurrentUserFailureNetworkError {
NSString *kTestAPIKey = @"fakeAPIKey";
NSString *kTestAccessToken = @"fakeAccessToken";
[self waitForSignInWithAccessToken:kTestAccessToken
APIKey:kTestAPIKey
completion:nil];
NSString *kTestAPIKey2 = @"fakeAPIKey2";
FIRUser *user2 = [FIRAuth auth].currentUser;
user2.requestConfiguration = [[FIRAuthRequestConfiguration alloc]initWithAPIKey:kTestAPIKey2];
NSError *underlyingError = [NSError errorWithDomain:@"Test Error" code:1 userInfo:nil];
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
.andDispatchError2([FIRAuthErrorUtils networkErrorWithUnderlyingError:underlyingError]);
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] updateCurrentUser:user2 completion:^(NSError *_Nullable error) {
XCTAssertEqual(error.code, FIRAuthErrorCodeNetworkError);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testUpdateCurrentUserFailureNUllUser
@brief Tests the flow of a failed @c updateCurrentUser:completion:
call with FIRAuthErrorCodeNullUser.
*/
- (void)testUpdateCurrentUserFailureNUllUser {
NSString *kTestAccessToken = @"fakeAccessToken";
NSString *kTestAPIKey = @"fakeAPIKey";
[self waitForSignInWithAccessToken:kTestAccessToken
APIKey:kTestAPIKey
completion:nil];
FIRUser *fakeNilUser = nil;
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] updateCurrentUser:fakeNilUser completion:^(NSError *_Nullable error) {
XCTAssertEqual(error.code, FIRAuthErrorCodeNullUser);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testUpdateCurrentUserSuccess
@brief Tests the flow of a successful @c updateCurrentUser:completion:
call with a network error.
*/
- (void)testUpdateCurrentUserSuccess {
// Sign in with the first user.
[self waitForSignInWithAccessToken:kAccessToken
APIKey:kAPIKey
completion:nil];
FIRUser *user1 = [FIRAuth auth].currentUser;
NSString *kTestAPIKey = @"fakeAPIKey";
user1.requestConfiguration = [[FIRAuthRequestConfiguration alloc]initWithAPIKey:kTestAPIKey];
[[FIRAuth auth] signOut:nil];
NSString *kTestAccessToken2 = @"fakeAccessToken2";
[self waitForSignInWithAccessToken:kTestAccessToken2
APIKey:kAPIKey
completion:nil];
FIRUser *user2 = [FIRAuth auth].currentUser;
[self expectGetAccountInfoWithAccessToken:kAccessToken];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
// Current user should now be user2.
XCTAssertEqualObjects([FIRAuth auth].currentUser, user2);
[[FIRAuth auth] updateCurrentUser:user1 completion:^(NSError *_Nullable error) {
XCTAssertNil(error);
// Current user should now be user1.
XCTAssertEqualObjects([FIRAuth auth].currentUser, user1);
XCTAssertNotEqualObjects([FIRAuth auth].currentUser, user2);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
}
/** @fn testSignOut
@brief Tests the @c signOut: method.
*/
- (void)testSignOut {
[self waitForSignIn];
// Verify signing out succeeds and clears the current user.
NSError *error;
XCTAssertTrue([[FIRAuth auth] signOut:&error]);
XCTAssertNil([FIRAuth auth].currentUser);
}
/** @fn testIsSignInWithEmailLink
@brief Tests the @c isSignInWithEmailLink: method.
*/
- (void)testIsSignInWithEmailLink {
XCTAssertTrue([[FIRAuth auth] isSignInWithEmailLink:kFakeEmailSignInlink]);
XCTAssertTrue([[FIRAuth auth] isSignInWithEmailLink:kFakeEmailSignInDeeplink]);
XCTAssertFalse([[FIRAuth auth] isSignInWithEmailLink:kBadSignInEmailLink]);
XCTAssertFalse([[FIRAuth auth] isSignInWithEmailLink:@""]);
}
/** @fn testAuthStateChanges
@brief Tests @c addAuthStateDidChangeListener: and @c removeAuthStateDidChangeListener: methods.
*/
- (void)testAuthStateChanges {
// Set up listener.
__block XCTestExpectation *expectation;
__block BOOL shouldHaveUser;
FIRAuthStateDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(auth, [FIRAuth auth]);
XCTAssertEqual(user, [FIRAuth auth].currentUser);
if (shouldHaveUser) {
XCTAssertNotNil(user);
} else {
XCTAssertNil(user);
}
// `expectation` being nil means the listener is not expected to be fired at this moment.
XCTAssertNotNil(expectation);
[expectation fulfill];
};
[[FIRAuth auth] signOut:NULL];
[self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
// Listener should fire immediately when attached.
expectation = [self expectationWithDescription:@"initial"];
shouldHaveUser = NO;
FIRAuthStateDidChangeListenerHandle handle =
[[FIRAuth auth] addAuthStateDidChangeListener:listener];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Listener should fire for signing in.
expectation = [self expectationWithDescription:@"sign-in"];
shouldHaveUser = YES;
[self waitForSignIn];
// Listener should not fire for signing in again.
shouldHaveUser = YES;
[self waitForSignIn];
[self waitForTimeIntervel:kWaitInterval]; // make sure listener is not called
// Listener should fire for signing out.
expectation = [self expectationWithDescription:@"sign-out"];
shouldHaveUser = NO;
[[FIRAuth auth] signOut:NULL];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Listener should no longer fire once detached.
expectation = nil;
[[FIRAuth auth] removeAuthStateDidChangeListener:handle];
[self waitForSignIn];
[self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
}
/** @fn testIDTokenChanges
@brief Tests @c addIDTokenDidChangeListener: and @c removeIDTokenDidChangeListener: methods.
*/
- (void)testIDTokenChanges {
// Set up listener.
__block XCTestExpectation *expectation;
__block BOOL shouldHaveUser;
FIRIDTokenDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
XCTAssertTrue([NSThread isMainThread]);
XCTAssertEqual(auth, [FIRAuth auth]);
XCTAssertEqual(user, [FIRAuth auth].currentUser);
if (shouldHaveUser) {
XCTAssertNotNil(user);
} else {
XCTAssertNil(user);
}
// `expectation` being nil means the listener is not expected to be fired at this moment.
XCTAssertNotNil(expectation);
[expectation fulfill];
};
[[FIRAuth auth] signOut:NULL];
[self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
// Listener should fire immediately when attached.
expectation = [self expectationWithDescription:@"initial"];
shouldHaveUser = NO;
FIRIDTokenDidChangeListenerHandle handle =
[[FIRAuth auth] addIDTokenDidChangeListener:listener];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Listener should fire for signing in.
expectation = [self expectationWithDescription:@"sign-in"];
shouldHaveUser = YES;
[self waitForSignIn];
// Listener should fire for signing in again as the same user with another access token.
expectation = [self expectationWithDescription:@"sign-in again"];
shouldHaveUser = YES;
[self waitForSignInWithAccessToken:kNewAccessToken APIKey:nil completion:nil];
// Listener should fire for signing out.
expectation = [self expectationWithDescription:@"sign-out"];
shouldHaveUser = NO;
[[FIRAuth auth] signOut:NULL];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Listener should no longer fire once detached.
expectation = nil;
[[FIRAuth auth] removeIDTokenDidChangeListener:handle];
[self waitForSignIn];
[self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
}
#pragma mark - Automatic Token Refresh Tests.
/** @fn testAutomaticTokenRefresh
@brief Tests a successful flow to automatically refresh tokens for a signed in user.
*/
- (void)testAutomaticTokenRefresh {
[[FIRAuth auth] signOut:NULL];
// Enable auto refresh
[self enableAutoTokenRefresh];
// Sign in a user.
[self waitForSignIn];
// Set up expectation for secureToken RPC made by token refresh task.
[self mockSecureTokenResponseWithError:nil];
// Verify that the current user's access token is the "old" access token before automatic token
// refresh.
XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
// Execute saved token refresh task.
XCTestExpectation *dispatchAfterExpectation =
[self expectationWithDescription:@"dispatchAfterExpectation"];
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
self->_FIRAuthDispatcherCallback();
[dispatchAfterExpectation fulfill];
});
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Verify that current user's access token is the "new" access token provided in the mock secure
// token response during automatic token refresh.
XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
OCMVerifyAll(_mockBackend);
}
/** @fn testAutomaticTokenRefreshInvalidTokenFailure
@brief Tests an unsuccessful flow to auto refresh tokens with an "invalid token" error.
This error should cause the user to be signed out.
*/
- (void)testAutomaticTokenRefreshInvalidTokenFailure {
[[FIRAuth auth] signOut:NULL];
// Enable auto refresh
[self enableAutoTokenRefresh];
// Sign in a user.
[self waitForSignIn];
// Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
[self mockSecureTokenResponseWithError:[FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]];
// Verify that current user is still valid.
XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
// Execute saved token refresh task.
XCTestExpectation *dispatchAfterExpectation =
[self expectationWithDescription:@"dispatchAfterExpectation"];
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
self->_FIRAuthDispatcherCallback();
[dispatchAfterExpectation fulfill];
});
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Verify that the user is nil after failed attempt to refresh tokens caused signed out.
XCTAssertNil([FIRAuth auth].currentUser);
OCMVerifyAll(_mockBackend);
}
/** @fn testAutomaticTokenRefreshRetry
@brief Tests that a retry is attempted for a automatic token refresh task (which is not due to
invalid tokens). The initial attempt to refresh the access token fails, but the second
attempt is successful.
*/
- (void)testAutomaticTokenRefreshRetry {
[[FIRAuth auth] signOut:NULL];
// Enable auto refresh
[self enableAutoTokenRefresh];
// Sign in a user.
[self waitForSignIn];
// Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
[self mockSecureTokenResponseWithError:[NSError errorWithDomain:@"ERROR" code:-1 userInfo:nil]];
// Execute saved token refresh task.
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
self->_FIRAuthDispatcherCallback();
self->_FIRAuthDispatcherCallback = nil;
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// The old access token should still be the current user's access token and not the new access
// token (kNewAccessToken).
XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
// Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
[self mockSecureTokenResponseWithError:nil];
// Execute saved token refresh task.
XCTestExpectation *dispatchAfterExpectation =
[self expectationWithDescription:@"dispatchAfterExpectation"];
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
self->_FIRAuthDispatcherCallback();
[dispatchAfterExpectation fulfill];
});
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Verify that current user's access token is the "new" access token provided in the mock secure
// token response during automatic token refresh.
XCTAssertEqualObjects([FIRAuth auth].currentUser.rawAccessToken, kNewAccessToken);
OCMVerifyAll(_mockBackend);
}
#if TARGET_OS_IOS
/** @fn testAutomaticTokenRefreshInvalidTokenFailure
@brief Tests that app foreground notification triggers the scheduling of an automatic token
refresh task.
*/
- (void)testAutoRefreshAppForegroundedNotification {
[[FIRAuth auth] signOut:NULL];
// Enable auto refresh
[self enableAutoTokenRefresh];
// Sign in a user.
[self waitForSignIn];
// Post "UIApplicationDidBecomeActiveNotification" to trigger scheduling token refresh task.
[[NSNotificationCenter defaultCenter]
postNotificationName:UIApplicationDidBecomeActiveNotification object:nil];
// Verify that current user is still valid with old access token.
XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
// Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
[self mockSecureTokenResponseWithError:nil];
// Execute saved token refresh task.
XCTestExpectation *dispatchAfterExpectation =
[self expectationWithDescription:@"dispatchAfterExpectation"];
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
self->_FIRAuthDispatcherCallback();
[dispatchAfterExpectation fulfill];
});
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
// Verify that current user is still valid with new access token.
XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
OCMVerifyAll(_mockBackend);
}
#endif
#if TARGET_OS_IOS
#pragma mark - Application Delegate tests
- (void)testAppDidRegisterForRemoteNotifications_APNSTokenUpdated {
NSData *apnsToken = [NSData data];
OCMExpect([self.mockTokenManager setToken:[OCMArg checkWithBlock:^BOOL(FIRAuthAPNSToken *token) {
XCTAssertEqual(token.data, apnsToken);
XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeUnknown);
return YES;
}]]);
[self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
didRegisterForRemoteNotificationsWithDeviceToken:apnsToken];
[self.mockTokenManager verify];
}
- (void)testAppDidFailToRegisterForRemoteNotifications_TokenManagerCancels {
NSError *error = [NSError errorWithDomain:@"FIRAuthTests" code:-1 userInfo:nil];
OCMExpect([self.mockTokenManager cancelWithError:error]);
[self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
didFailToRegisterForRemoteNotificationsWithError:error];
[self.mockTokenManager verify];
}
- (void)testAppDidReceiveRemoteNotification_NotificationManagerHandleCanNotification {
NSDictionary *notification = @{@"test" : @""};
OCMExpect([self.mockNotificationManager canHandleNotification:notification]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
didReceiveRemoteNotification:notification];
#pragma clang diagnostic pop
[self.mockNotificationManager verify];
}
- (void)testAppDidReceiveRemoteNotificationWithCompletion_NotificationManagerHandleCanNotification {
NSDictionary *notification = @{@"test" : @""};
OCMExpect([self.mockNotificationManager canHandleNotification:notification]);
[self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
didReceiveRemoteNotification:notification
fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
[self.mockNotificationManager verify];
}
- (void)testAppOpenURL_AuthPresenterCanHandleURL {
if (@available(iOS 9.0, *)) {
// 'application:openURL:options:' is only available on iOS 9.0 or newer.
NSURL *url = [NSURL URLWithString:@"https://localhost"];
[OCMExpect([self.mockAuthURLPresenter canHandleURL:url]) andReturnValue:@(YES)];
XCTAssertTrue([self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
openURL:url
options:@{}]);
[self.mockAuthURLPresenter verify];
}
}
- (void)testAppOpenURLWithSourceApplication_AuthPresenterCanHandleURL {
NSURL *url = [NSURL URLWithString:@"https://localhost"];
[OCMExpect([self.mockAuthURLPresenter canHandleURL:url]) andReturnValue:@(YES)];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
XCTAssertTrue([self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
openURL:url
sourceApplication:@""
annotation:[[NSObject alloc] init]]);
#pragma clang diagnostic pop
[self.mockAuthURLPresenter verify];
}
#endif // TARGET_OS_IOS
#pragma mark - Interoperability Tests
/** @fn testComponentsBeingRegistered
@brief Tests that Auth provides the necessary components for interoperability with other SDKs.
*/
- (void)testComponentsBeingRegistered {
// Verify that the components are registered properly. Check the count, because any time a new
// component is added it should be added to the test suite as well.
NSArray<FIRComponent *> *components = [FIRAuth componentsToRegister];
XCTAssertTrue(components.count == 1);
FIRComponent *component = [components firstObject];
XCTAssert(component.protocol == @protocol(FIRAuthInterop));
}
#pragma mark - Helpers
/** @fn mockSecureTokenResponseWithError:
@brief Set up expectation for secureToken RPC.
@param error The error that the mock should return if any.
*/
- (void)mockSecureTokenResponseWithError:(nullable NSError *)error {
// Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
XCTestExpectation *secureTokenResponseExpectation =
[self expectationWithDescription:@"secureTokenResponseExpectation"];
OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRSecureTokenRequest *_Nullable request,
FIRSecureTokenResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.refreshToken, kRefreshToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
if (error) {
callback(nil, error);
[secureTokenResponseExpectation fulfill];
return;
}
id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
OCMStub([mockSecureTokenResponse accessToken]).andReturn(kNewAccessToken);
NSDate *futureDate =
[[NSDate date] dateByAddingTimeInterval:kTestTokenExpirationTimeInterval];
OCMStub([mockSecureTokenResponse approximateExpirationDate]).andReturn(futureDate);
callback(mockSecureTokenResponse, nil);
[secureTokenResponseExpectation fulfill];
});
});
}
/** @fn enableAutoTokenRefresh
@brief Enables automatic token refresh by invoking FIRAuth's implementation of FIRApp's
|getTokenWithImplementation|.
*/
- (void)enableAutoTokenRefresh {
XCTestExpectation *expectation = [self expectationWithDescription:@"autoTokenRefreshcallback"];
[[FIRAuth auth] getTokenForcingRefresh:NO withCallback:^(NSString *_Nullable token,
NSError *_Nullable error) {
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
}
/** @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 expectGetAccountInfo
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
data.
*/
- (void)expectGetAccountInfo {
[self expectGetAccountInfoWithAccessToken:kAccessToken];
}
/** @fn expectGetAccountInfoWithAccessToken
@param accessToken The access token for the user to check against.
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
data.
*/
- (void)expectGetAccountInfoWithAccessToken:(NSString *)accessToken {
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
FIRGetAccountInfoResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.accessToken, accessToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
callback(mockGetAccountInfoResponse, nil);
});
});
}
/** @fn assertUser
@brief Asserts the given FIRUser matching the fake data returned by @c expectGetAccountInfo.
@param user The user object to be verified.
*/
- (void)assertUser:(FIRUser *)user {
XCTAssertNotNil(user);
XCTAssertEqualObjects(user.uid, kLocalID);
XCTAssertEqualObjects(user.displayName, kDisplayName);
XCTAssertEqualObjects(user.email, kEmail);
XCTAssertFalse(user.anonymous);
XCTAssertEqual(user.providerData.count, 0u);
}
/** @fn expectGetAccountInfoGoogle
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
data for a Google Sign-In user.
*/
- (void)expectGetAccountInfoGoogle {
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(FIRGoogleAuthProviderID);
OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
.andReturn((@[ mockGoogleUserInfo ]));
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
callback(mockGetAccountInfoResponse, nil);
});
});
}
/** @fn assertUserGoogle
@brief Asserts the given FIRUser matching the fake data returned by
@c expectGetAccountInfoGoogle.
@param user The user object to be verified.
*/
- (void)assertUserGoogle:(FIRUser *)user {
XCTAssertNotNil(user);
XCTAssertEqualObjects(user.uid, kLocalID);
XCTAssertEqualObjects(user.displayName, kDisplayName);
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 expectGetAccountInfoAnonymous
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
account data.
*/
- (void)expectGetAccountInfoAnonymous {
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 mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
callback(mockGetAccountInfoResponse, nil);
});
});
}
/** @fn assertUserAnonymous
@brief Asserts the given FIRUser matching the fake data returned by
@c expectGetAccountInfoAnonymous.
@param user The user object to be verified.
*/
- (void)assertUserAnonymous:(FIRUser *)user {
XCTAssertNotNil(user);
XCTAssertEqualObjects(user.uid, kLocalID);
XCTAssertNil(user.displayName);
XCTAssertTrue(user.anonymous);
XCTAssertEqual(user.providerData.count, 0u);
}
/** @fn waitForSignIn
@brief Signs in a user to prepare for tests.
@remarks This method also waits for all other pending @c XCTestExpectation instances.
*/
- (void)waitForSignIn {
[self waitForSignInWithAccessToken:kAccessToken APIKey:nil completion:nil];
}
/** @fn waitForSignInWithAccessToken:
@brief Signs in a user to prepare for tests.
@param accessToken The access token for the user to have.
@param APIKey Optionally, The API key associated with the user.
@param completion Optionally, The completion invoked at the end of the flow.
@remarks This method also waits for all other pending @c XCTestExpectation instances.
*/
- (void)waitForSignInWithAccessToken:(NSString *)accessToken
APIKey:(nullable NSString *)APIKey
completion:(nullable FIRAuthResultCallback)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(accessToken);
OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
.andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
callback(mockVeriyPasswordResponse, nil);
});
});
[self expectGetAccountInfoWithAccessToken:accessToken];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signInWithEmail:kEmail
password:kFakePassword
completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
result.user.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey];
[expectation fulfill];
if (completion) {
completion(result.user, error);
}
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
OCMVerifyAll(_mockBackend);
XCTAssertNotNil([FIRAuth auth].currentUser);
}
/** @fn waitForTimeInterval:
@brief Wait for a particular time interval.
@remarks This method also waits for all other pending @c XCTestExpectation instances.
*/
- (void)waitForTimeIntervel:(NSTimeInterval)timeInterval {
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
XCTestExpectation *expectation = [self expectationWithDescription:@"waitForTimeIntervel:"];
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("com.google.FIRAuthUnitTests.waitForTimeIntervel", NULL);
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeInterval * NSEC_PER_SEC), queue, ^() {
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:timeInterval + kExpectationTimeout handler:nil];
}
- (void)waitForAuthGlobalWorkQueueDrain {
dispatch_semaphore_t workerSemaphore = dispatch_semaphore_create(0);
dispatch_async(FIRAuthGlobalWorkQueue(), ^{
dispatch_semaphore_signal(workerSemaphore);
});
dispatch_semaphore_wait(workerSemaphore, DISPATCH_TIME_FOREVER /*DISPATCH_TIME_NOW + 10 * NSEC_PER_SEC*/);
}
@end