mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-11 22:55:59 +05:45
* Adds passing state and continue URL in OOBCodes actions. (#82) * Adds actionCodeSettings class (#83) * Adds FIRActionCodeSettings class * Removes iOSAppStoreId to reflect update spec. * Adds “reset password in app” to sample app (#84) * Adds “reset password in app” to sample app * Addresses comments * Addresses comments * Adds @param documentation for actionCodeSettings (#85) Adds @param documentation for actionCodeSettings in FIRGetOOBConfirmationCodeRequest. * Adds request configuration class Adds a class that will comprise of all configurations needed to make a request to the Firebase Auth backend; including APIKey and Language code in the future. * Addresses comments. * Adds Setting Language Add Setting Language Feature to Firebase Auth. - Only adds support for two languages (English and Spanish) in this change. (Also supports two languages in test), more to come after this change is accepted. - For now sample app tests language setting only when using “reset password in app” option, the email sent will be in the current app language. Additional tests to come after change is accepted. * Amends code for unit tests Will add more comprehensive testing when code accepted. * Ecodes strings files in UTF-8 * Addresses comments * Addresses comments * Remove comments in .strings * Adds remaining TC languages to Firebase Auth. * Add line break to .strings files * remove language code english fallback Remove the fallback that sends “en” as the language code to the backend if no language code is specified. * addresses comment * Fixes FIRSecureToken Crash Integrates FIRSecureTokenService and FIRSecureTokenRequest with FIRAuthRequestConfiguration. * Addresses comment * Add auth language input Adds Auth language input to the Sample App in preparation for manual testing. * removes unnecessary comment * address comments * Add app language option Allow user to set the current app language code as the auth language code. This is in preparation for manual testing before release. * Addresses Comment * Adds missing continue URI Adds missing continue URL to Firebear error handling. * Remove unused line Removes unused line from FIRPhoneAuthProvider.m * Moves the new public header to the right place. * Fixes broken macOS build. * Removes trailing spaces. * Addresses review comments.
1772 lines
73 KiB
Objective-C
1772 lines
73 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 "FirebaseCommunity/FIRAppInternal.h"
|
|
#import "FirebaseCommunity/FIREmailAuthProvider.h"
|
|
#import "FirebaseCommunity/FIRGoogleAuthProvider.h"
|
|
#import "FirebaseCommunity/FIRAdditionalUserInfo.h"
|
|
#import "FIRAuth_Internal.h"
|
|
#import "FIRAuthErrorUtils.h"
|
|
#import "FIRAuthDispatcher.h"
|
|
#import "FIRAuthGlobalWorkQueue.h"
|
|
#import "FIRUser_Internal.h"
|
|
#import "FIRAuthBackend.h"
|
|
#import "FIRCreateAuthURIRequest.h"
|
|
#import "FIRCreateAuthURIResponse.h"
|
|
#import "FIRGetAccountInfoRequest.h"
|
|
#import "FIRGetAccountInfoResponse.h"
|
|
#import "FIRGetOOBConfirmationCodeRequest.h"
|
|
#import "FIRGetOOBConfirmationCodeResponse.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 "OCMStubRecorder+FIRAuthUnitTests.h"
|
|
#import <OCMock/OCMock.h>
|
|
|
|
#if TARGET_OS_IOS
|
|
#import "FIRPhoneAuthCredential.h"
|
|
#import "FIRPhoneAuthProvider.h"
|
|
#endif
|
|
|
|
/** @var kFirebaseAppName1
|
|
@brief A fake Firebase app name.
|
|
*/
|
|
static NSString *const kFirebaseAppName1 = @"FIREBASE_APP_NAME_1";
|
|
|
|
/** @var kFirebaseAppName2
|
|
@brief Another fake Firebase app name.
|
|
*/
|
|
static NSString *const kFirebaseAppName2 = @"FIREBASE_APP_NAME_2";
|
|
|
|
/** @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 kExpectationTimeout
|
|
@brief The maximum time waiting for expectations to fulfill.
|
|
*/
|
|
static const NSTimeInterval kExpectationTimeout = 1;
|
|
|
|
/** @var kWaitInterval
|
|
@brief The time waiting for background tasks to finish before continue when necessary.
|
|
*/
|
|
static const NSTimeInterval kWaitInterval = .5;
|
|
|
|
/** @class FIRAuthTests
|
|
@brief Tests for @c FIRAuth.
|
|
*/
|
|
@interface FIRAuthTests : XCTestCase
|
|
@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];
|
|
_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);
|
|
_FIRAuthDispatcherCallback = task;
|
|
}];
|
|
}
|
|
|
|
- (void)tearDown {
|
|
[FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
|
|
[[FIRAuthDispatcher sharedInstance] setDispatchAfterImplementation:nil];
|
|
[super tearDown];
|
|
}
|
|
|
|
#pragma mark - Life Cycle Tests
|
|
|
|
/** @fn testSingleton
|
|
@brief Verifies the @c auth method behaves like a singleton.
|
|
*/
|
|
- (void)testSingleton {
|
|
FIRAuth *auth1 = [FIRAuth auth];
|
|
XCTAssertNotNil(auth1);
|
|
FIRAuth *auth2 = [FIRAuth auth];
|
|
XCTAssertEqual(auth1, auth2);
|
|
}
|
|
|
|
/** @fn testDefaultAuth
|
|
@brief Verifies the @c auth method associates with the default Firebase app.
|
|
*/
|
|
- (void)testDefaultAuth {
|
|
FIRAuth *auth1 = [FIRAuth auth];
|
|
FIRAuth *auth2 = [FIRAuth authWithApp:[FIRApp defaultApp]];
|
|
XCTAssertEqual(auth1, auth2);
|
|
XCTAssertEqual(auth1.app, [FIRApp defaultApp]);
|
|
}
|
|
|
|
/** @fn testNilAppException
|
|
@brief Verifies the @c auth method raises an exception if the default FIRApp is not configured.
|
|
*/
|
|
- (void)testNilAppException {
|
|
[FIRApp resetApps];
|
|
XCTAssertThrows([FIRAuth auth]);
|
|
}
|
|
|
|
/** @fn testAppAPIkey
|
|
@brief Verifies the API key is correctly copied from @c FIRApp to @c FIRAuth .
|
|
*/
|
|
- (void)testAppAPIkey {
|
|
FIRAuth *auth = [FIRAuth auth];
|
|
XCTAssertEqualObjects(auth.requestConfiguration.APIKey, kAPIKey);
|
|
}
|
|
|
|
/** @fn testAppAssociation
|
|
@brief Verifies each @c FIRApp instance associates with a @c FIRAuth .
|
|
*/
|
|
- (void)testAppAssociation {
|
|
FIRApp *app1 = [self app1];
|
|
FIRAuth *auth1 = [FIRAuth authWithApp:app1];
|
|
XCTAssertNotNil(auth1);
|
|
XCTAssertEqual(auth1.app, app1);
|
|
|
|
FIRApp *app2 = [self app2];
|
|
FIRAuth *auth2 = [FIRAuth authWithApp:app2];
|
|
XCTAssertNotNil(auth2);
|
|
XCTAssertEqual(auth2.app, app2);
|
|
|
|
XCTAssertNotEqual(auth1, auth2);
|
|
}
|
|
|
|
/** @fn testLifeCycle
|
|
@brief Verifies the life cycle of @c FIRAuth is the same as its associated @c FIRApp .
|
|
*/
|
|
- (void)testLifeCycle {
|
|
__weak FIRApp *app;
|
|
__weak FIRAuth *auth;
|
|
@autoreleasepool {
|
|
FIRApp *app1 = [self app1];
|
|
app = app1;
|
|
auth = [FIRAuth authWithApp:app1];
|
|
// Verify that neither the app nor the auth is released yet, i.e., the app owns the auth
|
|
// because nothing else retains the auth.
|
|
XCTAssertNotNil(app);
|
|
XCTAssertNotNil(auth);
|
|
}
|
|
[self waitForTimeIntervel:kWaitInterval];
|
|
// Verify that both the app and the auth are released upon exit of the autorelease pool,
|
|
// i.e., the app is the sole owner of the auth.
|
|
XCTAssertNil(app);
|
|
XCTAssertNil(auth);
|
|
}
|
|
|
|
/** @fn testGetUID
|
|
@brief Verifies that FIRApp's getUIDImplementation is correctly set by FIRAuth.
|
|
*/
|
|
- (void)testGetUID {
|
|
FIRApp *app = [FIRApp defaultApp];
|
|
XCTAssertNotNil(app.getUIDImplementation);
|
|
[[FIRAuth auth] signOut:NULL];
|
|
XCTAssertNil(app.getUIDImplementation());
|
|
[self waitForSignIn];
|
|
XCTAssertEqualObjects(app.getUIDImplementation(), kLocalID);
|
|
}
|
|
|
|
#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"];
|
|
[[FIRAuth auth] fetchProvidersForEmail:kEmail
|
|
completion:^(NSArray<NSString *> *_Nullable providers,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqualObjects(providers, allProviders);
|
|
XCTAssertNil(error);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testFetchProvidersForEmailSuccessDeprecatedProviderID
|
|
@brief Tests the flow of a successful @c fetchProvidersForEmail:completion: call using the
|
|
deprecated FIREmailPasswordAuthProviderID.
|
|
*/
|
|
- (void)testFetchProvidersForEmailSuccessDeprecatedProviderID {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
NSArray<NSString *> *allProviders =
|
|
@[ FIRGoogleAuthProviderID, FIREmailPasswordAuthProviderID ];
|
|
#pragma clang diagnostic pop
|
|
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"];
|
|
[[FIRAuth auth] fetchProvidersForEmail:kEmail
|
|
completion:^(NSArray<NSString *> *_Nullable providers,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqualObjects(providers, allProviders);
|
|
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"];
|
|
[[FIRAuth auth] fetchProvidersForEmail:kEmail
|
|
completion:^(NSArray<NSString *> *_Nullable providers,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(providers);
|
|
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);
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
|
|
[self stubTokensWithMockResponse:mockVerifyPhoneResponse];
|
|
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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUser:user];
|
|
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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(user);
|
|
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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(user);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationID);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
}
|
|
#endif
|
|
|
|
/** @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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUser: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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(user);
|
|
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 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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUser:user];
|
|
XCTAssertNil(error);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
[self assertUser:[FIRAuth auth].currentUser];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testSignInWithEmailCredentialSuccess
|
|
@brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
|
|
email-password credential using the deprecated FIREmailPasswordAuthProvider.
|
|
*/
|
|
- (void)testSignInWithEmailCredentialSuccessWithDepricatedProvider {
|
|
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];
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
FIRAuthCredential *emailCredential =
|
|
[FIREmailPasswordAuthProvider credentialWithEmail:kEmail password:kFakePassword];
|
|
#pragma clang diagnostic pop
|
|
[[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUser: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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(user);
|
|
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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
}
|
|
|
|
/** @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:^(FIRUser *_Nullable user,
|
|
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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserGoogle:user];
|
|
XCTAssertNil(error);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
[self assertUserGoogle:[FIRAuth auth].currentUser];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @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] signInAndRetrieveDataWithCredential:googleCredential
|
|
completion:^(FIRAuthDataResult *_Nullable authResult,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserGoogle:authResult.user];
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
|
|
XCTAssertEqualObjects(authResult.additionalUserInfo.username, 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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(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 signInAnonymously:completion: 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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUserAnonymous:user];
|
|
XCTAssertNil(error);
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
[self assertUserAnonymous:[FIRAuth auth].currentUser];
|
|
OCMVerifyAll(_mockBackend);
|
|
}
|
|
|
|
/** @fn testSignInAnonymouslyFailure
|
|
@brief Tests the flow of a failed @c signInAnonymously:completion: 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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(user);
|
|
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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUser: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:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(user);
|
|
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:^(FIRUser *_Nullable user, NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
[self assertUser: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:^(FIRUser *_Nullable user, NSError *_Nullable error) {
|
|
XCTAssertTrue([NSThread isMainThread]);
|
|
XCTAssertNil(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 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:^(FIRUser *_Nullable user, 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:^(FIRUser *_Nullable user, 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 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 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.
|
|
expectation = [self expectationWithDescription:@"sign-in again"];
|
|
shouldHaveUser = YES;
|
|
[self waitForSignIn];
|
|
|
|
// 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(_FIRAuthDispatcherCallback);
|
|
_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(_FIRAuthDispatcherCallback);
|
|
_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(_FIRAuthDispatcherCallback);
|
|
_FIRAuthDispatcherCallback();
|
|
_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(_FIRAuthDispatcherCallback);
|
|
_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(_FIRAuthDispatcherCallback);
|
|
_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
|
|
|
|
#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].app getTokenForcingRefresh:NO withCallback:^(NSString *_Nullable token,
|
|
NSError *_Nullable error) {
|
|
[expectation fulfill];
|
|
}];
|
|
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
}
|
|
|
|
/** @fn app1
|
|
@brief Creates a Firebase app.
|
|
@return A @c FIRApp with some name.
|
|
*/
|
|
- (FIRApp *)app1 {
|
|
return [FIRApp appForAuthUnitTestsWithName:kFirebaseAppName1];
|
|
}
|
|
|
|
/** @fn app2
|
|
@brief Creates another Firebase app.
|
|
@return A @c FIRApp with some other name.
|
|
*/
|
|
- (FIRApp *)app2 {
|
|
return [FIRApp appForAuthUnitTestsWithName:kFirebaseAppName2];
|
|
}
|
|
|
|
/** @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 {
|
|
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);
|
|
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 {
|
|
OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
|
|
.andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
|
|
FIRVerifyPasswordResponseCallback callback) {
|
|
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
|
|
[self stubTokensWithMockResponse:mockVeriyPasswordResponse];
|
|
callback(mockVeriyPasswordResponse, nil);
|
|
});
|
|
});
|
|
[self expectGetAccountInfo];
|
|
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
[[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
|
|
NSError *_Nullable error) {
|
|
[expectation fulfill];
|
|
}];
|
|
[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];
|
|
}
|
|
|
|
@end
|