FIRUserTests.m 93 KB

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