| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156 |
- /*
- * 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 <XCTest/XCTest.h>
- @import HeartbeatLoggingTestUtils;
- #import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
- #import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h"
- #import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h"
- #import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h"
- #import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h"
- #import "FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h"
- #import "FirebaseAuth/Tests/Unit/FIRFakeBackendRPCIssuer.h"
- #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
- /** @var kFakeRequestURL
- @brief Used as a fake URL for a fake RPC request. We don't test this here, since it's tested
- for the specific RPC requests in their various unit tests.
- */
- static NSString *const kFakeRequestURL = @"https://www.google.com/";
- /** @var kFakeAPIkey
- @brief Used as a fake APIKey for a fake RPC request. We don't test this here.
- */
- static NSString *const kFakeAPIkey = @"FAKE_API_KEY";
- /** @var kFakeFirebaseAppID
- @brief Used as a fake Firebase app ID for a fake RPC request. We don't test this here.
- */
- static NSString *const kFakeFirebaseAppID = @"FAKE_APP_ID";
- /** @var kFakeErrorDomain
- @brief A value to use for fake @c NSErrors.
- */
- static NSString *const kFakeErrorDomain = @"fakeDomain";
- /** @var kFakeErrorCode
- @brief A value to use for fake @c NSErrors.
- */
- static const NSUInteger kFakeErrorCode = -1;
- /** @var kUnknownServerErrorMessage
- @brief A value to use for fake server errors with an unknown message.
- */
- static NSString *const kUnknownServerErrorMessage = @"UNKNOWN_MESSAGE";
- /** @var kErrorMessageCaptchaRequired
- @brief The error message in JSON responses from the server for CAPTCHA required.
- */
- static NSString *const kErrorMessageCaptchaRequired = @"CAPTCHA_REQUIRED";
- /** @var kErrorMessageCaptchaRequiredInvalidPassword
- @brief The error message in JSON responses from the server for CAPTCHA required with invalid
- password.
- */
- static NSString *const kErrorMessageCaptchaRequiredInvalidPassword =
- @"CAPTCHA_REQUIRED_INVALID_PASSWORD";
- /** @var kErrorMessageCaptchaCheckFailed
- @brief The error message in JSON responses from the server for CAPTCHA check failed.
- */
- static NSString *const kErrorMessageCaptchaCheckFailed = @"CAPTCHA_CHECK_FAILED";
- /** @var kErrorMessageEmailExists
- @brief The error message in JSON responses from the server for user's email already exists.
- */
- static NSString *const kErrorMessageEmailExists = @"EMAIL_EXISTS";
- /** @var kErrorMessageKey
- @brief The key for the error message in an error response.
- */
- static NSString *const kErrorMessageKey = @"message";
- /** @var kTestKey
- @brief A key to use for a successful response dictionary.
- */
- static NSString *const kTestKey = @"TestKey";
- /** @var kUserDisabledErrorMessage
- @brief This is the base error message the server will respond with if the user's account has
- been disabled.
- */
- static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED";
- /** @var kFakeUserDisabledCustomErrorMessage
- @brief This is a fake custom error message the server can respond with if the user's account has
- been disabled.
- */
- static NSString *const kFakeUserDisabledCustomErrorMessage = @"The user has been disabled.";
- /** @var kServerErrorDetailMarker
- @brief This marker indicates that the server error message contains a detail error message which
- should be used instead of the hardcoded client error message.
- */
- static NSString *const kServerErrorDetailMarker = @" : ";
- /** @var kTestValue
- @brief A value to use for a successful response dictionary.
- */
- static NSString *const kTestValue = @"TestValue";
- #pragma mark - FIRAuthBackendRPCImplementation
- /** @class FIRAuthBackendRPCImplementation
- @brief Exposes an otherwise private class to these tests. See the real implementation for
- documentation.
- */
- @interface FIRAuthBackendRPCImplementation : NSObject <FIRAuthBackendImplementation>
- /** @fn postWithRequest:response:callback:
- @brief Calls the RPC using HTTP POST.
- @remarks Possible error responses:
- @see FIRAuthInternalErrorCodeRPCRequestEncodingError
- @see FIRAuthInternalErrorCodeJSONSerializationError
- @see FIRAuthInternalErrorCodeNetworkError
- @see FIRAuthInternalErrorCodeUnexpectedErrorResponse
- @see FIRAuthInternalErrorCodeUnexpectedResponse
- @see FIRAuthInternalErrorCodeRPCResponseDecodingError
- @param request The request.
- @param response The empty response to be filled.
- @param callback The callback for both success and failure.
- */
- - (void)postWithRequest:(id<FIRAuthRPCRequest>)request
- response:(id<FIRAuthRPCResponse>)response
- callback:(void (^)(NSError *error))callback;
- @end
- #pragma mark - FIRFakeHeartbeatLogger
- /// A fake heartbeat logger used for dependency injection during testing.
- @interface FIRFakeHeartbeatLogger : NSObject <FIRHeartbeatLoggerProtocol>
- @property(nonatomic, copy, nullable) FIRHeartbeatsPayload * (^onFlushHeartbeatsIntoPayloadHandler)
- (void);
- @property(nonatomic, copy, nullable) FIRHeartbeatInfoCode (^onHeartbeatCodeForTodayHandler)(void);
- @end
- @implementation FIRFakeHeartbeatLogger
- - (nonnull FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload {
- if (self.onFlushHeartbeatsIntoPayloadHandler) {
- return self.onFlushHeartbeatsIntoPayloadHandler();
- } else {
- return nil;
- }
- }
- - (FIRHeartbeatInfoCode)heartbeatCodeForToday {
- // This API should not be used by the below tests because the Auth
- // SDK uses only the V2 heartbeat API (`flushHeartbeatsIntoPayload`) for
- // getting heartbeats.
- [self doesNotRecognizeSelector:_cmd];
- return FIRHeartbeatInfoCodeNone;
- }
- - (void)log {
- // This API should not be used by the below tests because the Auth
- // SDK does not log heartbeats in it's networking context.
- [self doesNotRecognizeSelector:_cmd];
- }
- @end
- #pragma mark - FIRFakeRequest
- /** @class FIRFakeRequest
- @brief Allows us to fake a request with deterministic request bodies and encoding errors
- returned from the @c FIRAuthRPCRequest-specified @c unencodedHTTPRequestBodyWithError:
- method.
- */
- @interface FIRFakeRequest : NSObject <FIRAuthRPCRequest>
- /** @fn fakeRequest
- @brief A "normal" request which returns an encodable request object with no error.
- */
- + (nullable instancetype)fakeRequest;
- /** @fn fakeRequestWithEncodingError
- @brief A request which returns a fake error during the encoding process.
- */
- + (nullable instancetype)fakeRequestWithEncodingError:(NSError *)error;
- /** @fn fakeRequestWithUnserializableRequestBody
- @brief A request which returns a request object which can not be properly serialized by
- @c NSJSONSerialization.
- */
- + (nullable instancetype)fakeRequestWithUnserializableRequestBody;
- /** @fn fakeRequestWithNoBody
- @brief A request which returns a nil request body but no error.
- */
- + (nullable instancetype)fakeRequestWithNoBody;
- /** @fn init
- @brief Please use initWithRequestBody:encodingError:
- */
- - (nullable instancetype)init NS_UNAVAILABLE;
- /** @fn initWithRequestBody:encodingError:
- @brief Designated initializer.
- @param requestBody The fake request body to return when @c unencodedHTTPRequestBodyWithError: is
- invoked.
- @param encodingError The fake error to return when @c unencodedHTTPRequestBodyWithError is
- invoked.
- @param requestConfiguration The request configuration associated with the fake request.
- */
- - (nullable instancetype)initWithRequestBody:(nullable id)requestBody
- encodingError:(nullable NSError *)encodingError
- requestConfiguration:
- (nullable FIRAuthRequestConfiguration *)requestConfiguration
- NS_DESIGNATED_INITIALIZER;
- @end
- @implementation FIRFakeRequest {
- /** @var _requestBody
- @brief The fake request body object we will return when @c unencodedHTTPRequestBodyWithError:
- is invoked.
- */
- id _Nullable _requestBody;
- /** @var _requestEncodingError
- @brief The fake error object we will return when @c unencodedHTTPRequestBodyWithError:
- is invoked.
- */
- NSError *_Nullable _requestEncodingError;
- /** @var _requestConfiguration
- @brief The request configuration to return.
- */
- FIRAuthRequestConfiguration *_Nullable _requestConfiguration;
- }
- + (nullable instancetype)fakeRequest {
- return [[self alloc] initWithRequestBody:@{} encodingError:nil requestConfiguration:nil];
- }
- + (nullable instancetype)fakeRequestWithRequestConfiguration:
- (FIRAuthRequestConfiguration *)requestConfiguration {
- return [[self alloc] initWithRequestBody:@{}
- encodingError:nil
- requestConfiguration:requestConfiguration];
- }
- + (nullable instancetype)fakeRequestWithEncodingError:(NSError *)error {
- return [[self alloc] initWithRequestBody:nil encodingError:error requestConfiguration:nil];
- }
- + (nullable instancetype)fakeRequestWithUnserializableRequestBody {
- return [[self alloc] initWithRequestBody:@{@"unencodableValue" : self}
- encodingError:nil
- requestConfiguration:nil];
- }
- + (nullable instancetype)fakeRequestWithNoBody {
- return [[self alloc] initWithRequestBody:nil encodingError:nil requestConfiguration:nil];
- }
- - (nullable instancetype)initWithRequestBody:(nullable id)requestBody
- encodingError:(nullable NSError *)encodingError
- requestConfiguration:
- (nullable FIRAuthRequestConfiguration *)requestConfiguration {
- self = [super init];
- if (self) {
- _requestBody = requestBody;
- _requestEncodingError = encodingError;
- _requestConfiguration = requestConfiguration;
- }
- return self;
- }
- - (NSURL *)requestURL {
- return [NSURL URLWithString:kFakeRequestURL];
- }
- - (BOOL)containsPostBody {
- return YES;
- }
- - (FIRAuthRequestConfiguration *)requestConfiguration {
- if (!_requestConfiguration) {
- _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kFakeAPIkey
- appID:kFakeFirebaseAppID];
- }
- return _requestConfiguration;
- }
- - (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
- if (error) {
- *error = _requestEncodingError;
- }
- return _requestBody;
- }
- @end
- #pragma mark - FIRFakeResponse
- /** @class FIRFakeResponse
- @brief Allows us to inspect the dictionaries received by @c FIRAuthRPCResponse classes, and
- provide deterministic responses to the @c setWithDictionary:error:
- methods.
- */
- @interface FIRFakeResponse : NSObject <FIRAuthRPCResponse>
- /** @property receivedDictionary
- @brief The dictionary passed to the @c setWithDictionary:error: method.
- */
- @property(nonatomic, strong, readonly, nullable) NSDictionary *receivedDictionary;
- /** @fn fakeResponse
- @brief A "normal" sucessful response (no error, no expected kind.)
- */
- + (nullable instancetype)fakeResponse;
- /** @fn fakeResponseWithDecodingError
- @brief A response which returns a fake error during the decoding process.
- */
- + (nullable instancetype)fakeResponseWithDecodingError;
- /** @fn init
- @brief Please use initWithDecodingError:
- */
- - (nullable instancetype)init NS_UNAVAILABLE;
- - (nullable instancetype)initWithDecodingError:(nullable NSError *)decodingError
- NS_DESIGNATED_INITIALIZER;
- @end
- @implementation FIRFakeResponse {
- /** @var _responseDecodingError
- @brief The value to return for an error when the @c setWithDictionary:error: method is
- invoked.
- */
- NSError *_Nullable _responseDecodingError;
- }
- + (nullable instancetype)fakeResponse {
- return [[self alloc] initWithDecodingError:nil];
- }
- + (nullable instancetype)fakeResponseWithDecodingError {
- NSError *decodingError = [FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:self];
- return [[self alloc] initWithDecodingError:decodingError];
- }
- - (nullable instancetype)initWithDecodingError:(nullable NSError *)decodingError {
- self = [super init];
- if (self) {
- _responseDecodingError = decodingError;
- }
- return self;
- }
- - (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error {
- if (_responseDecodingError) {
- if (error) {
- *error = _responseDecodingError;
- }
- return NO;
- }
- _receivedDictionary = dictionary;
- return YES;
- }
- @end
- #pragma mark - FIRAuthBackendRPCImplementationTests
- /** @class FIRAuthBackendRPCImplementationTests
- @brief This set of unit tests is designed primarily to test the possible outcomes of the
- @c FIRAuthBackendRPCImplementation.postWithRequest:response:callback: method.
- */
- @interface FIRAuthBackendRPCImplementationTests : XCTestCase
- @end
- @implementation FIRAuthBackendRPCImplementationTests {
- /** @var _RPCIssuer
- @brief This backend RPC issuer is used to fake network responses for each test in the suite.
- In the @c setUp method we initialize this and set @c FIRAuthBackend's RPC issuer to it.
- */
- FIRFakeBackendRPCIssuer *_RPCIssuer;
- /** @var _RPCImplementation
- @brief This backend RPC implementation is used to make fake network requests for each test in
- the suite.
- */
- FIRAuthBackendRPCImplementation *_RPCImplementation;
- }
- - (void)setUp {
- FIRFakeBackendRPCIssuer *RPCIssuer = [[FIRFakeBackendRPCIssuer alloc] init];
- [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:RPCIssuer];
- _RPCIssuer = RPCIssuer;
- _RPCImplementation = [FIRAuthBackend implementation];
- }
- - (void)tearDown {
- [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
- _RPCIssuer = nil;
- _RPCImplementation = nil;
- }
- /** @fn testRequest_IncludesHeartbeatPayload_WhenHeartbeatsNeedSending
- @brief This test checks the behavior of @c postWithRequest:response:callback:
- to verify that a heartbeats payload is attached as a header to an
- outgoing request when there are stored heartbeats that need sending.
- */
- - (void)testRequest_IncludesHeartbeatPayload_WhenHeartbeatsNeedSending {
- // Given
- FIRFakeHeartbeatLogger *fakeHeartbeatLogger = [[FIRFakeHeartbeatLogger alloc] init];
- FIRAuthRequestConfiguration *requestConfiguration =
- [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kFakeAPIkey
- appID:kFakeFirebaseAppID
- heartbeatLogger:fakeHeartbeatLogger];
- FIRFakeRequest *request =
- [FIRFakeRequest fakeRequestWithRequestConfiguration:requestConfiguration];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- // When
- FIRHeartbeatsPayload *nonEmptyHeartbeatsPayload =
- [FIRHeartbeatLoggingTestUtils nonEmptyHeartbeatsPayload];
- fakeHeartbeatLogger.onFlushHeartbeatsIntoPayloadHandler = ^FIRHeartbeatsPayload * {
- return nonEmptyHeartbeatsPayload;
- };
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // Then
- NSString *expectedHeader = FIRHeaderValueFromHeartbeatsPayload(nonEmptyHeartbeatsPayload);
- XCTAssertEqualObjects([_RPCIssuer.completeRequest valueForHTTPHeaderField:@"X-Firebase-Client"],
- expectedHeader);
- }
- /** @fn testRequest_DoesNotIncludeAHeartbeatPayload_WhenNoHeartbeatsNeedSending
- @brief This test checks the behavior of @c postWithRequest:response:callback:
- to verify that a request header does not contain heartbeat data in the
- case that there are no stored heartbeats that need sending.
- */
- - (void)testRequest_DoesNotIncludeAHeartbeatPayload_WhenNoHeartbeatsNeedSending {
- // Given
- FIRFakeHeartbeatLogger *fakeHeartbeatLogger = [[FIRFakeHeartbeatLogger alloc] init];
- FIRAuthRequestConfiguration *requestConfiguration =
- [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kFakeAPIkey
- appID:kFakeFirebaseAppID
- heartbeatLogger:fakeHeartbeatLogger];
- FIRFakeRequest *request =
- [FIRFakeRequest fakeRequestWithRequestConfiguration:requestConfiguration];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- // When
- FIRHeartbeatsPayload *emptyHeartbeatsPayload =
- [FIRHeartbeatLoggingTestUtils emptyHeartbeatsPayload];
- fakeHeartbeatLogger.onFlushHeartbeatsIntoPayloadHandler = ^FIRHeartbeatsPayload * {
- return emptyHeartbeatsPayload;
- };
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // Then
- XCTAssertNil([_RPCIssuer.completeRequest valueForHTTPHeaderField:@"X-Firebase-Client"]);
- }
- /** @fn testRequestEncodingError
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- request passed returns an error during it's unencodedHTTPRequestBodyWithError: method.
- The error returned should be delivered to the caller without any change.
- */
- - (void)testRequestEncodingError {
- NSError *encodingError = [NSError errorWithDomain:kFakeErrorDomain
- code:kFakeErrorCode
- userInfo:@{}];
- FIRFakeRequest *request = [FIRFakeRequest fakeRequestWithEncodingError:encodingError];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // There is no need to call [_RPCIssuer respondWithError:...] in this test because a request
- // should never have been tried - and we we know that's the case when we test @c callbackInvoked.
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeRPCRequestEncodingError);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNil(deserializedResponse);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testBodyDataSerializationError
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- request returns an object which isn't serializable by @c NSJSONSerialization.
- The error from @c NSJSONSerialization should be returned as the underlyingError for an
- @c NSError with the code @c FIRAuthErrorCodeJSONSerializationError.
- */
- - (void)testBodyDataSerializationError {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequestWithUnserializableRequestBody];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // There is no need to call [_RPCIssuer respondWithError:...] in this test because a request
- // should never have been tried - and we we know that's the case when we test @c callbackInvoked.
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeJSONSerializationError);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNil(underlyingUnderlyingError);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNil(deserializedResponse);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testNetworkError
- @brief This test checks to make sure a network error is properly wrapped and forwarded with the
- correct code (FIRAuthErrorCodeNetworkError).
- */
- - (void)testNetworkError {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // It shouldn't matter what the error domain/code/userInfo are, any junk values are suitable. The
- // implementation should treat any error with no response data as a network error.
- NSError *responseError = [NSError errorWithDomain:kFakeErrorDomain
- code:kFakeErrorCode
- userInfo:nil];
- [_RPCIssuer respondWithError:responseError];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeNetworkError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingError.code, kFakeErrorCode);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNil(underlyingUnderlyingError);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNil(deserializedResponse);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testUnparsableErrorResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response isn't deserializable by @c NSJSONSerialization and an error
- condition (with an associated error response message) was expected. We are expecting to
- receive the original network error wrapped in an @c NSError with the code
- @c FIRAuthErrorCodeUnexpectedHTTPResponse.
- */
- - (void)testUnparsableErrorResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- NSData *data =
- [@"<html><body>An error occurred.</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithData:data error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedErrorResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNil(deserializedResponse);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNotNil(dataResponse);
- XCTAssertEqualObjects(dataResponse, data);
- }
- /** @fn testUnparsableSuccessResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response isn't deserializable by @c NSJSONSerialization and no error
- condition was indicated. We are expecting to
- receive the @c NSJSONSerialization error wrapped in an @c NSError with the code
- @c FIRAuthErrorCodeUnexpectedServerResponse.
- */
- - (void)testUnparsableSuccessResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- NSData *data = [@"<xml>Some non-JSON value.</xml>" dataUsingEncoding:NSUTF8StringEncoding];
- [_RPCIssuer respondWithData:data error:nil];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, NSCocoaErrorDomain);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNil(deserializedResponse);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNotNil(dataResponse);
- XCTAssertEqualObjects(dataResponse, data);
- }
- /** @fn testNonDictionaryErrorResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response deserialized by @c NSJSONSerialization is not a dictionary, and an error was
- expected. We are expecting to receive the original network error wrapped in an @c NSError
- with the code @c FIRAuthInternalErrorCodeUnexpectedErrorResponse with the decoded response
- in the @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDeserializedResponseKey.
- */
- - (void)testNonDictionaryErrorResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // We are responding with a JSON-encoded string value representing an array - which is unexpected.
- // It should normally be a dictionary, and we need to check for this sort of thing. Because we can
- // successfully decode this value, however, we do return it in the error results. We check for
- // this array later in the test.
- NSData *data = [@"[]" dataUsingEncoding:NSUTF8StringEncoding];
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithData:data error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedErrorResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSArray class]]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testNonDictionarySuccessResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response deserialized by @c NSJSONSerialization is not a dictionary, and no error was
- expected. We are expecting to receive an @c NSError with the code
- @c FIRAuthErrorCodeUnexpectedServerResponse with the decoded response in the
- @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDecodedResponseKey.
- */
- - (void)testNonDictionarySuccessResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // We are responding with a JSON-encoded string value representing an array - which is unexpected.
- // It should normally be a dictionary, and we need to check for this sort of thing. Because we can
- // successfully decode this value, however, we do return it in the error results. We check for
- // this array later in the test.
- NSData *data = [@"[]" dataUsingEncoding:NSUTF8StringEncoding];
- [_RPCIssuer respondWithData:data error:nil];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNil(underlyingUnderlyingError);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSArray class]]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testCaptchaRequiredResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- we get an error message indicating captcha is required. The backend should not be returning
- this error to mobile clients. If it does, we should wrap it in an @c NSError with the code
- @c FIRAuthInternalErrorCodeUnexpectedErrorResponse with the decoded error message in the
- @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDeserializedResponseKey.
- */
- - (void)testCaptchaRequiredResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithServerErrorMessage:kErrorMessageCaptchaRequired error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedErrorResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSDictionary class]]);
- XCTAssertNotNil(deserializedResponse[@"message"]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testCaptchaCheckFailedResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- we get an error message indicating captcha check failed. The backend should not be returning
- this error to mobile clients. If it does, we should wrap it in an @c NSError with the code
- @c FIRAuthErrorCodeUnexpectedServerResponse with the decoded error message in the
- @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDecodedErrorResponseKey.
- */
- - (void)testCaptchaCheckFailedResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithServerErrorMessage:kErrorMessageCaptchaCheckFailed error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeCaptchaCheckFailed);
- }
- /** @fn testCaptchaRequiredInvalidPasswordResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- we get an error message indicating captcha is required and an invalid password was entered.
- The backend should not be returning this error to mobile clients. If it does, we should wrap
- it in an @c NSError with the code
- @c FIRAuthInternalErrorCodeUnexpectedErrorResponse with the decoded error message in the
- @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDeserializedResponseKey.
- */
- - (void)testCaptchaRequiredInvalidPasswordResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithServerErrorMessage:kErrorMessageCaptchaRequiredInvalidPassword
- error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedErrorResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSDictionary class]]);
- XCTAssertNotNil(deserializedResponse[@"message"]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testDecodableErrorResponseWithUnknownMessage
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response deserialized by @c NSJSONSerialization represents a valid error response (and an
- error was indicated) but we didn't receive an error message we know about. We are expecting
- to receive the original network error wrapped in an @c NSError with the code
- @c FIRAuthInternalErrorCodeUnexpectedErrorResponse with the decoded
- error message in the @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDeserializedResponseKey.
- */
- - (void)testDecodableErrorResponseWithUnknownMessage {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // We need to return a valid "error" response here, but we are going to intentionally use a bogus
- // error message.
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithServerErrorMessage:kUnknownServerErrorMessage error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedErrorResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSDictionary class]]);
- XCTAssertNotNil(deserializedResponse[@"message"]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testErrorResponseWithNoErrorMessage
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response deserialized by @c NSJSONSerialization is a dictionary, and an error was indicated,
- but no error information was present in the decoded response. We are expecting to receive
- the original network error wrapped in an @c NSError with the code
- @c FIRAuthErrorCodeUnexpectedServerResponse with the decoded
- response message in the @c NSError.userInfo dictionary associated with the key
- @c FIRAuthErrorUserInfoDeserializedResponseKey.
- */
- - (void)testErrorResponseWithNoErrorMessage {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- NSError *error = [NSError errorWithDomain:kFakeErrorDomain code:kFakeErrorCode userInfo:@{}];
- [_RPCIssuer respondWithJSON:@{} error:error];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeUnexpectedErrorResponse);
- NSError *underlyingUnderlyingError = underlyingError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingUnderlyingError);
- XCTAssertEqualObjects(underlyingUnderlyingError.domain, kFakeErrorDomain);
- XCTAssertEqual(underlyingUnderlyingError.code, kFakeErrorCode);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSDictionary class]]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testClientErrorResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response contains a client error specified by an error messsage sent from the backend.
- */
- - (void)testClientErrorResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackerror;
- __block BOOL callBackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callBackInvoked = YES;
- callbackerror = error;
- }];
- NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:nil];
- NSString *customErrorMessage =
- [NSString stringWithFormat:@"%@%@%@", kUserDisabledErrorMessage, kServerErrorDetailMarker,
- kFakeUserDisabledCustomErrorMessage];
- [_RPCIssuer respondWithServerErrorMessage:customErrorMessage error:error];
- XCTAssertNotNil(callbackerror, @"An error should be returned from callback.");
- XCTAssert(callBackInvoked);
- XCTAssertEqual(callbackerror.code, FIRAuthErrorCodeUserDisabled);
- NSString *customMessage = callbackerror.userInfo[NSLocalizedDescriptionKey];
- XCTAssertEqualObjects(customMessage, kFakeUserDisabledCustomErrorMessage);
- }
- /** @fn testUndecodableSuccessResponse
- @brief This test checks the behaviour of @c postWithRequest:response:callback: when the
- response isn't decodable by the response class but no error condition was expected. We are
- expecting to receive an @c NSError with the code
- @c FIRAuthErrorCodeUnexpectedServerResponse and the error from @c setWithDictionary:error:
- as the value of the underlyingError.
- */
- - (void)testUndecodableSuccessResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponseWithDecodingError];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- // It doesn't matter what we respond with here, as long as it's not an error response. The fake
- // response will deterministicly simulate a decoding error regardless of the response value it was
- // given.
- [_RPCIssuer respondWithJSON:@{}];
- XCTAssert(callbackInvoked);
- XCTAssertNotNil(callbackError);
- XCTAssertEqualObjects(callbackError.domain, FIRAuthErrorDomain);
- XCTAssertEqual(callbackError.code, FIRAuthErrorCodeInternalError);
- NSError *underlyingError = callbackError.userInfo[NSUnderlyingErrorKey];
- XCTAssertNotNil(underlyingError);
- XCTAssertEqualObjects(underlyingError.domain, FIRAuthInternalErrorDomain);
- XCTAssertEqual(underlyingError.code, FIRAuthInternalErrorCodeRPCResponseDecodingError);
- id deserializedResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDeserializedResponseKey];
- XCTAssertNotNil(deserializedResponse);
- XCTAssert([deserializedResponse isKindOfClass:[NSDictionary class]]);
- id dataResponse = underlyingError.userInfo[FIRAuthErrorUserInfoDataKey];
- XCTAssertNil(dataResponse);
- }
- /** @fn testSuccessfulResponse
- @brief Tests that a decoded dictionary is handed to the response instance.
- */
- - (void)testSuccessfulResponse {
- FIRFakeRequest *request = [FIRFakeRequest fakeRequest];
- FIRFakeResponse *response = [FIRFakeResponse fakeResponse];
- __block NSError *callbackError;
- __block BOOL callbackInvoked;
- [_RPCImplementation postWithRequest:request
- response:response
- callback:^(NSError *error) {
- callbackInvoked = YES;
- callbackError = error;
- }];
- [_RPCIssuer respondWithJSON:@{kTestKey : kTestValue}];
- XCTAssert(callbackInvoked);
- XCTAssertNil(callbackError);
- XCTAssertNotNil(response.receivedDictionary);
- XCTAssertEqualObjects(response.receivedDictionary[kTestKey], kTestValue);
- }
- @end
|