FIRAuthTests.m 129 KB

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