FIRAuthTests.m 123 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696
  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 <OCMock/OCMock.h>
  18. #import <XCTest/XCTest.h>
  19. #import <GoogleUtilities/GULAppDelegateSwizzler.h>
  20. #import "FirebaseAuth/Interop/FIRAuthInterop.h"
  21. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h"
  22. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h"
  23. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h"
  24. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h"
  25. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h"
  26. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h"
  27. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h"
  28. #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
  29. #import "FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h"
  30. #import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h"
  31. #import "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h"
  32. #import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h"
  33. #import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h"
  34. #import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h"
  35. #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h"
  36. #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h"
  37. #import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h"
  38. #import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h"
  39. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h"
  40. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h"
  41. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h"
  42. #import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h"
  43. #import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h"
  44. #import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h"
  45. #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h"
  46. #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h"
  47. #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h"
  48. #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h"
  49. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h"
  50. #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
  51. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
  52. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
  53. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h"
  54. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h"
  55. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h"
  56. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h"
  57. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h"
  58. #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h"
  59. #import "FirebaseAuth/Sources/User/FIRUser_Internal.h"
  60. #import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h"
  61. #import "FirebaseAuth/Tests/Unit/FIRApp+FIRAuthUnitTests.h"
  62. #import "FirebaseAuth/Tests/Unit/OCMStubRecorder+FIRAuthUnitTests.h"
  63. #if TARGET_OS_IOS
  64. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h"
  65. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h"
  66. #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h"
  67. #import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h"
  68. #import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h"
  69. #import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h"
  70. #import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h"
  71. #endif // TARGET_OS_IOS
  72. /** @var kAPIKey
  73. @brief The fake API key.
  74. */
  75. static NSString *const kAPIKey = @"FAKE_API_KEY";
  76. /** @var kFirebaseAppID
  77. @brief The fake Firebase app ID.
  78. */
  79. static NSString *const kFirebaseAppID = @"FAKE_APP_ID";
  80. /** @var kAccessToken
  81. @brief The fake access token.
  82. */
  83. static NSString *const kAccessToken = @"ACCESS_TOKEN";
  84. /** @var kNewAccessToken
  85. @brief Another fake access token used to simulate token refreshed via automatic token refresh.
  86. */
  87. NSString *kNewAccessToken = @"NewAccessToken";
  88. /** @var kAccessTokenValidInterval
  89. @brief The time to live for the fake access token.
  90. */
  91. static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
  92. /** @var kTestTokenExpirationTimeInterval
  93. @brief The fake time interval that it takes a token to expire.
  94. */
  95. static const NSTimeInterval kTestTokenExpirationTimeInterval = 55 * 60;
  96. /** @var kRefreshToken
  97. @brief The fake refresh token.
  98. */
  99. static NSString *const kRefreshToken = @"REFRESH_TOKEN";
  100. /** @var kEmail
  101. @brief The fake user email.
  102. */
  103. static NSString *const kEmail = @"user@company.com";
  104. /** @var kFakePassword
  105. @brief The fake user password.
  106. */
  107. static NSString *const kFakePassword = @"!@#$%^";
  108. /** @var kPasswordHash
  109. @brief The fake user password hash.
  110. */
  111. static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
  112. /** @var kLocalID
  113. @brief The fake local user ID.
  114. */
  115. static NSString *const kLocalID = @"LOCAL_ID";
  116. /** @var kDisplayName
  117. @brief The fake user display name.
  118. */
  119. static NSString *const kDisplayName = @"User Doe";
  120. /** @var kGoogleUD
  121. @brief The fake user ID under Google Sign-In.
  122. */
  123. static NSString *const kGoogleID = @"GOOGLE_ID";
  124. /** @var kGoogleEmail
  125. @brief The fake user email under Google Sign-In.
  126. */
  127. static NSString *const kGoogleEmail = @"user@gmail.com";
  128. /** @var kGoogleDisplayName
  129. @brief The fake user display name under Google Sign-In.
  130. */
  131. static NSString *const kGoogleDisplayName = @"Google Doe";
  132. /** @var kGoogleAccessToken
  133. @brief The fake access token from Google Sign-In.
  134. */
  135. static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
  136. /** @var kGoogleIDToken
  137. @brief The fake ID token from Google Sign-In.
  138. */
  139. static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
  140. /** @var kCustomToken
  141. @brief The fake custom token to sign in.
  142. */
  143. static NSString *const kCustomToken = @"CUSTOM_TOKEN";
  144. /** @var kVerificationCode
  145. @brief Fake verification code used for testing.
  146. */
  147. static NSString *const kVerificationCode = @"12345678";
  148. /** @var kVerificationID
  149. @brief Fake verification ID for testing.
  150. */
  151. static NSString *const kVerificationID = @"55432";
  152. /** @var kOAuthRequestURI
  153. @brief Fake OAuthRequest URI for testing.
  154. */
  155. static NSString *const kOAuthRequestURI = @"requestURI";
  156. /** @var kOAuthSessionID
  157. @brief Fake session ID for testing.
  158. */
  159. static NSString *const kOAuthSessionID = @"sessionID";
  160. /** @var kFakeWebSignInUserInteractionFailureReason
  161. @brief Fake reason for FIRAuthErrorCodeWebSignInUserInteractionFailure error while testing.
  162. */
  163. static NSString *const kFakeWebSignInUserInteractionFailureReason = @"fake_reason";
  164. /** @var kContinueURL
  165. @brief Fake string value of continue url.
  166. */
  167. static NSString *const kContinueURL = @"continueURL";
  168. /** @var kCanHandleCodeInAppKey
  169. @brief The key for the request parameter indicating whether the action code can be handled in
  170. the app or not.
  171. */
  172. static NSString *const kCanHandleCodeInAppKey = @"canHandleCodeInApp";
  173. /** @var kFIREmailLinkAuthSignInMethod
  174. @brief Fake email link sign-in method for testing.
  175. */
  176. static NSString *const kFIREmailLinkAuthSignInMethod = @"emailLink";
  177. /** @var kFIRFacebookAuthSignInMethod
  178. @brief Fake Facebook sign-in method for testing.
  179. */
  180. static NSString *const kFIRFacebookAuthSignInMethod = @"facebook.com";
  181. /** @var kBadSignInEmailLink
  182. @brief Bad sign-in link to test email link sign-in
  183. */
  184. static NSString *const kBadSignInEmailLink = @"http://www.facebook.com";
  185. /** @var kFakeEmailSignInDeeplink
  186. @brief Fake email sign-in link
  187. */
  188. static NSString *const kFakeEmailSignInDeeplink =
  189. @"https://example.domain.com/?apiKey=testAPIKey&oobCode=testoobcode&mode=signIn";
  190. /** @var kFakeEmailSignInlink
  191. @brief Fake email sign-in link
  192. */
  193. static NSString *const kFakeEmailSignInlink =
  194. @"https://test.app.goo.gl/?link=https://test.firebase"
  195. "app.com/__/auth/"
  196. "action?apiKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueU"
  197. "rl%3Dhttps://test.apps.com&ibi=com.test.com&ifl=https://test.firebaseapp.com/__/auth/"
  198. "action?ap"
  199. "iKey%3DtestAPIKey%26mode%3DsignIn%26oobCode%3Dtestoobcode%26continueUrl%3Dhttps://"
  200. "test.apps.co"
  201. "m";
  202. /** @var kExpectationTimeout
  203. @brief The maximum time waiting for expectations to fulfill.
  204. */
  205. static const NSTimeInterval kExpectationTimeout = 2;
  206. /** @var kWaitInterval
  207. @brief The time waiting for background tasks to finish before continue when necessary.
  208. */
  209. static const NSTimeInterval kWaitInterval = .5;
  210. #if TARGET_OS_IOS
  211. /** @class FIRAuthAppDelegate
  212. @brief Application delegate implementation to test the app delegate proxying
  213. */
  214. @interface FIRAuthAppDelegate : NSObject <UIApplicationDelegate>
  215. @end
  216. @implementation FIRAuthAppDelegate
  217. - (void)application:(UIApplication *)application
  218. didReceiveRemoteNotification:(NSDictionary *)userInfo
  219. fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  220. }
  221. - (BOOL)application:(UIApplication *)app
  222. openURL:(NSURL *)url
  223. options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
  224. return NO;
  225. }
  226. @end
  227. #endif // TARGET_OS_IOS
  228. @interface GULAppDelegateSwizzler (FIRMessagingRemoteNotificationsProxyTest)
  229. + (void)resetProxyOriginalDelegateOnceToken;
  230. @end
  231. /** Category for FIRAuth to expose FIRComponentRegistrant conformance. */
  232. @interface FIRAuth () <FIRLibrary>
  233. @end
  234. /** @class FIRAuthTests
  235. @brief Tests for @c FIRAuth.
  236. */
  237. @interface FIRAuthTests : XCTestCase
  238. #if TARGET_OS_IOS
  239. /// A partial mock of `[FIRAuth auth].tokenManager`
  240. @property(nonatomic, strong) id mockTokenManager;
  241. /// A partial mock of `[FIRAuth auth].notificationManager`
  242. @property(nonatomic, strong) id mockNotificationManager;
  243. /// A partial mock of `[FIRAuth auth].authURLPresenter`
  244. @property(nonatomic, strong) id mockAuthURLPresenter;
  245. /// An application delegate instance returned by `self.mockApplication.delegate`
  246. @property(nonatomic, strong) FIRAuthAppDelegate *fakeApplicationDelegate;
  247. #endif // TARGET_OS_IOS
  248. @end
  249. @implementation FIRAuthTests {
  250. /** @var _mockBackend
  251. @brief The mock @c FIRAuthBackendImplementation .
  252. */
  253. id _mockBackend;
  254. /** @var _FIRAuthDispatcherCallback
  255. @brief Used to save a task from FIRAuthDispatcher to be executed later.
  256. */
  257. __block void (^_Nonnull _FIRAuthDispatcherCallback)(void);
  258. }
  259. /** @fn googleProfile
  260. @brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
  261. */
  262. + (NSDictionary *)googleProfile {
  263. static NSDictionary *kGoogleProfile = nil;
  264. static dispatch_once_t onceToken;
  265. dispatch_once(&onceToken, ^{
  266. kGoogleProfile = @{
  267. @"iss" : @"https://accounts.google.com\\",
  268. @"email" : kGoogleEmail,
  269. @"given_name" : @"User",
  270. @"family_name" : @"Doe"
  271. };
  272. });
  273. return kGoogleProfile;
  274. }
  275. - (void)setUp {
  276. [super setUp];
  277. #if TARGET_OS_IOS
  278. // Make sure the `self.fakeApplicationDelegate` will be swizzled on FIRAuth init.
  279. [GULAppDelegateSwizzler resetProxyOriginalDelegateOnceToken];
  280. self.fakeApplicationDelegate = [[FIRAuthAppDelegate alloc] init];
  281. [[GULAppDelegateSwizzler sharedApplication]
  282. setDelegate:(id<UIApplicationDelegate>)self.fakeApplicationDelegate];
  283. #endif // TARGET_OS_IOS
  284. _mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
  285. [FIRAuthBackend setBackendImplementation:_mockBackend];
  286. [FIRApp resetAppForAuthUnitTests];
  287. // Set FIRAuthDispatcher implementation in order to save the token refresh task for later
  288. // execution.
  289. [[FIRAuthDispatcher sharedInstance]
  290. setDispatchAfterImplementation:^(NSTimeInterval delay, dispatch_queue_t _Nonnull queue,
  291. void (^task)(void)) {
  292. XCTAssertNotNil(task);
  293. XCTAssert(delay > 0);
  294. XCTAssertEqualObjects(FIRAuthGlobalWorkQueue(), queue);
  295. self->_FIRAuthDispatcherCallback = task;
  296. }];
  297. #if TARGET_OS_IOS
  298. // Wait until FIRAuth initialization completes
  299. [self waitForAuthGlobalWorkQueueDrain];
  300. self.mockTokenManager = OCMPartialMock([FIRAuth auth].tokenManager);
  301. self.mockNotificationManager = OCMPartialMock([FIRAuth auth].notificationManager);
  302. self.mockAuthURLPresenter = OCMPartialMock([FIRAuth auth].authURLPresenter);
  303. #endif // TARGET_OS_IOS
  304. }
  305. - (void)tearDown {
  306. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
  307. [[FIRAuthDispatcher sharedInstance] setDispatchAfterImplementation:nil];
  308. #if TARGET_OS_IOS
  309. [self.mockAuthURLPresenter stopMocking];
  310. self.mockAuthURLPresenter = nil;
  311. [self.mockNotificationManager stopMocking];
  312. self.mockNotificationManager = nil;
  313. [self.mockTokenManager stopMocking];
  314. self.mockTokenManager = nil;
  315. self.fakeApplicationDelegate = nil;
  316. #endif // TARGET_OS_IOS
  317. [super tearDown];
  318. }
  319. #pragma mark - Server API Tests
  320. /** @fn testFetchSignInMethodsForEmailSuccess
  321. @brief Tests the flow of a successful @c fetchSignInMethodsForEmail:completion: call.
  322. */
  323. - (void)testFetchSignInMethodsForEmailSuccess {
  324. NSArray<NSString *> *allSignInMethods =
  325. @[ kFIREmailLinkAuthSignInMethod, kFIRFacebookAuthSignInMethod ];
  326. OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
  327. .andCallBlock2(
  328. ^(FIRCreateAuthURIRequest *_Nullable request, FIRCreateAuthURIResponseCallback callback) {
  329. XCTAssertEqualObjects(request.identifier, kEmail);
  330. XCTAssertNotNil(request.endpoint);
  331. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  332. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  333. id mockCreateAuthURIResponse = OCMClassMock([FIRCreateAuthURIResponse class]);
  334. OCMStub([mockCreateAuthURIResponse signinMethods]).andReturn(allSignInMethods);
  335. callback(mockCreateAuthURIResponse, nil);
  336. });
  337. });
  338. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  339. [[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
  340. completion:^(NSArray<NSString *> *_Nullable signInMethods,
  341. NSError *_Nullable error) {
  342. XCTAssertTrue([NSThread isMainThread]);
  343. XCTAssertEqualObjects(signInMethods, allSignInMethods);
  344. XCTAssertTrue([allSignInMethods isKindOfClass:[NSArray class]]);
  345. XCTAssertNil(error);
  346. [expectation fulfill];
  347. }];
  348. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  349. OCMVerifyAll(_mockBackend);
  350. }
  351. /** @fn testFetchSignInMethodsForEmailFailure
  352. @brief Tests the flow of a failed @c fetchSignInMethodsForEmail:completion: call.
  353. */
  354. - (void)testFetchSignInMethodsForEmailFailure {
  355. OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]])
  356. .andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
  357. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  358. [[FIRAuth auth] fetchSignInMethodsForEmail:kEmail
  359. completion:^(NSArray<NSString *> *_Nullable signInMethods,
  360. NSError *_Nullable error) {
  361. XCTAssertTrue([NSThread isMainThread]);
  362. XCTAssertNil(signInMethods);
  363. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  364. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  365. [expectation fulfill];
  366. }];
  367. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  368. OCMVerifyAll(_mockBackend);
  369. }
  370. #if TARGET_OS_IOS
  371. /** @fn testPhoneAuthSuccess
  372. @brief Tests the flow of a successful @c signInWithCredential:completion for phone auth.
  373. */
  374. - (void)testPhoneAuthSuccess {
  375. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  376. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  377. FIRVerifyPhoneNumberResponseCallback callback) {
  378. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  379. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  380. XCTAssertEqual(request.operation, FIRAuthOperationTypeSignUpOrSignIn);
  381. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  382. id mockVerifyPhoneResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
  383. [self stubTokensWithMockResponse:mockVerifyPhoneResponse];
  384. // Stub isNewUser flag in the response.
  385. OCMStub([mockVerifyPhoneResponse isNewUser]).andReturn(YES);
  386. callback(mockVerifyPhoneResponse, nil);
  387. });
  388. });
  389. [self expectGetAccountInfo];
  390. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  391. [[FIRAuth auth] signOut:NULL];
  392. FIRAuthCredential *credential =
  393. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  394. verificationCode:kVerificationCode];
  395. [[FIRAuth auth] signInWithCredential:credential
  396. completion:^(FIRAuthDataResult *_Nullable authDataResult,
  397. NSError *_Nullable error) {
  398. XCTAssertTrue([NSThread isMainThread]);
  399. [self assertUser:authDataResult.user];
  400. XCTAssertTrue(authDataResult.additionalUserInfo.isNewUser);
  401. XCTAssertNil(error);
  402. [expectation fulfill];
  403. }];
  404. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  405. [self assertUser:[FIRAuth auth].currentUser];
  406. OCMVerifyAll(_mockBackend);
  407. }
  408. /** @fn testPhoneAuthMissingVerificationCode
  409. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  410. to an empty verification code
  411. */
  412. - (void)testPhoneAuthMissingVerificationCode {
  413. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  414. [[FIRAuth auth] signOut:NULL];
  415. FIRAuthCredential *credential =
  416. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  417. verificationCode:@""];
  418. [[FIRAuth auth]
  419. signInWithCredential:credential
  420. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  421. XCTAssertTrue([NSThread isMainThread]);
  422. XCTAssertNil(result);
  423. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationCode);
  424. [expectation fulfill];
  425. }];
  426. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  427. }
  428. /** @fn testPhoneAuthMissingVerificationID
  429. @brief Tests the flow of an unsuccessful @c signInWithCredential:completion for phone auth due
  430. to an empty verification ID.
  431. */
  432. - (void)testPhoneAuthMissingVerificationID {
  433. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  434. [[FIRAuth auth] signOut:NULL];
  435. FIRAuthCredential *credential =
  436. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:@""
  437. verificationCode:kVerificationCode];
  438. [[FIRAuth auth]
  439. signInWithCredential:credential
  440. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  441. XCTAssertTrue([NSThread isMainThread]);
  442. XCTAssertNil(result);
  443. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingVerificationID);
  444. [expectation fulfill];
  445. }];
  446. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  447. }
  448. #endif
  449. /** @fn testSignInWithEmailLinkSuccess
  450. @brief Tests the flow of a successful @c signInWithEmail:link:completion: call.
  451. */
  452. - (void)testSignInWithEmailLinkSuccess {
  453. NSString *fakeCode = @"testoobcode";
  454. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  455. .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
  456. FIREmailLinkSigninResponseCallback callback) {
  457. XCTAssertEqualObjects(request.email, kEmail);
  458. XCTAssertEqualObjects(request.oobCode, fakeCode);
  459. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  460. id mockEmailLinkSignInResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
  461. [self stubTokensWithMockResponse:mockEmailLinkSignInResponse];
  462. callback(mockEmailLinkSignInResponse, nil);
  463. OCMStub([mockEmailLinkSignInResponse refreshToken]).andReturn(kRefreshToken);
  464. });
  465. });
  466. [self expectGetAccountInfo];
  467. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  468. [[FIRAuth auth] signOut:NULL];
  469. [[FIRAuth auth]
  470. signInWithEmail:kEmail
  471. link:kFakeEmailSignInlink
  472. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  473. XCTAssertTrue([NSThread isMainThread]);
  474. XCTAssertNotNil(authResult.user);
  475. XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
  476. XCTAssertFalse(authResult.user.anonymous);
  477. XCTAssertEqualObjects(authResult.user.email, kEmail);
  478. XCTAssertNil(error);
  479. [expectation fulfill];
  480. }];
  481. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  482. [self assertUser:[FIRAuth auth].currentUser];
  483. OCMVerifyAll(_mockBackend);
  484. }
  485. /** @fn testSignInWithEmailLinkSuccessDeeplink
  486. @brief Tests the flow of a successful @c signInWithEmail:link:completion: call using a deep
  487. link.
  488. */
  489. - (void)testSignInWithEmailLinkSuccessDeeplink {
  490. NSString *fakeCode = @"testoobcode";
  491. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  492. .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
  493. FIREmailLinkSigninResponseCallback callback) {
  494. XCTAssertEqualObjects(request.email, kEmail);
  495. XCTAssertEqualObjects(request.oobCode, fakeCode);
  496. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  497. id mockEmailLinkSignInResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
  498. [self stubTokensWithMockResponse:mockEmailLinkSignInResponse];
  499. callback(mockEmailLinkSignInResponse, nil);
  500. OCMStub([mockEmailLinkSignInResponse refreshToken]).andReturn(kRefreshToken);
  501. });
  502. });
  503. [self expectGetAccountInfo];
  504. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  505. [[FIRAuth auth] signOut:NULL];
  506. [[FIRAuth auth]
  507. signInWithEmail:kEmail
  508. link:kFakeEmailSignInDeeplink
  509. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  510. XCTAssertTrue([NSThread isMainThread]);
  511. XCTAssertNotNil(authResult.user);
  512. XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
  513. XCTAssertFalse(authResult.user.anonymous);
  514. XCTAssertEqualObjects(authResult.user.email, kEmail);
  515. XCTAssertNil(error);
  516. [expectation fulfill];
  517. }];
  518. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  519. [self assertUser:[FIRAuth auth].currentUser];
  520. OCMVerifyAll(_mockBackend);
  521. }
  522. /** @fn testSignInWithEmailLinkFailure
  523. @brief Tests the flow of a failed @c signInWithEmail:link:completion: call.
  524. */
  525. - (void)testSignInWithEmailLinkFailure {
  526. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  527. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  528. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  529. [[FIRAuth auth] signOut:NULL];
  530. [[FIRAuth auth]
  531. signInWithEmail:kEmail
  532. link:kFakeEmailSignInlink
  533. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  534. XCTAssertTrue([NSThread isMainThread]);
  535. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  536. [expectation fulfill];
  537. }];
  538. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  539. OCMVerifyAll(_mockBackend);
  540. }
  541. /** @fn testSignInWithEmailPasswordSuccess
  542. @brief Tests the flow of a successful @c signInWithEmail:password:completion: call.
  543. */
  544. - (void)testSignInWithEmailPasswordSuccess {
  545. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  546. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  547. FIRVerifyPasswordResponseCallback callback) {
  548. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  549. XCTAssertEqualObjects(request.email, kEmail);
  550. XCTAssertEqualObjects(request.password, kFakePassword);
  551. XCTAssertTrue(request.returnSecureToken);
  552. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  553. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  554. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  555. callback(mockVerifyPasswordResponse, nil);
  556. });
  557. });
  558. [self expectGetAccountInfo];
  559. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  560. [[FIRAuth auth] signOut:NULL];
  561. [[FIRAuth auth] signInWithEmail:kEmail
  562. password:kFakePassword
  563. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  564. XCTAssertTrue([NSThread isMainThread]);
  565. [self assertUser:result.user];
  566. XCTAssertNil(error);
  567. [expectation fulfill];
  568. }];
  569. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  570. [self assertUser:[FIRAuth auth].currentUser];
  571. OCMVerifyAll(_mockBackend);
  572. }
  573. /** @fn testSignInWithEmailPasswordFailure
  574. @brief Tests the flow of a failed @c signInWithEmail:password:completion: call.
  575. */
  576. - (void)testSignInWithEmailPasswordFailure {
  577. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  578. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  579. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  580. [[FIRAuth auth] signOut:NULL];
  581. [[FIRAuth auth] signInWithEmail:kEmail
  582. password:kFakePassword
  583. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  584. XCTAssertTrue([NSThread isMainThread]);
  585. XCTAssertNil(result.user);
  586. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  587. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  588. [expectation fulfill];
  589. }];
  590. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  591. XCTAssertNil([FIRAuth auth].currentUser);
  592. OCMVerifyAll(_mockBackend);
  593. }
  594. /** @fn testSignInAndRetrieveDataWithEmailPasswordSuccess
  595. @brief Tests the flow of a successful @c signInAndRetrieveDataWithEmail:password:completion:
  596. call.
  597. */
  598. - (void)testSignInAndRetrieveDataWithEmailPasswordSuccess {
  599. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  600. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  601. FIRVerifyPasswordResponseCallback callback) {
  602. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  603. XCTAssertEqualObjects(request.email, kEmail);
  604. XCTAssertEqualObjects(request.password, kFakePassword);
  605. XCTAssertTrue(request.returnSecureToken);
  606. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  607. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  608. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  609. callback(mockVerifyPasswordResponse, nil);
  610. });
  611. });
  612. [self expectGetAccountInfo];
  613. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  614. [[FIRAuth auth] signOut:NULL];
  615. [[FIRAuth auth]
  616. signInWithEmail:kEmail
  617. password:kFakePassword
  618. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  619. XCTAssertTrue([NSThread isMainThread]);
  620. [self assertUser:result.user];
  621. XCTAssertFalse(result.additionalUserInfo.isNewUser);
  622. XCTAssertEqualObjects(result.additionalUserInfo.providerID, FIREmailAuthProviderID);
  623. XCTAssertNil(error);
  624. [expectation fulfill];
  625. }];
  626. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  627. [self assertUser:[FIRAuth auth].currentUser];
  628. OCMVerifyAll(_mockBackend);
  629. }
  630. /** @fn testSignInAndRetrieveDataWithEmailPasswordFailure
  631. @brief Tests the flow of a failed @c signInAndRetrieveDataWithEmail:password:completion: call.
  632. */
  633. - (void)testSignInAndRetrieveDataWithEmailPasswordFailure {
  634. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  635. .andDispatchError2([FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]);
  636. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  637. [[FIRAuth auth] signOut:NULL];
  638. [[FIRAuth auth] signInWithEmail:kEmail
  639. password:kFakePassword
  640. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  641. XCTAssertTrue([NSThread isMainThread]);
  642. XCTAssertNil(result);
  643. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  644. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  645. [expectation fulfill];
  646. }];
  647. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  648. XCTAssertNil([FIRAuth auth].currentUser);
  649. OCMVerifyAll(_mockBackend);
  650. }
  651. /** @fn testResetPasswordSuccess
  652. @brief Tests the flow of a successful @c confirmPasswordResetWithCode:newPassword:completion:
  653. call.
  654. */
  655. - (void)testResetPasswordSuccess {
  656. NSString *fakeEmail = @"fakeEmail";
  657. NSString *fakeCode = @"fakeCode";
  658. NSString *fakeNewPassword = @"fakeNewPassword";
  659. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  660. .andCallBlock2(
  661. ^(FIRResetPasswordRequest *_Nullable request, FIRResetPasswordCallback callback) {
  662. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  663. XCTAssertEqualObjects(request.oobCode, fakeCode);
  664. XCTAssertEqualObjects(request.updatedPassword, fakeNewPassword);
  665. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  666. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  667. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  668. callback(mockResetPasswordResponse, nil);
  669. });
  670. });
  671. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  672. [[FIRAuth auth] signOut:NULL];
  673. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  674. newPassword:fakeNewPassword
  675. completion:^(NSError *_Nullable error) {
  676. XCTAssertTrue([NSThread isMainThread]);
  677. XCTAssertNil(error);
  678. [expectation fulfill];
  679. }];
  680. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  681. OCMVerifyAll(_mockBackend);
  682. }
  683. /** @fn testResetPasswordFailure
  684. @brief Tests the flow of a failed @c confirmPasswordResetWithCode:newPassword:completion:
  685. call.
  686. */
  687. - (void)testResetPasswordFailure {
  688. NSString *fakeCode = @"fakeCode";
  689. NSString *fakeNewPassword = @"fakeNewPassword";
  690. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  691. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  692. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  693. [[FIRAuth auth] signOut:NULL];
  694. [[FIRAuth auth] confirmPasswordResetWithCode:fakeCode
  695. newPassword:fakeNewPassword
  696. completion:^(NSError *_Nullable error) {
  697. XCTAssertTrue([NSThread isMainThread]);
  698. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  699. [expectation fulfill];
  700. }];
  701. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  702. OCMVerifyAll(_mockBackend);
  703. }
  704. /** @fn testCheckActionCodeSuccess
  705. @brief Tests the flow of a successful @c checkActionCode:completion call.
  706. */
  707. - (void)testCheckActionCodeSuccess {
  708. NSString *verifyEmailRequestType = @"VERIFY_EMAIL";
  709. NSString *fakeEmail = @"fakeEmail";
  710. NSString *fakeNewEmail = @"fakeNewEmail";
  711. NSString *fakeCode = @"fakeCode";
  712. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  713. .andCallBlock2(
  714. ^(FIRResetPasswordRequest *_Nullable request, 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. OCMStub([mockResetPasswordResponse verifiedEmail]).andReturn(fakeNewEmail);
  721. OCMStubRecorder *stub =
  722. OCMStub([(FIRResetPasswordResponse *)mockResetPasswordResponse requestType]);
  723. stub.andReturn(verifyEmailRequestType);
  724. callback(mockResetPasswordResponse, nil);
  725. });
  726. });
  727. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  728. [[FIRAuth auth] checkActionCode:fakeCode
  729. completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) {
  730. XCTAssertTrue([NSThread isMainThread]);
  731. XCTAssertNil(error);
  732. XCTAssertEqual(info.operation, FIRActionCodeOperationVerifyEmail);
  733. XCTAssert([fakeNewEmail isEqualToString:info.email]);
  734. [expectation fulfill];
  735. }];
  736. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  737. OCMVerifyAll(_mockBackend);
  738. }
  739. /** @fn testCheckActionCodeFailure
  740. @brief Tests the flow of a failed @c checkActionCode:completion call.
  741. */
  742. - (void)testCheckActionCodeFailure {
  743. NSString *fakeCode = @"fakeCode";
  744. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  745. ._andDispatchError2([FIRAuthErrorUtils expiredActionCodeErrorWithMessage:nil]);
  746. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  747. [[FIRAuth auth] signOut:NULL];
  748. [[FIRAuth auth] checkActionCode:fakeCode
  749. completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) {
  750. XCTAssertTrue([NSThread isMainThread]);
  751. XCTAssertNotNil(error);
  752. XCTAssertEqual(error.code, FIRAuthErrorCodeExpiredActionCode);
  753. [expectation fulfill];
  754. }];
  755. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  756. OCMVerifyAll(_mockBackend);
  757. }
  758. /** @fn testApplyActionCodeSuccess
  759. @brief Tests the flow of a successful @c applyActionCode:completion call.
  760. */
  761. - (void)testApplyActionCodeSuccess {
  762. NSString *fakeCode = @"fakeCode";
  763. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  764. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  765. FIRSetAccountInfoResponseCallback callback) {
  766. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  767. XCTAssertEqualObjects(request.OOBCode, fakeCode);
  768. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  769. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  770. callback(mockSetAccountInfoResponse, nil);
  771. });
  772. });
  773. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  774. [[FIRAuth auth] applyActionCode:fakeCode
  775. completion:^(NSError *_Nullable error) {
  776. XCTAssertTrue([NSThread isMainThread]);
  777. XCTAssertNil(error);
  778. [expectation fulfill];
  779. }];
  780. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  781. OCMVerifyAll(_mockBackend);
  782. }
  783. /** @fn testApplyActionCodeFailure
  784. @brief Tests the flow of a failed @c checkActionCode:completion call.
  785. */
  786. - (void)testApplyActionCodeFailure {
  787. NSString *fakeCode = @"fakeCode";
  788. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  789. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  790. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  791. [[FIRAuth auth] signOut:NULL];
  792. [[FIRAuth auth] applyActionCode:fakeCode
  793. completion:^(NSError *_Nullable error) {
  794. XCTAssertTrue([NSThread isMainThread]);
  795. XCTAssertNotNil(error);
  796. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  797. [expectation fulfill];
  798. }];
  799. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  800. OCMVerifyAll(_mockBackend);
  801. }
  802. /** @fn testVerifyPasswordResetCodeSuccess
  803. @brief Tests the flow of a successful @c verifyPasswordResetCode:completion call.
  804. */
  805. - (void)testVerifyPasswordResetCodeSuccess {
  806. NSString *passwordResetRequestType = @"PASSWORD_RESET";
  807. NSString *fakeEmail = @"fakeEmail";
  808. NSString *fakeCode = @"fakeCode";
  809. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  810. .andCallBlock2(
  811. ^(FIRResetPasswordRequest *_Nullable request, FIRResetPasswordCallback callback) {
  812. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  813. XCTAssertEqualObjects(request.oobCode, fakeCode);
  814. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  815. id mockResetPasswordResponse = OCMClassMock([FIRResetPasswordResponse class]);
  816. OCMStub([mockResetPasswordResponse email]).andReturn(fakeEmail);
  817. OCMStubRecorder *stub =
  818. OCMStub([(FIRResetPasswordResponse *)mockResetPasswordResponse requestType]);
  819. stub.andReturn(passwordResetRequestType);
  820. callback(mockResetPasswordResponse, nil);
  821. });
  822. });
  823. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  824. [[FIRAuth auth] verifyPasswordResetCode:fakeCode
  825. completion:^(NSString *_Nullable email, NSError *_Nullable error) {
  826. XCTAssertTrue([NSThread isMainThread]);
  827. XCTAssertNil(error);
  828. XCTAssertEqual(email, fakeEmail);
  829. [expectation fulfill];
  830. }];
  831. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  832. OCMVerifyAll(_mockBackend);
  833. }
  834. /** @fn testVerifyPasswordResetCodeFailure
  835. @brief Tests the flow of a failed @c verifyPasswordResetCode:completion call.
  836. */
  837. - (void)testVeridyPasswordResetCodeFailure {
  838. NSString *fakeCode = @"fakeCode";
  839. OCMExpect([_mockBackend resetPassword:[OCMArg any] callback:[OCMArg any]])
  840. ._andDispatchError2([FIRAuthErrorUtils invalidActionCodeErrorWithMessage:nil]);
  841. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  842. [[FIRAuth auth] signOut:NULL];
  843. [[FIRAuth auth] verifyPasswordResetCode:fakeCode
  844. completion:^(NSString *_Nullable email, NSError *_Nullable error) {
  845. XCTAssertTrue([NSThread isMainThread]);
  846. XCTAssertNotNil(error);
  847. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidActionCode);
  848. [expectation fulfill];
  849. }];
  850. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  851. OCMVerifyAll(_mockBackend);
  852. }
  853. /** @fn testSignInWithEmailLinkCredentialSuccess
  854. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  855. email sign-in link credential using FIREmailAuthProvider.
  856. */
  857. - (void)testSignInWithEmailLinkCredentialSuccess {
  858. NSString *fakeCode = @"testoobcode";
  859. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  860. .andCallBlock2(^(FIREmailLinkSignInRequest *_Nullable request,
  861. FIREmailLinkSigninResponseCallback callback) {
  862. XCTAssertEqualObjects(request.email, kEmail);
  863. XCTAssertEqualObjects(request.oobCode, fakeCode);
  864. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  865. id mockEmailLinkSigninResponse = OCMClassMock([FIREmailLinkSignInResponse class]);
  866. [self stubTokensWithMockResponse:mockEmailLinkSigninResponse];
  867. callback(mockEmailLinkSigninResponse, nil);
  868. });
  869. });
  870. [self expectGetAccountInfo];
  871. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  872. [[FIRAuth auth] signOut:NULL];
  873. FIRAuthCredential *emailCredential =
  874. [FIREmailAuthProvider credentialWithEmail:kEmail link:kFakeEmailSignInlink];
  875. [[FIRAuth auth]
  876. signInWithCredential:emailCredential
  877. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  878. XCTAssertTrue([NSThread isMainThread]);
  879. XCTAssertNotNil(authResult.user);
  880. XCTAssertEqualObjects(authResult.user.refreshToken, kRefreshToken);
  881. XCTAssertFalse(authResult.user.anonymous);
  882. XCTAssertEqualObjects(authResult.user.email, kEmail);
  883. XCTAssertNil(error);
  884. [expectation fulfill];
  885. }];
  886. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  887. [self assertUser:[FIRAuth auth].currentUser];
  888. OCMVerifyAll(_mockBackend);
  889. }
  890. /** @fn testSignInWithEmailLinkCredentialFailure
  891. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  892. email-email sign-in link credential using FIREmailAuthProvider.
  893. */
  894. - (void)testSignInWithEmailLinkCredentialFailure {
  895. OCMExpect([_mockBackend emailLinkSignin:[OCMArg any] callback:[OCMArg any]])
  896. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  897. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  898. [[FIRAuth auth] signOut:NULL];
  899. FIRAuthCredential *emailCredential =
  900. [FIREmailAuthProvider credentialWithEmail:kEmail link:kFakeEmailSignInlink];
  901. [[FIRAuth auth]
  902. signInWithCredential:emailCredential
  903. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  904. XCTAssertTrue([NSThread isMainThread]);
  905. XCTAssertNil(result);
  906. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  907. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  908. [expectation fulfill];
  909. }];
  910. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  911. XCTAssertNil([FIRAuth auth].currentUser);
  912. OCMVerifyAll(_mockBackend);
  913. }
  914. /** @fn testSignInWithEmailCredentialSuccess
  915. @brief Tests the flow of a successfully @c signInWithCredential:completion: call with an
  916. email-password credential.
  917. */
  918. - (void)testSignInWithEmailCredentialSuccess {
  919. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  920. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  921. FIRVerifyPasswordResponseCallback callback) {
  922. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  923. XCTAssertEqualObjects(request.email, kEmail);
  924. XCTAssertEqualObjects(request.password, kFakePassword);
  925. XCTAssertTrue(request.returnSecureToken);
  926. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  927. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  928. [self stubTokensWithMockResponse:mockVerifyPasswordResponse];
  929. callback(mockVerifyPasswordResponse, nil);
  930. });
  931. });
  932. [self expectGetAccountInfo];
  933. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  934. [[FIRAuth auth] signOut:NULL];
  935. FIRAuthCredential *emailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail
  936. password:kFakePassword];
  937. [[FIRAuth auth]
  938. signInWithCredential:emailCredential
  939. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  940. XCTAssertTrue([NSThread isMainThread]);
  941. [self assertUser:result.user];
  942. XCTAssertNil(error);
  943. [expectation fulfill];
  944. }];
  945. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  946. [self assertUser:[FIRAuth auth].currentUser];
  947. OCMVerifyAll(_mockBackend);
  948. }
  949. /** @fn testSignInWithEmailCredentialFailure
  950. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  951. email-password credential.
  952. */
  953. - (void)testSignInWithEmailCredentialFailure {
  954. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  955. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  956. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  957. [[FIRAuth auth] signOut:NULL];
  958. FIRAuthCredential *emailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail
  959. password:kFakePassword];
  960. [[FIRAuth auth]
  961. signInWithCredential:emailCredential
  962. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  963. XCTAssertTrue([NSThread isMainThread]);
  964. XCTAssertNil(result);
  965. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  966. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  967. [expectation fulfill];
  968. }];
  969. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  970. XCTAssertNil([FIRAuth auth].currentUser);
  971. OCMVerifyAll(_mockBackend);
  972. }
  973. /** @fn testSignInWithEmailCredentialEmptyPassword
  974. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  975. email-password credential using an empty password. This error occurs on the client side,
  976. so there is no need to fake an RPC response.
  977. */
  978. - (void)testSignInWithEmailCredentialEmptyPassword {
  979. NSString *emptyString = @"";
  980. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  981. [[FIRAuth auth] signOut:NULL];
  982. FIRAuthCredential *emailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail
  983. password:emptyString];
  984. [[FIRAuth auth]
  985. signInWithCredential:emailCredential
  986. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  987. XCTAssertTrue([NSThread isMainThread]);
  988. XCTAssertEqual(error.code, FIRAuthErrorCodeWrongPassword);
  989. [expectation fulfill];
  990. }];
  991. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  992. }
  993. #if TARGET_OS_IOS
  994. /** @fn testSignInWithProviderSuccess
  995. @brief Tests a successful @c signInWithProvider:UIDelegate:completion: call with an OAuth
  996. provider configured for Google.
  997. */
  998. - (void)testSignInWithProviderSuccess {
  999. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1000. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1001. FIRVerifyAssertionResponseCallback callback) {
  1002. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1003. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1004. XCTAssertTrue(request.returnSecureToken);
  1005. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1006. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1007. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1008. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1009. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1010. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1011. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1012. callback(mockVerifyAssertionResponse, nil);
  1013. });
  1014. });
  1015. [self expectGetAccountInfoGoogle];
  1016. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1017. [[FIRAuth auth] signOut:NULL];
  1018. id mockProvider = OCMClassMock([FIROAuthProvider class]);
  1019. OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
  1020. .andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
  1021. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1022. FIROAuthCredential *credential =
  1023. [[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
  1024. sessionID:kOAuthSessionID
  1025. OAuthResponseURLString:kOAuthRequestURI];
  1026. callback(credential, nil);
  1027. });
  1028. });
  1029. [[FIRAuth auth]
  1030. signInWithProvider:mockProvider
  1031. UIDelegate:nil
  1032. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1033. XCTAssertTrue([NSThread isMainThread]);
  1034. [self assertUserGoogle:authResult.user];
  1035. XCTAssertNil(error);
  1036. [expectation fulfill];
  1037. }];
  1038. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1039. OCMVerifyAll(_mockBackend);
  1040. }
  1041. /** @fn testSignInWithProviderFailure
  1042. @brief Tests a failed @c signInWithProvider:UIDelegate:completion: call with the error code
  1043. FIRAuthErrorCodeWebSignInUserInteractionFailure.
  1044. */
  1045. - (void)testSignInWithProviderFailure {
  1046. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1047. .andDispatchError2([FIRAuthErrorUtils
  1048. webSignInUserInteractionFailureWithReason:kFakeWebSignInUserInteractionFailureReason]);
  1049. [[FIRAuth auth] signOut:NULL];
  1050. id mockProvider = OCMClassMock([FIROAuthProvider class]);
  1051. OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
  1052. .andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
  1053. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1054. FIROAuthCredential *credential =
  1055. [[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
  1056. sessionID:kOAuthSessionID
  1057. OAuthResponseURLString:kOAuthRequestURI];
  1058. callback(credential, nil);
  1059. });
  1060. });
  1061. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1062. [[FIRAuth auth]
  1063. signInWithProvider:mockProvider
  1064. UIDelegate:nil
  1065. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1066. XCTAssertTrue([NSThread isMainThread]);
  1067. XCTAssertNil(authResult);
  1068. XCTAssertEqual(error.code, FIRAuthErrorCodeWebSignInUserInteractionFailure);
  1069. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey],
  1070. kFakeWebSignInUserInteractionFailureReason);
  1071. [expectation fulfill];
  1072. }];
  1073. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1074. OCMVerifyAll(_mockBackend);
  1075. }
  1076. /** @fn testSignInWithGoogleAccountExistsError
  1077. @brief Tests the flow of a failed @c signInWithCredential:completion: with a Google credential
  1078. where the backend returns a needs @needConfirmation equal to true. An
  1079. FIRAuthErrorCodeAccountExistsWithDifferentCredential error should be thrown.
  1080. */
  1081. - (void)testSignInWithGoogleAccountExistsError {
  1082. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1083. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1084. FIRVerifyAssertionResponseCallback callback) {
  1085. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1086. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1087. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  1088. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  1089. XCTAssertTrue(request.returnSecureToken);
  1090. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1091. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1092. OCMStub([mockVerifyAssertionResponse needConfirmation]).andReturn(YES);
  1093. OCMStub([mockVerifyAssertionResponse email]).andReturn(kEmail);
  1094. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1095. callback(mockVerifyAssertionResponse, nil);
  1096. });
  1097. });
  1098. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1099. [[FIRAuth auth] signOut:NULL];
  1100. FIRAuthCredential *googleCredential =
  1101. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1102. [[FIRAuth auth]
  1103. signInWithCredential:googleCredential
  1104. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1105. XCTAssertTrue([NSThread isMainThread]);
  1106. XCTAssertEqual(error.code, FIRAuthErrorCodeAccountExistsWithDifferentCredential);
  1107. XCTAssertEqualObjects(error.userInfo[FIRAuthErrorUserInfoEmailKey], kEmail);
  1108. [expectation fulfill];
  1109. }];
  1110. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1111. OCMVerifyAll(_mockBackend);
  1112. }
  1113. /** @fn testSignInWithGoogleCredentialSuccess
  1114. @brief Tests the flow of a successful @c signInWithCredential:completion: call with an
  1115. Google Sign-In credential.
  1116. */
  1117. - (void)testSignInWithGoogleCredentialSuccess {
  1118. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1119. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1120. FIRVerifyAssertionResponseCallback callback) {
  1121. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1122. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1123. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  1124. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  1125. XCTAssertTrue(request.returnSecureToken);
  1126. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1127. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1128. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1129. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1130. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1131. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1132. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1133. callback(mockVerifyAssertionResponse, nil);
  1134. });
  1135. });
  1136. [self expectGetAccountInfoGoogle];
  1137. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1138. [[FIRAuth auth] signOut:NULL];
  1139. FIRAuthCredential *googleCredential =
  1140. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1141. [[FIRAuth auth]
  1142. signInWithCredential:googleCredential
  1143. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1144. XCTAssertTrue([NSThread isMainThread]);
  1145. [self assertUserGoogle:result.user];
  1146. XCTAssertNil(error);
  1147. [expectation fulfill];
  1148. }];
  1149. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1150. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1151. OCMVerifyAll(_mockBackend);
  1152. }
  1153. /** @fn testSignInWithOAuthCredentialSuccess
  1154. @brief Tests the flow of a successful @c signInWithCredential:completion: call with a generic
  1155. OAuth credential (In this case, configured for the Google IDP).
  1156. */
  1157. - (void)testSignInWithOAuthCredentialSuccess {
  1158. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1159. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1160. FIRVerifyAssertionResponseCallback callback) {
  1161. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1162. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1163. XCTAssertEqualObjects(request.requestURI, kOAuthRequestURI);
  1164. XCTAssertEqualObjects(request.sessionID, kOAuthSessionID);
  1165. XCTAssertTrue(request.returnSecureToken);
  1166. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1167. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1168. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1169. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1170. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1171. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1172. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1173. callback(mockVerifyAssertionResponse, nil);
  1174. });
  1175. });
  1176. [self expectGetAccountInfoGoogle];
  1177. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1178. [[FIRAuth auth] signOut:NULL];
  1179. id mockProvider = OCMClassMock([FIROAuthProvider class]);
  1180. OCMExpect([mockProvider getCredentialWithUIDelegate:[OCMArg any] completion:[OCMArg any]])
  1181. .andCallBlock2(^(id<FIRAuthUIDelegate> delegate, FIRAuthCredentialCallback callback) {
  1182. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1183. FIROAuthCredential *credential =
  1184. [[FIROAuthCredential alloc] initWithProviderID:FIRGoogleAuthProviderID
  1185. sessionID:kOAuthSessionID
  1186. OAuthResponseURLString:kOAuthRequestURI];
  1187. callback(credential, nil);
  1188. });
  1189. });
  1190. [mockProvider
  1191. getCredentialWithUIDelegate:nil
  1192. completion:^(FIRAuthCredential *_Nullable credential,
  1193. NSError *_Nullable error) {
  1194. XCTAssertTrue([credential isKindOfClass:[FIROAuthCredential class]]);
  1195. FIROAuthCredential *OAuthCredential = (FIROAuthCredential *)credential;
  1196. XCTAssertEqualObjects(OAuthCredential.OAuthResponseURLString,
  1197. kOAuthRequestURI);
  1198. XCTAssertEqualObjects(OAuthCredential.sessionID, kOAuthSessionID);
  1199. [[FIRAuth auth] signInWithCredential:OAuthCredential
  1200. completion:^(FIRAuthDataResult *_Nullable result,
  1201. NSError *_Nullable error) {
  1202. XCTAssertTrue([NSThread isMainThread]);
  1203. [self assertUserGoogle:result.user];
  1204. XCTAssertNil(error);
  1205. [expectation fulfill];
  1206. }];
  1207. }];
  1208. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1209. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1210. OCMVerifyAll(_mockBackend);
  1211. }
  1212. #endif // TARGET_OS_IOS
  1213. /** @fn testSignInWithCredentialSuccess
  1214. @brief Tests the flow of a successful @c signInWithCredential:completion: call
  1215. with an Google Sign-In credential.
  1216. */
  1217. - (void)testSignInWithCredentialSuccess {
  1218. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1219. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1220. FIRVerifyAssertionResponseCallback callback) {
  1221. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1222. XCTAssertEqualObjects(request.providerID, FIRGoogleAuthProviderID);
  1223. XCTAssertEqualObjects(request.providerIDToken, kGoogleIDToken);
  1224. XCTAssertEqualObjects(request.providerAccessToken, kGoogleAccessToken);
  1225. XCTAssertTrue(request.returnSecureToken);
  1226. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1227. id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1228. OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kGoogleID);
  1229. OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRGoogleAuthProviderID);
  1230. OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
  1231. OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kGoogleDisplayName);
  1232. OCMStub([mockVerifyAssertionResponse profile]).andReturn([[self class] googleProfile]);
  1233. OCMStub([mockVerifyAssertionResponse username]).andReturn(kDisplayName);
  1234. [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
  1235. callback(mockVerifyAssertionResponse, nil);
  1236. });
  1237. });
  1238. [self expectGetAccountInfoGoogle];
  1239. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1240. [[FIRAuth auth] signOut:NULL];
  1241. FIRAuthCredential *googleCredential =
  1242. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1243. [[FIRAuth auth]
  1244. signInWithCredential:googleCredential
  1245. completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
  1246. XCTAssertTrue([NSThread isMainThread]);
  1247. [self assertUserGoogle:authResult.user];
  1248. XCTAssertEqualObjects(authResult.additionalUserInfo.profile,
  1249. [[self class] googleProfile]);
  1250. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
  1251. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID,
  1252. FIRGoogleAuthProviderID);
  1253. XCTAssertNil(error);
  1254. [expectation fulfill];
  1255. }];
  1256. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1257. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1258. OCMVerifyAll(_mockBackend);
  1259. }
  1260. /** @fn testSignInWithGoogleCredentialFailure
  1261. @brief Tests the flow of a failed @c signInWithCredential:completion: call with an
  1262. Google Sign-In credential.
  1263. */
  1264. - (void)testSignInWithGoogleCredentialFailure {
  1265. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1266. .andDispatchError2([FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:kGoogleEmail]);
  1267. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1268. [[FIRAuth auth] signOut:NULL];
  1269. FIRAuthCredential *googleCredential =
  1270. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1271. [[FIRAuth auth]
  1272. signInWithCredential:googleCredential
  1273. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1274. XCTAssertTrue([NSThread isMainThread]);
  1275. XCTAssertNil(result.user);
  1276. XCTAssertEqual(error.code, FIRAuthErrorCodeEmailAlreadyInUse);
  1277. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1278. [expectation fulfill];
  1279. }];
  1280. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1281. XCTAssertNil([FIRAuth auth].currentUser);
  1282. OCMVerifyAll(_mockBackend);
  1283. }
  1284. /** @fn testSignInAnonymouslySuccess
  1285. @brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
  1286. */
  1287. - (void)testSignInAnonymouslySuccess {
  1288. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1289. .andCallBlock2(
  1290. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1291. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1292. XCTAssertNil(request.email);
  1293. XCTAssertNil(request.password);
  1294. XCTAssertTrue(request.returnSecureToken);
  1295. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1296. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1297. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1298. callback(mockSignUpNewUserResponse, nil);
  1299. });
  1300. });
  1301. [self expectGetAccountInfoAnonymous];
  1302. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1303. [[FIRAuth auth] signOut:NULL];
  1304. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1305. NSError *_Nullable error) {
  1306. XCTAssertTrue([NSThread isMainThread]);
  1307. [self assertUserAnonymous:result.user];
  1308. XCTAssertNil(error);
  1309. FIRAdditionalUserInfo *userInfo = result.additionalUserInfo;
  1310. XCTAssertNotNil(userInfo);
  1311. XCTAssertTrue(userInfo.isNewUser);
  1312. XCTAssertNil(userInfo.username);
  1313. XCTAssertNil(userInfo.profile);
  1314. XCTAssertNil(userInfo.providerID);
  1315. [expectation fulfill];
  1316. }];
  1317. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1318. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  1319. OCMVerifyAll(_mockBackend);
  1320. }
  1321. /** @fn testSignInAnonymouslyFailure
  1322. @brief Tests the flow of a failed @c signInAnonymouslyWithCompletion: call.
  1323. */
  1324. - (void)testSignInAnonymouslyFailure {
  1325. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1326. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  1327. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1328. [[FIRAuth auth] signOut:NULL];
  1329. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1330. NSError *_Nullable error) {
  1331. XCTAssertTrue([NSThread isMainThread]);
  1332. XCTAssertNil(result.user);
  1333. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  1334. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1335. [expectation fulfill];
  1336. }];
  1337. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1338. XCTAssertNil([FIRAuth auth].currentUser);
  1339. OCMVerifyAll(_mockBackend);
  1340. }
  1341. /** @fn testSignInAnonymouslyAndRetrieveDataSuccess
  1342. @brief Tests the flow of a successful @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
  1343. */
  1344. - (void)testSignInAnonymouslyAndRetrieveDataSuccess {
  1345. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1346. .andCallBlock2(
  1347. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1348. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1349. XCTAssertNil(request.email);
  1350. XCTAssertNil(request.password);
  1351. XCTAssertTrue(request.returnSecureToken);
  1352. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1353. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1354. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1355. callback(mockSignUpNewUserResponse, nil);
  1356. });
  1357. });
  1358. [self expectGetAccountInfoAnonymous];
  1359. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1360. [[FIRAuth auth] signOut:NULL];
  1361. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1362. NSError *_Nullable error) {
  1363. XCTAssertTrue([NSThread isMainThread]);
  1364. [self assertUserAnonymous:result.user];
  1365. XCTAssertNil(error);
  1366. [expectation fulfill];
  1367. }];
  1368. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1369. [self assertUserAnonymous:[FIRAuth auth].currentUser];
  1370. OCMVerifyAll(_mockBackend);
  1371. }
  1372. /** @fn testSignInAnonymouslyAndRetrieveDataFailure
  1373. @brief Tests the flow of a failed @c signInAnonymouslyAndRetrieveDataWithCompletion: call.
  1374. */
  1375. - (void)testSignInAnonymouslyAndRetrieveDataFailure {
  1376. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1377. .andDispatchError2([FIRAuthErrorUtils operationNotAllowedErrorWithMessage:nil]);
  1378. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1379. [[FIRAuth auth] signOut:NULL];
  1380. [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable result,
  1381. NSError *_Nullable error) {
  1382. XCTAssertTrue([NSThread isMainThread]);
  1383. XCTAssertNil(result);
  1384. XCTAssertEqual(error.code, FIRAuthErrorCodeOperationNotAllowed);
  1385. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1386. [expectation fulfill];
  1387. }];
  1388. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1389. XCTAssertNil([FIRAuth auth].currentUser);
  1390. OCMVerifyAll(_mockBackend);
  1391. }
  1392. /** @fn testSignInWithCustomTokenSuccess
  1393. @brief Tests the flow of a successful @c signInWithCustomToken:completion: call.
  1394. */
  1395. - (void)testSignInWithCustomTokenSuccess {
  1396. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1397. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1398. FIRVerifyCustomTokenResponseCallback callback) {
  1399. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1400. XCTAssertEqualObjects(request.token, kCustomToken);
  1401. XCTAssertTrue(request.returnSecureToken);
  1402. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1403. id mockVerifyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1404. [self stubTokensWithMockResponse:mockVerifyCustomTokenResponse];
  1405. callback(mockVerifyCustomTokenResponse, nil);
  1406. });
  1407. });
  1408. [self expectGetAccountInfo];
  1409. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1410. [[FIRAuth auth] signOut:NULL];
  1411. [[FIRAuth auth]
  1412. signInWithCustomToken:kCustomToken
  1413. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1414. XCTAssertTrue([NSThread isMainThread]);
  1415. [self assertUser:result.user];
  1416. XCTAssertNil(error);
  1417. [expectation fulfill];
  1418. }];
  1419. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1420. [self assertUser:[FIRAuth auth].currentUser];
  1421. OCMVerifyAll(_mockBackend);
  1422. }
  1423. /** @fn testSignInWithCustomTokenFailure
  1424. @brief Tests the flow of a failed @c signInWithCustomToken:completion: call.
  1425. */
  1426. - (void)testSignInWithCustomTokenFailure {
  1427. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1428. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1429. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1430. [[FIRAuth auth] signOut:NULL];
  1431. [[FIRAuth auth]
  1432. signInWithCustomToken:kCustomToken
  1433. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1434. XCTAssertTrue([NSThread isMainThread]);
  1435. XCTAssertNil(result.user);
  1436. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1437. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1438. [expectation fulfill];
  1439. }];
  1440. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1441. XCTAssertNil([FIRAuth auth].currentUser);
  1442. OCMVerifyAll(_mockBackend);
  1443. }
  1444. /** @fn testSignInAndRetrieveDataWithCustomTokenSuccess
  1445. @brief Tests the flow of a successful @c signInAndRetrieveDataWithCustomToken:completion: call.
  1446. */
  1447. - (void)testSignInAndRetrieveDataWithCustomTokenSuccess {
  1448. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1449. .andCallBlock2(^(FIRVerifyCustomTokenRequest *_Nullable request,
  1450. FIRVerifyCustomTokenResponseCallback callback) {
  1451. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1452. XCTAssertEqualObjects(request.token, kCustomToken);
  1453. XCTAssertTrue(request.returnSecureToken);
  1454. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1455. id mockVerifyCustomTokenResponse = OCMClassMock([FIRVerifyCustomTokenResponse class]);
  1456. [self stubTokensWithMockResponse:mockVerifyCustomTokenResponse];
  1457. callback(mockVerifyCustomTokenResponse, nil);
  1458. });
  1459. });
  1460. [self expectGetAccountInfo];
  1461. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1462. [[FIRAuth auth] signOut:NULL];
  1463. [[FIRAuth auth]
  1464. signInWithCustomToken:kCustomToken
  1465. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1466. XCTAssertTrue([NSThread isMainThread]);
  1467. [self assertUser:result.user];
  1468. XCTAssertFalse(result.additionalUserInfo.isNewUser);
  1469. XCTAssertNil(error);
  1470. [expectation fulfill];
  1471. }];
  1472. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1473. [self assertUser:[FIRAuth auth].currentUser];
  1474. OCMVerifyAll(_mockBackend);
  1475. }
  1476. /** @fn testSignInAndRetrieveDataWithCustomTokenFailure
  1477. @brief Tests the flow of a failed @c signInAndRetrieveDataWithCustomToken:completion: call.
  1478. */
  1479. - (void)testSignInAndRetrieveDataWithCustomTokenFailure {
  1480. OCMExpect([_mockBackend verifyCustomToken:[OCMArg any] callback:[OCMArg any]])
  1481. .andDispatchError2([FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:nil]);
  1482. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1483. [[FIRAuth auth] signOut:NULL];
  1484. [[FIRAuth auth]
  1485. signInWithCustomToken:kCustomToken
  1486. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1487. XCTAssertTrue([NSThread isMainThread]);
  1488. XCTAssertNil(result);
  1489. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidCustomToken);
  1490. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1491. [expectation fulfill];
  1492. }];
  1493. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1494. XCTAssertNil([FIRAuth auth].currentUser);
  1495. OCMVerifyAll(_mockBackend);
  1496. }
  1497. /** @fn testCreateUserWithEmailPasswordSuccess
  1498. @brief Tests the flow of a successful @c createUserWithEmail:password:completion: call.
  1499. */
  1500. - (void)testCreateUserWithEmailPasswordSuccess {
  1501. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1502. .andCallBlock2(
  1503. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1504. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1505. XCTAssertEqualObjects(request.email, kEmail);
  1506. XCTAssertEqualObjects(request.password, kFakePassword);
  1507. XCTAssertTrue(request.returnSecureToken);
  1508. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1509. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1510. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1511. callback(mockSignUpNewUserResponse, nil);
  1512. });
  1513. });
  1514. [self expectGetAccountInfo];
  1515. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1516. [[FIRAuth auth] signOut:NULL];
  1517. [[FIRAuth auth]
  1518. createUserWithEmail:kEmail
  1519. password:kFakePassword
  1520. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1521. XCTAssertTrue([NSThread isMainThread]);
  1522. [self assertUser:result.user];
  1523. XCTAssertNil(error);
  1524. [expectation fulfill];
  1525. }];
  1526. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1527. [self assertUser:[FIRAuth auth].currentUser];
  1528. OCMVerifyAll(_mockBackend);
  1529. }
  1530. /** @fn testCreateUserWithEmailPasswordFailure
  1531. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call.
  1532. */
  1533. - (void)testCreateUserWithEmailPasswordFailure {
  1534. NSString *reason = @"Password shouldn't be a common word.";
  1535. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1536. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1537. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1538. [[FIRAuth auth] signOut:NULL];
  1539. [[FIRAuth auth]
  1540. createUserWithEmail:kEmail
  1541. password:kFakePassword
  1542. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1543. XCTAssertTrue([NSThread isMainThread]);
  1544. XCTAssertNil(result.user);
  1545. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1546. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1547. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1548. [expectation fulfill];
  1549. }];
  1550. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1551. XCTAssertNil([FIRAuth auth].currentUser);
  1552. OCMVerifyAll(_mockBackend);
  1553. }
  1554. /** @fn testCreateUserAndRetrieveDataWithEmailPasswordSuccess
  1555. @brief Tests the flow of a successful @c createUserAndRetrieveDataWithEmail:password:completion:
  1556. call.
  1557. */
  1558. - (void)testCreateUserAndRetrieveDataWithEmailPasswordSuccess {
  1559. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1560. .andCallBlock2(
  1561. ^(FIRSignUpNewUserRequest *_Nullable request, FIRSignupNewUserCallback callback) {
  1562. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1563. XCTAssertEqualObjects(request.email, kEmail);
  1564. XCTAssertEqualObjects(request.password, kFakePassword);
  1565. XCTAssertTrue(request.returnSecureToken);
  1566. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1567. id mockSignUpNewUserResponse = OCMClassMock([FIRSignUpNewUserResponse class]);
  1568. [self stubTokensWithMockResponse:mockSignUpNewUserResponse];
  1569. callback(mockSignUpNewUserResponse, nil);
  1570. });
  1571. });
  1572. [self expectGetAccountInfo];
  1573. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1574. [[FIRAuth auth] signOut:NULL];
  1575. [[FIRAuth auth]
  1576. createUserWithEmail:kEmail
  1577. password:kFakePassword
  1578. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1579. XCTAssertTrue([NSThread isMainThread]);
  1580. [self assertUser:result.user];
  1581. XCTAssertTrue(result.additionalUserInfo.isNewUser);
  1582. XCTAssertNil(error);
  1583. [expectation fulfill];
  1584. }];
  1585. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1586. [self assertUser:[FIRAuth auth].currentUser];
  1587. OCMVerifyAll(_mockBackend);
  1588. }
  1589. /** @fn testCreateUserAndRetrieveDataWithEmailPasswordFailure
  1590. @brief Tests the flow of a failed @c createUserAndRetrieveDataWithEmail:password:completion:
  1591. call.
  1592. */
  1593. - (void)testCreateUserAndRetrieveDataWithEmailPasswordFailure {
  1594. NSString *reason = @"Password shouldn't be a common word.";
  1595. OCMExpect([_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]])
  1596. .andDispatchError2([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:reason]);
  1597. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1598. [[FIRAuth auth] signOut:NULL];
  1599. [[FIRAuth auth]
  1600. createUserWithEmail:kEmail
  1601. password:kFakePassword
  1602. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1603. XCTAssertTrue([NSThread isMainThread]);
  1604. XCTAssertNil(result);
  1605. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1606. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1607. XCTAssertEqualObjects(error.userInfo[NSLocalizedFailureReasonErrorKey], reason);
  1608. [expectation fulfill];
  1609. }];
  1610. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1611. XCTAssertNil([FIRAuth auth].currentUser);
  1612. OCMVerifyAll(_mockBackend);
  1613. }
  1614. /** @fn testCreateUserEmptyPasswordFailure
  1615. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1616. empty password. This error occurs on the client side, so there is no need to fake an RPC
  1617. response.
  1618. */
  1619. - (void)testCreateUserEmptyPasswordFailure {
  1620. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1621. [[FIRAuth auth] signOut:NULL];
  1622. [[FIRAuth auth]
  1623. createUserWithEmail:kEmail
  1624. password:@""
  1625. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1626. XCTAssertTrue([NSThread isMainThread]);
  1627. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  1628. [expectation fulfill];
  1629. }];
  1630. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1631. }
  1632. /** @fn testCreateUserEmptyEmailFailure
  1633. @brief Tests the flow of a failed @c createUserWithEmail:password:completion: call due to an
  1634. empty email adress. This error occurs on the client side, so there is no need to fake an RPC
  1635. response.
  1636. */
  1637. - (void)testCreateUserEmptyEmailFailure {
  1638. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1639. [[FIRAuth auth] signOut:NULL];
  1640. [[FIRAuth auth]
  1641. createUserWithEmail:@""
  1642. password:kFakePassword
  1643. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  1644. XCTAssertTrue([NSThread isMainThread]);
  1645. XCTAssertEqual(error.code, FIRAuthErrorCodeMissingEmail);
  1646. [expectation fulfill];
  1647. }];
  1648. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1649. }
  1650. /** @fn testSendPasswordResetEmailSuccess
  1651. @brief Tests the flow of a successful @c sendPasswordResetWithEmail:completion: call.
  1652. */
  1653. - (void)testSendPasswordResetEmailSuccess {
  1654. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1655. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  1656. FIRGetOOBConfirmationCodeResponseCallback callback) {
  1657. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1658. XCTAssertEqualObjects(request.email, kEmail);
  1659. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1660. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  1661. });
  1662. });
  1663. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1664. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail
  1665. completion:^(NSError *_Nullable error) {
  1666. XCTAssertTrue([NSThread isMainThread]);
  1667. XCTAssertNil(error);
  1668. [expectation fulfill];
  1669. }];
  1670. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1671. OCMVerifyAll(_mockBackend);
  1672. }
  1673. /** @fn testSendPasswordResetEmailFailure
  1674. @brief Tests the flow of a failed @c sendPasswordResetWithEmail:completion: call.
  1675. */
  1676. - (void)testSendPasswordResetEmailFailure {
  1677. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1678. .andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
  1679. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1680. [[FIRAuth auth] sendPasswordResetWithEmail:kEmail
  1681. completion:^(NSError *_Nullable error) {
  1682. XCTAssertTrue([NSThread isMainThread]);
  1683. XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
  1684. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1685. [expectation fulfill];
  1686. }];
  1687. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1688. OCMVerifyAll(_mockBackend);
  1689. }
  1690. /** @fn testSendSignInLinkToEmailSuccess
  1691. @brief Tests the flow of a successful @c sendSignInLinkToEmail:actionCodeSettings:completion:
  1692. call.
  1693. */
  1694. - (void)testSendSignInLinkToEmailSuccess {
  1695. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1696. .andCallBlock2(^(FIRGetOOBConfirmationCodeRequest *_Nullable request,
  1697. FIRGetOOBConfirmationCodeResponseCallback callback) {
  1698. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1699. XCTAssertEqualObjects(request.email, kEmail);
  1700. XCTAssertEqualObjects(request.continueURL, kContinueURL);
  1701. XCTAssertTrue(request.handleCodeInApp);
  1702. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1703. callback([[FIRGetOOBConfirmationCodeResponse alloc] init], nil);
  1704. });
  1705. });
  1706. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1707. [[FIRAuth auth] sendSignInLinkToEmail:kEmail
  1708. actionCodeSettings:[self fakeActionCodeSettings]
  1709. completion:^(NSError *_Nullable error) {
  1710. XCTAssertTrue([NSThread isMainThread]);
  1711. XCTAssertNil(error);
  1712. [expectation fulfill];
  1713. }];
  1714. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1715. OCMVerifyAll(_mockBackend);
  1716. }
  1717. /** @fn testSendSignInLinkToEmailFailure
  1718. @brief Tests the flow of a failed @c sendSignInLinkToEmail:actionCodeSettings:completion:
  1719. call.
  1720. */
  1721. - (void)testSendSignInLinkToEmailFailure {
  1722. OCMExpect([_mockBackend getOOBConfirmationCode:[OCMArg any] callback:[OCMArg any]])
  1723. .andDispatchError2([FIRAuthErrorUtils appNotAuthorizedError]);
  1724. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1725. [[FIRAuth auth] sendSignInLinkToEmail:kEmail
  1726. actionCodeSettings:[self fakeActionCodeSettings]
  1727. completion:^(NSError *_Nullable error) {
  1728. XCTAssertTrue([NSThread isMainThread]);
  1729. XCTAssertEqual(error.code, FIRAuthErrorCodeAppNotAuthorized);
  1730. XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]);
  1731. [expectation fulfill];
  1732. }];
  1733. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1734. OCMVerifyAll(_mockBackend);
  1735. }
  1736. /** @fn fakeActionCodeSettings
  1737. @brief Constructs and returns a fake instance of @c FIRActionCodeSettings for testing.
  1738. @return An instance of @c FIRActionCodeSettings for testing.
  1739. */
  1740. - (FIRActionCodeSettings *)fakeActionCodeSettings {
  1741. FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
  1742. actionCodeSettings.URL = [NSURL URLWithString:kContinueURL];
  1743. actionCodeSettings.handleCodeInApp = YES;
  1744. return actionCodeSettings;
  1745. }
  1746. /** @fn testUpdateCurrentUserFailure
  1747. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1748. call.
  1749. */
  1750. - (void)testUpdateCurrentUserFailure {
  1751. NSString *kTestAccessToken = @"fakeAccessToken";
  1752. NSString *kTestAPIKey = @"fakeAPIKey";
  1753. [self waitForSignInWithAccessToken:kTestAccessToken APIKey:kTestAPIKey completion:nil];
  1754. NSString *kTestAPIKey2 = @"fakeAPIKey2";
  1755. FIRUser *user2 = [FIRAuth auth].currentUser;
  1756. user2.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey2
  1757. appID:kFirebaseAppID];
  1758. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1759. .andDispatchError2([FIRAuthErrorUtils invalidAPIKeyError]);
  1760. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1761. [[FIRAuth auth] updateCurrentUser:user2
  1762. completion:^(NSError *_Nullable error) {
  1763. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidAPIKey);
  1764. [expectation fulfill];
  1765. }];
  1766. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1767. OCMVerifyAll(_mockBackend);
  1768. }
  1769. /** @fn testUpdateCurrentUserFailureNetworkError
  1770. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1771. call with a network error.
  1772. */
  1773. - (void)testUpdateCurrentUserFailureNetworkError {
  1774. NSString *kTestAPIKey = @"fakeAPIKey";
  1775. NSString *kTestAccessToken = @"fakeAccessToken";
  1776. [self waitForSignInWithAccessToken:kTestAccessToken APIKey:kTestAPIKey completion:nil];
  1777. NSString *kTestAPIKey2 = @"fakeAPIKey2";
  1778. FIRUser *user2 = [FIRAuth auth].currentUser;
  1779. user2.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey2
  1780. appID:kFirebaseAppID];
  1781. NSError *underlyingError = [NSError errorWithDomain:@"Test Error" code:1 userInfo:nil];
  1782. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1783. .andDispatchError2([FIRAuthErrorUtils networkErrorWithUnderlyingError:underlyingError]);
  1784. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1785. [[FIRAuth auth] updateCurrentUser:user2
  1786. completion:^(NSError *_Nullable error) {
  1787. XCTAssertEqual(error.code, FIRAuthErrorCodeNetworkError);
  1788. [expectation fulfill];
  1789. }];
  1790. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1791. OCMVerifyAll(_mockBackend);
  1792. }
  1793. /** @fn testUpdateCurrentUserFailureNUllUser
  1794. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1795. call with FIRAuthErrorCodeNullUser.
  1796. */
  1797. - (void)testUpdateCurrentUserFailureNUllUser {
  1798. NSString *kTestAccessToken = @"fakeAccessToken";
  1799. NSString *kTestAPIKey = @"fakeAPIKey";
  1800. [self waitForSignInWithAccessToken:kTestAccessToken APIKey:kTestAPIKey completion:nil];
  1801. FIRUser *fakeNilUser = nil;
  1802. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1803. [[FIRAuth auth] updateCurrentUser:fakeNilUser
  1804. completion:^(NSError *_Nullable error) {
  1805. XCTAssertEqual(error.code, FIRAuthErrorCodeNullUser);
  1806. [expectation fulfill];
  1807. }];
  1808. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1809. OCMVerifyAll(_mockBackend);
  1810. }
  1811. /** @fn testUpdateCurrentUserFailureTenantIDMismatch
  1812. @brief Tests the flow of a failed @c updateCurrentUser:completion:
  1813. call with FIRAuthErrorCodeTenantIDMismatch.
  1814. */
  1815. - (void)testUpdateCurrentUserFailureTenantIDMismatch {
  1816. // User without tenant id
  1817. [self waitForSignInWithAccessToken:kAccessToken APIKey:kAPIKey completion:nil];
  1818. FIRUser *user1 = [FIRAuth auth].currentUser;
  1819. [[FIRAuth auth] signOut:nil];
  1820. // User with tenant id "tenant-id"
  1821. [FIRAuth auth].tenantID = @"tenant-id-1";
  1822. NSString *kTestAccessToken2 = @"fakeAccessToken2";
  1823. [self waitForSignInWithAccessToken:kTestAccessToken2 APIKey:kAPIKey completion:nil];
  1824. FIRUser *user2 = [FIRAuth auth].currentUser;
  1825. [[FIRAuth auth] signOut:nil];
  1826. [FIRAuth auth].tenantID = @"tenant-id-2";
  1827. XCTestExpectation *expectation1 = [self expectationWithDescription:@"callback"];
  1828. [[FIRAuth auth] updateCurrentUser:user1
  1829. completion:^(NSError *_Nullable error) {
  1830. XCTAssertEqual(error.code, FIRAuthErrorCodeTenantIDMismatch);
  1831. [expectation1 fulfill];
  1832. }];
  1833. [[FIRAuth auth] signOut:nil];
  1834. [FIRAuth auth].tenantID = @"tenant-id-2";
  1835. XCTestExpectation *expectation2 = [self expectationWithDescription:@"callback"];
  1836. [[FIRAuth auth] updateCurrentUser:user2
  1837. completion:^(NSError *_Nullable error) {
  1838. XCTAssertEqual(error.code, FIRAuthErrorCodeTenantIDMismatch);
  1839. [expectation2 fulfill];
  1840. }];
  1841. [[FIRAuth auth] signOut:nil];
  1842. [FIRAuth auth].tenantID = nil;
  1843. XCTestExpectation *expectation3 = [self expectationWithDescription:@"callback"];
  1844. [[FIRAuth auth] updateCurrentUser:user2
  1845. completion:^(NSError *_Nullable error) {
  1846. XCTAssertEqual(error.code, FIRAuthErrorCodeTenantIDMismatch);
  1847. [expectation3 fulfill];
  1848. }];
  1849. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1850. OCMVerifyAll(_mockBackend);
  1851. }
  1852. /** @fn testUpdateCurrentUserSuccess
  1853. @brief Tests the flow of a successful @c updateCurrentUser:completion:
  1854. call with a network error.
  1855. */
  1856. - (void)testUpdateCurrentUserSuccess {
  1857. // Sign in with the first user.
  1858. [self waitForSignInWithAccessToken:kAccessToken APIKey:kAPIKey completion:nil];
  1859. FIRUser *user1 = [FIRAuth auth].currentUser;
  1860. NSString *kTestAPIKey = @"fakeAPIKey";
  1861. user1.requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey
  1862. appID:kFirebaseAppID];
  1863. [[FIRAuth auth] signOut:nil];
  1864. NSString *kTestAccessToken2 = @"fakeAccessToken2";
  1865. [self waitForSignInWithAccessToken:kTestAccessToken2 APIKey:kAPIKey completion:nil];
  1866. FIRUser *user2 = [FIRAuth auth].currentUser;
  1867. [self expectGetAccountInfoWithAccessToken:kAccessToken];
  1868. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1869. // Current user should now be user2.
  1870. XCTAssertEqualObjects([FIRAuth auth].currentUser, user2);
  1871. [[FIRAuth auth] updateCurrentUser:user1
  1872. completion:^(NSError *_Nullable error) {
  1873. XCTAssertNil(error);
  1874. // Current user should now be user1.
  1875. XCTAssertEqualObjects([FIRAuth auth].currentUser, user1);
  1876. XCTAssertNotEqualObjects([FIRAuth auth].currentUser, user2);
  1877. [expectation fulfill];
  1878. }];
  1879. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1880. OCMVerifyAll(_mockBackend);
  1881. }
  1882. /** @fn testSignOut
  1883. @brief Tests the @c signOut: method.
  1884. */
  1885. - (void)testSignOut {
  1886. [self waitForSignIn];
  1887. // Verify signing out succeeds and clears the current user.
  1888. NSError *error;
  1889. XCTAssertTrue([[FIRAuth auth] signOut:&error]);
  1890. XCTAssertNil([FIRAuth auth].currentUser);
  1891. }
  1892. /** @fn testIsSignInWithEmailLink
  1893. @brief Tests the @c isSignInWithEmailLink: method.
  1894. */
  1895. - (void)testIsSignInWithEmailLink {
  1896. XCTAssertTrue([[FIRAuth auth] isSignInWithEmailLink:kFakeEmailSignInlink]);
  1897. XCTAssertTrue([[FIRAuth auth] isSignInWithEmailLink:kFakeEmailSignInDeeplink]);
  1898. XCTAssertFalse([[FIRAuth auth] isSignInWithEmailLink:kBadSignInEmailLink]);
  1899. XCTAssertFalse([[FIRAuth auth] isSignInWithEmailLink:@""]);
  1900. }
  1901. /** @fn testAuthStateChanges
  1902. @brief Tests @c addAuthStateDidChangeListener: and @c removeAuthStateDidChangeListener: methods.
  1903. */
  1904. - (void)testAuthStateChanges {
  1905. // Set up listener.
  1906. __block XCTestExpectation *expectation;
  1907. __block BOOL shouldHaveUser;
  1908. FIRAuthStateDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  1909. XCTAssertTrue([NSThread isMainThread]);
  1910. XCTAssertEqual(auth, [FIRAuth auth]);
  1911. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  1912. if (shouldHaveUser) {
  1913. XCTAssertNotNil(user);
  1914. } else {
  1915. XCTAssertNil(user);
  1916. }
  1917. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1918. XCTAssertNotNil(expectation);
  1919. [expectation fulfill];
  1920. };
  1921. [[FIRAuth auth] signOut:NULL];
  1922. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  1923. // Listener should fire immediately when attached.
  1924. expectation = [self expectationWithDescription:@"initial"];
  1925. shouldHaveUser = NO;
  1926. FIRAuthStateDidChangeListenerHandle handle =
  1927. [[FIRAuth auth] addAuthStateDidChangeListener:listener];
  1928. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1929. // Listener should fire for signing in.
  1930. expectation = [self expectationWithDescription:@"sign-in"];
  1931. shouldHaveUser = YES;
  1932. [self waitForSignIn];
  1933. // Listener should not fire for signing in again.
  1934. shouldHaveUser = YES;
  1935. [self waitForSignIn];
  1936. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is not called
  1937. // Listener should fire for signing out.
  1938. expectation = [self expectationWithDescription:@"sign-out"];
  1939. shouldHaveUser = NO;
  1940. [[FIRAuth auth] signOut:NULL];
  1941. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1942. // Listener should no longer fire once detached.
  1943. expectation = nil;
  1944. [[FIRAuth auth] removeAuthStateDidChangeListener:handle];
  1945. [self waitForSignIn];
  1946. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  1947. }
  1948. /** @fn testIDTokenChanges
  1949. @brief Tests @c addIDTokenDidChangeListener: and @c removeIDTokenDidChangeListener: methods.
  1950. */
  1951. - (void)testIDTokenChanges {
  1952. // Set up listener.
  1953. __block XCTestExpectation *expectation;
  1954. __block BOOL shouldHaveUser;
  1955. FIRIDTokenDidChangeListenerBlock listener = ^(FIRAuth *auth, FIRUser *_Nullable user) {
  1956. XCTAssertTrue([NSThread isMainThread]);
  1957. XCTAssertEqual(auth, [FIRAuth auth]);
  1958. XCTAssertEqual(user, [FIRAuth auth].currentUser);
  1959. if (shouldHaveUser) {
  1960. XCTAssertNotNil(user);
  1961. } else {
  1962. XCTAssertNil(user);
  1963. }
  1964. // `expectation` being nil means the listener is not expected to be fired at this moment.
  1965. XCTAssertNotNil(expectation);
  1966. [expectation fulfill];
  1967. };
  1968. [[FIRAuth auth] signOut:NULL];
  1969. [self waitForTimeIntervel:kWaitInterval]; // Wait until dust settled from previous tests.
  1970. // Listener should fire immediately when attached.
  1971. expectation = [self expectationWithDescription:@"initial"];
  1972. shouldHaveUser = NO;
  1973. FIRIDTokenDidChangeListenerHandle handle = [[FIRAuth auth] addIDTokenDidChangeListener:listener];
  1974. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1975. // Listener should fire for signing in.
  1976. expectation = [self expectationWithDescription:@"sign-in"];
  1977. shouldHaveUser = YES;
  1978. [self waitForSignIn];
  1979. // Listener should fire for signing in again as the same user with another access token.
  1980. expectation = [self expectationWithDescription:@"sign-in again"];
  1981. shouldHaveUser = YES;
  1982. [self waitForSignInWithAccessToken:kNewAccessToken APIKey:nil completion:nil];
  1983. // Listener should fire for signing out.
  1984. expectation = [self expectationWithDescription:@"sign-out"];
  1985. shouldHaveUser = NO;
  1986. [[FIRAuth auth] signOut:NULL];
  1987. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1988. // Listener should no longer fire once detached.
  1989. expectation = nil;
  1990. [[FIRAuth auth] removeIDTokenDidChangeListener:handle];
  1991. [self waitForSignIn];
  1992. [self waitForTimeIntervel:kWaitInterval]; // make sure listener is no longer called
  1993. }
  1994. /** @fn testUseEmulator
  1995. @brief Tests the @c useEmulatorWithHost:port: method.
  1996. */
  1997. - (void)testUseEmulator {
  1998. [[FIRAuth auth] useEmulatorWithHost:@"host" port:12345];
  1999. XCTAssertEqualObjects(@"host:12345", [FIRAuth auth].requestConfiguration.emulatorHostAndPort);
  2000. #if TARGET_OS_IOS
  2001. XCTAssertTrue([FIRAuth auth].settings.isAppVerificationDisabledForTesting);
  2002. #endif
  2003. }
  2004. /** @fn testUseEmulatorNeverCalled
  2005. @brief Tests that the emulatorHostAndPort stored in @c FIRAuthRequestConfiguration is nil if the
  2006. @c useEmulatorWithHost:port: is not called.
  2007. */
  2008. - (void)testUseEmulatorNeverCalled {
  2009. XCTAssertEqualObjects(nil, [FIRAuth auth].requestConfiguration.emulatorHostAndPort);
  2010. #if TARGET_OS_IOS
  2011. XCTAssertFalse([FIRAuth auth].settings.isAppVerificationDisabledForTesting);
  2012. #endif
  2013. }
  2014. /** @fn testUseEmulatorIPv6Address
  2015. @brief Tests the @c useEmulatorWithHost:port: method with an IPv6 host address.
  2016. */
  2017. - (void)testUseEmulatorIPv6Address {
  2018. [[FIRAuth auth] useEmulatorWithHost:@"::1" port:12345];
  2019. XCTAssertEqualObjects(@"[::1]:12345", [FIRAuth auth].requestConfiguration.emulatorHostAndPort);
  2020. #if TARGET_OS_IOS
  2021. XCTAssertTrue([FIRAuth auth].settings.isAppVerificationDisabledForTesting);
  2022. #endif
  2023. }
  2024. #pragma mark - Automatic Token Refresh Tests.
  2025. /** @fn testAutomaticTokenRefresh
  2026. @brief Tests a successful flow to automatically refresh tokens for a signed in user.
  2027. */
  2028. - (void)testAutomaticTokenRefresh {
  2029. [[FIRAuth auth] signOut:NULL];
  2030. // Enable auto refresh
  2031. [self enableAutoTokenRefresh];
  2032. // Sign in a user.
  2033. [self waitForSignIn];
  2034. // Set up expectation for secureToken RPC made by token refresh task. We call this twice, because
  2035. // we retry once if the access token is already expired.
  2036. [self mockSecureTokenResponseWithError:nil];
  2037. [self mockSecureTokenResponseWithError:nil];
  2038. // Verify that the current user's access token is the "old" access token before automatic token
  2039. // refresh.
  2040. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2041. // Execute saved token refresh task.
  2042. XCTestExpectation *dispatchAfterExpectation =
  2043. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2044. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2045. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2046. self->_FIRAuthDispatcherCallback();
  2047. [dispatchAfterExpectation fulfill];
  2048. });
  2049. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2050. // Verify that current user's access token is the "new" access token provided in the mock secure
  2051. // token response during automatic token refresh.
  2052. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2053. OCMVerifyAll(_mockBackend);
  2054. }
  2055. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  2056. @brief Tests an unsuccessful flow to auto refresh tokens with an "invalid token" error.
  2057. This error should cause the user to be signed out.
  2058. */
  2059. - (void)testAutomaticTokenRefreshInvalidTokenFailure {
  2060. [[FIRAuth auth] signOut:NULL];
  2061. // Enable auto refresh
  2062. [self enableAutoTokenRefresh];
  2063. // Sign in a user.
  2064. [self waitForSignIn];
  2065. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  2066. [self mockSecureTokenResponseWithError:[FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]];
  2067. // Verify that current user is still valid.
  2068. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2069. // Execute saved token refresh task.
  2070. XCTestExpectation *dispatchAfterExpectation =
  2071. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2072. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2073. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2074. self->_FIRAuthDispatcherCallback();
  2075. [dispatchAfterExpectation fulfill];
  2076. });
  2077. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2078. // Verify that the user is nil after failed attempt to refresh tokens caused signed out.
  2079. XCTAssertNil([FIRAuth auth].currentUser);
  2080. OCMVerifyAll(_mockBackend);
  2081. }
  2082. /** @fn testAutomaticTokenRefreshRetry
  2083. @brief Tests that a retry is attempted for a automatic token refresh task (which is not due to
  2084. invalid tokens). The initial attempt to refresh the access token fails, but the second
  2085. attempt is successful.
  2086. */
  2087. - (void)testAutomaticTokenRefreshRetry {
  2088. [[FIRAuth auth] signOut:NULL];
  2089. // Enable auto refresh
  2090. [self enableAutoTokenRefresh];
  2091. // Sign in a user.
  2092. [self waitForSignIn];
  2093. // Set up expectation for secureToken RPC made by a failed attempt to refresh tokens.
  2094. [self mockSecureTokenResponseWithError:[NSError errorWithDomain:@"ERROR" code:-1 userInfo:nil]];
  2095. // Execute saved token refresh task.
  2096. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2097. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2098. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2099. self->_FIRAuthDispatcherCallback();
  2100. self->_FIRAuthDispatcherCallback = nil;
  2101. [expectation fulfill];
  2102. });
  2103. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2104. // The old access token should still be the current user's access token and not the new access
  2105. // token (kNewAccessToken).
  2106. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2107. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens. We call
  2108. // this twice, because we retry once if the access token is already expired.
  2109. [self mockSecureTokenResponseWithError:nil];
  2110. [self mockSecureTokenResponseWithError:nil];
  2111. // Execute saved token refresh task.
  2112. XCTestExpectation *dispatchAfterExpectation =
  2113. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2114. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2115. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2116. self->_FIRAuthDispatcherCallback();
  2117. [dispatchAfterExpectation fulfill];
  2118. });
  2119. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2120. // Verify that current user's access token is the "new" access token provided in the mock secure
  2121. // token response during automatic token refresh.
  2122. XCTAssertEqualObjects([FIRAuth auth].currentUser.rawAccessToken, kNewAccessToken);
  2123. OCMVerifyAll(_mockBackend);
  2124. }
  2125. #if TARGET_OS_IOS
  2126. /** @fn testAutomaticTokenRefreshInvalidTokenFailure
  2127. @brief Tests that app foreground notification triggers the scheduling of an automatic token
  2128. refresh task.
  2129. */
  2130. - (void)testAutoRefreshAppForegroundedNotification {
  2131. [[FIRAuth auth] signOut:NULL];
  2132. // Enable auto refresh
  2133. [self enableAutoTokenRefresh];
  2134. // Sign in a user.
  2135. [self waitForSignIn];
  2136. // Post "UIApplicationDidBecomeActiveNotification" to trigger scheduling token refresh task.
  2137. [[NSNotificationCenter defaultCenter]
  2138. postNotificationName:UIApplicationDidBecomeActiveNotification
  2139. object:nil];
  2140. // Verify that current user is still valid with old access token.
  2141. XCTAssertEqualObjects(kAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2142. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens. We call
  2143. // this twice, because we retry once if the access token is already expired.
  2144. [self mockSecureTokenResponseWithError:nil];
  2145. [self mockSecureTokenResponseWithError:nil];
  2146. // Execute saved token refresh task.
  2147. XCTestExpectation *dispatchAfterExpectation =
  2148. [self expectationWithDescription:@"dispatchAfterExpectation"];
  2149. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2150. XCTAssertNotNil(self->_FIRAuthDispatcherCallback);
  2151. self->_FIRAuthDispatcherCallback();
  2152. [dispatchAfterExpectation fulfill];
  2153. });
  2154. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2155. // Verify that current user is still valid with new access token.
  2156. XCTAssertEqualObjects(kNewAccessToken, [FIRAuth auth].currentUser.rawAccessToken);
  2157. OCMVerifyAll(_mockBackend);
  2158. }
  2159. #endif
  2160. #if TARGET_OS_IOS
  2161. #pragma mark - Application Delegate tests
  2162. - (void)testAppDidRegisterForRemoteNotifications_APNSTokenUpdated {
  2163. NSData *apnsToken = [NSData data];
  2164. OCMExpect([self.mockTokenManager setToken:[OCMArg checkWithBlock:^BOOL(FIRAuthAPNSToken *token) {
  2165. XCTAssertEqual(token.data, apnsToken);
  2166. XCTAssertEqual(token.type, FIRAuthAPNSTokenTypeUnknown);
  2167. return YES;
  2168. }]]);
  2169. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2170. didRegisterForRemoteNotificationsWithDeviceToken:apnsToken];
  2171. [self.mockTokenManager verify];
  2172. }
  2173. - (void)testAppDidFailToRegisterForRemoteNotifications_TokenManagerCancels {
  2174. NSError *error = [NSError errorWithDomain:@"FIRAuthTests" code:-1 userInfo:nil];
  2175. OCMExpect([self.mockTokenManager cancelWithError:error]);
  2176. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2177. didFailToRegisterForRemoteNotificationsWithError:error];
  2178. [self.mockTokenManager verify];
  2179. }
  2180. - (void)testAppDidReceiveRemoteNotification_NotificationManagerHandleCanNotification {
  2181. NSDictionary *notification = @{@"test" : @""};
  2182. OCMExpect([self.mockNotificationManager canHandleNotification:notification]);
  2183. #pragma clang diagnostic push
  2184. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  2185. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2186. didReceiveRemoteNotification:notification];
  2187. #pragma clang diagnostic pop
  2188. [self.mockNotificationManager verify];
  2189. }
  2190. - (void)testAppDidReceiveRemoteNotificationWithCompletion_NotificationManagerHandleCanNotification {
  2191. NSDictionary *notification = @{@"test" : @""};
  2192. OCMExpect([self.mockNotificationManager canHandleNotification:notification]);
  2193. [self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2194. didReceiveRemoteNotification:notification
  2195. fetchCompletionHandler:^(UIBackgroundFetchResult result){
  2196. }];
  2197. [self.mockNotificationManager verify];
  2198. }
  2199. - (void)testAppOpenURL_AuthPresenterCanHandleURL {
  2200. if (@available(iOS 9.0, *)) {
  2201. // 'application:openURL:options:' is only available on iOS 9.0 or newer.
  2202. NSURL *url = [NSURL URLWithString:@"https://localhost"];
  2203. [OCMExpect([self.mockAuthURLPresenter canHandleURL:url]) andReturnValue:@(YES)];
  2204. XCTAssertTrue([self.fakeApplicationDelegate
  2205. application:[GULAppDelegateSwizzler sharedApplication]
  2206. openURL:url
  2207. options:@{}]);
  2208. [self.mockAuthURLPresenter verify];
  2209. }
  2210. }
  2211. - (void)testAppOpenURLWithSourceApplication_AuthPresenterCanHandleURL {
  2212. NSURL *url = [NSURL URLWithString:@"https://localhost"];
  2213. [OCMExpect([self.mockAuthURLPresenter canHandleURL:url]) andReturnValue:@(YES)];
  2214. #pragma clang diagnostic push
  2215. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  2216. XCTAssertTrue([self.fakeApplicationDelegate application:[GULAppDelegateSwizzler sharedApplication]
  2217. openURL:url
  2218. sourceApplication:@""
  2219. annotation:[[NSObject alloc] init]]);
  2220. #pragma clang diagnostic pop
  2221. [self.mockAuthURLPresenter verify];
  2222. }
  2223. #endif // TARGET_OS_IOS
  2224. #pragma mark - Interoperability Tests
  2225. /** @fn testComponentsBeingRegistered
  2226. @brief Tests that Auth provides the necessary components for interoperability with other SDKs.
  2227. */
  2228. - (void)testComponentsBeingRegistered {
  2229. // Verify that the components are registered properly. Check the count, because any time a new
  2230. // component is added it should be added to the test suite as well.
  2231. NSArray<FIRComponent *> *components = [FIRAuth componentsToRegister];
  2232. XCTAssertTrue(components.count == 1);
  2233. FIRComponent *component = [components firstObject];
  2234. XCTAssert(component.protocol == @protocol(FIRAuthInterop));
  2235. }
  2236. #pragma mark - Helpers
  2237. /** @fn mockSecureTokenResponseWithError:
  2238. @brief Set up expectation for secureToken RPC.
  2239. @param error The error that the mock should return if any.
  2240. */
  2241. - (void)mockSecureTokenResponseWithError:(nullable NSError *)error {
  2242. // Set up expectation for secureToken RPC made by a successful attempt to refresh tokens.
  2243. XCTestExpectation *secureTokenResponseExpectation =
  2244. [self expectationWithDescription:@"secureTokenResponseExpectation"];
  2245. OCMExpect([_mockBackend secureToken:[OCMArg any] callback:[OCMArg any]])
  2246. .andCallBlock2(
  2247. ^(FIRSecureTokenRequest *_Nullable request, FIRSecureTokenResponseCallback callback) {
  2248. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2249. XCTAssertEqualObjects(request.refreshToken, kRefreshToken);
  2250. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2251. if (error) {
  2252. callback(nil, error);
  2253. [secureTokenResponseExpectation fulfill];
  2254. return;
  2255. }
  2256. id mockSecureTokenResponse = OCMClassMock([FIRSecureTokenResponse class]);
  2257. OCMStub([mockSecureTokenResponse accessToken]).andReturn(kNewAccessToken);
  2258. NSDate *futureDate =
  2259. [[NSDate date] dateByAddingTimeInterval:kTestTokenExpirationTimeInterval];
  2260. OCMStub([mockSecureTokenResponse approximateExpirationDate]).andReturn(futureDate);
  2261. callback(mockSecureTokenResponse, nil);
  2262. [secureTokenResponseExpectation fulfill];
  2263. });
  2264. });
  2265. }
  2266. /** @fn enableAutoTokenRefresh
  2267. @brief Enables automatic token refresh by invoking FIRAuth's implementation of FIRApp's
  2268. |getTokenWithImplementation|.
  2269. */
  2270. - (void)enableAutoTokenRefresh {
  2271. XCTestExpectation *expectation = [self expectationWithDescription:@"autoTokenRefreshcallback"];
  2272. [[FIRAuth auth] getTokenForcingRefresh:NO
  2273. withCallback:^(NSString *_Nullable token, NSError *_Nullable error) {
  2274. [expectation fulfill];
  2275. }];
  2276. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2277. }
  2278. /** @fn stubSecureTokensWithMockResponse
  2279. @brief Creates stubs on the mock response object with access and refresh tokens
  2280. @param mockResponse The mock response object.
  2281. */
  2282. - (void)stubTokensWithMockResponse:(id)mockResponse {
  2283. OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
  2284. OCMStub([mockResponse approximateExpirationDate])
  2285. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  2286. OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
  2287. }
  2288. /** @fn expectGetAccountInfo
  2289. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  2290. data.
  2291. */
  2292. - (void)expectGetAccountInfo {
  2293. [self expectGetAccountInfoWithAccessToken:kAccessToken];
  2294. }
  2295. /** @fn expectGetAccountInfoWithAccessToken
  2296. @param accessToken The access token for the user to check against.
  2297. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  2298. data.
  2299. */
  2300. - (void)expectGetAccountInfoWithAccessToken:(NSString *)accessToken {
  2301. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2302. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  2303. FIRGetAccountInfoResponseCallback callback) {
  2304. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2305. XCTAssertEqualObjects(request.accessToken, accessToken);
  2306. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2307. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  2308. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  2309. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  2310. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  2311. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  2312. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  2313. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  2314. mockGetAccountInfoResponseUser
  2315. ]);
  2316. callback(mockGetAccountInfoResponse, nil);
  2317. });
  2318. });
  2319. }
  2320. /** @fn assertUser
  2321. @brief Asserts the given FIRUser matching the fake data returned by @c expectGetAccountInfo.
  2322. @param user The user object to be verified.
  2323. */
  2324. - (void)assertUser:(FIRUser *)user {
  2325. XCTAssertNotNil(user);
  2326. XCTAssertEqualObjects(user.uid, kLocalID);
  2327. XCTAssertEqualObjects(user.displayName, kDisplayName);
  2328. XCTAssertEqualObjects(user.email, kEmail);
  2329. XCTAssertFalse(user.anonymous);
  2330. XCTAssertEqual(user.providerData.count, 0u);
  2331. }
  2332. /** @fn expectGetAccountInfoGoogle
  2333. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  2334. data for a Google Sign-In user.
  2335. */
  2336. - (void)expectGetAccountInfoGoogle {
  2337. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2338. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  2339. FIRGetAccountInfoResponseCallback callback) {
  2340. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2341. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  2342. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2343. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  2344. OCMStub([mockGoogleUserInfo providerID]).andReturn(FIRGoogleAuthProviderID);
  2345. OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
  2346. OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
  2347. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  2348. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  2349. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  2350. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
  2351. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  2352. .andReturn((@[ mockGoogleUserInfo ]));
  2353. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  2354. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  2355. mockGetAccountInfoResponseUser
  2356. ]);
  2357. callback(mockGetAccountInfoResponse, nil);
  2358. });
  2359. });
  2360. }
  2361. /** @fn assertUserGoogle
  2362. @brief Asserts the given FIRUser matching the fake data returned by
  2363. @c expectGetAccountInfoGoogle.
  2364. @param user The user object to be verified.
  2365. */
  2366. - (void)assertUserGoogle:(FIRUser *)user {
  2367. XCTAssertNotNil(user);
  2368. XCTAssertEqualObjects(user.uid, kLocalID);
  2369. XCTAssertEqualObjects(user.displayName, kDisplayName);
  2370. XCTAssertEqual(user.providerData.count, 1u);
  2371. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  2372. XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
  2373. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  2374. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  2375. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  2376. }
  2377. /** @fn expectGetAccountInfoAnonymous
  2378. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
  2379. account data.
  2380. */
  2381. - (void)expectGetAccountInfoAnonymous {
  2382. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  2383. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  2384. FIRGetAccountInfoResponseCallback callback) {
  2385. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  2386. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  2387. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2388. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  2389. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  2390. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  2391. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
  2392. mockGetAccountInfoResponseUser
  2393. ]);
  2394. callback(mockGetAccountInfoResponse, nil);
  2395. });
  2396. });
  2397. }
  2398. /** @fn assertUserAnonymous
  2399. @brief Asserts the given FIRUser matching the fake data returned by
  2400. @c expectGetAccountInfoAnonymous.
  2401. @param user The user object to be verified.
  2402. */
  2403. - (void)assertUserAnonymous:(FIRUser *)user {
  2404. XCTAssertNotNil(user);
  2405. XCTAssertEqualObjects(user.uid, kLocalID);
  2406. XCTAssertNil(user.displayName);
  2407. XCTAssertTrue(user.anonymous);
  2408. XCTAssertEqual(user.providerData.count, 0u);
  2409. }
  2410. /** @fn waitForSignIn
  2411. @brief Signs in a user to prepare for tests.
  2412. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  2413. */
  2414. - (void)waitForSignIn {
  2415. [self waitForSignInWithAccessToken:kAccessToken APIKey:nil completion:nil];
  2416. }
  2417. /** @fn waitForSignInWithAccessToken:
  2418. @brief Signs in a user to prepare for tests.
  2419. @param accessToken The access token for the user to have.
  2420. @param APIKey Optionally, The API key associated with the user.
  2421. @param completion Optionally, The completion invoked at the end of the flow.
  2422. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  2423. */
  2424. - (void)waitForSignInWithAccessToken:(NSString *)accessToken
  2425. APIKey:(nullable NSString *)APIKey
  2426. completion:(nullable FIRAuthResultCallback)completion {
  2427. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  2428. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  2429. FIRVerifyPasswordResponseCallback callback) {
  2430. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  2431. id mockVerifyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  2432. OCMStub([mockVerifyPasswordResponse IDToken]).andReturn(accessToken);
  2433. OCMStub([mockVerifyPasswordResponse approximateExpirationDate])
  2434. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  2435. OCMStub([mockVerifyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  2436. callback(mockVerifyPasswordResponse, nil);
  2437. });
  2438. });
  2439. [self expectGetAccountInfoWithAccessToken:accessToken];
  2440. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  2441. [[FIRAuth auth] signInWithEmail:kEmail
  2442. password:kFakePassword
  2443. completion:^(FIRAuthDataResult *_Nullable result, NSError *_Nullable error) {
  2444. result.user.requestConfiguration =
  2445. [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey
  2446. appID:kFirebaseAppID];
  2447. [expectation fulfill];
  2448. if (completion) {
  2449. completion(result.user, error);
  2450. }
  2451. }];
  2452. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  2453. OCMVerifyAll(_mockBackend);
  2454. XCTAssertNotNil([FIRAuth auth].currentUser);
  2455. }
  2456. /** @fn waitForTimeInterval:
  2457. @brief Wait for a particular time interval.
  2458. @remarks This method also waits for all other pending @c XCTestExpectation instances.
  2459. */
  2460. - (void)waitForTimeIntervel:(NSTimeInterval)timeInterval {
  2461. static dispatch_queue_t queue;
  2462. static dispatch_once_t onceToken;
  2463. XCTestExpectation *expectation = [self expectationWithDescription:@"waitForTimeIntervel:"];
  2464. dispatch_once(&onceToken, ^{
  2465. queue = dispatch_queue_create("com.google.FIRAuthUnitTests.waitForTimeIntervel", NULL);
  2466. });
  2467. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeInterval * NSEC_PER_SEC), queue, ^() {
  2468. [expectation fulfill];
  2469. });
  2470. [self waitForExpectationsWithTimeout:timeInterval + kExpectationTimeout handler:nil];
  2471. }
  2472. - (void)waitForAuthGlobalWorkQueueDrain {
  2473. dispatch_semaphore_t workerSemaphore = dispatch_semaphore_create(0);
  2474. dispatch_async(FIRAuthGlobalWorkQueue(), ^{
  2475. dispatch_semaphore_signal(workerSemaphore);
  2476. });
  2477. dispatch_semaphore_wait(workerSemaphore,
  2478. DISPATCH_TIME_FOREVER /*DISPATCH_TIME_NOW + 10 * NSEC_PER_SEC*/);
  2479. }
  2480. @end