FIRUserTests.m 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876
  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. XCTAssertTrue([NSThread isMainThread]);
  1192. XCTAssertNil(linkAuthResult);
  1193. XCTAssertEqual(error.code, FIRAuthErrorCodeTooManyRequests);
  1194. [expectation fulfill];
  1195. }];
  1196. }];
  1197. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1198. OCMVerifyAll(_mockBackend);
  1199. }
  1200. /** @fn testlinkCredentialSuccess
  1201. @brief Tests the flow of a successful @c linkWithCredential:completion: call, without additional
  1202. IDP data.
  1203. */
  1204. - (void)testlinkCredentialSuccess {
  1205. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1206. federatedID:kFacebookID
  1207. displayName:kFacebookDisplayName
  1208. profile:[[self class] googleProfile]
  1209. providerIDToken:kFacebookIDToken
  1210. providerAccessToken:kFacebookAccessToken];
  1211. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1212. [[FIRAuth auth] signOut:NULL];
  1213. FIRAuthCredential *facebookCredential =
  1214. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1215. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1216. completion:^(FIRAuthDataResult *_Nullable authResult,
  1217. NSError *_Nullable error) {
  1218. XCTAssertTrue([NSThread isMainThread]);
  1219. [self assertUserFacebook:authResult.user];
  1220. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1221. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1222. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1223. XCTAssertNil(error);
  1224. [self expectVerifyAssertionRequest:FIRGoogleAuthProviderID
  1225. federatedID:kGoogleID
  1226. displayName:kGoogleDisplayName
  1227. profile:[[self class] googleProfile]
  1228. providerIDToken:kGoogleIDToken
  1229. providerAccessToken:kGoogleAccessToken];
  1230. FIRAuthCredential *linkGoogleCredential =
  1231. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1232. [authResult.user linkWithCredential:linkGoogleCredential
  1233. completion:^(FIRUser *_Nullable user,
  1234. NSError *_Nullable error) {
  1235. XCTAssertNil(error);
  1236. id<FIRUserInfo> userInfo = user.providerData.firstObject;
  1237. XCTAssertEqual(userInfo.providerID, FIRGoogleAuthProviderID);
  1238. XCTAssertEqual([FIRAuth auth].currentUser, authResult.user);
  1239. [expectation fulfill];
  1240. }];
  1241. }];
  1242. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1243. [self assertUserGoogle:[FIRAuth auth].currentUser];
  1244. OCMVerifyAll(_mockBackend);
  1245. }
  1246. /** @fn testlinkCredentialError
  1247. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion: call, with an error
  1248. from the backend.
  1249. */
  1250. - (void)testlinkCredentialError {
  1251. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1252. federatedID:kFacebookID
  1253. displayName:kFacebookDisplayName
  1254. profile:[[self class] googleProfile]
  1255. providerIDToken:kFacebookIDToken
  1256. providerAccessToken:kFacebookAccessToken];
  1257. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1258. [[FIRAuth auth] signOut:NULL];
  1259. FIRAuthCredential *facebookCredential =
  1260. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1261. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1262. completion:^(FIRAuthDataResult *_Nullable authResult,
  1263. NSError *_Nullable error) {
  1264. XCTAssertTrue([NSThread isMainThread]);
  1265. [self assertUserFacebook:authResult.user];
  1266. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1267. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1268. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1269. XCTAssertNil(error);
  1270. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1271. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1272. FIRVerifyAssertionResponseCallback callback) {
  1273. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1274. callback(nil, [FIRAuthErrorUtils userDisabledErrorWithMessage:nil]);
  1275. });
  1276. });
  1277. FIRAuthCredential *linkGoogleCredential =
  1278. [FIRGoogleAuthProvider credentialWithIDToken:kGoogleIDToken accessToken:kGoogleAccessToken];
  1279. [authResult.user linkWithCredential:linkGoogleCredential
  1280. completion:^(FIRUser *_Nullable user,
  1281. NSError *_Nullable error) {
  1282. XCTAssertNil(user);
  1283. XCTAssertEqual(error.code, FIRAuthErrorCodeUserDisabled);
  1284. [expectation fulfill];
  1285. }];
  1286. }];
  1287. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1288. OCMVerifyAll(_mockBackend);
  1289. }
  1290. /** @fn testlinkCredentialProviderAlreadyLinkedError
  1291. @brief Tests the flow of an unsuccessful @c linkWithCredential:completion: call, with a client
  1292. side error.
  1293. */
  1294. - (void)testlinkCredentialProviderAlreadyLinkedError {
  1295. [self expectVerifyAssertionRequest:FIRFacebookAuthProviderID
  1296. federatedID:kFacebookID
  1297. displayName:kFacebookDisplayName
  1298. profile:[[self class] googleProfile]
  1299. providerIDToken:kFacebookIDToken
  1300. providerAccessToken:kFacebookAccessToken];
  1301. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1302. [[FIRAuth auth] signOut:NULL];
  1303. FIRAuthCredential *facebookCredential =
  1304. [FIRFacebookAuthProvider credentialWithAccessToken:kFacebookAccessToken];
  1305. [[FIRAuth auth] signInAndRetrieveDataWithCredential:facebookCredential
  1306. completion:^(FIRAuthDataResult *_Nullable authResult,
  1307. NSError *_Nullable error) {
  1308. XCTAssertTrue([NSThread isMainThread]);
  1309. [self assertUserFacebook:authResult.user];
  1310. XCTAssertEqualObjects(authResult.additionalUserInfo.profile, [[self class] googleProfile]);
  1311. XCTAssertEqualObjects(authResult.additionalUserInfo.username, kUserName);
  1312. XCTAssertEqualObjects(authResult.additionalUserInfo.providerID, FIRFacebookAuthProviderID);
  1313. XCTAssertNil(error);
  1314. FIRAuthCredential *linkFacebookCredential =
  1315. [FIRFacebookAuthProvider credentialWithAccessToken:kGoogleAccessToken];
  1316. [authResult.user linkWithCredential:linkFacebookCredential
  1317. completion:^(FIRUser *_Nullable user,
  1318. NSError *_Nullable error) {
  1319. XCTAssertNil(user);
  1320. XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
  1321. [expectation fulfill];
  1322. }];
  1323. }];
  1324. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1325. OCMVerifyAll(_mockBackend);
  1326. }
  1327. #if TARGET_OS_IOS
  1328. /** @fn testlinkPhoneAuthCredentialSuccess
  1329. @brief Tests the flow of a successful @c linkAndRetrieveDataWithCredential:completion:
  1330. call using a phoneAuthCredential.
  1331. */
  1332. - (void)testlinkPhoneAuthCredentialSuccess {
  1333. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1334. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1335. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1336. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1337. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1338. if (phoneNumber.length) {
  1339. NSDictionary *userInfoDictionary = @{ @"providerId" : FIRPhoneAuthProviderID };
  1340. FIRGetAccountInfoResponseProviderUserInfo *userInfo =
  1341. [[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:userInfoDictionary];
  1342. OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(@[ userInfo ]);
  1343. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1344. }
  1345. return mockGetAccountInfoResponseUser;
  1346. };
  1347. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1348. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1349. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1350. completion:^(FIRUser *user) {
  1351. [self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber error:nil];
  1352. id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
  1353. [self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
  1354. FIRPhoneAuthCredential *credential =
  1355. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1356. verificationCode:kVerificationCode];
  1357. [user linkAndRetrieveDataWithCredential:credential
  1358. completion:^(FIRAuthDataResult *_Nullable
  1359. linkAuthResult,
  1360. NSError *_Nullable error) {
  1361. XCTAssertNil(error);
  1362. XCTAssertEqualObjects([FIRAuth auth].currentUser.providerData.firstObject.providerID,
  1363. FIRPhoneAuthProviderID);
  1364. XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
  1365. [expectation fulfill];
  1366. }];
  1367. }];
  1368. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1369. OCMVerifyAll(_mockBackend);
  1370. }
  1371. /** @fn testUnlinkPhoneAuthCredentialSuccess
  1372. @brief Tests the flow of a successful @c unlinkFromProvider:completion: call using a
  1373. @c FIRPhoneAuthProvider.
  1374. */
  1375. - (void)testUnlinkPhoneAuthCredentialSuccess {
  1376. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1377. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1378. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1379. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1380. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1381. if (phoneNumber.length) {
  1382. NSDictionary *userInfoDictionary = @{ @"providerId" : FIRPhoneAuthProviderID };
  1383. FIRGetAccountInfoResponseProviderUserInfo *userInfo =
  1384. [[FIRGetAccountInfoResponseProviderUserInfo alloc] initWithDictionary:userInfoDictionary];
  1385. OCMStub([mockGetAccountInfoResponseUser providerUserInfo]).andReturn(@[ userInfo ]);
  1386. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1387. }
  1388. return mockGetAccountInfoResponseUser;
  1389. };
  1390. OCMExpect([_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1391. .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request,
  1392. FIRSetAccountInfoResponseCallback callback) {
  1393. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1394. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1395. XCTAssertNotNil(request.deleteProviders);
  1396. XCTAssertNil(request.email);
  1397. XCTAssertNil(request.localID);
  1398. XCTAssertNil(request.displayName);
  1399. XCTAssertNil(request.photoURL);
  1400. XCTAssertNil(request.password);
  1401. XCTAssertNil(request.providers);
  1402. XCTAssertNil(request.deleteAttributes);
  1403. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1404. id mockSetAccountInfoResponse = OCMClassMock([FIRSetAccountInfoResponse class]);
  1405. callback(mockSetAccountInfoResponse, nil);
  1406. });
  1407. });
  1408. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1409. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1410. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1411. completion:^(FIRUser *user) {
  1412. [self expectVerifyPhoneNumberRequestWithPhoneNumber:kPhoneNumber error:nil];
  1413. id userInfoResponseUpdate = mockUserInfoWithPhoneNumber(kPhoneNumber);
  1414. [self expectGetAccountInfoWithMockUserInfoResponse:userInfoResponseUpdate];
  1415. FIRPhoneAuthCredential *credential =
  1416. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1417. verificationCode:kVerificationCode];
  1418. // Link phone credential.
  1419. [user linkAndRetrieveDataWithCredential:credential
  1420. completion:^(FIRAuthDataResult *_Nullable
  1421. linkAuthResult,
  1422. NSError *_Nullable error) {
  1423. XCTAssertNil(error);
  1424. XCTAssertEqualObjects([FIRAuth auth].currentUser.providerData.firstObject.providerID,
  1425. FIRPhoneAuthProviderID);
  1426. XCTAssertEqualObjects([FIRAuth auth].currentUser.phoneNumber, kPhoneNumber);
  1427. // Immediately unlink the phone auth provider.
  1428. [user unlinkFromProvider:FIRPhoneAuthProviderID
  1429. completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  1430. XCTAssertNil(error);
  1431. XCTAssertNil([FIRAuth auth].currentUser.phoneNumber);
  1432. [expectation fulfill];
  1433. }];
  1434. }];
  1435. }];
  1436. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1437. OCMVerifyAll(_mockBackend);
  1438. }
  1439. /** @fn testlinkPhoneAuthCredentialFailure
  1440. @brief Tests the flow of a failed call to @c linkAndRetrieveDataWithCredential:completion: due
  1441. to a phone provider already being linked.
  1442. */
  1443. - (void)testlinkPhoneAuthCredentialFailure {
  1444. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1445. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1446. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1447. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1448. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1449. if (phoneNumber.length) {
  1450. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1451. }
  1452. return mockGetAccountInfoResponseUser;
  1453. };
  1454. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1455. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1456. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1457. completion:^(FIRUser *user) {
  1458. NSError *error = [FIRAuthErrorUtils providerAlreadyLinkedError];
  1459. [self expectVerifyPhoneNumberRequestWithPhoneNumber:nil error:error];
  1460. FIRPhoneAuthCredential *credential =
  1461. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1462. verificationCode:kVerificationCode];
  1463. [user linkAndRetrieveDataWithCredential:credential
  1464. completion:^(FIRAuthDataResult *_Nullable
  1465. linkAuthResult,
  1466. NSError *_Nullable error) {
  1467. XCTAssertEqual(error.code, FIRAuthErrorCodeProviderAlreadyLinked);
  1468. [expectation fulfill];
  1469. }];
  1470. }];
  1471. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1472. OCMVerifyAll(_mockBackend);
  1473. }
  1474. /** @fn testlinkPhoneCredentialAlreadyExistsError
  1475. @brief Tests the flow of @c linkAndRetrieveDataWithCredential:completion:
  1476. call using a phoneAuthCredential and a credential already exisits error. In this case we
  1477. should get a FIRAuthCredential in the error object.
  1478. */
  1479. - (void)testlinkPhoneCredentialAlreadyExistsError {
  1480. id (^mockUserInfoWithPhoneNumber)(NSString *) = ^(NSString *phoneNumber) {
  1481. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1482. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1483. OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail);
  1484. OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash);
  1485. if (phoneNumber.length) {
  1486. OCMStub([mockGetAccountInfoResponseUser phoneNumber]).andReturn(phoneNumber);
  1487. }
  1488. return mockGetAccountInfoResponseUser;
  1489. };
  1490. void (^expectVerifyPhoneNumberRequest)(NSString *) = ^(NSString *phoneNumber) {
  1491. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  1492. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  1493. FIRVerifyPhoneNumberResponseCallback callback) {
  1494. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  1495. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  1496. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1497. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1498. FIRPhoneAuthCredential *credential =
  1499. [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:kTemporaryProof
  1500. phoneNumber:kPhoneNumber
  1501. providerID:FIRPhoneAuthProviderID];
  1502. callback(nil,
  1503. [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil
  1504. credential:credential]);
  1505. });
  1506. });
  1507. };
  1508. XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
  1509. id userInfoResponse = mockUserInfoWithPhoneNumber(nil);
  1510. [self signInWithEmailPasswordWithMockUserInfoResponse:userInfoResponse
  1511. completion:^(FIRUser *user) {
  1512. expectVerifyPhoneNumberRequest(kPhoneNumber);
  1513. FIRPhoneAuthCredential *credential =
  1514. [[FIRPhoneAuthProvider provider] credentialWithVerificationID:kVerificationID
  1515. verificationCode:kVerificationCode];
  1516. [user linkAndRetrieveDataWithCredential:credential
  1517. completion:^(FIRAuthDataResult *_Nullable
  1518. linkAuthResult,
  1519. NSError *_Nullable error) {
  1520. XCTAssertNil(linkAuthResult);
  1521. XCTAssertEqual(error.code, FIRAuthErrorCodeCredentialAlreadyInUse);
  1522. FIRPhoneAuthCredential *credential = error.userInfo[FIRAuthUpdatedCredentialKey];
  1523. XCTAssertEqual(credential.temporaryProof, kTemporaryProof);
  1524. XCTAssertEqual(credential.phoneNumber, kPhoneNumber);
  1525. [expectation fulfill];
  1526. }];
  1527. }];
  1528. [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
  1529. OCMVerifyAll(_mockBackend);
  1530. }
  1531. #endif
  1532. #pragma mark - Helpers
  1533. /** @fn signInWithEmailPasswordWithMockGetAccountInfoResponse:completion:
  1534. @brief Signs in with an email and password account with mocked backend end calls.
  1535. @param mockUserInfoResponse A mocked FIRGetAccountInfoResponseUser object.
  1536. @param completion The completion block that takes the newly signed-in user as the only
  1537. parameter.
  1538. */
  1539. - (void)signInWithEmailPasswordWithMockUserInfoResponse:(id)mockUserInfoResponse
  1540. completion:(void (^)(FIRUser *user))completion {
  1541. OCMExpect([_mockBackend verifyPassword:[OCMArg any] callback:[OCMArg any]])
  1542. .andCallBlock2(^(FIRVerifyPasswordRequest *_Nullable request,
  1543. FIRVerifyPasswordResponseCallback callback) {
  1544. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1545. id mockVeriyPasswordResponse = OCMClassMock([FIRVerifyPasswordResponse class]);
  1546. OCMStub([mockVeriyPasswordResponse IDToken]).andReturn(kAccessToken);
  1547. OCMStub([mockVeriyPasswordResponse approximateExpirationDate])
  1548. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1549. OCMStub([mockVeriyPasswordResponse refreshToken]).andReturn(kRefreshToken);
  1550. callback(mockVeriyPasswordResponse, nil);
  1551. });
  1552. });
  1553. [self expectGetAccountInfoWithMockUserInfoResponse:mockUserInfoResponse];
  1554. [[FIRAuth auth] signOut:NULL];
  1555. [[FIRAuth auth] signInWithEmail:kEmail password:kFakePassword completion:^(FIRUser *_Nullable user,
  1556. NSError *_Nullable error) {
  1557. XCTAssertNotNil(user);
  1558. XCTAssertNil(error);
  1559. completion(user);
  1560. }];
  1561. }
  1562. /** @fn expectGetAccountInfoWithMockUserInfoResponse:
  1563. @brief Expects a GetAccountInfo request on the mock backend and calls back with provided
  1564. fake account data.
  1565. @param mockUserInfoResponse A mock @c FIRGetAccountInfoResponseUser object containing user info.
  1566. */
  1567. - (void)expectGetAccountInfoWithMockUserInfoResponse:(id)mockUserInfoResponse {
  1568. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1569. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1570. FIRGetAccountInfoResponseCallback callback) {
  1571. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1572. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1573. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1574. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1575. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockUserInfoResponse ]);
  1576. callback(mockGetAccountInfoResponse, nil);
  1577. });
  1578. });
  1579. }
  1580. /** @fn dictionaryWithUserInfoArray:
  1581. @brief Converts an array of @c FIRUserInfo into a dictionary that indexed by provider IDs.
  1582. @param userInfoArray An array of @c FIRUserInfo objects.
  1583. @return A dictionary contains same values as @c userInfoArray does but keyed by their
  1584. @c providerID .
  1585. */
  1586. - (NSDictionary<NSString *, id<FIRUserInfo>> *)
  1587. dictionaryWithUserInfoArray:(NSArray<id<FIRUserInfo>> *)userInfoArray {
  1588. NSMutableDictionary<NSString *, id<FIRUserInfo>> *map =
  1589. [NSMutableDictionary dictionaryWithCapacity:userInfoArray.count];
  1590. for (id<FIRUserInfo> userInfo in userInfoArray) {
  1591. XCTAssertNil(map[userInfo.providerID]);
  1592. map[userInfo.providerID] = userInfo;
  1593. }
  1594. return map;
  1595. }
  1596. /** @fn stubSecureTokensWithMockResponse
  1597. @brief Creates stubs on the mock response object with access and refresh tokens
  1598. @param mockResponse The mock response object.
  1599. */
  1600. - (void)stubTokensWithMockResponse:(id)mockResponse {
  1601. OCMStub([mockResponse IDToken]).andReturn(kAccessToken);
  1602. OCMStub([mockResponse approximateExpirationDate])
  1603. .andReturn([NSDate dateWithTimeIntervalSinceNow:kAccessTokenTimeToLive]);
  1604. OCMStub([mockResponse refreshToken]).andReturn(kRefreshToken);
  1605. }
  1606. /** @fn assertUserGoogle
  1607. @brief Asserts the given FIRUser matching the fake data returned by
  1608. @c expectGetAccountInfo:federatedID:displayName: .
  1609. @param user The user object to be verified.
  1610. */
  1611. - (void)assertUserGoogle:(FIRUser *)user {
  1612. XCTAssertNotNil(user);
  1613. XCTAssertEqualObjects(user.uid, kLocalID);
  1614. XCTAssertEqualObjects(user.displayName, kGoogleDisplayName);
  1615. XCTAssertEqual(user.providerData.count, 1u);
  1616. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  1617. XCTAssertEqualObjects(googleUserInfo.providerID, FIRGoogleAuthProviderID);
  1618. XCTAssertEqualObjects(googleUserInfo.uid, kGoogleID);
  1619. XCTAssertEqualObjects(googleUserInfo.displayName, kGoogleDisplayName);
  1620. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  1621. }
  1622. /** @fn assertUserFacebook
  1623. @brief Asserts the given FIRUser matching the fake data returned by
  1624. @c expectGetAccountInfo:federatedID:displayName: .
  1625. @param user The user object to be verified.
  1626. */
  1627. - (void)assertUserFacebook:(FIRUser *)user {
  1628. XCTAssertNotNil(user);
  1629. XCTAssertEqualObjects(user.uid, kLocalID);
  1630. XCTAssertEqualObjects(user.displayName, kFacebookDisplayName);
  1631. XCTAssertEqual(user.providerData.count, 1u);
  1632. id<FIRUserInfo> googleUserInfo = user.providerData[0];
  1633. XCTAssertEqualObjects(googleUserInfo.providerID, FIRFacebookAuthProviderID);
  1634. XCTAssertEqualObjects(googleUserInfo.uid, kFacebookID);
  1635. XCTAssertEqualObjects(googleUserInfo.displayName, kFacebookDisplayName);
  1636. XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
  1637. }
  1638. /** @fn expectGetAccountInfo:federatedID:displayName:
  1639. @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
  1640. data for a Google Sign-In user.
  1641. */
  1642. - (void)expectGetAccountInfo:(NSString *)providerId
  1643. federatedID:(NSString *)federatedID
  1644. displayName:(NSString *)displayName {
  1645. OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
  1646. .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
  1647. FIRGetAccountInfoResponseCallback callback) {
  1648. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1649. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1650. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1651. id mockGoogleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
  1652. OCMStub([mockGoogleUserInfo providerID]).andReturn(providerId);
  1653. OCMStub([mockGoogleUserInfo displayName]).andReturn(displayName);
  1654. OCMStub([mockGoogleUserInfo federatedID]).andReturn(federatedID);
  1655. OCMStub([mockGoogleUserInfo email]).andReturn(kGoogleEmail);
  1656. id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
  1657. OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
  1658. OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(displayName);
  1659. OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
  1660. .andReturn((@[ mockGoogleUserInfo ]));
  1661. id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
  1662. OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ mockGetAccountInfoResponseUser ]);
  1663. callback(mockGetAccountInfoResponse, nil);
  1664. });
  1665. });
  1666. }
  1667. /** @fn expectVerifyAssertionRequest:federatedID:displayName:profile:providerAccessToken:
  1668. @brief Expects a Verify Assertion request on the mock backend and calls back with fake account
  1669. data.
  1670. */
  1671. - (void)expectVerifyAssertionRequest:(NSString *)providerId
  1672. federatedID:(NSString *)federatedID
  1673. displayName:(NSString *)displayName
  1674. profile:(NSDictionary *)profile
  1675. providerIDToken:(nullable NSString *)providerIDToken
  1676. providerAccessToken:(NSString *)providerAccessToken {
  1677. OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
  1678. .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
  1679. FIRVerifyAssertionResponseCallback callback) {
  1680. XCTAssertEqualObjects(request.APIKey, kAPIKey);
  1681. XCTAssertEqualObjects(request.providerID, providerId);
  1682. XCTAssertEqualObjects(request.providerIDToken, providerIDToken);
  1683. XCTAssertEqualObjects(request.providerAccessToken, providerAccessToken);
  1684. XCTAssertTrue(request.returnSecureToken);
  1685. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1686. id mockVeriyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
  1687. OCMStub([mockVeriyAssertionResponse federatedID]).andReturn(federatedID);
  1688. OCMStub([mockVeriyAssertionResponse providerID]).andReturn(providerId);
  1689. OCMStub([mockVeriyAssertionResponse localID]).andReturn(kLocalID);
  1690. OCMStub([mockVeriyAssertionResponse displayName]).andReturn(displayName);
  1691. OCMStub([mockVeriyAssertionResponse profile]).andReturn(profile);
  1692. OCMStub([mockVeriyAssertionResponse username]).andReturn(kUserName);
  1693. [self stubTokensWithMockResponse:mockVeriyAssertionResponse];
  1694. callback(mockVeriyAssertionResponse, nil);
  1695. });
  1696. });
  1697. [self expectGetAccountInfo:providerId federatedID:federatedID displayName:displayName];
  1698. }
  1699. #if TARGET_OS_IOS
  1700. /** @fn expectVerifyPhoneNumberRequestWithPhoneNumber:error:
  1701. @brief Expects a verify phone numner request on the mock backend and calls back with fake
  1702. account data or an error.
  1703. @param phoneNumber Optionally; The phone number to use in the mocked response.
  1704. @param error Optionally; The error to return in the mocked response.
  1705. */
  1706. - (void)expectVerifyPhoneNumberRequestWithPhoneNumber:(nullable NSString *)phoneNumber
  1707. error:(nullable NSError*)error {
  1708. OCMExpect([_mockBackend verifyPhoneNumber:[OCMArg any] callback:[OCMArg any]])
  1709. .andCallBlock2(^(FIRVerifyPhoneNumberRequest *_Nullable request,
  1710. FIRVerifyPhoneNumberResponseCallback callback) {
  1711. XCTAssertEqualObjects(request.verificationID, kVerificationID);
  1712. XCTAssertEqualObjects(request.verificationCode, kVerificationCode);
  1713. XCTAssertEqualObjects(request.accessToken, kAccessToken);
  1714. dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
  1715. if (error) {
  1716. callback(nil, error);
  1717. return;
  1718. }
  1719. id mockVerifyPhoneNumberResponse = OCMClassMock([FIRVerifyPhoneNumberResponse class]);
  1720. OCMStub([mockVerifyPhoneNumberResponse phoneNumber]).andReturn(phoneNumber);
  1721. callback(mockVerifyPhoneNumberResponse, nil);
  1722. });
  1723. });
  1724. }
  1725. #endif
  1726. @end
  1727. NS_ASSUME_NONNULL_END