|
|
@@ -160,6 +160,36 @@ static NSString *const kGoogleAccessToken = @"GOOGLE_ACCESS_TOKEN";
|
|
|
*/
|
|
|
static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
|
|
|
|
|
|
+/** @var FIRAppleAuthProviderID
|
|
|
+ @brief The provider ID for Apple Sign-In.
|
|
|
+ */
|
|
|
+NSString *const FIRAppleAuthProviderID = @"apple.com";
|
|
|
+
|
|
|
+/** @var kAppleUD
|
|
|
+ @brief The fake user ID under Apple Sign-In.
|
|
|
+ */
|
|
|
+static NSString *const kAppleID = @"APPLE_ID";
|
|
|
+
|
|
|
+/** @var kAppleEmail
|
|
|
+ @brief The fake user email under Apple Sign-In.
|
|
|
+ */
|
|
|
+static NSString *const kAppleEmail = @"user@icloud.com";
|
|
|
+
|
|
|
+/** @var kAppleDisplayName
|
|
|
+ @brief The fake user display name under Apple Sign-In.
|
|
|
+ */
|
|
|
+static NSString *const kAppleDisplayName = @"Apple Doe";
|
|
|
+
|
|
|
+/** @var kAppleAccessToken
|
|
|
+ @brief The fake access token from Apple Sign-In.
|
|
|
+ */
|
|
|
+static NSString *const kAppleAccessToken = @"Apple_ACCESS_TOKEN";
|
|
|
+
|
|
|
+/** @var kAppleIDToken
|
|
|
+ @brief The fake ID token from Apple Sign-In.
|
|
|
+ */
|
|
|
+static NSString *const kAppleIDToken = @"APPLE_ID_TOKEN";
|
|
|
+
|
|
|
/** @var kCustomToken
|
|
|
@brief The fake custom token to sign in.
|
|
|
*/
|
|
|
@@ -321,6 +351,23 @@ static const NSTimeInterval kWaitInterval = .5;
|
|
|
return kGoogleProfile;
|
|
|
}
|
|
|
|
|
|
+/** @fn appleProfile
|
|
|
+ @brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
|
|
|
+ */
|
|
|
++ (NSDictionary *)appleProfile {
|
|
|
+ static NSDictionary *kAppleProfile = nil;
|
|
|
+ static dispatch_once_t onceToken;
|
|
|
+ dispatch_once(&onceToken, ^{
|
|
|
+ kAppleProfile = @{
|
|
|
+ @"iss" : @"https://accounts.apple.com\\",
|
|
|
+ @"email" : kAppleEmail,
|
|
|
+ @"given_name" : @"User",
|
|
|
+ @"family_name" : @"Doe"
|
|
|
+ };
|
|
|
+ });
|
|
|
+ return kAppleProfile;
|
|
|
+}
|
|
|
+
|
|
|
- (void)setUp {
|
|
|
[super setUp];
|
|
|
|
|
|
@@ -1374,6 +1421,54 @@ static const NSTimeInterval kWaitInterval = .5;
|
|
|
OCMVerifyAll(_mockBackend);
|
|
|
}
|
|
|
|
|
|
+/** @fn testSignInWithAppleCredentialSuccess
|
|
|
+ @brief Tests the flow of a successful @c signInWithCredential:completion: call
|
|
|
+ with an Apple Sign-In credential.
|
|
|
+ */
|
|
|
+- (void)testSignInWithAppleCredentialSuccess {
|
|
|
+ OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
|
|
|
+ .andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
|
|
|
+ FIRVerifyAssertionResponseCallback callback) {
|
|
|
+ XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
|
+ XCTAssertEqualObjects(request.providerID, FIRAppleAuthProviderID);
|
|
|
+ XCTAssertEqualObjects(request.providerIDToken, kAppleIDToken);
|
|
|
+ XCTAssertEqualObjects(request.providerAccessToken, kAppleAccessToken);
|
|
|
+ XCTAssertTrue(request.returnSecureToken);
|
|
|
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
|
+ id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
|
|
|
+ OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kAppleID);
|
|
|
+ OCMStub([mockVerifyAssertionResponse providerID]).andReturn(FIRAppleAuthProviderID);
|
|
|
+ OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
|
|
|
+ OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kAppleDisplayName);
|
|
|
+ OCMStub([mockVerifyAssertionResponse profile]).andReturn([[self class] appleProfile]);
|
|
|
+ OCMStub([mockVerifyAssertionResponse username]).andReturn(kDisplayName);
|
|
|
+ [self stubTokensWithMockResponse:mockVerifyAssertionResponse];
|
|
|
+ callback(mockVerifyAssertionResponse, nil);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ [self expectGetAccountInfoApple];
|
|
|
+ XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
|
|
|
+ [[FIRAuth auth] signOut:NULL];
|
|
|
+ FIRAuthCredential *appleCredential =
|
|
|
+ [FIROAuthProvider credentialWithProviderID:FIRAppleAuthProviderID IDToken:kAppleIDToken rawNonce:nil accessToken:kAppleAccessToken displayName:kAppleDisplayName];
|
|
|
+ [[FIRAuth auth]
|
|
|
+ signInWithCredential:appleCredential
|
|
|
+ completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
|
|
|
+ XCTAssertTrue([NSThread isMainThread]);
|
|
|
+ [self assertUserApple:authResult.user];
|
|
|
+ XCTAssertEqualObjects(authResult.additionalUserInfo.profile,
|
|
|
+ [[self class] appleProfile]);
|
|
|
+ XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
|
|
|
+ XCTAssertEqualObjects(authResult.additionalUserInfo.providerID,
|
|
|
+ FIRAppleAuthProviderID);
|
|
|
+ XCTAssertNil(error);
|
|
|
+ [expectation fulfill];
|
|
|
+ }];
|
|
|
+ [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
|
|
|
+ [self assertUserApple:[FIRAuth auth].currentUser];
|
|
|
+ OCMVerifyAll(_mockBackend);
|
|
|
+}
|
|
|
+
|
|
|
/** @fn testSignInAnonymouslySuccess
|
|
|
@brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
|
|
|
*/
|
|
|
@@ -2584,6 +2679,53 @@ static const NSTimeInterval kWaitInterval = .5;
|
|
|
XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
|
|
|
}
|
|
|
|
|
|
+/** @fn expectGetAccountInfoApple
|
|
|
+ @brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
|
|
|
+ data for a Apple Sign-In user.
|
|
|
+ */
|
|
|
+- (void)expectGetAccountInfoApple {
|
|
|
+ OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
|
|
|
+ .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
|
|
|
+ FIRGetAccountInfoResponseCallback callback) {
|
|
|
+ XCTAssertEqualObjects(request.APIKey, kAPIKey);
|
|
|
+ XCTAssertEqualObjects(request.accessToken, kAccessToken);
|
|
|
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
|
|
|
+ id mockAppleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
|
|
|
+ OCMStub([mockAppleUserInfo providerID]).andReturn(FIRAppleAuthProviderID);
|
|
|
+ OCMStub([mockAppleUserInfo displayName]).andReturn(kAppleDisplayName);
|
|
|
+ OCMStub([mockAppleUserInfo federatedID]).andReturn(kAppleID);
|
|
|
+ OCMStub([mockAppleUserInfo email]).andReturn(kAppleEmail);
|
|
|
+ id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
|
|
|
+ OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
|
|
|
+ OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
|
|
|
+ OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
|
|
|
+ .andReturn((@[ mockAppleUserInfo ]));
|
|
|
+ id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
|
|
|
+ OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
|
|
|
+ mockGetAccountInfoResponseUser
|
|
|
+ ]);
|
|
|
+ callback(mockGetAccountInfoResponse, nil);
|
|
|
+ });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/** @fn assertUserApple
|
|
|
+ @brief Asserts the given FIRUser matching the fake data returned by
|
|
|
+ @c expectGetAccountInfoApple.
|
|
|
+ @param user The user object to be verified.
|
|
|
+ */
|
|
|
+- (void)assertUserApple:(FIRUser *)user {
|
|
|
+ XCTAssertNotNil(user);
|
|
|
+ XCTAssertEqualObjects(user.uid, kLocalID);
|
|
|
+ XCTAssertEqualObjects(user.displayName, kDisplayName);
|
|
|
+ XCTAssertEqual(user.providerData.count, 1u);
|
|
|
+ id<FIRUserInfo> appleUserInfo = user.providerData[0];
|
|
|
+ XCTAssertEqualObjects(appleUserInfo.providerID, FIRAppleAuthProviderID);
|
|
|
+ XCTAssertEqualObjects(appleUserInfo.uid, kAppleID);
|
|
|
+ XCTAssertEqualObjects(appleUserInfo.displayName, kAppleDisplayName);
|
|
|
+ XCTAssertEqualObjects(appleUserInfo.email, kAppleEmail);
|
|
|
+}
|
|
|
+
|
|
|
/** @fn expectGetAccountInfoAnonymous
|
|
|
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
|
|
|
account data.
|