FIRUserTests.m 88 KB

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