FIRUserTests.m 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <Foundation/Foundation.h>
  17. #import <XCTest/XCTest.h>
  18. #import "FirebaseCommunity/FIRUser.h"
  19. #import "FirebaseCommunity/FIREmailAuthProvider.h"
  20. #import "FirebaseCommunity/FIRFacebookAuthProvider.h"
  21. #import "FirebaseCommunity/FIRGoogleAuthProvider.h"
  22. #import "FirebaseCommunity/FIRAdditionalUserInfo.h"
  23. #import "FirebaseCommunity/FIRAuth.h"
  24. #import "FIRAuthErrorUtils.h"
  25. #import "FIRAuthGlobalWorkQueue.h"
  26. #import "FIRUser_Internal.h"
  27. #import "FIRUserInfo.h"
  28. #import "FIRAuthBackend.h"
  29. #import "FIRGetAccountInfoRequest.h"
  30. #import "FIRGetAccountInfoResponse.h"
  31. #import "FIRSetAccountInfoRequest.h"
  32. #import "FIRSetAccountInfoResponse.h"
  33. #import "FIRVerifyAssertionResponse.h"
  34. #import "FIRVerifyAssertionRequest.h"
  35. #import "FIRVerifyPasswordRequest.h"
  36. #import "FIRVerifyPasswordResponse.h"
  37. #import "FIRVerifyPhoneNumberRequest.h"
  38. #import "FIRVerifyPhoneNumberResponse.h"
  39. #import "FIRApp+FIRAuthUnitTests.h"
  40. #import "OCMStubRecorder+FIRAuthUnitTests.h"
  41. #import <OCMock/OCMock.h>
  42. #if TARGET_OS_IOS
  43. #import "Phone/FIRPhoneAuthCredential_Internal.h"
  44. #import "FIRPhoneAuthProvider.h"
  45. #endif
  46. NS_ASSUME_NONNULL_BEGIN
  47. /** @var kAPIKey
  48. @brief The fake API key.
  49. */
  50. static NSString *const kAPIKey = @"FAKE_API_KEY";
  51. /** @var kAccessToken
  52. @brief The fake access token.
  53. */
  54. static NSString *const kAccessToken = @"ACCESS_TOKEN";
  55. /** @var kNewAccessToken
  56. @brief A new value for the fake access token.
  57. */
  58. static NSString *const kNewAccessToken = @"NEW_ACCESS_TOKEN";
  59. /** @var kAccessTokenValidInterval
  60. @brief The time to live for the fake access token.
  61. */
  62. static const NSTimeInterval kAccessTokenTimeToLive = 60 * 60;
  63. /** @var kRefreshToken
  64. @brief The fake refresh token.
  65. */
  66. static NSString *const kRefreshToken = @"REFRESH_TOKEN";
  67. /** @var kLocalID
  68. @brief The fake local user ID.
  69. */
  70. static NSString *const kLocalID = @"LOCAL_ID";
  71. /** @var kAnotherLocalID
  72. @brief The fake local ID of another user.
  73. */
  74. static NSString *const kAnotherLocalID = @"ANOTHER_LOCAL_ID";
  75. /** @var kGoogleIDToken
  76. @brief The fake ID token from Google Sign-In.
  77. */
  78. static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
  79. /** @var kFacebookIDToken
  80. @brief The fake ID token from Facebook Sign-In. Facebook provider ID token is always nil.
  81. */
  82. static NSString *const kFacebookIDToken = nil;
  83. /** @var kGoogleAccessToken
  84. @brief The fake access token from Google Sign-In.
  85. */
  86. static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
  87. /** @var kFacebookAccessToken
  88. @brief The fake access token from Facebook Sign-In.
  89. */
  90. static NSString *const kFacebookAccessToken = @"FACEBOOK_ACCESS_TOKEN";
  91. /** @var kEmail
  92. @brief The fake user email.
  93. */
  94. static NSString *const kEmail = @"user@company.com";
  95. /** @var kPhoneNumber
  96. @brief The fake user phone number.
  97. */
  98. static NSString *const kPhoneNumber = @"12345658";
  99. /** @var kTemporaryProof
  100. @brief The fake temporary proof.
  101. */
  102. static NSString *const kTemporaryProof = @"12345658";
  103. /** @var kNewEmail
  104. @brief A new value for the fake user email.
  105. */
  106. static NSString *const kNewEmail = @"newuser@company.com";
  107. /** @var kUserName
  108. @brief The fake user name.
  109. */
  110. static NSString *const kUserName = @"User Doe";
  111. /** @var kNewDisplayName
  112. @brief A new value for the fake user display name.
  113. */
  114. static NSString *const kNewDisplayName = @"New User Doe";
  115. /** @var kPhotoURL
  116. @brief The fake user profile image URL string.
  117. */
  118. static NSString *const kPhotoURL = @"https://host.domain/image";
  119. /** @var kNewPhotoURL
  120. @brief A new value for the fake user profile image URL string..
  121. */
  122. static NSString *const kNewPhotoURL = @"https://host.domain/new/image";
  123. /** @var kFakePassword
  124. @brief The fake user password.
  125. */
  126. static NSString *const kFakePassword = @"123456";
  127. /** @var kNewPassword
  128. @brief The fake new user password.
  129. */
  130. static NSString *const kNewPassword = @"1234567";
  131. /** @var kPasswordHash
  132. @brief The fake user password hash.
  133. */
  134. static NSString *const kPasswordHash = @"UkVEQUNURUQ=";
  135. /** @var kGoogleUD
  136. @brief The fake user ID under Google Sign-In.
  137. */
  138. static NSString *const kGoogleID = @"GOOGLE_ID";
  139. /** @var kGoogleEmail
  140. @brief The fake user email under Google Sign-In.
  141. */
  142. static NSString *const kGoogleEmail = @"user@gmail.com";
  143. /** @var kGoogleDisplayName
  144. @brief The fake user display name under Google Sign-In.
  145. */
  146. static NSString *const kGoogleDisplayName = @"Google Doe";
  147. /** @var kEmailDisplayName
  148. @brief The fake user display name for email password user.
  149. */
  150. static NSString *const kEmailDisplayName = @"Email Doe";
  151. /** @var kFacebookDisplayName
  152. @brief The fake user display name under Facebook Sign-In.
  153. */
  154. static NSString *const kFacebookDisplayName = @"Facebook Doe";
  155. /** @var kGooglePhotoURL
  156. @brief The fake user profile image URL string under Google Sign-In.
  157. */
  158. static NSString *const kGooglePhotoURL = @"https://googleusercontents.com/user/profile";
  159. /** @var kFacebookID
  160. @brief The fake user ID under Facebook Login.
  161. */
  162. static NSString *const kFacebookID = @"FACEBOOK_ID";
  163. /** @var kFacebookEmail
  164. @brief The fake user email under Facebook Login.
  165. */
  166. static NSString *const kFacebookEmail = @"user@facebook.com";
  167. /** @var kVerificationCode
  168. @brief Fake verification code used for testing.
  169. */
  170. static NSString *const kVerificationCode = @"12345678";
  171. /** @var kVerificationID
  172. @brief Fake verification ID for testing.
  173. */
  174. static NSString *const kVerificationID = @"55432";
  175. /** @var kUserArchiverKey
  176. @brief The key used to archive and unarchive the user object for test NSSecureCoding.
  177. */
  178. static NSString *const kUserArchiverKey = @"userArchiverKey";
  179. /** @var kExpectationTimeout
  180. @brief The maximum time waiting for expectations to fulfill.
  181. */
  182. static const NSTimeInterval kExpectationTimeout = 1;
  183. /** @class FIRUserTests
  184. @brief Tests for @c FIRUser .
  185. */
  186. @interface FIRUserTests : XCTestCase
  187. @end
  188. @implementation FIRUserTests {
  189. /** @var _mockBackend
  190. @brief The mock @c FIRAuthBackendImplementation .
  191. */
  192. id _mockBackend;
  193. }
  194. /** @fn googleProfile
  195. @brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
  196. */
  197. + (NSDictionary *)googleProfile {
  198. static NSDictionary *kGoogleProfile = nil;
  199. static dispatch_once_t onceToken;
  200. dispatch_once(&onceToken, ^{
  201. kGoogleProfile = @{
  202. @"email": kGoogleEmail,
  203. @"given_name": @"User",
  204. @"family_name": @"Doe"
  205. };
  206. });
  207. return kGoogleProfile;
  208. }
  209. - (void)setUp {
  210. [super setUp];
  211. _mockBackend = OCMProtocolMock(@protocol(FIRAuthBackendImplementation));
  212. [FIRAuthBackend setBackendImplementation:_mockBackend];
  213. [FIRApp resetAppForAuthUnitTests];
  214. }
  215. - (void)tearDown {
  216. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
  217. [super tearDown];
  218. }
  219. #pragma mark - Tests
  220. /** @fn testUserPropertiesAndNSSecureCoding
  221. @brief Tests properties of the @c FIRUser instance before and after being
  222. serialized/deserialized.
  223. */
  224. - (void)testUserPropertiesAndNSSecureCoding {
  225. // Mock auth provider user info for email/password for GetAccountInfo.
  226. id mockPasswordUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  227. OCMStub([mockPasswordUserInfo providerID]).andReturn(FIREmailAuthProviderID);
  228. OCMStub([mockPasswordUserInfo federatedID]).andReturn(kEmail);
  229. OCMStub([mockPasswordUserInfo email]).andReturn(kEmail);
  230. // Mock auth provider user info from Google for GetAccountInfo.
  231. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  232. OCMStub([mockGoogleUserInfo providerID]).andReturn(FIRGoogleAuthProviderID);
  233. OCMStub([mockGoogleUserInfo displayName]).andReturn(kGoogleDisplayName);
  234. OCMStub([mockGoogleUserInfo photoURL]).andReturn([NSURL URLWithString:kGooglePhotoURL]);
  235. OCMStub([mockGoogleUserInfo federatedID]).andReturn(kGoogleID);
  236. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  237. // Mock auth provider user info from Facebook for GetAccountInfo.
  238. id mockFacebookUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  239. OCMStub([mockFacebookUserInfo providerID]).andReturn(FIRFacebookAuthProviderID);
  240. OCMStub([mockFacebookUserInfo federatedID]).andReturn(kFacebookID);
  241. OCMStub([mockFacebookUserInfo email]).andReturn(kFacebookEmail);
  242. #if TARGET_OS_IOS
  243. // Mock auth provider user info from Phone auth provider for GetAccountInfo.
  244. id mockPhoneUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  245. OCMStub([mockPhoneUserInfo providerID]).andReturn(FIRPhoneAuthProviderID);
  246. OCMStub([mockPhoneUserInfo phoneNumber]).andReturn(kPhoneNumber);
  247. #endif
  248. // Mock the root user info object for GetAccountInfo.
  249. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  250. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  251. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  252. OCMStub([mockGetAccountInfoResponseUser emailVerified]).andReturn(YES);
  253. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  254. OCMStub([mockGetAccountInfoResponseUser photoURL]).andReturn([NSURL URLWithString:kPhotoURL]);
  255. NSArray *providerUserInfos = @[
  256. #if TARGET_OS_IOS
  257. mockPhoneUserInfo,
  258. #endif
  259. mockPasswordUserInfo,
  260. mockGoogleUserInfo,
  261. mockFacebookUserInfo
  262. ];
  263. OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(providerUserInfos);
  264. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  265. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  266. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  267. completion:^(FIRUser *user) {
  268. // Verify FIRUserInfo properties on FIRUser itself.
  269. XCTAssertEqualObjects(user.providerID, @"Firebase");
  270. XCTAssertEqualObjects(user.uid, kLocalID);
  271. XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
  272. XCTAssertEqualObjects(user.photoURL, [NSURL URLWithString:kPhotoURL]);
  273. XCTAssertEqualObjects(user.email, kEmail);
  274. // Verify FIRUser properties besides providerData contents.
  275. XCTAssertFalse(user.anonymous);
  276. XCTAssertTrue(user.emailVerified);
  277. XCTAssertEqualObjects(user.refreshToken, kRefreshToken);
  278. XCTAssertEqual(user.providerData.count, providerUserInfos.count);
  279. NSDictionary<NSString *, id<FIRUserInfo>> *providerMap =
  280. [self dictionaryWithUserInfoArray:user.providerData];
  281. // Verify FIRUserInfo properties from email/password.
  282. id<FIRUserInfo> passwordUserInfo = providerMap[FIREmailAuthProviderID];
  283. XCTAssertEqualObjects(passwordUserInfo.uid, kEmail);
  284. XCTAssertNil(passwordUserInfo.displayName);
  285. XCTAssertNil(passwordUserInfo.photoURL);
  286. XCTAssertEqualObjects(passwordUserInfo.email, kEmail);
  287. // Verify FIRUserInfo properties from the Google auth provider.
  288. id<FIRUserInfo> googleUserInfo = providerMap[FIRGoogleAuthProviderID];
  289. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  290. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  291. XCTAssertEqualObjects(googleUserInfo.photoURL, [NSURL URLWithString:kGooglePhotoURL]);
  292. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  293. // Verify FIRUserInfo properties from the Facebook auth provider.
  294. id<FIRUserInfo> facebookUserInfo = providerMap[FIRFacebookAuthProviderID];
  295. XCTAssertEqualObjects(facebookUserInfo.uid, kFacebookID);
  296. XCTAssertNil(facebookUserInfo.displayName);
  297. XCTAssertNil(facebookUserInfo.photoURL);
  298. XCTAssertEqualObjects(facebookUserInfo.email, kFacebookEmail);
  299. #if TARGET_OS_IOS
  300. // Verify FIRUserInfo properties from the phone auth provider.
  301. id<FIRUserInfo> phoneUserInfo = providerMap[FIRPhoneAuthProviderID];
  302. XCTAssertEqualObjects(phoneUserInfo.phoneNumber, kPhoneNumber);
  303. #endif
  304. // Test NSSecureCoding
  305. XCTAssertTrue([FIRUser supportsSecureCoding]);
  306. NSMutableData *data = [NSMutableData data];
  307. NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
  308. [archiver encodeObject:user forKey:kUserArchiverKey];
  309. [archiver finishEncoding];
  310. NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
  311. FIRUser *unarchivedUser = [unarchiver decodeObjectForKey:kUserArchiverKey];
  312. // Verify NSSecureCoding for FIRUser
  313. XCTAssertEqualObjects(unarchivedUser.providerID, user.providerID);
  314. XCTAssertEqualObjects(unarchivedUser.uid, user.uid);
  315. XCTAssertEqualObjects(unarchivedUser.email, user.email);
  316. XCTAssertEqualObjects(unarchivedUser.photoURL, user.photoURL);
  317. XCTAssertEqualObjects(unarchivedUser.displayName, user.displayName);
  318. // Verify NSSecureCoding properties besides providerData contents.
  319. XCTAssertEqual(unarchivedUser.anonymous, user.anonymous);
  320. XCTAssertEqual(unarchivedUser.emailVerified, user.emailVerified);
  321. XCTAssertEqualObjects(unarchivedUser.refreshToken, user.refreshToken);
  322. XCTAssertEqual(unarchivedUser.providerData.count, user.providerData.count);
  323. NSDictionary<NSString *, id<FIRUserInfo>> *unarchivedProviderMap =
  324. [self dictionaryWithUserInfoArray:unarchivedUser.providerData];
  325. // Verify NSSecureCoding properties from email/password.
  326. id<FIRUserInfo> unarchivedPasswordUserInfo = unarchivedProviderMap[FIREmailAuthProviderID];
  327. XCTAssertEqualObjects(unarchivedPasswordUserInfo.uid, passwordUserInfo.uid);
  328. XCTAssertEqualObjects(unarchivedPasswordUserInfo.displayName, passwordUserInfo.displayName);
  329. XCTAssertEqualObjects(unarchivedPasswordUserInfo.photoURL, passwordUserInfo.photoURL);
  330. XCTAssertEqualObjects(unarchivedPasswordUserInfo.email, passwordUserInfo.email);
  331. // Verify NSSecureCoding properties from the Google auth provider.
  332. id<FIRUserInfo> unarchivedGoogleUserInfo = unarchivedProviderMap[FIRGoogleAuthProviderID];
  333. XCTAssertEqualObjects(unarchivedGoogleUserInfo.uid, googleUserInfo.uid);
  334. XCTAssertEqualObjects(unarchivedGoogleUserInfo.displayName, googleUserInfo.displayName);
  335. XCTAssertEqualObjects(unarchivedGoogleUserInfo.photoURL, googleUserInfo.photoURL);
  336. XCTAssertEqualObjects(unarchivedGoogleUserInfo.email, googleUserInfo.email);
  337. // Verify NSSecureCoding properties from the Facebook auth provider.
  338. id<FIRUserInfo> unarchivedFacebookUserInfo = unarchivedProviderMap[FIRFacebookAuthProviderID];
  339. XCTAssertEqualObjects(unarchivedFacebookUserInfo.uid, facebookUserInfo.uid);
  340. XCTAssertEqualObjects(unarchivedFacebookUserInfo.displayName, facebookUserInfo.displayName);
  341. XCTAssertEqualObjects(unarchivedFacebookUserInfo.photoURL, facebookUserInfo.photoURL);
  342. XCTAssertEqualObjects(unarchivedFacebookUserInfo.email, facebookUserInfo.email);
  343. #if TARGET_OS_IOS
  344. // Verify FIRUserInfo properties from the phone auth provider.
  345. id<FIRUserInfo> unarchivedPhoneUserInfo = unarchivedProviderMap[FIRPhoneAuthProviderID];
  346. XCTAssertEqualObjects(unarchivedPhoneUserInfo.phoneNumber, phoneUserInfo.phoneNumber);
  347. #endif
  348. [expectation fulfill];
  349. }];
  350. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  351. OCMVerifyAll(_mockBackend);
  352. }
  353. /** @fn testUpdateEmailSuccess
  354. @brief Tests the flow of a successful @c updateEmail:completion: call.
  355. */
  356. - (void)testUpdateEmailSuccess {
  357. id (^mockUserInfoWithDisplayName)(NSString *) = ^(NSString *displayName) {
  358. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  359. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  360. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  361. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
  362. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  363. return mockGetAccountInfoResponseUser;
  364. };
  365. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  366. id userInfoResponse = mockUserInfoWithDisplayName(kGoogleDisplayName);
  367. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  368. completion:^(FIRUser *user) {
  369. // Pretend that the display name on the server has been changed since last request.
  370. [self
  371. expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoWithDisplayName(kNewDisplayName)];
  372. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  373. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  374. FIRSetAccountInfoResponseCallback callback) {
  375. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  376. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  377. XCTAssertEqualObjects(request.email, kNewEmail);
  378. XCTAssertNil(request.localID);
  379. XCTAssertNil(request.displayName);
  380. XCTAssertNil(request.photoURL);
  381. XCTAssertNil(request.password);
  382. XCTAssertNil(request.providers);
  383. XCTAssertNil(request.deleteAttributes);
  384. XCTAssertNil(request.deleteProviders);
  385. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  386. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  387. OCMStub([mockSetAccountInfoResponse email]).andReturn(kNewEmail);
  388. OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
  389. callback(mockSetAccountInfoResponse, nil);
  390. });
  391. });
  392. [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
  393. XCTAssertNil(error);
  394. XCTAssertEqualObjects(user.email, kNewEmail);
  395. XCTAssertEqualObjects(user.displayName, kNewDisplayName);
  396. [expectation fulfill];
  397. }];
  398. }];
  399. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  400. OCMVerifyAll(_mockBackend);
  401. }
  402. /** @fn testUpdateEmailFailure
  403. @brief Tests the flow of a failed @c updateEmail:completion: call.
  404. */
  405. - (void)testUpdateEmailFailure {
  406. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  407. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  408. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  409. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  410. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  411. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  412. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  413. completion:^(FIRUser *user) {
  414. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  415. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  416. .andDispatchError2([FIRAuthErrorUtils invalidEmailErrorWithMessage:nil]);
  417. [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) {
  418. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidEmail);
  419. // Email should not have changed on the client side.
  420. XCTAssertEqualObjects(user.email, kEmail);
  421. [expectation fulfill];
  422. }];
  423. }];
  424. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  425. OCMVerifyAll(_mockBackend);
  426. }
  427. #if TARGET_OS_IOS
  428. /** @fn testUpdatePhoneSuccess
  429. @brief Tests the flow of a successful @c updatePhoneNumberCredential:completion: call.
  430. */
  431. - (void)testUpdatePhoneSuccess {
  432. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  433. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  434. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  435. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  436. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  437. if (phoneNumber.length) {
  438. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  439. }
  440. return mockGetAccountInfoResponseUser;
  441. };
  442. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  443. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  444. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  445. completion:^(FIRUser *user) {
  446. [self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber error:nil];
  447. id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
  448. [self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
  449. FIRPhoneAuthCredential *credential =
  450. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  451. verificationCode:kVerificationCode];
  452. [user updatePhoneNumberCredential:credential
  453. completion:^(NSError * _Nullable error) {
  454. XCTAssertNil(error);
  455. XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
  456. [expectation fulfill];
  457. }];
  458. }];
  459. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  460. OCMVerifyAll(_mockBackend);
  461. }
  462. /** @fn testUpdatePhoneNumberFailure
  463. @brief Tests the flow of a failed @c updatePhoneNumberCredential:completion: call.
  464. */
  465. - (void)testUpdatePhoneNumberFailure {
  466. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  467. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  468. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  469. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  470. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  471. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  472. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  473. completion:^(FIRUser *user) {
  474. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  475. .andDispatchError2([FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:nil]);
  476. FIRPhoneAuthCredential *credential =
  477. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  478. verificationCode:kVerificationCode];
  479. [user updatePhoneNumberCredential:credential completion:^(NSError *_Nullable error) {
  480. XCTAssertEqual(error.code, FIRAuthErrorCodeInvalidPhoneNumber);
  481. [expectation fulfill];
  482. }];
  483. }];
  484. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  485. OCMVerifyAll(_mockBackend);
  486. }
  487. #endif
  488. /** @fn testUpdatePasswordSuccess
  489. @brief Tests the flow of a successful @c updatePassword:completion: call.
  490. */
  491. - (void)testUpdatePasswordSuccess {
  492. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  493. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  494. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  495. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  496. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  497. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  498. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  499. completion:^(FIRUser *user) {
  500. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  501. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  502. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  503. FIRSetAccountInfoResponseCallback callback) {
  504. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  505. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  506. XCTAssertEqualObjects(request.password, kNewPassword);
  507. XCTAssertNil(request.localID);
  508. XCTAssertNil(request.displayName);
  509. XCTAssertNil(request.photoURL);
  510. XCTAssertNil(request.email);
  511. XCTAssertNil(request.providers);
  512. XCTAssertNil(request.deleteAttributes);
  513. XCTAssertNil(request.deleteProviders);
  514. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  515. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  516. OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
  517. callback(mockSetAccountInfoResponse, nil);
  518. });
  519. });
  520. [user updatePassword:kNewPassword completion:^(NSError *_Nullable error) {
  521. XCTAssertNil(error);
  522. XCTAssertFalse(user.isAnonymous);
  523. [expectation fulfill];
  524. }];
  525. }];
  526. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  527. OCMVerifyAll(_mockBackend);
  528. }
  529. /** @fn testUpdatePasswordFailure
  530. @brief Tests the flow of a failed @c updatePassword:completion: call.
  531. */
  532. - (void)testUpdatePasswordFailure {
  533. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  534. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  535. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  536. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  537. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  538. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  539. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  540. completion:^(FIRUser *user) {
  541. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  542. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  543. .andDispatchError2([FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  544. [user updatePassword:kNewPassword completion:^(NSError *_Nullable error) {
  545. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  546. [expectation fulfill];
  547. }];
  548. }];
  549. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  550. OCMVerifyAll(_mockBackend);
  551. }
  552. /** @fn testUpdateEmptyPasswordFailure
  553. @brief Tests the flow of a failed @c updatePassword:completion: call due to an empty password.
  554. */
  555. - (void)testUpdateEmptyPasswordFailure {
  556. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  557. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  558. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  559. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  560. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  561. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  562. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  563. completion:^(FIRUser *user) {
  564. [user updatePassword:@"" completion:^(NSError *_Nullable error) {
  565. XCTAssertEqual(error.code, FIRAuthErrorCodeWeakPassword);
  566. [expectation fulfill];
  567. }];
  568. }];
  569. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  570. }
  571. /** @fn testChangeProfileSuccess
  572. @brief Tests a successful user profile change flow.
  573. */
  574. - (void)testChangeProfileSuccess {
  575. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  576. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  577. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  578. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  579. OCMStub([mockGetAccountInfoResponseUser photoURL]).andReturn(kPhotoURL);
  580. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  581. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  582. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  583. completion:^(FIRUser *user) {
  584. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  585. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  586. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  587. FIRSetAccountInfoResponseCallback callback) {
  588. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  589. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  590. XCTAssertEqualObjects(request.displayName, kNewDisplayName);
  591. XCTAssertEqualObjects(request.photoURL, [NSURL URLWithString:kNewPhotoURL]);
  592. XCTAssertNil(request.localID);
  593. XCTAssertNil(request.email);
  594. XCTAssertNil(request.password);
  595. XCTAssertNil(request.providers);
  596. XCTAssertNil(request.deleteAttributes);
  597. XCTAssertNil(request.deleteProviders);
  598. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  599. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  600. OCMStub([mockSetAccountInfoResponse displayName]).andReturn(kNewDisplayName);
  601. callback(mockSetAccountInfoResponse, nil);
  602. });
  603. });
  604. FIRUserProfileChangeRequest *profileChange = [user profileChangeRequest];
  605. profileChange.photoURL = [NSURL URLWithString:kNewPhotoURL];
  606. profileChange.displayName = kNewDisplayName;
  607. [profileChange commitChangesWithCompletion:^(NSError *_Nullable error) {
  608. XCTAssertNil(error);
  609. XCTAssertEqualObjects(user.displayName, kNewDisplayName);
  610. XCTAssertEqualObjects(user.photoURL, [NSURL URLWithString:kNewPhotoURL]);
  611. [expectation fulfill];
  612. }];
  613. }];
  614. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  615. OCMVerifyAll(_mockBackend);
  616. }
  617. /** @fn testChangeProfileFailure
  618. @brief Tests a failed user profile change flow.
  619. */
  620. - (void)testChangeProfileFailure {
  621. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  622. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  623. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  624. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  625. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  626. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  627. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  628. completion:^(FIRUser *user) {
  629. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  630. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  631. .andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
  632. FIRUserProfileChangeRequest *profileChange = [user profileChangeRequest];
  633. profileChange.displayName = kNewDisplayName;
  634. [profileChange commitChangesWithCompletion:^(NSError *_Nullable error) {
  635. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  636. XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
  637. [expectation fulfill];
  638. }];
  639. }];
  640. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  641. OCMVerifyAll(_mockBackend);
  642. }
  643. /** @fn testReloadSuccess
  644. @brief Tests the flow of a successful @c reloadWithCompletion: call.
  645. */
  646. - (void)testReloadSuccess {
  647. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  648. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  649. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  650. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  651. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  652. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  653. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  654. completion:^(FIRUser *user) {
  655. id mockGetAccountInfoResponseUserNew = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  656. OCMStub([mockGetAccountInfoResponseUserNew localID]).andReturn(kLocalID);
  657. OCMStub([mockGetAccountInfoResponseUserNew email]).andReturn(kNewEmail);
  658. OCMStub([mockGetAccountInfoResponseUserNew displayName]).andReturn(kNewDisplayName);
  659. OCMStub([mockGetAccountInfoResponseUserNew passwordHash]).andReturn(kPasswordHash);
  660. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUserNew];
  661. [user reloadWithCompletion:^(NSError *_Nullable error) {
  662. XCTAssertNil(error);
  663. XCTAssertEqualObjects(user.email, kNewEmail);
  664. XCTAssertEqualObjects(user.displayName, kNewDisplayName);
  665. [expectation fulfill];
  666. }];
  667. }];
  668. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  669. OCMVerifyAll(_mockBackend);
  670. }
  671. /** @fn testReloadFailure
  672. @brief Tests the flow of a failed @c reloadWithCompletion: call.
  673. */
  674. - (void)testReloadFailure {
  675. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  676. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  677. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  678. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  679. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  680. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  681. completion:^(FIRUser *user) {
  682. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  683. .andDispatchError2([FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]);
  684. [user reloadWithCompletion:^(NSError *_Nullable error) {
  685. XCTAssertEqual(error.code, FIRAuthErrorCodeUserTokenExpired);
  686. [expectation fulfill];
  687. }];
  688. }];
  689. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  690. OCMVerifyAll(_mockBackend);
  691. }
  692. /** @fn testReauthenticateSuccess
  693. @brief Tests the flow of a successful @c reauthenticateWithCredential:completion: call.
  694. */
  695. - (void)testReauthenticateSuccess {
  696. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  697. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  698. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  699. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  700. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  701. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  702. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  703. completion:^(FIRUser *user) {
  704. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  705. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  706. FIRVerifyPasswordResponseCallback callback) {
  707. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  708. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  709. // New authentication comes back with new access token.
  710. OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kNewAccessToken);
  711. OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
  712. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  713. OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  714. callback(mockVeriyPasswordResponse, nil);
  715. });
  716. });
  717. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  718. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  719. FIRGetAccountInfoResponseCallback callback) {
  720. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  721. // Verify that the new access token is being used for subsequent requests.
  722. XCTAssertEqualObjects(request.accessToken, kNewAccessToken);
  723. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  724. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  725. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  726. callback(mockGetAccountInfoResponse, nil);
  727. });
  728. });
  729. FIRAuthCredential *emailCredential =
  730. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  731. [user reauthenticateWithCredential:emailCredential completion:^(NSError *_Nullable error) {
  732. XCTAssertNil(error);
  733. // Verify that the current user is unchanged.
  734. XCTAssertEqual([FIRAuth auth].currentUser, user);
  735. [expectation fulfill];
  736. }];
  737. }];
  738. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  739. OCMVerifyAll(_mockBackend);
  740. }
  741. /** @fn testReauthenticateAndRetrieveDataSuccess
  742. @brief Tests the flow of a successful @c reauthenticateAndRetrieveDataWithCredential:completion:
  743. call.
  744. */
  745. - (void)testReauthenticateAndRetrieveDataSuccess {
  746. [self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
  747. federatedID:kGoogleID
  748. displayName:kGoogleDisplayName
  749. profile:[[self class] googleProfile]
  750. providerIDToken:kGoogleIDToken
  751. providerAccessToken:kGoogleAccessToken];
  752. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  753. [[FIRAuth auth] signOut:NULL];
  754. FIRAuthCredential *googleCredential =
  755. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  756. [[FIRAuth auth] signInAndRetrieveDataWithCredential:googleCredential
  757. completion:^(FIRAuthDataResult *_Nullable authResult,
  758. NSError *_Nullable error) {
  759. XCTAssertTrue([NSThread isMainThread]);
  760. [self assertUserGoogle:authResult.user];
  761. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  762. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  763. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRGoogleAuthProviderID);
  764. XCTAssertNil(error);
  765. [self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
  766. federatedID:kGoogleID
  767. displayName:kGoogleDisplayName
  768. profile:[[self class] googleProfile]
  769. providerIDToken:kGoogleIDToken
  770. providerAccessToken:kGoogleAccessToken];
  771. FIRAuthCredential *reauthenticateGoogleCredential =
  772. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  773. [authResult.user
  774. reauthenticateAndRetrieveDataWithCredential:reauthenticateGoogleCredential
  775. completion:^(FIRAuthDataResult *_Nullable
  776. reauthenticateAuthResult,
  777. NSError *_Nullable error) {
  778. XCTAssertNil(error);
  779. // Verify that the current user is unchanged.
  780. XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
  781. // Verify that the current user and reauthenticated user are not same pointers.
  782. XCTAssertNotEqualObjects(authResult.user, reauthenticateAuthResult.user);
  783. // Verify that anyway the current user and reauthenticated user have same IDs.
  784. XCTAssertEqualObjects(authResult.user.uid, reauthenticateAuthResult.user.uid);
  785. XCTAssertEqualObjects(authResult.user.displayName, reauthenticateAuthResult.user.displayName);
  786. XCTAssertEqualObjects(reauthenticateAuthResult.additionalUserInfo.profile,
  787. [[self class] googleProfile]);
  788. XCTAssertEqualObjects(reauthenticateAuthResult.additionalUserInfo.username, kUserName);
  789. XCTAssertEqualObjects(reauthenticateAuthResult.additionalUserInfo.providerID,
  790. FIRGoogleAuthProviderID);
  791. [expectation fulfill];
  792. }];
  793. }];
  794. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  795. [self assertUserGoogle:[FIRAuth auth].currentUser];
  796. OCMVerifyAll(_mockBackend);
  797. }
  798. /** @fn testReauthenticateFailure
  799. @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call.
  800. */
  801. - (void)testReauthenticateFailure {
  802. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  803. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  804. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  805. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  806. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  807. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  808. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  809. completion:^(FIRUser *user) {
  810. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  811. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  812. FIRVerifyPasswordResponseCallback callback) {
  813. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  814. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  815. OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kNewAccessToken);
  816. OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
  817. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  818. OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  819. callback(mockVeriyPasswordResponse, nil);
  820. });
  821. });
  822. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  823. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  824. FIRGetAccountInfoResponseCallback callback) {
  825. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  826. id mockGetAccountInfoResponseUserNew = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  827. // The newly-signed-in user has a different ID.
  828. OCMStub([mockGetAccountInfoResponseUserNew localID]).andReturn(kAnotherLocalID);
  829. OCMStub([mockGetAccountInfoResponseUserNew email]).andReturn(kNewEmail);
  830. OCMStub([mockGetAccountInfoResponseUserNew displayName]).andReturn(kNewDisplayName);
  831. OCMStub([mockGetAccountInfoResponseUserNew passwordHash]).andReturn(kPasswordHash);
  832. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  833. OCMStub([mockGetAccountInfoResponse users])
  834. .andReturn(@[ mockGetAccountInfoResponseUserNew ]);
  835. callback(mockGetAccountInfoResponse, nil);
  836. });
  837. });
  838. FIRAuthCredential *emailCredential =
  839. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  840. [user reauthenticateWithCredential:emailCredential completion:^(NSError *_Nullable error) {
  841. // Verify user mismatch error.
  842. XCTAssertEqual(error.code, FIRAuthErrorCodeUserMismatch);
  843. // Verify that the current user is unchanged.
  844. XCTAssertEqual([FIRAuth auth].currentUser, user);
  845. [expectation fulfill];
  846. }];
  847. }];
  848. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  849. OCMVerifyAll(_mockBackend);
  850. }
  851. /** @fn testReauthenticateUserMismatchFailure
  852. @brief Tests the flow of a failed @c reauthenticateWithCredential:completion: call due to trying
  853. to reauthenticate a user that does not exist.
  854. */
  855. - (void)testReauthenticateUserMismatchFailure {
  856. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  857. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  858. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  859. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kGoogleDisplayName);
  860. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  861. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  862. [self signInWithEmailPasswordWithMockUserInfoResponse:mockGetAccountInfoResponseUser
  863. completion:^(FIRUser *user) {
  864. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  865. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  866. FIRVerifyAssertionResponseCallback callback) {
  867. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  868. callback(nil, [FIRAuthErrorUtils userNotFoundErrorWithMessage:nil]);
  869. });
  870. });
  871. FIRAuthCredential *googleCredential =
  872. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  873. [user reauthenticateWithCredential:googleCredential completion:^(NSError *_Nullable error) {
  874. // Verify user mismatch error.
  875. XCTAssertEqual(error.code, FIRAuthErrorCodeUserMismatch);
  876. // Verify that the current user is unchanged.
  877. XCTAssertEqual([FIRAuth auth].currentUser, user);
  878. [expectation fulfill];
  879. }];
  880. }];
  881. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  882. OCMVerifyAll(_mockBackend);
  883. }
  884. /** @fn testlinkAndRetrieveDataSuccess
  885. @brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
  886. call.
  887. */
  888. - (void)testlinkAndRetrieveDataSuccess {
  889. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  890. federatedID:kFacebookID
  891. displayName:kFacebookDisplayName
  892. profile:[[self class] googleProfile]
  893. providerIDToken:kFacebookIDToken
  894. providerAccessToken:kFacebookAccessToken];
  895. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  896. [[FIRAuth auth] signOut:NULL];
  897. FIRAuthCredential *facebookCredential =
  898. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  899. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  900. completion:^(FIRAuthDataResult *_Nullable authResult,
  901. NSError *_Nullable error) {
  902. XCTAssertTrue([NSThread isMainThread]);
  903. [self assertUserFacebook:authResult.user];
  904. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  905. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  906. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  907. XCTAssertNil(error);
  908. [self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
  909. federatedID:kGoogleID
  910. displayName:kGoogleDisplayName
  911. profile:[[self class] googleProfile]
  912. providerIDToken:kGoogleIDToken
  913. providerAccessToken:kGoogleAccessToken];
  914. FIRAuthCredential *linkGoogleCredential =
  915. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  916. [authResult.user linkAndRetrieveDataWithCredential:linkGoogleCredential
  917. completion:^(FIRAuthDataResult *_Nullable
  918. linkAuthResult,
  919. NSError *_Nullable error) {
  920. XCTAssertNil(error);
  921. // Verify that the current user is unchanged.
  922. XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
  923. // Verify that the current user and reauthenticated user are same pointers.
  924. XCTAssertEqualObjects(authResult.user, linkAuthResult.user);
  925. // Verify that anyway the current user and linked user have same IDs.
  926. XCTAssertEqualObjects(authResult.user.uid, linkAuthResult.user.uid);
  927. XCTAssertEqualObjects(authResult.user.displayName, linkAuthResult.user.displayName);
  928. XCTAssertEqualObjects(linkAuthResult.additionalUserInfo.profile,
  929. [[self class] googleProfile]);
  930. XCTAssertEqualObjects(linkAuthResult.additionalUserInfo.username, kUserName);
  931. XCTAssertEqualObjects(linkAuthResult.additionalUserInfo.providerID,
  932. FIRGoogleAuthProviderID);
  933. [expectation fulfill];
  934. }];
  935. }];
  936. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  937. [self assertUserGoogle:[FIRAuth auth].currentUser];
  938. OCMVerifyAll(_mockBackend);
  939. }
  940. /** @fn testlinkAndRetrieveDataError
  941. @brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
  942. call with an error from the backend.
  943. */
  944. - (void)testlinkAndRetrieveDataError {
  945. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  946. federatedID:kFacebookID
  947. displayName:kFacebookDisplayName
  948. profile:[[self class] googleProfile]
  949. providerIDToken:kFacebookIDToken
  950. providerAccessToken:kFacebookAccessToken];
  951. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  952. [[FIRAuth auth] signOut:NULL];
  953. FIRAuthCredential *facebookCredential =
  954. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  955. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  956. completion:^(FIRAuthDataResult *_Nullable authResult,
  957. NSError *_Nullable error) {
  958. XCTAssertTrue([NSThread isMainThread]);
  959. [self assertUserFacebook:authResult.user];
  960. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  961. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  962. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  963. XCTAssertNil(error);
  964. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  965. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  966. FIRVerifyAssertionResponseCallback callback) {
  967. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  968. callback(nil, [FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  969. });
  970. });
  971. FIRAuthCredential *linkGoogleCredential =
  972. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  973. [authResult.user linkAndRetrieveDataWithCredential:linkGoogleCredential
  974. completion:^(FIRAuthDataResult *_Nullable
  975. linkAuthResult,
  976. NSError *_Nullable error) {
  977. XCTAssertNil(linkAuthResult);
  978. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  979. [expectation fulfill];
  980. }];
  981. }];
  982. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  983. OCMVerifyAll(_mockBackend);
  984. }
  985. /** @fn testlinkAndRetrieveDataProviderAlreadyLinked
  986. @brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
  987. call with FIRAuthErrorCodeProviderAlreadyLinked, which is a client side error.
  988. */
  989. - (void)testlinkAndRetrieveDataProviderAlreadyLinked {
  990. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  991. federatedID:kFacebookID
  992. displayName:kFacebookDisplayName
  993. profile:[[self class] googleProfile]
  994. providerIDToken:kFacebookIDToken
  995. providerAccessToken:kFacebookAccessToken];
  996. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  997. [[FIRAuth auth] signOut:NULL];
  998. FIRAuthCredential *facebookCredential =
  999. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1000. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1001. completion:^(FIRAuthDataResult *_Nullable authResult,
  1002. NSError *_Nullable error) {
  1003. XCTAssertTrue([NSThread isMainThread]);
  1004. [self assertUserFacebook:authResult.user];
  1005. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1006. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1007. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1008. XCTAssertNil(error);
  1009. FIRAuthCredential *linkFacebookCredential =
  1010. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1011. [authResult.user linkAndRetrieveDataWithCredential:linkFacebookCredential
  1012. completion:^(FIRAuthDataResult *_Nullable
  1013. linkAuthResult,
  1014. NSError *_Nullable error) {
  1015. XCTAssertNil(linkAuthResult);
  1016. XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
  1017. [expectation fulfill];
  1018. }];
  1019. }];
  1020. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1021. OCMVerifyAll(_mockBackend);
  1022. }
  1023. /** @fn testlinkEmailAndRetrieveDataSuccess
  1024. @brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
  1025. invocation for email credential.
  1026. */
  1027. - (void)testlinkEmailAndRetrieveDataSuccess {
  1028. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1029. federatedID:kFacebookID
  1030. displayName:kFacebookDisplayName
  1031. profile:[[self class] googleProfile]
  1032. providerIDToken:kFacebookIDToken
  1033. providerAccessToken:kFacebookAccessToken];
  1034. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1035. [[FIRAuth auth] signOut:NULL];
  1036. FIRAuthCredential *facebookCredential =
  1037. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1038. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1039. completion:^(FIRAuthDataResult *_Nullable authResult,
  1040. NSError *_Nullable error) {
  1041. XCTAssertTrue([NSThread isMainThread]);
  1042. [self assertUserFacebook:authResult.user];
  1043. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1044. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1045. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1046. XCTAssertNil(error);
  1047. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1048. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1049. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1050. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kEmailDisplayName);
  1051. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1052. // Get account info is expected to be invoked twice.
  1053. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  1054. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  1055. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1056. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  1057. FIRSetAccountInfoResponseCallback callback) {
  1058. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1059. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1060. XCTAssertEqualObjects(request.password, kFakePassword);
  1061. XCTAssertNil(request.localID);
  1062. XCTAssertNil(request.displayName);
  1063. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1064. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  1065. callback(mockSetAccountInfoResponse, nil);
  1066. });
  1067. });
  1068. FIRAuthCredential *linkEmailCredential =
  1069. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  1070. [authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
  1071. completion:^(FIRAuthDataResult *_Nullable
  1072. linkAuthResult,
  1073. NSError *_Nullable error) {
  1074. XCTAssertNil(error);
  1075. XCTAssertEqualObjects(linkAuthResult.user.email, kEmail);
  1076. XCTAssertEqualObjects(linkAuthResult.user.displayName, kEmailDisplayName);
  1077. [expectation fulfill];
  1078. }];
  1079. }];
  1080. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1081. OCMVerifyAll(_mockBackend);
  1082. }
  1083. /** @fn testlinkEmailProviderAlreadyLinkedError
  1084. @brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
  1085. invocation for email credential and FIRAuthErrorCodeProviderAlreadyLinked which is a client
  1086. side error.
  1087. */
  1088. - (void)testlinkEmailProviderAlreadyLinkedError {
  1089. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1090. federatedID:kFacebookID
  1091. displayName:kFacebookDisplayName
  1092. profile:[[self class] googleProfile]
  1093. providerIDToken:kFacebookIDToken
  1094. providerAccessToken:kFacebookAccessToken];
  1095. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1096. [[FIRAuth auth] signOut:NULL];
  1097. FIRAuthCredential *facebookCredential =
  1098. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1099. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1100. completion:^(FIRAuthDataResult *_Nullable authResult,
  1101. NSError *_Nullable error) {
  1102. XCTAssertTrue([NSThread isMainThread]);
  1103. [self assertUserFacebook:authResult.user];
  1104. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1105. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1106. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1107. XCTAssertNil(error);
  1108. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1109. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1110. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1111. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kEmailDisplayName);
  1112. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1113. // Get account info is expected to be invoked twice.
  1114. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  1115. [self expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser];
  1116. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1117. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  1118. FIRSetAccountInfoResponseCallback callback) {
  1119. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1120. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1121. XCTAssertEqualObjects(request.password, kFakePassword);
  1122. XCTAssertNil(request.localID);
  1123. XCTAssertNil(request.displayName);
  1124. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1125. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  1126. callback(mockSetAccountInfoResponse, nil);
  1127. });
  1128. });
  1129. FIRAuthCredential *linkEmailCredential =
  1130. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  1131. [authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
  1132. completion:^(FIRAuthDataResult *_Nullable
  1133. linkAuthResult,
  1134. NSError *_Nullable error) {
  1135. XCTAssertNil(error);
  1136. XCTAssertEqualObjects(linkAuthResult.user.email, kEmail);
  1137. XCTAssertEqualObjects(linkAuthResult.user.displayName, kEmailDisplayName);
  1138. // Try linking same credential a second time to trigger client side error.
  1139. [authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
  1140. completion:^(FIRAuthDataResult *_Nullable
  1141. linkAuthResult,
  1142. NSError *_Nullable error) {
  1143. XCTAssertNil(linkAuthResult);
  1144. XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
  1145. [expectation fulfill];
  1146. }];
  1147. }];
  1148. }];
  1149. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1150. OCMVerifyAll(_mockBackend);
  1151. }
  1152. /** @fn testlinkEmailAndRetrieveDataError
  1153. @brief Tests the flow of an unsuccessful @c linkAndRetrieveDataWithCredential:completion:
  1154. invocation for email credential and an error from the backend.
  1155. */
  1156. - (void)testlinkEmailAndRetrieveDataError {
  1157. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1158. federatedID:kFacebookID
  1159. displayName:kFacebookDisplayName
  1160. profile:[[self class] googleProfile]
  1161. providerIDToken:kFacebookIDToken
  1162. providerAccessToken:kFacebookAccessToken];
  1163. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1164. [[FIRAuth auth] signOut:NULL];
  1165. FIRAuthCredential *facebookCredential =
  1166. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1167. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1168. completion:^(FIRAuthDataResult *_Nullable authResult,
  1169. NSError *_Nullable error) {
  1170. XCTAssertTrue([NSThread isMainThread]);
  1171. [self assertUserFacebook:authResult.user];
  1172. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1173. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1174. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1175. XCTAssertNil(error);
  1176. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1177. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1178. FIRGetAccountInfoResponseCallback callback) {
  1179. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1180. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1181. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1182. callback(nil, [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]);
  1183. });
  1184. });
  1185. FIRAuthCredential *linkEmailCredential =
  1186. [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];
  1187. [authResult.user linkAndRetrieveDataWithCredential:linkEmailCredential
  1188. completion:^(FIRAuthDataResult *_Nullable
  1189. linkAuthResult,
  1190. NSError *_Nullable error) {
  1191. XCTAssertNil(linkAuthResult);
  1192. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  1193. [expectation fulfill];
  1194. }];
  1195. }];
  1196. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1197. OCMVerifyAll(_mockBackend);
  1198. }
  1199. /** @fn testlinkCredentialSuccess
  1200. @brief Tests the flow of a successful @c linkWithCredential:completion: call, without additional
  1201. IDP data.
  1202. */
  1203. - (void)testlinkCredentialSuccess {
  1204. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1205. federatedID:kFacebookID
  1206. displayName:kFacebookDisplayName
  1207. profile:[[self class] googleProfile]
  1208. providerIDToken:kFacebookIDToken
  1209. providerAccessToken:kFacebookAccessToken];
  1210. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1211. [[FIRAuth auth] signOut:NULL];
  1212. FIRAuthCredential *facebookCredential =
  1213. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1214. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1215. completion:^(FIRAuthDataResult *_Nullable authResult,
  1216. NSError *_Nullable error) {
  1217. XCTAssertTrue([NSThread isMainThread]);
  1218. [self assertUserFacebook:authResult.user];
  1219. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1220. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1221. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1222. XCTAssertNil(error);
  1223. [self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
  1224. federatedID:kGoogleID
  1225. displayName:kGoogleDisplayName
  1226. profile:[[self class] googleProfile]
  1227. providerIDToken:kGoogleIDToken
  1228. providerAccessToken:kGoogleAccessToken];
  1229. FIRAuthCredential *linkGoogleCredential =
  1230. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1231. [authResult.user linkWithCredential:linkGoogleCredential
  1232. completion:^(FIRUser *_Nullable user,
  1233. NSError *_Nullable error) {
  1234. XCTAssertNil(error);
  1235. id<FIRUserInfo> userInfo = user.providerData.firstObject;
  1236. XCTAssertEqual(userInfo.providerID, FIRGoogleAuthProviderID);
  1237. XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
  1238. [expectation fulfill];
  1239. }];
  1240. }];
  1241. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1242. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1243. OCMVerifyAll(_mockBackend);
  1244. }
  1245. /** @fn testlinkCredentialError
  1246. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion: call, with an error
  1247. from the backend.
  1248. */
  1249. - (void)testlinkCredentialError {
  1250. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1251. federatedID:kFacebookID
  1252. displayName:kFacebookDisplayName
  1253. profile:[[self class] googleProfile]
  1254. providerIDToken:kFacebookIDToken
  1255. providerAccessToken:kFacebookAccessToken];
  1256. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1257. [[FIRAuth auth] signOut:NULL];
  1258. FIRAuthCredential *facebookCredential =
  1259. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1260. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1261. completion:^(FIRAuthDataResult *_Nullable authResult,
  1262. NSError *_Nullable error) {
  1263. XCTAssertTrue([NSThread isMainThread]);
  1264. [self assertUserFacebook:authResult.user];
  1265. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1266. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1267. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1268. XCTAssertNil(error);
  1269. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1270. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1271. FIRVerifyAssertionResponseCallback callback) {
  1272. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1273. callback(nil, [FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  1274. });
  1275. });
  1276. FIRAuthCredential *linkGoogleCredential =
  1277. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1278. [authResult.user linkWithCredential:linkGoogleCredential
  1279. completion:^(FIRUser *_Nullable user,
  1280. NSError *_Nullable error) {
  1281. XCTAssertNil(user);
  1282. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  1283. [expectation fulfill];
  1284. }];
  1285. }];
  1286. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1287. OCMVerifyAll(_mockBackend);
  1288. }
  1289. /** @fn testlinkCredentialProviderAlreadyLinkedError
  1290. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion: call, with a client
  1291. side error.
  1292. */
  1293. - (void)testlinkCredentialProviderAlreadyLinkedError {
  1294. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1295. federatedID:kFacebookID
  1296. displayName:kFacebookDisplayName
  1297. profile:[[self class] googleProfile]
  1298. providerIDToken:kFacebookIDToken
  1299. providerAccessToken:kFacebookAccessToken];
  1300. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1301. [[FIRAuth auth] signOut:NULL];
  1302. FIRAuthCredential *facebookCredential =
  1303. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1304. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1305. completion:^(FIRAuthDataResult *_Nullable authResult,
  1306. NSError *_Nullable error) {
  1307. XCTAssertTrue([NSThread isMainThread]);
  1308. [self assertUserFacebook:authResult.user];
  1309. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1310. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1311. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1312. XCTAssertNil(error);
  1313. FIRAuthCredential *linkFacebookCredential =
  1314. [FIRFacebookAuthProvider credentialWithAccessToken:kGoogleAccessToken];
  1315. [authResult.user linkWithCredential:linkFacebookCredential
  1316. completion:^(FIRUser *_Nullable user,
  1317. NSError *_Nullable error) {
  1318. XCTAssertNil(user);
  1319. XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
  1320. [expectation fulfill];
  1321. }];
  1322. }];
  1323. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1324. OCMVerifyAll(_mockBackend);
  1325. }
  1326. #if TARGET_OS_IOS
  1327. /** @fn testlinkPhoneAuthCredentialSuccess
  1328. @brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
  1329. call using a phoneAuthCredential.
  1330. */
  1331. - (void)testlinkPhoneAuthCredentialSuccess {
  1332. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1333. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1334. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1335. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1336. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1337. if (phoneNumber.length) {
  1338. NSDictionary *userInfoDictionary = @{ @"providerId" : FIRPhoneAuthProviderID };
  1339. FIRGetAccountInfoResponseProviderUserInfo *userInfo =
  1340. [[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:userInfoDictionary];
  1341. OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(@[ userInfo ]);
  1342. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1343. }
  1344. return mockGetAccountInfoResponseUser;
  1345. };
  1346. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1347. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1348. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1349. completion:^(FIRUser *user) {
  1350. [self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber error:nil];
  1351. id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
  1352. [self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
  1353. FIRPhoneAuthCredential *credential =
  1354. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1355. verificationCode:kVerificationCode];
  1356. [user linkAndRetrieveDataWithCredential:credential
  1357. completion:^(FIRAuthDataResult *_Nullable
  1358. linkAuthResult,
  1359. NSError *_Nullable error) {
  1360. XCTAssertNil(error);
  1361. XCTAssertEqualObjects([FIRAuth auth].currentUser.providerData.firstObject.providerID,
  1362. FIRPhoneAuthProviderID);
  1363. XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
  1364. [expectation fulfill];
  1365. }];
  1366. }];
  1367. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1368. OCMVerifyAll(_mockBackend);
  1369. }
  1370. /** @fn testUnlinkPhoneAuthCredentialSuccess
  1371. @brief Tests the flow of a successful @c unlinkFromProvider:completion: call using a
  1372. @c FIRPhoneAuthProvider.
  1373. */
  1374. - (void)testUnlinkPhoneAuthCredentialSuccess {
  1375. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1376. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1377. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1378. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1379. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1380. if (phoneNumber.length) {
  1381. NSDictionary *userInfoDictionary = @{ @"providerId" : FIRPhoneAuthProviderID };
  1382. FIRGetAccountInfoResponseProviderUserInfo *userInfo =
  1383. [[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:userInfoDictionary];
  1384. OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(@[ userInfo ]);
  1385. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1386. }
  1387. return mockGetAccountInfoResponseUser;
  1388. };
  1389. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1390. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  1391. FIRSetAccountInfoResponseCallback callback) {
  1392. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1393. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1394. XCTAssertNotNil(request.deleteProviders);
  1395. XCTAssertNil(request.email);
  1396. XCTAssertNil(request.localID);
  1397. XCTAssertNil(request.displayName);
  1398. XCTAssertNil(request.photoURL);
  1399. XCTAssertNil(request.password);
  1400. XCTAssertNil(request.providers);
  1401. XCTAssertNil(request.deleteAttributes);
  1402. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1403. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  1404. callback(mockSetAccountInfoResponse, nil);
  1405. });
  1406. });
  1407. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1408. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1409. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1410. completion:^(FIRUser *user) {
  1411. [self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber error:nil];
  1412. id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
  1413. [self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
  1414. FIRPhoneAuthCredential *credential =
  1415. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1416. verificationCode:kVerificationCode];
  1417. // Link phone credential.
  1418. [user linkAndRetrieveDataWithCredential:credential
  1419. completion:^(FIRAuthDataResult *_Nullable
  1420. linkAuthResult,
  1421. NSError *_Nullable error) {
  1422. XCTAssertNil(error);
  1423. XCTAssertEqualObjects([FIRAuth auth].currentUser.providerData.firstObject.providerID,
  1424. FIRPhoneAuthProviderID);
  1425. XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
  1426. // Immediately unlink the phone auth provider.
  1427. [user unlinkFromProvider:FIRPhoneAuthProviderID
  1428. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1429. XCTAssertNil(error);
  1430. XCTAssertNil([FIRAuth auth].currentUser.phoneNumber);
  1431. [expectation fulfill];
  1432. }];
  1433. }];
  1434. }];
  1435. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1436. OCMVerifyAll(_mockBackend);
  1437. }
  1438. /** @fn testlinkPhoneAuthCredentialFailure
  1439. @brief Tests the flow of a failed call to @c linkAndRetrieveDataWithCredential:completion: due
  1440. to a phone provider already being linked.
  1441. */
  1442. - (void)testlinkPhoneAuthCredentialFailure {
  1443. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1444. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1445. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1446. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1447. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1448. if (phoneNumber.length) {
  1449. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1450. }
  1451. return mockGetAccountInfoResponseUser;
  1452. };
  1453. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1454. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1455. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1456. completion:^(FIRUser *user) {
  1457. NSError *error = [FIRAuthErrorUtils providerAlreadyLinkedError];
  1458. [self expectVerifyPhoneNumberRequestWithPhoneNumber:nil error:error];
  1459. FIRPhoneAuthCredential *credential =
  1460. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1461. verificationCode:kVerificationCode];
  1462. [user linkAndRetrieveDataWithCredential:credential
  1463. completion:^(FIRAuthDataResult *_Nullable
  1464. linkAuthResult,
  1465. NSError *_Nullable error) {
  1466. XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
  1467. [expectation fulfill];
  1468. }];
  1469. }];
  1470. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1471. OCMVerifyAll(_mockBackend);
  1472. }
  1473. /** @fn testlinkPhoneCredentialAlreadyExistsError
  1474. @brief Tests the flow of @c linkAndRetrieveDataWithCredential:completion:
  1475. call using a phoneAuthCredential and a credential already exisits error. In this case we
  1476. should get a FIRAuthCredential in the error object.
  1477. */
  1478. - (void)testlinkPhoneCredentialAlreadyExistsError {
  1479. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1480. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1481. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1482. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1483. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1484. if (phoneNumber.length) {
  1485. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1486. }
  1487. return mockGetAccountInfoResponseUser;
  1488. };
  1489. void (^expectVerifyPhoneNumberRequest)(NSString *) = ^(NSString *phoneNumber) {
  1490. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  1491. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  1492. FIRVerifyPhoneNumberResponseCallback callback) {
  1493. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  1494. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  1495. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1496. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1497. FIRPhoneAuthCredential *credential =
  1498. [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:kTemporaryProof
  1499. phoneNumber:kPhoneNumber
  1500. providerID:FIRPhoneAuthProviderID];
  1501. callback(nil,
  1502. [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil
  1503. credential:credential]);
  1504. });
  1505. });
  1506. };
  1507. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1508. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1509. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1510. completion:^(FIRUser *user) {
  1511. expectVerifyPhoneNumberRequest(kPhoneNumber);
  1512. FIRPhoneAuthCredential *credential =
  1513. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1514. verificationCode:kVerificationCode];
  1515. [user linkAndRetrieveDataWithCredential:credential
  1516. completion:^(FIRAuthDataResult *_Nullable
  1517. linkAuthResult,
  1518. NSError *_Nullable error) {
  1519. XCTAssertNil(linkAuthResult);
  1520. XCTAssertEqual(error.code, FIRAuthErrorCodeCredentialAlreadyInUse);
  1521. FIRPhoneAuthCredential *credential = error.userInfo[FIRAuthUpdatedCredentialKey];
  1522. XCTAssertEqual(credential.temporaryProof, kTemporaryProof);
  1523. XCTAssertEqual(credential.phoneNumber, kPhoneNumber);
  1524. [expectation fulfill];
  1525. }];
  1526. }];
  1527. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1528. OCMVerifyAll(_mockBackend);
  1529. }
  1530. #endif
  1531. #pragma mark - Helpers
  1532. /** @fn signInWithEmailPasswordWithMockGetAccountInfoResponse:completion:
  1533. @brief Signs in with an email and password account with mocked backend end calls.
  1534. @param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
  1535. @param completion The completion block that takes the newly signed-in user as the only
  1536. parameter.
  1537. */
  1538. - (void)signInWithEmailPasswordWithMockUserInfoResponse:(id)mockUserInfoResponse
  1539. completion:(void (^)(FIRUser *user))completion {
  1540. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  1541. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  1542. FIRVerifyPasswordResponseCallback callback) {
  1543. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1544. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  1545. OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kAccessToken);
  1546. OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
  1547. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1548. OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  1549. callback(mockVeriyPasswordResponse, nil);
  1550. });
  1551. });
  1552. [self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
  1553. [[FIRAuth auth] signOut:NULL];
  1554. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  1555. NSError *_Nullable error) {
  1556. XCTAssertNotNil(user);
  1557. XCTAssertNil(error);
  1558. completion(user);
  1559. }];
  1560. }
  1561. /** @fn expectGetAccountInfoWithMockUserInfoResponse:
  1562. @brief Expects a GetAccountInfo request on the mock backend and calls back with provided
  1563. fake account data.
  1564. @param mockUserInfoResponse A mock @c FIRGetAccountInfoResponseUser object containing user info.
  1565. */
  1566. - (void)expectGetAccountInfoWithMockUserInfoResponse:(id)mockUserInfoResponse {
  1567. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1568. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1569. FIRGetAccountInfoResponseCallback callback) {
  1570. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1571. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1572. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1573. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1574. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockUserInfoResponse ]);
  1575. callback(mockGetAccountInfoResponse, nil);
  1576. });
  1577. });
  1578. }
  1579. /** @fn dictionaryWithUserInfoArray:
  1580. @brief Converts an array of @c FIRUserInfo into a dictionary that indexed by provider IDs.
  1581. @param userInfoArray An array of @c FIRUserInfo objects.
  1582. @return A dictionary contains same values as @c userInfoArray does but keyed by their
  1583. @c providerID .
  1584. */
  1585. - (NSDictionary<NSString *, id<FIRUserInfo>> *)
  1586. dictionaryWithUserInfoArray:(NSArray<id<FIRUserInfo>> *)userInfoArray {
  1587. NSMutableDictionary<NSString *, id<FIRUserInfo>> *map =
  1588. [NSMutableDictionary dictionaryWithCapacity:userInfoArray.count];
  1589. for (id<FIRUserInfo> userInfo in userInfoArray) {
  1590. XCTAssertNil(map[userInfo.providerID]);
  1591. map[userInfo.providerID] = userInfo;
  1592. }
  1593. return map;
  1594. }
  1595. /** @fn stubSecureTokensWithMockResponse
  1596. @brief Creates stubs on the mock response object with access and refresh tokens
  1597. @param mockResponse The mock response object.
  1598. */
  1599. - (void)stubTokensWithMockResponse:(id)mockResponse {
  1600. OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
  1601. OCMStub([mockResponse approximateExpirationDate])
  1602. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1603. OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
  1604. }
  1605. /** @fn assertUserGoogle
  1606. @brief Asserts the given FIRUser matching the fake data returned by
  1607. @c expectGetAccountInfo:federatedID:displayName: .
  1608. @param user The user object to be verified.
  1609. */
  1610. - (void)assertUserGoogle:(FIRUser *)user {
  1611. XCTAssertNotNil(user);
  1612. XCTAssertEqualObjects(user.uid, kLocalID);
  1613. XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
  1614. XCTAssertEqual(user.providerData.count, 1u);
  1615. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  1616. XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
  1617. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  1618. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  1619. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  1620. }
  1621. /** @fn assertUserFacebook
  1622. @brief Asserts the given FIRUser matching the fake data returned by
  1623. @c expectGetAccountInfo:federatedID:displayName: .
  1624. @param user The user object to be verified.
  1625. */
  1626. - (void)assertUserFacebook:(FIRUser *)user {
  1627. XCTAssertNotNil(user);
  1628. XCTAssertEqualObjects(user.uid, kLocalID);
  1629. XCTAssertEqualObjects(user.displayName, kFacebookDisplayName);
  1630. XCTAssertEqual(user.providerData.count, 1u);
  1631. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  1632. XCTAssertEqualObjects(googleUserInfo.providerID, FIRFacebookAuthProviderID);
  1633. XCTAssertEqualObjects(googleUserInfo.uid, kFacebookID);
  1634. XCTAssertEqualObjects(googleUserInfo.displayName, kFacebookDisplayName);
  1635. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  1636. }
  1637. /** @fn expectGetAccountInfo:federatedID:displayName:
  1638. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1639. data for a Google Sign-In user.
  1640. */
  1641. - (void)expectGetAccountInfo:(NSString *)providerId
  1642. federatedID:(NSString *)federatedID
  1643. displayName:(NSString *)displayName {
  1644. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1645. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1646. FIRGetAccountInfoResponseCallback callback) {
  1647. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1648. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1649. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1650. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  1651. OCMStub([mockGoogleUserInfo providerID]).andReturn(providerId);
  1652. OCMStub([mockGoogleUserInfo displayName]).andReturn(displayName);
  1653. OCMStub([mockGoogleUserInfo federatedID]).andReturn(federatedID);
  1654. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  1655. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1656. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1657. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
  1658. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  1659. .andReturn((@[ mockGoogleUserInfo ]));
  1660. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1661. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1662. callback(mockGetAccountInfoResponse, nil);
  1663. });
  1664. });
  1665. }
  1666. /** @fn expectVerifyAssertionRequest:federatedID:displayName:profile:providerAccessToken:
  1667. @brief Expects a Verify Assertion request on the mock backend and calls back with fake account
  1668. data.
  1669. */
  1670. - (void)expectVerifyAssertionRequest:(NSString *)providerId
  1671. federatedID:(NSString *)federatedID
  1672. displayName:(NSString *)displayName
  1673. profile:(NSDictionary *)profile
  1674. providerIDToken:(nullable NSString *)providerIDToken
  1675. providerAccessToken:(NSString *)providerAccessToken {
  1676. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1677. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1678. FIRVerifyAssertionResponseCallback callback) {
  1679. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1680. XCTAssertEqualObjects(request.providerID, providerId);
  1681. XCTAssertEqualObjects(request.providerIDToken, providerIDToken);
  1682. XCTAssertEqualObjects(request.providerAccessToken, providerAccessToken);
  1683. XCTAssertTrue(request.returnSecureToken);
  1684. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1685. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1686. OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(federatedID);
  1687. OCMStub([mockVeriyAssertionResponse providerID]).andReturn(providerId);
  1688. OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
  1689. OCMStub([mockVeriyAssertionResponse displayName]).andReturn(displayName);
  1690. OCMStub([mockVeriyAssertionResponse profile]).andReturn(profile);
  1691. OCMStub([mockVeriyAssertionResponse username]).andReturn(kUserName);
  1692. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  1693. callback(mockVeriyAssertionResponse, nil);
  1694. });
  1695. });
  1696. [self expectGetAccountInfo:providerId federatedID:federatedID displayName:displayName];
  1697. }
  1698. #if TARGET_OS_IOS
  1699. /** @fn expectVerifyPhoneNumberRequestWithPhoneNumber:error:
  1700. @brief Expects a verify phone numner request on the mock backend and calls back with fake
  1701. account data or an error.
  1702. @param phoneNumber Optionally; The phone number to use in the mocked response.
  1703. @param error Optionally; The error to return in the mocked response.
  1704. */
  1705. - (void)expectVerifyPhoneNumberRequestWithPhoneNumber:(nullable NSString *)phoneNumber
  1706. error:(nullable NSError*)error {
  1707. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  1708. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  1709. FIRVerifyPhoneNumberResponseCallback callback) {
  1710. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  1711. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  1712. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1713. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1714. if (error) {
  1715. callback(nil, error);
  1716. return;
  1717. }
  1718. id mockVerifyPhoneNumberResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
  1719. OCMStub([mockVerifyPhoneNumberResponse phoneNumber]).andReturn(phoneNumber);
  1720. callback(mockVerifyPhoneNumberResponse, nil);
  1721. });
  1722. });
  1723. }
  1724. #endif
  1725. @end
  1726. NS_ASSUME_NONNULL_END