FIRUserTests.m 91 KB

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