FIRAuthTests.m 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <Foundation/Foundation.h>
  17. #import <XCTest/XCTest.h>
  18. #import <FirebaseCore/FIRAppInternal.h>
  19. #import <FirebaseAuth/FIREmailAuthProvider.h>
  20. #import <FirebaseAuth/FIRGoogleAuthProvider.h>
  21. #import <FirebaseAuth/FIRAdditionalUserInfo.h>
  22. #import "FIRAuth_Internal.h"
  23. #import "FIRAuthOperationType.h"
  24. #import "FIRAuthErrorUtils.h"
  25. #import "FIRAuthDispatcher.h"
  26. #import "FIRAuthGlobalWorkQueue.h"
  27. #import "FIRUser_Internal.h"
  28. #import "FIRAuthBackend.h"
  29. #import "FIRCreateAuthURIRequest.h"
  30. #import "FIRCreateAuthURIResponse.h"
  31. #import "FIRGetAccountInfoRequest.h"
  32. #import "FIRGetAccountInfoResponse.h"
  33. #import "FIRGetOOBConfirmationCodeRequest.h"
  34. #import "FIRGetOOBConfirmationCodeResponse.h"
  35. #import "FIRSecureTokenRequest.h"
  36. #import "FIRSecureTokenResponse.h"
  37. #import "FIRResetPasswordRequest.h"
  38. #import "FIRResetPasswordResponse.h"
  39. #import "FIRSetAccountInfoRequest.h"
  40. #import "FIRSetAccountInfoResponse.h"
  41. #import "FIRSignUpNewUserRequest.h"
  42. #import "FIRSignUpNewUserResponse.h"
  43. #import "FIRVerifyCustomTokenRequest.h"
  44. #import "FIRVerifyCustomTokenResponse.h"
  45. #import "FIRVerifyAssertionRequest.h"
  46. #import "FIRVerifyAssertionResponse.h"
  47. #import "FIRVerifyPasswordRequest.h"
  48. #import "FIRVerifyPasswordResponse.h"
  49. #import "FIRVerifyPhoneNumberRequest.h"
  50. #import "FIRVerifyPhoneNumberResponse.h"
  51. #import "FIRApp+FIRAuthUnitTests.h"
  52. #import "OCMStubRecorder+FIRAuthUnitTests.h"
  53. #import <OCMock/OCMock.h>
  54. #if TARGET_OS_IOS
  55. #import "FIRPhoneAuthCredential.h"
  56. #import "FIRPhoneAuthProvider.h"
  57. #endif
  58. /** @var kFirebaseAppName1
  59. @brief A fake Firebase app name.
  60. */
  61. static NSString *const kFirebaseAppName1 = @"FIREBASE_APP_NAME_1";
  62. /** @var kFirebaseAppName2
  63. @brief Another fake Firebase app name.
  64. */
  65. static NSString *const kFirebaseAppName2 = @"FIREBASE_APP_NAME_2";
  66. /** @var kAPIKey
  67. @brief The fake API key.
  68. */
  69. static NSString *const kAPIKey = @"FAKE_API_KEY";
  70. /** @var kAccessToken
  71. @brief The fake access token.
  72. */
  73. static NSString *const kAccessToken = @"ACCESS_TOKEN";
  74. /** @var kNewAccessToken
  75. @brief Another fake access token used to simulate token refreshed via automatic token refresh.
  76. */
  77. NSString *kNewAccessToken = @"NewAccessToken";
  78. /** @var kAccessTokenValidInterval
  79. @brief The time to live for the fake access token.
  80. */
  81. static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
  82. /** @var kTestTokenExpirationTimeInterval
  83. @brief The fake time interval that it takes a token to expire.
  84. */
  85. static const NSTimeInterval kTestTokenExpirationTimeInterval = 55 * 60;
  86. /** @var kRefreshToken
  87. @brief The fake refresh token.
  88. */
  89. static NSString *const kRefreshToken = @"REFRESH_TOKEN";
  90. /** @var kEmail
  91. @brief The fake user email.
  92. */
  93. static NSString *const kEmail = @"user@company.com";
  94. /** @var kFakePassword
  95. @brief The fake user password.
  96. */
  97. static NSString *const kFakePassword = @"!@#$%^";
  98. /** @var kPasswordHash
  99. @brief The fake user password hash.
  100. */
  101. static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
  102. /** @var kLocalID
  103. @brief The fake local user ID.
  104. */
  105. static NSString *const kLocalID = @"LOCAL_ID";
  106. /** @var kDisplayName
  107. @brief The fake user display name.
  108. */
  109. static NSString *const kDisplayName = @"User Doe";
  110. /** @var kGoogleUD
  111. @brief The fake user ID under Google Sign-In.
  112. */
  113. static NSString *const kGoogleID = @"GOOGLE_ID";
  114. /** @var kGoogleEmail
  115. @brief The fake user email under Google Sign-In.
  116. */
  117. static NSString *const kGoogleEmail = @"user@gmail.com";
  118. /** @var kGoogleDisplayName
  119. @brief The fake user display name under Google Sign-In.
  120. */
  121. static NSString *const kGoogleDisplayName = @"Google Doe";
  122. /** @var kGoogleAccessToken
  123. @brief The fake access token from Google Sign-In.
  124. */
  125. static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
  126. /** @var kGoogleIDToken
  127. @brief The fake ID token from Google Sign-In.
  128. */
  129. static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
  130. /** @var kCustomToken
  131. @brief The fake custom token to sign in.
  132. */
  133. static NSString *const kCustomToken = @"CUSTOM_TOKEN";
  134. /** @var kVerificationCode
  135. @brief Fake verification code used for testing.
  136. */
  137. static NSString *const kVerificationCode = @"12345678";
  138. /** @var kVerificationID
  139. @brief Fake verification ID for testing.
  140. */
  141. static NSString *const kVerificationID = @"55432";
  142. /** @var kExpectationTimeout
  143. @brief The maximum time waiting for expectations to fulfill.
  144. */
  145. static const NSTimeInterval kExpectationTimeout = 2;
  146. /** @var kWaitInterval
  147. @brief The time waiting for background tasks to finish before continue when necessary.
  148. */
  149. static const NSTimeInterval kWaitInterval = .5;
  150. /** @class FIRAuthTests
  151. @brief Tests for @c FIRAuth.
  152. */
  153. @interface FIRAuthTests : XCTestCase
  154. @end
  155. @implementation FIRAuthTests {
  156. /** @var _mockBackend
  157. @brief The mock @c FIRAuthBackendImplementation .
  158. */
  159. id _mockBackend;
  160. /** @var _FIRAuthDispatcherCallback
  161. @brief Used to save a task from FIRAuthDispatcher to be executed later.
  162. */
  163. __block void (^_Nonnull _FIRAuthDispatcherCallback)(void);
  164. }
  165. /** @fn googleProfile
  166. @brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
  167. */
  168. + (NSDictionary *)googleProfile {
  169. static NSDictionary *kGoogleProfile = nil;
  170. static dispatch_once_t onceToken;
  171. dispatch_once(&onceToken, ^{
  172. kGoogleProfile = @{
  173. @"iss": @"https://accounts.google.com\\",
  174. @"email": kGoogleEmail,
  175. @"given_name": @"User",
  176. @"family_name": @"Doe"
  177. };
  178. });
  179. return kGoogleProfile;
  180. }
  181. - (void)setUp {
  182. [super setUp];
  183. _mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
  184. [FIRAuthBackend setBackendImplementation:_mockBackend];
  185. [FIRApp resetAppForAuthUnitTests];
  186. // Set FIRAuthDispatcher implementation in order to save the token refresh task for later
  187. // execution.
  188. [[FIRAuthDispatcher sharedInstance]
  189. setDispatchAfterImplementation:^(NSTimeInterval delay,
  190. dispatch_queue_t _Nonnull queue,
  191. void (^task)(void)) {
  192. XCTAssertNotNil(task);
  193. XCTAssert(delay > 0);
  194. XCTAssertEqualObjects(FIRAuthGlobalWorkQueue(), queue);
  195. _FIRAuthDispatcherCallback = task;
  196. }];
  197. }
  198. - (void)tearDown {
  199. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
  200. [[FIRAuthDispatcher sharedInstance] setDispatchAfterImplementation:nil];
  201. [super tearDown];
  202. }
  203. #pragma mark - Life Cycle Tests
  204. /** @fn testSingleton
  205. @brief Verifies the @c auth method behaves like a singleton.
  206. */
  207. - (void)testSingleton {
  208. FIRAuth *auth1 = [FIRAuth auth];
  209. XCTAssertNotNil(auth1);
  210. FIRAuth *auth2 = [FIRAuth auth];
  211. XCTAssertEqual(auth1, auth2);
  212. }
  213. /** @fn testDefaultAuth
  214. @brief Verifies the @c auth method associates with the default Firebase app.
  215. */
  216. - (void)testDefaultAuth {
  217. FIRAuth *auth1 = [FIRAuth auth];
  218. FIRAuth *auth2 = [FIRAuth authWithApp:[FIRApp defaultApp]];
  219. XCTAssertEqual(auth1, auth2);
  220. XCTAssertEqual(auth1.app, [FIRApp defaultApp]);
  221. }
  222. /** @fn testNilAppException
  223. @brief Verifies the @c auth method raises an exception if the default FIRApp is not configured.
  224. */
  225. - (void)testNilAppException {
  226. [FIRApp resetApps];
  227. XCTAssertThrows([FIRAuth auth]);
  228. }
  229. /** @fn testAppAPIkey
  230. @brief Verifies the API key is correctly copied from @c FIRApp to @c FIRAuth .
  231. */
  232. - (void)testAppAPIkey {
  233. FIRAuth *auth = [FIRAuth auth];
  234. XCTAssertEqualObjects(auth.requestConfiguration.APIKey, kAPIKey);
  235. }
  236. /** @fn testAppAssociation
  237. @brief Verifies each @c FIRApp instance associates with a @c FIRAuth .
  238. */
  239. - (void)testAppAssociation {
  240. FIRApp *app1 = [self app1];
  241. FIRAuth *auth1 = [FIRAuth authWithApp:app1];
  242. XCTAssertNotNil(auth1);
  243. XCTAssertEqual(auth1.app, app1);
  244. FIRApp *app2 = [self app2];
  245. FIRAuth *auth2 = [FIRAuth authWithApp:app2];
  246. XCTAssertNotNil(auth2);
  247. XCTAssertEqual(auth2.app, app2);
  248. XCTAssertNotEqual(auth1, auth2);
  249. }
  250. /** @fn testLifeCycle
  251. @brief Verifies the life cycle of @c FIRAuth is the same as its associated @c FIRApp .
  252. */
  253. - (void)testLifeCycle {
  254. __weak FIRApp *app;
  255. __weak FIRAuth *auth;
  256. @autoreleasepool {
  257. FIRApp *app1 = [self app1];
  258. app = app1;
  259. auth = [FIRAuth authWithApp:app1];
  260. // Verify that neither the app nor the auth is released yet, i.e., the app owns the auth
  261. // because nothing else retains the auth.
  262. XCTAssertNotNil(app);
  263. XCTAssertNotNil(auth);
  264. }
  265. [self waitForTimeIntervel:kWaitInterval];
  266. // Verify that both the app and the auth are released upon exit of the autorelease pool,
  267. // i.e., the app is the sole owner of the auth.
  268. XCTAssertNil(app);
  269. XCTAssertNil(auth);
  270. }
  271. /** @fn testGetUID
  272. @brief Verifies that FIRApp's getUIDImplementation is correctly set by FIRAuth.
  273. */
  274. - (void)testGetUID {
  275. FIRApp *app = [FIRApp defaultApp];
  276. XCTAssertNotNil(app.getUIDImplementation);
  277. [[FIRAuth auth] signOut:NULL];
  278. XCTAssertNil(app.getUIDImplementation());
  279. [self waitForSignIn];
  280. XCTAssertEqualObjects(app.getUIDImplementation(), kLocalID);
  281. }
  282. #pragma mark - Server API Tests
  283. /** @fn testFetchProvidersForEmailSuccess
  284. @brief Tests the flow of a successful @c fetchProvidersForEmail:completion: call.
  285. */
  286. - (void)testFetchProvidersForEmailSuccess {
  287. NSArray<NSString *> *allProviders =
  288. @[ FIRGoogleAuthProviderID, FIREmailAuthProviderID ];
  289. OCMExpect([_mockBackend createAuthURI:[OCMArg any]
  290. callback:[OCMArg any]])
  291. .andCallBlock2(^(FIRCreateAuthURIRequest *_Nullable request,
  292. FIRCreateAuthURIResponseCallback callback) {
  293. XCTAssertEqualObjects(request.identifier, kEmail);
  294. XCTAssertNotNil(request.endpoint);
  295. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  296. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  297. id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
  298. OCMStub([mockCreateAuthURIResponse allProviders]).andReturn(allProviders);
  299. callback(mockCreateAuthURIResponse, nil);
  300. });
  301. });
  302. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  303. [[FIRAuth auth] fetchProvidersForEmail:kEmail
  304. completion:^(NSArray<NSString *> *_Nullable providers,
  305. NSError *_Nullable error) {
  306. XCTAssertTrue([NSThread isMainThread]);
  307. XCTAssertEqualObjects(providers, allProviders);
  308. XCTAssertNil(error);
  309. [expectation fulfill];
  310. }];
  311. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  312. OCMVerifyAll(_mockBackend);
  313. }
  314. /** @fn testFetchProvidersForEmailSuccessDeprecatedProviderID
  315. @brief Tests the flow of a successful @c fetchProvidersForEmail:completion: call using the
  316. deprecated FIREmailPasswordAuthProviderID.
  317. */
  318. - (void)testFetchProvidersForEmailSuccessDeprecatedProviderID {
  319. #pragma clang diagnostic push
  320. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  321. NSArray<NSString *> *allProviders =
  322. @[ FIRGoogleAuthProviderID, FIREmailPasswordAuthProviderID ];
  323. #pragma clang diagnostic pop
  324. OCMExpect([_mockBackend createAuthURI:[OCMArg any]
  325. callback:[OCMArg any]])
  326. .andCallBlock2(^(FIRCreateAuthURIRequest *_Nullable request,
  327. FIRCreateAuthURIResponseCallback callback) {
  328. XCTAssertEqualObjects(request.identifier, kEmail);
  329. XCTAssertNotNil(request.endpoint);
  330. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  331. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  332. id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
  333. OCMStub([mockCreateAuthURIResponse allProviders]).andReturn(allProviders);
  334. callback(mockCreateAuthURIResponse, nil);
  335. });
  336. });
  337. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  338. [[FIRAuth auth] fetchProvidersForEmail:kEmail
  339. completion:^(NSArray<NSString *> *_Nullable providers,
  340. NSError *_Nullable error) {
  341. XCTAssertTrue([NSThread isMainThread]);
  342. XCTAssertEqualObjects(providers, allProviders);
  343. XCTAssertNil(error);
  344. [expectation fulfill];
  345. }];
  346. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  347. OCMVerifyAll(_mockBackend);
  348. }
  349. /** @fn testFetchProvidersForEmailFailure
  350. @brief Tests the flow of a failed @c fetchProvidersForEmail:completion: call.
  351. */
  352. - (void)testFetchProvidersForEmailFailure {
  353. OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
  354. .andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
  355. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  356. [[FIRAuth auth] fetchProvidersForEmail:kEmail
  357. completion:^(NSArray<NSString *> *_Nullable providers,
  358. NSError *_Nullable error) {
  359. XCTAssertTrue([NSThread isMainThread]);
  360. XCTAssertNil(providers);
  361. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  362. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  363. [expectation fulfill];
  364. }];
  365. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  366. OCMVerifyAll(_mockBackend);
  367. }
  368. #if TARGET_OS_IOS
  369. /** @fn testPhoneAuthSuccess
  370. @brief Tests the flow of a successful @c signInWithCredential:completion for phone auth.
  371. */
  372. - (void)testPhoneAuthSuccess {
  373. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  374. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  375. FIRVerifyPhoneNumberResponseCallback callback) {
  376. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  377. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  378. XCTAssertEqual(request.operation, FIRAuthOperationTypeSignUpOrSignIn);
  379. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  380. id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
  381. [self stubTokensWithMockResponse:mockVerifyPhoneResponse];
  382. // Stub isNewUser flag in the response.
  383. OCMStub([mockVerifyPhoneResponse isNewUser]).andReturn(YES);
  384. callback(mockVerifyPhoneResponse, nil);
  385. });
  386. });
  387. [self expectGetAccountInfo];
  388. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  389. [[FIRAuth auth] signOut:NULL];
  390. FIRAuthCredential *credential =
  391. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  392. verificationCode:kVerificationCode];
  393. [[FIRAuth auth] signInAndRetrieveDataWithCredential:credential
  394. completion:^(FIRAuthDataResult *_Nullable authDataResult,
  395. NSError *_Nullable error) {
  396. XCTAssertTrue([NSThread isMainThread]);
  397. [self assertUser:authDataResult.user];
  398. XCTAssertTrue(authDataResult.additionalUserInfo.isNewUser);
  399. XCTAssertNil(error);
  400. [expectation fulfill];
  401. }];
  402. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  403. [self assertUser:[FIRAuth auth].currentUser];
  404. OCMVerifyAll(_mockBackend);
  405. }
  406. /** @fn testPhoneAuthMissingVerificationCode
  407. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  408. to an empty verification code
  409. */
  410. - (void)testPhoneAuthMissingVerificationCode {
  411. [self expectGetAccountInfo];
  412. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  413. [[FIRAuth auth] signOut:NULL];
  414. FIRAuthCredential *credential =
  415. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  416. verificationCode:@""];
  417. [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user,
  418. NSError *_Nullable error) {
  419. XCTAssertTrue([NSThread isMainThread]);
  420. XCTAssertNil(user);
  421. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationCode);
  422. [expectation fulfill];
  423. }];
  424. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  425. }
  426. /** @fn testPhoneAuthMissingVerificationID
  427. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  428. to an empty verification ID.
  429. */
  430. - (void)testPhoneAuthMissingVerificationID {
  431. [self expectGetAccountInfo];
  432. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  433. [[FIRAuth auth] signOut:NULL];
  434. FIRAuthCredential *credential =
  435. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:@""
  436. verificationCode:kVerificationCode];
  437. [[FIRAuth auth] signInWithCredential:credential completion:^(FIRUser *_Nullable user,
  438. NSError *_Nullable error) {
  439. XCTAssertTrue([NSThread isMainThread]);
  440. XCTAssertNil(user);
  441. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationID);
  442. [expectation fulfill];
  443. }];
  444. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  445. }
  446. #endif
  447. /** @fn testSignInWithEmailPasswordSuccess
  448. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  449. */
  450. - (void)testSignInWithEmailPasswordSuccess {
  451. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  452. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  453. FIRVerifyPasswordResponseCallback callback) {
  454. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  455. XCTAssertEqualObjects(request.email, kEmail);
  456. XCTAssertEqualObjects(request.password, kFakePassword);
  457. XCTAssertTrue(request.returnSecureToken);
  458. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  459. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  460. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  461. callback(mockVerifyPasswordResponse, nil);
  462. });
  463. });
  464. [self expectGetAccountInfo];
  465. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  466. [[FIRAuth auth] signOut:NULL];
  467. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  468. NSError *_Nullable error) {
  469. XCTAssertTrue([NSThread isMainThread]);
  470. [self assertUser:user];
  471. XCTAssertNil(error);
  472. [expectation fulfill];
  473. }];
  474. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  475. [self assertUser:[FIRAuth auth].currentUser];
  476. OCMVerifyAll(_mockBackend);
  477. }
  478. /** @fn testSignInWithEmailPasswordFailure
  479. @brief Tests the flow of a failed @c signInWithEmail:password:completion: call.
  480. */
  481. - (void)testSignInWithEmailPasswordFailure {
  482. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  483. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  484. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  485. [[FIRAuth auth] signOut:NULL];
  486. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  487. NSError *_Nullable error) {
  488. XCTAssertTrue([NSThread isMainThread]);
  489. XCTAssertNil(user);
  490. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  491. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  492. [expectation fulfill];
  493. }];
  494. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  495. XCTAssertNil([FIRAuth auth].currentUser);
  496. OCMVerifyAll(_mockBackend);
  497. }
  498. /** @fn testSignInAndRetrieveDataWithEmailPasswordSuccess
  499. @brief Tests the flow of a successful @c signInAndRetrieveDataWithEmail:password:completion:
  500. call.
  501. */
  502. - (void)testSignInAndRetrieveDataWithEmailPasswordSuccess {
  503. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  504. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  505. FIRVerifyPasswordResponseCallback callback) {
  506. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  507. XCTAssertEqualObjects(request.email, kEmail);
  508. XCTAssertEqualObjects(request.password, kFakePassword);
  509. XCTAssertTrue(request.returnSecureToken);
  510. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  511. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  512. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  513. callback(mockVerifyPasswordResponse, nil);
  514. });
  515. });
  516. [self expectGetAccountInfo];
  517. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  518. [[FIRAuth auth] signOut:NULL];
  519. [[FIRAuth auth] signInAndRetrieveDataWithEmail:kEmail
  520. password:kFakePassword
  521. completion:^(FIRAuthDataResult *_Nullable result,
  522. NSError *_Nullable error) {
  523. XCTAssertTrue([NSThread isMainThread]);
  524. [self assertUser:result.user];
  525. XCTAssertFalse(result.additionalUserInfo.isNewUser);
  526. XCTAssertEqualObjects(result.additionalUserInfo.providerID, FIREmailAuthProviderID);
  527. XCTAssertNil(error);
  528. [expectation fulfill];
  529. }];
  530. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  531. [self assertUser:[FIRAuth auth].currentUser];
  532. OCMVerifyAll(_mockBackend);
  533. }
  534. /** @fn testSignInAndRetrieveDataWithEmailPasswordFailure
  535. @brief Tests the flow of a failed @c signInAndRetrieveDataWithEmail:password:completion: call.
  536. */
  537. - (void)testSignInAndRetrieveDataWithEmailPasswordFailure {
  538. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  539. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  540. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  541. [[FIRAuth auth] signOut:NULL];
  542. [[FIRAuth auth] signInAndRetrieveDataWithEmail:kEmail
  543. password:kFakePassword
  544. completion:^(FIRAuthDataResult *_Nullable result,
  545. NSError *_Nullable error) {
  546. XCTAssertTrue([NSThread isMainThread]);
  547. XCTAssertNil(result);
  548. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  549. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  550. [expectation fulfill];
  551. }];
  552. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  553. XCTAssertNil([FIRAuth auth].currentUser);
  554. OCMVerifyAll(_mockBackend);
  555. }
  556. /** @fn testResetPasswordSuccess
  557. @brief Tests the flow of a successful @c confirmPasswordResetWithCode:newPassword:completion:
  558. call.
  559. */
  560. - (void)testResetPasswordSuccess {
  561. NSString *fakeEmail = @"fakeEmail";
  562. NSString *fakeCode = @"fakeCode";
  563. NSString *fakeNewPassword = @"fakeNewPassword";
  564. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  565. .andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
  566. FIRResetPasswordCallback callback) {
  567. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  568. XCTAssertEqualObjects(request.oobCode, fakeCode);
  569. XCTAssertEqualObjects(request.updatedPassword, fakeNewPassword);
  570. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  571. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  572. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  573. callback(mockResetPasswordResponse, nil);
  574. });
  575. });
  576. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  577. [[FIRAuth auth] signOut:NULL];
  578. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  579. newPassword:fakeNewPassword
  580. completion:^(NSError *_Nullable error) {
  581. XCTAssertTrue([NSThread isMainThread]);
  582. XCTAssertNil(error);
  583. [expectation fulfill];
  584. }];
  585. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  586. OCMVerifyAll(_mockBackend);
  587. }
  588. /** @fn testResetPasswordFailure
  589. @brief Tests the flow of a failed @c confirmPasswordResetWithCode:newPassword:completion:
  590. call.
  591. */
  592. - (void)testResetPasswordFailure {
  593. NSString *fakeCode = @"fakeCode";
  594. NSString *fakeNewPassword = @"fakeNewPassword";
  595. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  596. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  597. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  598. [[FIRAuth auth] signOut:NULL];
  599. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  600. newPassword:fakeNewPassword
  601. completion:^(NSError *_Nullable error) {
  602. XCTAssertTrue([NSThread isMainThread]);
  603. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  604. [expectation fulfill];
  605. }];
  606. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  607. OCMVerifyAll(_mockBackend);
  608. }
  609. /** @fn testCheckActionCodeSuccess
  610. @brief Tests the flow of a successful @c checkActionCode:completion call.
  611. */
  612. - (void)testCheckActionCodeSuccess {
  613. NSString *verifyEmailRequestType = @"VERIFY_EMAIL";
  614. NSString *fakeEmail = @"fakeEmail";
  615. NSString *fakeNewEmail = @"fakeNewEmail";
  616. NSString *fakeCode = @"fakeCode";
  617. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  618. .andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
  619. FIRResetPasswordCallback callback) {
  620. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  621. XCTAssertEqualObjects(request.oobCode, fakeCode);
  622. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  623. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  624. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  625. OCMStub([mockResetPasswordResponse verifiedEmail]).andReturn(fakeNewEmail);
  626. OCMStubRecorder *stub =
  627. OCMStub([(FIRResetPasswordResponse *) mockResetPasswordResponse requestType]);
  628. stub.andReturn(verifyEmailRequestType);
  629. callback(mockResetPasswordResponse, nil);
  630. });
  631. });
  632. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  633. [[FIRAuth auth] checkActionCode:fakeCode completion:^(FIRActionCodeInfo *_Nullable info,
  634. NSError *_Nullable error) {
  635. XCTAssertTrue([NSThread isMainThread]);
  636. XCTAssertNil(error);
  637. XCTAssertEqual(info.operation, FIRActionCodeOperationVerifyEmail);
  638. XCTAssert([fakeNewEmail isEqualToString:[info dataForKey:FIRActionCodeEmailKey]]);
  639. [expectation fulfill];
  640. }];
  641. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  642. OCMVerifyAll(_mockBackend);
  643. }
  644. /** @fn testCheckActionCodeFailure
  645. @brief Tests the flow of a failed @c checkActionCode:completion call.
  646. */
  647. - (void)testCheckActionCodeFailure {
  648. NSString *fakeCode = @"fakeCode";
  649. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  650. ._andDispatchError2([FIRAuthErrorUtils expiredActionCodeErrorWithMessage:nil]);
  651. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  652. [[FIRAuth auth] signOut:NULL];
  653. [[FIRAuth auth] checkActionCode:fakeCode completion:^(FIRActionCodeInfo *_Nullable info,
  654. NSError *_Nullable error) {
  655. XCTAssertTrue([NSThread isMainThread]);
  656. XCTAssertNotNil(error);
  657. XCTAssertEqual(error.code, FIRAuthErrorCodeExpiredActionCode);
  658. [expectation fulfill];
  659. }];
  660. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  661. OCMVerifyAll(_mockBackend);
  662. }
  663. /** @fn testApplyActionCodeSuccess
  664. @brief Tests the flow of a successful @c applyActionCode:completion call.
  665. */
  666. - (void)testApplyActionCodeSuccess {
  667. NSString *fakeCode = @"fakeCode";
  668. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  669. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  670. FIRSetAccountInfoResponseCallback callback) {
  671. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  672. XCTAssertEqualObjects(request.OOBCode, fakeCode);
  673. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  674. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  675. callback(mockSetAccountInfoResponse, nil);
  676. });
  677. });
  678. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  679. [[FIRAuth auth] applyActionCode:fakeCode completion:^(NSError *_Nullable error) {
  680. XCTAssertTrue([NSThread isMainThread]);
  681. XCTAssertNil(error);
  682. [expectation fulfill];
  683. }];
  684. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  685. OCMVerifyAll(_mockBackend);
  686. }
  687. /** @fn testApplyActionCodeFailure
  688. @brief Tests the flow of a failed @c checkActionCode:completion call.
  689. */
  690. - (void)testApplyActionCodeFailure {
  691. NSString *fakeCode = @"fakeCode";
  692. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  693. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  694. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  695. [[FIRAuth auth] signOut:NULL];
  696. [[FIRAuth auth] applyActionCode:fakeCode completion:^(NSError *_Nullable error) {
  697. XCTAssertTrue([NSThread isMainThread]);
  698. XCTAssertNotNil(error);
  699. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  700. [expectation fulfill];
  701. }];
  702. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  703. OCMVerifyAll(_mockBackend);
  704. }
  705. /** @fn testVerifyPasswordResetCodeSuccess
  706. @brief Tests the flow of a successful @c verifyPasswordResetCode:completion call.
  707. */
  708. - (void)testVerifyPasswordResetCodeSuccess {
  709. NSString *passwordResetRequestType = @"PASSWORD_RESET";
  710. NSString *fakeEmail = @"fakeEmail";
  711. NSString *fakeCode = @"fakeCode";
  712. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  713. .andCallBlock2(^(FIRResetPasswordRequest *_Nullable request,
  714. FIRResetPasswordCallback callback) {
  715. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  716. XCTAssertEqualObjects(request.oobCode, fakeCode);
  717. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  718. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  719. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  720. OCMStubRecorder *stub =
  721. OCMStub([(FIRResetPasswordResponse *) mockResetPasswordResponse requestType]);
  722. stub.andReturn(passwordResetRequestType);
  723. callback(mockResetPasswordResponse, nil);
  724. });
  725. });
  726. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  727. [[FIRAuth auth] verifyPasswordResetCode:fakeCode completion:^(NSString *_Nullable email,
  728. NSError *_Nullable error) {
  729. XCTAssertTrue([NSThread isMainThread]);
  730. XCTAssertNil(error);
  731. XCTAssertEqual(email, fakeEmail);
  732. [expectation fulfill];
  733. }];
  734. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  735. OCMVerifyAll(_mockBackend);
  736. }
  737. /** @fn testVerifyPasswordResetCodeFailure
  738. @brief Tests the flow of a failed @c verifyPasswordResetCode:completion call.
  739. */
  740. - (void)testVeridyPasswordResetCodeFailure {
  741. NSString *fakeCode = @"fakeCode";
  742. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  743. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  744. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  745. [[FIRAuth auth] signOut:NULL];
  746. [[FIRAuth auth] verifyPasswordResetCode:fakeCode completion:^(NSString *_Nullable email,
  747. NSError *_Nullable error) {
  748. XCTAssertTrue([NSThread isMainThread]);
  749. XCTAssertNotNil(error);
  750. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  751. [expectation fulfill];
  752. }];
  753. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  754. OCMVerifyAll(_mockBackend);
  755. }
  756. /** @fn testSignInWithEmailCredentialSuccess
  757. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  758. email-password credential.
  759. */
  760. - (void)testSignInWithEmailCredentialSuccess {
  761. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  762. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  763. FIRVerifyPasswordResponseCallback callback) {
  764. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  765. XCTAssertEqualObjects(request.email, kEmail);
  766. XCTAssertEqualObjects(request.password, kFakePassword);
  767. XCTAssertTrue(request.returnSecureToken);
  768. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  769. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  770. [self stubTokensWithMockResponse:mockVeriyPasswordResponse];
  771. callback(mockVeriyPasswordResponse, nil);
  772. });
  773. });
  774. [self expectGetAccountInfo];
  775. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  776. [[FIRAuth auth] signOut:NULL];
  777. FIRAuthCredential *emailCredential =
  778. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  779. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  780. NSError *_Nullable error) {
  781. XCTAssertTrue([NSThread isMainThread]);
  782. [self assertUser:user];
  783. XCTAssertNil(error);
  784. [expectation fulfill];
  785. }];
  786. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  787. [self assertUser:[FIRAuth auth].currentUser];
  788. OCMVerifyAll(_mockBackend);
  789. }
  790. /** @fn testSignInWithEmailCredentialSuccess
  791. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  792. email-password credential using the deprecated FIREmailPasswordAuthProvider.
  793. */
  794. - (void)testSignInWithEmailCredentialSuccessWithDepricatedProvider {
  795. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  796. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  797. FIRVerifyPasswordResponseCallback callback) {
  798. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  799. XCTAssertEqualObjects(request.email, kEmail);
  800. XCTAssertEqualObjects(request.password, kFakePassword);
  801. XCTAssertTrue(request.returnSecureToken);
  802. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  803. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  804. [self stubTokensWithMockResponse:mockVeriyPasswordResponse];
  805. callback(mockVeriyPasswordResponse, nil);
  806. });
  807. });
  808. [self expectGetAccountInfo];
  809. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  810. [[FIRAuth auth] signOut:NULL];
  811. #pragma clang diagnostic push
  812. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  813. FIRAuthCredential *emailCredential =
  814. [FIREmailPasswordAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  815. #pragma clang diagnostic pop
  816. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  817. NSError *_Nullable error) {
  818. XCTAssertTrue([NSThread isMainThread]);
  819. [self assertUser:user];
  820. XCTAssertNil(error);
  821. [expectation fulfill];
  822. }];
  823. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  824. [self assertUser:[FIRAuth auth].currentUser];
  825. OCMVerifyAll(_mockBackend);
  826. }
  827. /** @fn testSignInWithEmailCredentialFailure
  828. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  829. email-password credential.
  830. */
  831. - (void)testSignInWithEmailCredentialFailure {
  832. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  833. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  834. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  835. [[FIRAuth auth] signOut:NULL];
  836. FIRAuthCredential *emailCredential =
  837. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  838. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  839. NSError *_Nullable error) {
  840. XCTAssertTrue([NSThread isMainThread]);
  841. XCTAssertNil(user);
  842. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  843. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  844. [expectation fulfill];
  845. }];
  846. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  847. XCTAssertNil([FIRAuth auth].currentUser);
  848. OCMVerifyAll(_mockBackend);
  849. }
  850. /** @fn testSignInWithEmailCredentialEmptyPassword
  851. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  852. email-password credential using an empty password. This error occurs on the client side,
  853. so there is no need to fake an RPC response.
  854. */
  855. - (void)testSignInWithEmailCredentialEmptyPassword {
  856. NSString *emptyString = @"";
  857. [self expectGetAccountInfo];
  858. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  859. [[FIRAuth auth] signOut:NULL];
  860. FIRAuthCredential *emailCredential =
  861. [FIREmailAuthProvider credentialWithEmail:kEmail password:emptyString];
  862. [[FIRAuth auth] signInWithCredential:emailCredential completion:^(FIRUser *_Nullable user,
  863. NSError *_Nullable error) {
  864. XCTAssertTrue([NSThread isMainThread]);
  865. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  866. [expectation fulfill];
  867. }];
  868. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  869. }
  870. /** @fn testSignInWithGoogleAccountExistsError
  871. @brief Tests the flow of a failed @c signInWithCredential:completion: with a Google credential
  872. where the backend returns a needs @needConfirmation equal to true. An
  873. FIRAuthErrorCodeAccountExistsWithDifferentCredential error should be thrown.
  874. */
  875. - (void)testSignInWithGoogleAccountExistsError {
  876. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  877. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  878. FIRVerifyAssertionResponseCallback callback) {
  879. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  880. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  881. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  882. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  883. XCTAssertTrue(request.returnSecureToken);
  884. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  885. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  886. OCMStub([mockVeriyAssertionResponse needConfirmation]).andReturn(YES);
  887. OCMStub([mockVeriyAssertionResponse email]).andReturn(kEmail);
  888. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  889. callback(mockVeriyAssertionResponse, nil);
  890. });
  891. });
  892. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  893. [[FIRAuth auth] signOut:NULL];
  894. FIRAuthCredential *googleCredential =
  895. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  896. [[FIRAuth auth] signInWithCredential:googleCredential completion:^(FIRUser *_Nullable user,
  897. NSError *_Nullable error) {
  898. XCTAssertTrue([NSThread isMainThread]);
  899. XCTAssertEqual(error.code, FIRAuthErrorCodeAccountExistsWithDifferentCredential);
  900. XCTAssertEqualObjects(error.userInfo[FIRAuthErrorUserInfoEmailKey], kEmail);
  901. [expectation fulfill];
  902. }];
  903. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  904. OCMVerifyAll(_mockBackend);
  905. }
  906. /** @fn testSignInWithGoogleCredentialSuccess
  907. @brief Tests the flow of a successful @c signInWithCredential:completion: call with an
  908. Google Sign-In credential.
  909. */
  910. - (void)testSignInWithGoogleCredentialSuccess {
  911. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  912. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  913. FIRVerifyAssertionResponseCallback callback) {
  914. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  915. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  916. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  917. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  918. XCTAssertTrue(request.returnSecureToken);
  919. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  920. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  921. OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
  922. OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  923. OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
  924. OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  925. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  926. callback(mockVeriyAssertionResponse, nil);
  927. });
  928. });
  929. [self expectGetAccountInfoGoogle];
  930. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  931. [[FIRAuth auth] signOut:NULL];
  932. FIRAuthCredential *googleCredential =
  933. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  934. [[FIRAuth auth] signInWithCredential:googleCredential completion:^(FIRUser *_Nullable user,
  935. NSError *_Nullable error) {
  936. XCTAssertTrue([NSThread isMainThread]);
  937. [self assertUserGoogle:user];
  938. XCTAssertNil(error);
  939. [expectation fulfill];
  940. }];
  941. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  942. [self assertUserGoogle:[FIRAuth auth].currentUser];
  943. OCMVerifyAll(_mockBackend);
  944. }
  945. /** @fn testSignInAndRetrieveDataWithCredentialSuccess
  946. @brief Tests the flow of a successful @c signInAndRetrieveDataWithCredential:completion: call
  947. with an Google Sign-In credential.
  948. */
  949. - (void)testSignInAndRetrieveDataWithCredentialSuccess {
  950. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  951. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  952. FIRVerifyAssertionResponseCallback callback) {
  953. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  954. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  955. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  956. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  957. XCTAssertTrue(request.returnSecureToken);
  958. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  959. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  960. OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(kGoogleID);
  961. OCMStub([mockVeriyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  962. OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
  963. OCMStub([mockVeriyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  964. OCMStub([mockVeriyAssertionResponse profile]).andReturn([[self class] googleProfile]);
  965. OCMStub([mockVeriyAssertionResponse username]).andReturn(kDisplayName);
  966. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  967. callback(mockVeriyAssertionResponse, nil);
  968. });
  969. });
  970. [self expectGetAccountInfoGoogle];
  971. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  972. [[FIRAuth auth] signOut:NULL];
  973. FIRAuthCredential *googleCredential =
  974. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  975. [[FIRAuth auth] signInAndRetrieveDataWithCredential:googleCredential
  976. completion:^(FIRAuthDataResult *_Nullable authResult,
  977. NSError *_Nullable error) {
  978. XCTAssertTrue([NSThread isMainThread]);
  979. [self assertUserGoogle:authResult.user];
  980. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  981. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
  982. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRGoogleAuthProviderID);
  983. XCTAssertNil(error);
  984. [expectation fulfill];
  985. }];
  986. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  987. [self assertUserGoogle:[FIRAuth auth].currentUser];
  988. OCMVerifyAll(_mockBackend);
  989. }
  990. /** @fn testSignInWithGoogleCredentialFailure
  991. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  992. Google Sign-In credential.
  993. */
  994. - (void)testSignInWithGoogleCredentialFailure {
  995. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  996. .andDispatchError2([FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:kGoogleEmail]);
  997. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  998. [[FIRAuth auth] signOut:NULL];
  999. FIRAuthCredential *googleCredential =
  1000. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1001. [[FIRAuth auth] signInWithCredential:googleCredential completion:^(FIRUser *_Nullable user,
  1002. NSError *_Nullable error) {
  1003. XCTAssertTrue([NSThread isMainThread]);
  1004. XCTAssertNil(user);
  1005. XCTAssertEqual(error.code, FIRAuthErrorCodeEmailAlreadyInUse);
  1006. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1007. [expectation fulfill];
  1008. }];
  1009. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1010. XCTAssertNil([FIRAuth auth].currentUser);
  1011. OCMVerifyAll(_mockBackend);
  1012. }
  1013. /** @fn testSignInAnonymouslySuccess
  1014. @brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
  1015. */
  1016. - (void)testSignInAnonymouslySuccess {
  1017. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1018. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  1019. FIRSignupNewUserCallback callback) {
  1020. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1021. XCTAssertNil(request.email);
  1022. XCTAssertNil(request.password);
  1023. XCTAssertTrue(request.returnSecureToken);
  1024. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1025. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1026. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1027. callback(mockSignUpNewUserResponse, nil);
  1028. });
  1029. });
  1030. [self expectGetAccountInfoAnonymous];
  1031. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1032. [[FIRAuth auth] signOut:NULL];
  1033. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user,
  1034. NSError *_Nullable error) {
  1035. XCTAssertTrue([NSThread isMainThread]);
  1036. [self assertUserAnonymous:user];
  1037. XCTAssertNil(error);
  1038. [expectation fulfill];
  1039. }];
  1040. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1041. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  1042. OCMVerifyAll(_mockBackend);
  1043. }
  1044. /** @fn testSignInAnonymouslyFailure
  1045. @brief Tests the flow of a failed @c signInAnonymouslyWithCompletion: call.
  1046. */
  1047. - (void)testSignInAnonymouslyFailure {
  1048. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1049. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  1050. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1051. [[FIRAuth auth] signOut:NULL];
  1052. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user,
  1053. NSError *_Nullable error) {
  1054. XCTAssertTrue([NSThread isMainThread]);
  1055. XCTAssertNil(user);
  1056. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  1057. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1058. [expectation fulfill];
  1059. }];
  1060. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1061. XCTAssertNil([FIRAuth auth].currentUser);
  1062. OCMVerifyAll(_mockBackend);
  1063. }
  1064. /** @fn testSignInAnonymouslyAndRetrieveDataSuccess
  1065. @brief Tests the flow of a successful @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
  1066. */
  1067. - (void)testSignInAnonymouslyAndRetrieveDataSuccess {
  1068. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1069. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  1070. FIRSignupNewUserCallback callback) {
  1071. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1072. XCTAssertNil(request.email);
  1073. XCTAssertNil(request.password);
  1074. XCTAssertTrue(request.returnSecureToken);
  1075. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1076. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1077. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1078. callback(mockSignUpNewUserResponse, nil);
  1079. });
  1080. });
  1081. [self expectGetAccountInfoAnonymous];
  1082. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1083. [[FIRAuth auth] signOut:NULL];
  1084. [[FIRAuth auth] signInAnonymouslyAndRetrieveDataWithCompletion:
  1085. ^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1086. XCTAssertTrue([NSThread isMainThread]);
  1087. [self assertUserAnonymous:result.user];
  1088. XCTAssertNil(error);
  1089. [expectation fulfill];
  1090. }];
  1091. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1092. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  1093. OCMVerifyAll(_mockBackend);
  1094. }
  1095. /** @fn testSignInAnonymouslyAndRetrieveDataFailure
  1096. @brief Tests the flow of a failed @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
  1097. */
  1098. - (void)testSignInAnonymouslyAndRetrieveDataFailure {
  1099. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1100. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  1101. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1102. [[FIRAuth auth] signOut:NULL];
  1103. [[FIRAuth auth] signInAnonymouslyAndRetrieveDataWithCompletion:
  1104. ^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1105. XCTAssertTrue([NSThread isMainThread]);
  1106. XCTAssertNil(result);
  1107. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  1108. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1109. [expectation fulfill];
  1110. }];
  1111. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1112. XCTAssertNil([FIRAuth auth].currentUser);
  1113. OCMVerifyAll(_mockBackend);
  1114. }
  1115. /** @fn testSignInWithCustomTokenSuccess
  1116. @brief Tests the flow of a successful @c signInWithCustomToken:completion: call.
  1117. */
  1118. - (void)testSignInWithCustomTokenSuccess {
  1119. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1120. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1121. FIRVerifyCustomTokenResponseCallback callback) {
  1122. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1123. XCTAssertEqualObjects(request.token, kCustomToken);
  1124. XCTAssertTrue(request.returnSecureToken);
  1125. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1126. id mockVeriyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1127. [self stubTokensWithMockResponse:mockVeriyCustomTokenResponse];
  1128. callback(mockVeriyCustomTokenResponse, nil);
  1129. });
  1130. });
  1131. [self expectGetAccountInfo];
  1132. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1133. [[FIRAuth auth] signOut:NULL];
  1134. [[FIRAuth auth] signInWithCustomToken:kCustomToken completion:^(FIRUser *_Nullable user,
  1135. NSError *_Nullable error) {
  1136. XCTAssertTrue([NSThread isMainThread]);
  1137. [self assertUser:user];
  1138. XCTAssertNil(error);
  1139. [expectation fulfill];
  1140. }];
  1141. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1142. [self assertUser:[FIRAuth auth].currentUser];
  1143. OCMVerifyAll(_mockBackend);
  1144. }
  1145. /** @fn testSignInWithCustomTokenFailure
  1146. @brief Tests the flow of a failed @c signInWithCustomToken:completion: call.
  1147. */
  1148. - (void)testSignInWithCustomTokenFailure {
  1149. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1150. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1151. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1152. [[FIRAuth auth] signOut:NULL];
  1153. [[FIRAuth auth] signInWithCustomToken:kCustomToken completion:^(FIRUser *_Nullable user,
  1154. NSError *_Nullable error) {
  1155. XCTAssertTrue([NSThread isMainThread]);
  1156. XCTAssertNil(user);
  1157. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1158. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1159. [expectation fulfill];
  1160. }];
  1161. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1162. XCTAssertNil([FIRAuth auth].currentUser);
  1163. OCMVerifyAll(_mockBackend);
  1164. }
  1165. /** @fn testSignInAndRetrieveDataWithCustomTokenSuccess
  1166. @brief Tests the flow of a successful @c signInAndRetrieveDataWithCustomToken:completion: call.
  1167. */
  1168. - (void)testSignInAndRetrieveDataWithCustomTokenSuccess {
  1169. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1170. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1171. FIRVerifyCustomTokenResponseCallback callback) {
  1172. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1173. XCTAssertEqualObjects(request.token, kCustomToken);
  1174. XCTAssertTrue(request.returnSecureToken);
  1175. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1176. id mockVeriyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1177. [self stubTokensWithMockResponse:mockVeriyCustomTokenResponse];
  1178. callback(mockVeriyCustomTokenResponse, nil);
  1179. });
  1180. });
  1181. [self expectGetAccountInfo];
  1182. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1183. [[FIRAuth auth] signOut:NULL];
  1184. [[FIRAuth auth] signInAndRetrieveDataWithCustomToken:kCustomToken
  1185. completion:^(FIRAuthDataResult *_Nullable result,
  1186. NSError *_Nullable error) {
  1187. XCTAssertTrue([NSThread isMainThread]);
  1188. [self assertUser:result.user];
  1189. XCTAssertFalse(result.additionalUserInfo.isNewUser);
  1190. XCTAssertNil(error);
  1191. [expectation fulfill];
  1192. }];
  1193. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1194. [self assertUser:[FIRAuth auth].currentUser];
  1195. OCMVerifyAll(_mockBackend);
  1196. }
  1197. /** @fn testSignInAndRetrieveDataWithCustomTokenFailure
  1198. @brief Tests the flow of a failed @c signInAndRetrieveDataWithCustomToken:completion: call.
  1199. */
  1200. - (void)testSignInAndRetrieveDataWithCustomTokenFailure {
  1201. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1202. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1203. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1204. [[FIRAuth auth] signOut:NULL];
  1205. [[FIRAuth auth] signInAndRetrieveDataWithCustomToken:kCustomToken
  1206. completion:^(FIRAuthDataResult *_Nullable result,
  1207. NSError *_Nullable error) {
  1208. XCTAssertTrue([NSThread isMainThread]);
  1209. XCTAssertNil(result);
  1210. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1211. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1212. [expectation fulfill];
  1213. }];
  1214. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1215. XCTAssertNil([FIRAuth auth].currentUser);
  1216. OCMVerifyAll(_mockBackend);
  1217. }
  1218. /** @fn testCreateUserWithEmailPasswordSuccess
  1219. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1220. */
  1221. - (void)testCreateUserWithEmailPasswordSuccess {
  1222. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1223. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  1224. FIRSignupNewUserCallback callback) {
  1225. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1226. XCTAssertEqualObjects(request.email, kEmail);
  1227. XCTAssertEqualObjects(request.password, kFakePassword);
  1228. XCTAssertTrue(request.returnSecureToken);
  1229. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1230. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1231. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1232. callback(mockSignUpNewUserResponse, nil);
  1233. });
  1234. });
  1235. [self expectGetAccountInfo];
  1236. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1237. [[FIRAuth auth] signOut:NULL];
  1238. [[FIRAuth auth] createUserWithEmail:kEmail
  1239. password:kFakePassword
  1240. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1241. XCTAssertTrue([NSThread isMainThread]);
  1242. [self assertUser:user];
  1243. XCTAssertNil(error);
  1244. [expectation fulfill];
  1245. }];
  1246. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1247. [self assertUser:[FIRAuth auth].currentUser];
  1248. OCMVerifyAll(_mockBackend);
  1249. }
  1250. /** @fn testCreateUserWithEmailPasswordFailure
  1251. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call.
  1252. */
  1253. - (void)testCreateUserWithEmailPasswordFailure {
  1254. NSString *reason = @"Password shouldn't be a common word.";
  1255. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1256. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1257. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1258. [[FIRAuth auth] signOut:NULL];
  1259. [[FIRAuth auth] createUserWithEmail:kEmail
  1260. password:kFakePassword
  1261. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1262. XCTAssertTrue([NSThread isMainThread]);
  1263. XCTAssertNil(user);
  1264. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1265. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1266. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1267. [expectation fulfill];
  1268. }];
  1269. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1270. XCTAssertNil([FIRAuth auth].currentUser);
  1271. OCMVerifyAll(_mockBackend);
  1272. }
  1273. /** @fn testCreateUserAndRetrieveDataWithEmailPasswordSuccess
  1274. @brief Tests the flow of a successful @c createUserAndRetrieveDataWithEmail:password:completion:
  1275. call.
  1276. */
  1277. - (void)testCreateUserAndRetrieveDataWithEmailPasswordSuccess {
  1278. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1279. .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request,
  1280. FIRSignupNewUserCallback callback) {
  1281. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1282. XCTAssertEqualObjects(request.email, kEmail);
  1283. XCTAssertEqualObjects(request.password, kFakePassword);
  1284. XCTAssertTrue(request.returnSecureToken);
  1285. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1286. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1287. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1288. callback(mockSignUpNewUserResponse, nil);
  1289. });
  1290. });
  1291. [self expectGetAccountInfo];
  1292. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1293. [[FIRAuth auth] signOut:NULL];
  1294. [[FIRAuth auth] createUserAndRetrieveDataWithEmail:kEmail
  1295. password:kFakePassword
  1296. completion:^(FIRAuthDataResult *_Nullable result,
  1297. NSError *_Nullable error) {
  1298. XCTAssertTrue([NSThread isMainThread]);
  1299. [self assertUser:result.user];
  1300. XCTAssertTrue(result.additionalUserInfo.isNewUser);
  1301. XCTAssertNil(error);
  1302. [expectation fulfill];
  1303. }];
  1304. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1305. [self assertUser:[FIRAuth auth].currentUser];
  1306. OCMVerifyAll(_mockBackend);
  1307. }
  1308. /** @fn testCreateUserAndRetrieveDataWithEmailPasswordFailure
  1309. @brief Tests the flow of a failed @c createUserAndRetrieveDataWithEmail:password:completion:
  1310. call.
  1311. */
  1312. - (void)testCreateUserAndRetrieveDataWithEmailPasswordFailure {
  1313. NSString *reason = @"Password shouldn't be a common word.";
  1314. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1315. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1316. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1317. [[FIRAuth auth] signOut:NULL];
  1318. [[FIRAuth auth] createUserAndRetrieveDataWithEmail:kEmail
  1319. password:kFakePassword
  1320. completion:^(FIRAuthDataResult *_Nullable result,
  1321. NSError *_Nullable error) {
  1322. XCTAssertTrue([NSThread isMainThread]);
  1323. XCTAssertNil(result);
  1324. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1325. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1326. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1327. [expectation fulfill];
  1328. }];
  1329. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1330. XCTAssertNil([FIRAuth auth].currentUser);
  1331. OCMVerifyAll(_mockBackend);
  1332. }
  1333. /** @fn testCreateUserEmptyPasswordFailure
  1334. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1335. empty password. This error occurs on the client side, so there is no need to fake an RPC
  1336. response.
  1337. */
  1338. - (void)testCreateUserEmptyPasswordFailure {
  1339. [self expectGetAccountInfo];
  1340. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1341. [[FIRAuth auth] signOut:NULL];
  1342. [[FIRAuth auth] createUserWithEmail:kEmail
  1343. password:@""
  1344. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1345. XCTAssertTrue([NSThread isMainThread]);
  1346. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1347. [expectation fulfill];
  1348. }];
  1349. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1350. }
  1351. /** @fn testCreateUserEmptyEmailFailure
  1352. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1353. empty email adress. This error occurs on the client side, so there is no need to fake an RPC
  1354. response.
  1355. */
  1356. - (void)testCreateUserEmptyEmailFailure {
  1357. [self expectGetAccountInfo];
  1358. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1359. [[FIRAuth auth] signOut:NULL];
  1360. [[FIRAuth auth] createUserWithEmail:@""
  1361. password:kFakePassword
  1362. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1363. XCTAssertTrue([NSThread isMainThread]);
  1364. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingEmail);
  1365. [expectation fulfill];
  1366. }];
  1367. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1368. }
  1369. /** @fn testSendPasswordResetEmailSuccess
  1370. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  1371. */
  1372. - (void)testSendPasswordResetEmailSuccess {
  1373. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1374. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  1375. FIRGetOOBConfirmationCodeResponseCallback callback) {
  1376. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1377. XCTAssertEqualObjects(request.email, kEmail);
  1378. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1379. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  1380. });
  1381. });
  1382. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1383. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail completion:^(NSError *_Nullable error) {
  1384. XCTAssertTrue([NSThread isMainThread]);
  1385. XCTAssertNil(error);
  1386. [expectation fulfill];
  1387. }];
  1388. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1389. OCMVerifyAll(_mockBackend);
  1390. }
  1391. /** @fn testSendPasswordResetEmailFailure
  1392. @brief Tests the flow of a failed @c sendPasswordResetWithEmail:completion: call.
  1393. */
  1394. - (void)testSendPasswordResetEmailFailure {
  1395. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1396. .andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
  1397. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1398. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail completion:^(NSError *_Nullable error) {
  1399. XCTAssertTrue([NSThread isMainThread]);
  1400. XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
  1401. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1402. [expectation fulfill];
  1403. }];
  1404. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1405. OCMVerifyAll(_mockBackend);
  1406. }
  1407. /** @fn testSignOut
  1408. @brief Tests the @c signOut: method.
  1409. */
  1410. - (void)testSignOut {
  1411. [self waitForSignIn];
  1412. // Verify signing out succeeds and clears the current user.
  1413. NSError *error;
  1414. XCTAssertTrue([[FIRAuth auth] signOut:&error]);
  1415. XCTAssertNil([FIRAuth auth].currentUser);
  1416. }
  1417. /** @fn testAuthStateChanges
  1418. @brief Tests @c addAuthStateDidChangeListener: and @c removeAuthStateDidChangeListener: methods.
  1419. */
  1420. - (void)testAuthStateChanges {
  1421. // Set up listener.
  1422. __block XCTestExpectation *expectation;
  1423. __block BOOL shouldHaveUser;
  1424. FIRAuthStateDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  1425. XCTAssertTrue([NSThread isMainThread]);
  1426. XCTAssertEqual(auth, [FIRAuth auth]);
  1427. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  1428. if (shouldHaveUser) {
  1429. XCTAssertNotNil(user);
  1430. } else {
  1431. XCTAssertNil(user);
  1432. }
  1433. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1434. XCTAssertNotNil(expectation);
  1435. [expectation fulfill];
  1436. };
  1437. [[FIRAuth auth] signOut:NULL];
  1438. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  1439. // Listener should fire immediately when attached.
  1440. expectation = [self expectationWithDescription:@"initial"];
  1441. shouldHaveUser = NO;
  1442. FIRAuthStateDidChangeListenerHandle handle =
  1443. [[FIRAuth auth] addAuthStateDidChangeListener:listener];
  1444. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1445. // Listener should fire for signing in.
  1446. expectation = [self expectationWithDescription:@"sign-in"];
  1447. shouldHaveUser = YES;
  1448. [self waitForSignIn];
  1449. // Listener should not fire for signing in again.
  1450. shouldHaveUser = YES;
  1451. [self waitForSignIn];
  1452. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is not called
  1453. // Listener should fire for signing out.
  1454. expectation = [self expectationWithDescription:@"sign-out"];
  1455. shouldHaveUser = NO;
  1456. [[FIRAuth auth] signOut:NULL];
  1457. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1458. // Listener should no longer fire once detached.
  1459. expectation = nil;
  1460. [[FIRAuth auth] removeAuthStateDidChangeListener:handle];
  1461. [self waitForSignIn];
  1462. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  1463. }
  1464. /** @fn testIDTokenChanges
  1465. @brief Tests @c addIDTokenDidChangeListener: and @c removeIDTokenDidChangeListener: methods.
  1466. */
  1467. - (void)testIDTokenChanges {
  1468. // Set up listener.
  1469. __block XCTestExpectation *expectation;
  1470. __block BOOL shouldHaveUser;
  1471. FIRIDTokenDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  1472. XCTAssertTrue([NSThread isMainThread]);
  1473. XCTAssertEqual(auth, [FIRAuth auth]);
  1474. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  1475. if (shouldHaveUser) {
  1476. XCTAssertNotNil(user);
  1477. } else {
  1478. XCTAssertNil(user);
  1479. }
  1480. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1481. XCTAssertNotNil(expectation);
  1482. [expectation fulfill];
  1483. };
  1484. [[FIRAuth auth] signOut:NULL];
  1485. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  1486. // Listener should fire immediately when attached.
  1487. expectation = [self expectationWithDescription:@"initial"];
  1488. shouldHaveUser = NO;
  1489. FIRIDTokenDidChangeListenerHandle handle =
  1490. [[FIRAuth auth] addIDTokenDidChangeListener:listener];
  1491. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1492. // Listener should fire for signing in.
  1493. expectation = [self expectationWithDescription:@"sign-in"];
  1494. shouldHaveUser = YES;
  1495. [self waitForSignIn];
  1496. // Listener should fire for signing in again as the same user with another access token.
  1497. expectation = [self expectationWithDescription:@"sign-in again"];
  1498. shouldHaveUser = YES;
  1499. [self waitForSignInWithAccessToken:kNewAccessToken];
  1500. // Listener should fire for signing out.
  1501. expectation = [self expectationWithDescription:@"sign-out"];
  1502. shouldHaveUser = NO;
  1503. [[FIRAuth auth] signOut:NULL];
  1504. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1505. // Listener should no longer fire once detached.
  1506. expectation = nil;
  1507. [[FIRAuth auth] removeIDTokenDidChangeListener:handle];
  1508. [self waitForSignIn];
  1509. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  1510. }
  1511. #pragma mark - Automatic Token Refresh Tests.
  1512. /** @fn testAutomaticTokenRefresh
  1513. @brief Tests a successful flow to automatically refresh tokens for a signed in user.
  1514. */
  1515. - (void)testAutomaticTokenRefresh {
  1516. [[FIRAuth auth] signOut:NULL];
  1517. // Enable auto refresh
  1518. [self enableAutoTokenRefresh];
  1519. // Sign in a user.
  1520. [self waitForSignIn];
  1521. // Set up expectation for secureToken RPC made by token refresh task.
  1522. [self mockSecureTokenResponseWithError:nil];
  1523. // Verify that the current user's access token is the "old" access token before automatic token
  1524. // refresh.
  1525. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1526. // Execute saved token refresh task.
  1527. XCTestExpectation *dispatchAfterExpectation =
  1528. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1529. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1530. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1531. _FIRAuthDispatcherCallback();
  1532. [dispatchAfterExpectation fulfill];
  1533. });
  1534. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1535. // Verify that current user's access token is the "new" access token provided in the mock secure
  1536. // token response during automatic token refresh.
  1537. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1538. OCMVerifyAll(_mockBackend);
  1539. }
  1540. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  1541. @brief Tests an unsuccessful flow to auto refresh tokens with an "invalid token" error.
  1542. This error should cause the user to be signed out.
  1543. */
  1544. - (void)testAutomaticTokenRefreshInvalidTokenFailure {
  1545. [[FIRAuth auth] signOut:NULL];
  1546. // Enable auto refresh
  1547. [self enableAutoTokenRefresh];
  1548. // Sign in a user.
  1549. [self waitForSignIn];
  1550. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  1551. [self mockSecureTokenResponseWithError:[FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]];
  1552. // Verify that current user is still valid.
  1553. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1554. // Execute saved token refresh task.
  1555. XCTestExpectation *dispatchAfterExpectation =
  1556. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1557. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1558. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1559. _FIRAuthDispatcherCallback();
  1560. [dispatchAfterExpectation fulfill];
  1561. });
  1562. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1563. // Verify that the user is nil after failed attempt to refresh tokens caused signed out.
  1564. XCTAssertNil([FIRAuth auth].currentUser);
  1565. OCMVerifyAll(_mockBackend);
  1566. }
  1567. /** @fn testAutomaticTokenRefreshRetry
  1568. @brief Tests that a retry is attempted for a automatic token refresh task (which is not due to
  1569. invalid tokens). The initial attempt to refresh the access token fails, but the second
  1570. attempt is successful.
  1571. */
  1572. - (void)testAutomaticTokenRefreshRetry {
  1573. [[FIRAuth auth] signOut:NULL];
  1574. // Enable auto refresh
  1575. [self enableAutoTokenRefresh];
  1576. // Sign in a user.
  1577. [self waitForSignIn];
  1578. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  1579. [self mockSecureTokenResponseWithError:[NSError errorWithDomain:@"ERROR" code:-1 userInfo:nil]];
  1580. // Execute saved token refresh task.
  1581. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1582. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1583. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1584. _FIRAuthDispatcherCallback();
  1585. _FIRAuthDispatcherCallback = nil;
  1586. [expectation fulfill];
  1587. });
  1588. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1589. // The old access token should still be the current user's access token and not the new access
  1590. // token (kNewAccessToken).
  1591. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1592. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  1593. [self mockSecureTokenResponseWithError:nil];
  1594. // Execute saved token refresh task.
  1595. XCTestExpectation *dispatchAfterExpectation =
  1596. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1597. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1598. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1599. _FIRAuthDispatcherCallback();
  1600. [dispatchAfterExpectation fulfill];
  1601. });
  1602. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1603. // Verify that current user's access token is the "new" access token provided in the mock secure
  1604. // token response during automatic token refresh.
  1605. XCTAssertEqualObjects([FIRAuth auth].currentUser.rawAccessToken, kNewAccessToken);
  1606. OCMVerifyAll(_mockBackend);
  1607. }
  1608. #if TARGET_OS_IOS
  1609. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  1610. @brief Tests that app foreground notification triggers the scheduling of an automatic token
  1611. refresh task.
  1612. */
  1613. - (void)testAutoRefreshAppForegroundedNotification {
  1614. [[FIRAuth auth] signOut:NULL];
  1615. // Enable auto refresh
  1616. [self enableAutoTokenRefresh];
  1617. // Sign in a user.
  1618. [self waitForSignIn];
  1619. // Post "UIApplicationDidBecomeActiveNotification" to trigger scheduling token refresh task.
  1620. [[NSNotificationCenter defaultCenter]
  1621. postNotificationName:UIApplicationDidBecomeActiveNotification object:nil];
  1622. // Verify that current user is still valid with old access token.
  1623. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1624. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  1625. [self mockSecureTokenResponseWithError:nil];
  1626. // Execute saved token refresh task.
  1627. XCTestExpectation *dispatchAfterExpectation =
  1628. [self expectationWithDescription:@"dispatchAfterExpectation"];
  1629. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1630. XCTAssertNotNil(_FIRAuthDispatcherCallback);
  1631. _FIRAuthDispatcherCallback();
  1632. [dispatchAfterExpectation fulfill];
  1633. });
  1634. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1635. // Verify that current user is still valid with new access token.
  1636. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  1637. OCMVerifyAll(_mockBackend);
  1638. }
  1639. #endif
  1640. #pragma mark - Helpers
  1641. /** @fn mockSecureTokenResponseWithError:
  1642. @brief Set up expectation for secureToken RPC.
  1643. @param error The error that the mock should return if any.
  1644. */
  1645. - (void)mockSecureTokenResponseWithError:(nullable NSError *)error {
  1646. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  1647. XCTestExpectation *secureTokenResponseExpectation =
  1648. [self expectationWithDescription:@"secureTokenResponseExpectation"];
  1649. OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
  1650. .andCallBlock2(^(FIRSecureTokenRequest *_Nullable request,
  1651. FIRSecureTokenResponseCallback callback) {
  1652. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1653. XCTAssertEqualObjects(request.refreshToken, kRefreshToken);
  1654. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1655. if (error) {
  1656. callback(nil, error);
  1657. [secureTokenResponseExpectation fulfill];
  1658. return;
  1659. }
  1660. id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
  1661. OCMStub([mockSecureTokenResponse accessToken]).andReturn(kNewAccessToken);
  1662. NSDate *futureDate =
  1663. [[NSDate date] dateByAddingTimeInterval:kTestTokenExpirationTimeInterval];
  1664. OCMStub([mockSecureTokenResponse approximateExpirationDate]).andReturn(futureDate);
  1665. callback(mockSecureTokenResponse, nil);
  1666. [secureTokenResponseExpectation fulfill];
  1667. });
  1668. });
  1669. }
  1670. /** @fn enableAutoTokenRefresh
  1671. @brief Enables automatic token refresh by invoking FIRAuth's implementation of FIRApp's
  1672. |getTokenWithImplementation|.
  1673. */
  1674. - (void)enableAutoTokenRefresh {
  1675. XCTestExpectation *expectation = [self expectationWithDescription:@"autoTokenRefreshcallback"];
  1676. [[FIRAuth auth].app getTokenForcingRefresh:NO withCallback:^(NSString *_Nullable token,
  1677. NSError *_Nullable error) {
  1678. [expectation fulfill];
  1679. }];
  1680. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1681. }
  1682. /** @fn app1
  1683. @brief Creates a Firebase app.
  1684. @return A @c FIRApp with some name.
  1685. */
  1686. - (FIRApp *)app1 {
  1687. return [FIRApp appForAuthUnitTestsWithName:kFirebaseAppName1];
  1688. }
  1689. /** @fn app2
  1690. @brief Creates another Firebase app.
  1691. @return A @c FIRApp with some other name.
  1692. */
  1693. - (FIRApp *)app2 {
  1694. return [FIRApp appForAuthUnitTestsWithName:kFirebaseAppName2];
  1695. }
  1696. /** @fn stubSecureTokensWithMockResponse
  1697. @brief Creates stubs on the mock response object with access and refresh tokens
  1698. @param mockResponse The mock response object.
  1699. */
  1700. - (void)stubTokensWithMockResponse:(id)mockResponse {
  1701. OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
  1702. OCMStub([mockResponse approximateExpirationDate])
  1703. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1704. OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
  1705. }
  1706. /** @fn expectGetAccountInfo
  1707. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1708. data.
  1709. */
  1710. - (void)expectGetAccountInfo {
  1711. [self expectGetAccountInfoWithAccessToken:kAccessToken];
  1712. }
  1713. /** @fn expectGetAccountInfoWithAccessToken
  1714. @param accessToken The access token for the user to check against.
  1715. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1716. data.
  1717. */
  1718. - (void)expectGetAccountInfoWithAccessToken:(NSString *)accessToken {
  1719. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1720. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1721. FIRGetAccountInfoResponseCallback callback) {
  1722. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1723. XCTAssertEqualObjects(request.accessToken, accessToken);
  1724. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1725. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1726. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1727. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  1728. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1729. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1730. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1731. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1732. callback(mockGetAccountInfoResponse, nil);
  1733. });
  1734. });
  1735. }
  1736. /** @fn assertUser
  1737. @brief Asserts the given FIRUser matching the fake data returned by @c expectGetAccountInfo.
  1738. @param user The user object to be verified.
  1739. */
  1740. - (void)assertUser:(FIRUser *)user {
  1741. XCTAssertNotNil(user);
  1742. XCTAssertEqualObjects(user.uid, kLocalID);
  1743. XCTAssertEqualObjects(user.displayName, kDisplayName);
  1744. XCTAssertEqualObjects(user.email, kEmail);
  1745. XCTAssertFalse(user.anonymous);
  1746. XCTAssertEqual(user.providerData.count, 0u);
  1747. }
  1748. /** @fn expectGetAccountInfoGoogle
  1749. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1750. data for a Google Sign-In user.
  1751. */
  1752. - (void)expectGetAccountInfoGoogle {
  1753. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1754. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1755. FIRGetAccountInfoResponseCallback callback) {
  1756. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1757. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1758. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1759. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  1760. OCMStub([mockGoogleUserInfo providerID]).andReturn(FIRGoogleAuthProviderID);
  1761. OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
  1762. OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
  1763. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  1764. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1765. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1766. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  1767. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  1768. .andReturn((@[ mockGoogleUserInfo ]));
  1769. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1770. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1771. callback(mockGetAccountInfoResponse, nil);
  1772. });
  1773. });
  1774. }
  1775. /** @fn assertUserGoogle
  1776. @brief Asserts the given FIRUser matching the fake data returned by
  1777. @c expectGetAccountInfoGoogle.
  1778. @param user The user object to be verified.
  1779. */
  1780. - (void)assertUserGoogle:(FIRUser *)user {
  1781. XCTAssertNotNil(user);
  1782. XCTAssertEqualObjects(user.uid, kLocalID);
  1783. XCTAssertEqualObjects(user.displayName, kDisplayName);
  1784. XCTAssertEqual(user.providerData.count, 1u);
  1785. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  1786. XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
  1787. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  1788. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  1789. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  1790. }
  1791. /** @fn expectGetAccountInfoAnonymous
  1792. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
  1793. account data.
  1794. */
  1795. - (void)expectGetAccountInfoAnonymous {
  1796. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1797. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1798. FIRGetAccountInfoResponseCallback callback) {
  1799. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1800. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1801. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1802. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1803. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1804. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1805. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1806. callback(mockGetAccountInfoResponse, nil);
  1807. });
  1808. });
  1809. }
  1810. /** @fn assertUserAnonymous
  1811. @brief Asserts the given FIRUser matching the fake data returned by
  1812. @c expectGetAccountInfoAnonymous.
  1813. @param user The user object to be verified.
  1814. */
  1815. - (void)assertUserAnonymous:(FIRUser *)user {
  1816. XCTAssertNotNil(user);
  1817. XCTAssertEqualObjects(user.uid, kLocalID);
  1818. XCTAssertNil(user.displayName);
  1819. XCTAssertTrue(user.anonymous);
  1820. XCTAssertEqual(user.providerData.count, 0u);
  1821. }
  1822. /** @fn waitForSignIn
  1823. @brief Signs in a user to prepare for tests.
  1824. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  1825. */
  1826. - (void)waitForSignIn {
  1827. [self waitForSignInWithAccessToken:kAccessToken];
  1828. }
  1829. /** @fn waitForSignInWithAccessToken:
  1830. @brief Signs in a user to prepare for tests.
  1831. @param accessToken The access token for the user to have.
  1832. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  1833. */
  1834. - (void)waitForSignInWithAccessToken:(NSString *)accessToken {
  1835. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  1836. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  1837. FIRVerifyPasswordResponseCallback callback) {
  1838. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1839. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  1840. OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(accessToken);
  1841. OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
  1842. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1843. OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  1844. callback(mockVeriyPasswordResponse, nil);
  1845. });
  1846. });
  1847. [self expectGetAccountInfoWithAccessToken:accessToken];
  1848. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1849. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  1850. NSError *_Nullable error) {
  1851. [expectation fulfill];
  1852. }];
  1853. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1854. OCMVerifyAll(_mockBackend);
  1855. XCTAssertNotNil([FIRAuth auth].currentUser);
  1856. }
  1857. /** @fn waitForTimeInterval:
  1858. @brief Wait for a particular time interval.
  1859. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  1860. */
  1861. - (void)waitForTimeIntervel:(NSTimeInterval)timeInterval {
  1862. static dispatch_queue_t queue;
  1863. static dispatch_once_t onceToken;
  1864. XCTestExpectation *expectation = [self expectationWithDescription:@"waitForTimeIntervel:"];
  1865. dispatch_once(&onceToken, ^{
  1866. queue = dispatch_queue_create("com.google.FIRAuthUnitTests.waitForTimeIntervel", NULL);
  1867. });
  1868. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeInterval * NSEC_PER_SEC), queue, ^() {
  1869. [expectation fulfill];
  1870. });
  1871. [self waitForExpectationsWithTimeout:timeInterval + kExpectationTimeout handler:nil];
  1872. }
  1873. @end