@@ -228,6 +228,9 @@ @interface GIDSignInTest : XCTestCase {
228228 // Mock for |OIDAuthorizationService|
229229 id _oidAuthorizationService;
230230
231+ // Mock for |OIDExternalUserAgentSession|.
232+ id _authorizationFlow;
233+
231234 // Parameter saved from delegate call.
232235 NSError *_authError;
233236
@@ -332,14 +335,16 @@ - (void)setUp {
332335 });
333336 _user = OCMStrictClassMock ([GIDGoogleUser class ]);
334337 _oidAuthorizationService = OCMStrictClassMock ([OIDAuthorizationService class ]);
338+ _authorizationFlow = OCMProtocolMock (@protocol (OIDExternalUserAgentSession));
335339 OCMStub ([_oidAuthorizationService
336340 presentAuthorizationRequest: SAVE_TO_ARG_BLOCK (self ->_savedAuthorizationRequest)
337341#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
338342 presentingViewController:SAVE_TO_ARG_BLOCK (self->_savedPresentingViewController)
339343#elif TARGET_OS_OSX
340344 presentingWindow:SAVE_TO_ARG_BLOCK (self->_savedPresentingWindow)
341345#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
342- callback: COPY_TO_ARG_BLOCK (self ->_savedAuthorizationCallback)]);
346+ callback: COPY_TO_ARG_BLOCK (self ->_savedAuthorizationCallback)])
347+ .andReturn (_authorizationFlow);
343348 OCMStub ([self ->_oidAuthorizationService
344349 performTokenRequest: SAVE_TO_ARG_BLOCK (self ->_savedTokenRequest)
345350 originalAuthorizationResponse: [OCMArg any ]
@@ -379,6 +384,7 @@ - (void)tearDown {
379384 OCMVerifyAll (_authorization);
380385 OCMVerifyAll (_user);
381386 OCMVerifyAll (_oidAuthorizationService);
387+ OCMVerifyAll (_authorizationFlow);
382388
383389#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
384390 OCMVerifyAll (_presentingViewController);
@@ -1198,6 +1204,74 @@ - (void)testOAuthLogin_ModalCanceled {
11981204 XCTAssertEqual (_authError.code , kGIDSignInErrorCodeCanceled );
11991205}
12001206
1207+ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
1208+
1209+ - (void )testOAuthLogin_BackgroundedAuthFlowCanceledWhenAuthUIClears {
1210+ OCMStub ([_presentingViewController presentedViewController ]).andReturn (nil );
1211+
1212+ XCTestExpectation *completionExpectation =
1213+ [self expectationWithDescription: @" Completion should be called" ];
1214+ GIDSignInCompletion completion = ^(GIDSignInResult *_Nullable signInResult,
1215+ NSError *_Nullable error) {
1216+ [completionExpectation fulfill ];
1217+ self->_completion (signInResult, error);
1218+ };
1219+ [self beginInteractiveSignInWithCompletion: completion];
1220+
1221+ [[[_authorizationFlow expect ] andDo: ^(NSInvocation *invocation) {
1222+ self->_savedAuthorizationCallback (nil , [self authorizationFlowCancellationError ]);
1223+ }] cancel ];
1224+
1225+ [[NSNotificationCenter defaultCenter ]
1226+ postNotificationName: UIApplicationDidEnterBackgroundNotification object: nil ];
1227+ [[NSNotificationCenter defaultCenter ]
1228+ postNotificationName: UIApplicationDidBecomeActiveNotification object: nil ];
1229+
1230+ [self waitForExpectationsWithTimeout: 1 handler: nil ];
1231+ XCTAssertTrue (_completionCalled, @" should call delegate" );
1232+ XCTAssertEqual (_authError.code , kGIDSignInErrorCodeCanceled );
1233+ }
1234+
1235+ - (void )testOAuthLogin_BackgroundedAuthFlowIgnoresCompletedFlow {
1236+ OCMStub ([_presentingViewController presentedViewController ]).andReturn (nil );
1237+ [[_authorizationFlow reject ] cancel ];
1238+
1239+ XCTestExpectation *completionExpectation =
1240+ [self expectationWithDescription: @" Completion should be called" ];
1241+ GIDSignInCompletion completion = ^(GIDSignInResult *_Nullable signInResult,
1242+ NSError *_Nullable error) {
1243+ [completionExpectation fulfill ];
1244+ self->_completion (signInResult, error);
1245+ };
1246+ [self beginInteractiveSignInWithCompletion: completion];
1247+
1248+ [[NSNotificationCenter defaultCenter ]
1249+ postNotificationName: UIApplicationDidEnterBackgroundNotification object: nil ];
1250+ [[NSNotificationCenter defaultCenter ]
1251+ postNotificationName: UIApplicationDidBecomeActiveNotification object: nil ];
1252+ _savedAuthorizationCallback (nil , [self authorizationFlowCancellationError ]);
1253+
1254+ [self waitForExpectationsWithTimeout: 1 handler: nil ];
1255+ [self waitForInterruptedAuthFlowDelay ];
1256+ XCTAssertTrue (_completionCalled, @" should call delegate" );
1257+ XCTAssertEqual (_authError.code , kGIDSignInErrorCodeCanceled );
1258+ }
1259+
1260+ - (void )testOAuthLogin_DidBecomeActiveWithoutBackgroundDoesNotCancel {
1261+ OCMStub ([_presentingViewController presentedViewController ]).andReturn (nil );
1262+ [[_authorizationFlow reject ] cancel ];
1263+
1264+ [self beginInteractiveSignInWithCompletion: _completion];
1265+
1266+ [[NSNotificationCenter defaultCenter ]
1267+ postNotificationName: UIApplicationDidBecomeActiveNotification object: nil ];
1268+
1269+ [self waitForInterruptedAuthFlowDelay ];
1270+ XCTAssertFalse (_completionCalled, @" should not call delegate" );
1271+ }
1272+
1273+ #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
1274+
12011275- (void )testOAuthLogin_KeychainError {
12021276 // This error is going be overidden by `-[GIDSignIn errorWithString:code:]`
12031277 // We just need to fill in the error so that happens.
@@ -2050,6 +2124,33 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
20502124
20512125#pragma mark - Private Helpers
20522126
2127+ #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
2128+
2129+ - (void )beginInteractiveSignInWithCompletion:(nullable GIDSignInCompletion)completion {
2130+ [_signIn signInWithPresentingViewController: _presentingViewController completion: completion];
2131+ XCTAssertNotNil (_savedAuthorizationRequest);
2132+ XCTAssertNotNil (_savedAuthorizationCallback);
2133+ XCTAssertEqual (_savedPresentingViewController, _presentingViewController);
2134+ }
2135+
2136+ - (NSError *)authorizationFlowCancellationError {
2137+ return [NSError errorWithDomain: OIDGeneralErrorDomain
2138+ code: OIDErrorCodeUserCanceledAuthorizationFlow
2139+ userInfo: nil ];
2140+ }
2141+
2142+ - (void )waitForInterruptedAuthFlowDelay {
2143+ XCTestExpectation *expectation =
2144+ [self expectationWithDescription: @" Interrupted auth flow delay" ];
2145+ dispatch_after (dispatch_time (DISPATCH_TIME_NOW , (int64_t )(1 * NSEC_PER_SEC )),
2146+ dispatch_get_main_queue (), ^{
2147+ [expectation fulfill ];
2148+ });
2149+ [self waitForExpectationsWithTimeout: 2 handler: nil ];
2150+ }
2151+
2152+ #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
2153+
20532154- (NSDictionary <NSString *, NSString *> *)
20542155 additionalParametersWithEMMPasscodeInfoRequired: (BOOL )emmPasscodeInfoRequired
20552156 claimsAsJSONRequired: (BOOL )claimsAsJSONRequired {
0 commit comments