Kaynağa Gözat

Hengyul/gid authorization flow processor fake (#312)

Co-authored-by: pinlu <pl1223@nyu.edu>
Co-authored-by: Matthew Mathias <mdmathias@google.com>
henryhl22321 2 yıl önce
ebeveyn
işleme
b7d49e8209

+ 2 - 2
.github/workflows/unit_tests.yml

@@ -14,7 +14,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        os: [macos-11, macos-12]
+        os: [macos-12]
         podspec: [GoogleSignIn.podspec, GoogleSignInSwiftSupport.podspec]
         flag: [
           "", 
@@ -40,7 +40,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        os: [macos-11, macos-12]
+        os: [macos-12]
         sdk: ['macosx', 'iphonesimulator']
         include:
           - sdk: 'macosx'

+ 48 - 0
GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/API/GIDAuthorizationFlowProcessor.h"
+
+@class OIDAuthorizationResponse;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// The block type providing the response for the method `startWithOptions:emmSupport:completion:`.
+///
+/// @param authorizationResponse The `OIDAuthorizationResponse` object returned on success.
+/// @param error An `NSError` returned on failure.
+typedef void(^GIDAuthorizationFlowProcessorFakeResponseProviderBlock)
+    (OIDAuthorizationResponse *_Nullable authorizationResponse, NSError *_Nullable error);
+
+/// The block type setting up response value for the method
+/// `startWithOptions:emmSupport:completion:`.
+///
+/// @param responseProvider The block which provides the response.
+typedef void (^GIDAuthorizationFlowProcessorTestBlock)
+    (GIDAuthorizationFlowProcessorFakeResponseProviderBlock responseProvider);
+
+/// The fake implementation of the protocol `GIDAuthorizationFlowProcessor`.
+@interface GIDFakeAuthorizationFlowProcessor : NSObject <GIDAuthorizationFlowProcessor>
+
+/// The test block which provides the response value.
+@property(nonatomic) GIDAuthorizationFlowProcessorTestBlock testBlock;
+
+@end
+
+NS_ASSUME_NONNULL_END
+

+ 51 - 0
GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.m

@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.h"
+
+#ifdef SWIFT_PACKAGE
+@import AppAuth;
+#else
+#import <AppAuth/AppAuth.h>
+#endif
+
+@implementation GIDFakeAuthorizationFlowProcessor
+
+- (void)startWithOptions:(GIDSignInInternalOptions *)options
+              emmSupport:(nullable NSString *)emmSupport
+              completion:(void (^)(OIDAuthorizationResponse *_Nullable authorizationResponse,
+                                   NSError *_Nullable error))completion {
+  NSAssert(self.testBlock != nil, @"Set the test block before invoking this method.");
+  
+  self.testBlock(^(OIDAuthorizationResponse *authorizationResponse, NSError *error) {
+    completion(authorizationResponse, error);
+  });
+}
+
+- (BOOL)isStarted {
+  NSAssert(NO, @"Not implemented.");
+  return NO;
+}
+
+- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)url {
+  return YES;
+}
+
+- (void)cancelAuthenticationFlow {
+  NSAssert(NO, @"Not implemented.");
+}
+
+@end

+ 52 - 77
GoogleSignIn/Tests/Unit/GIDSignInTest.m

@@ -26,7 +26,8 @@
 // Test module imports
 @import GoogleSignIn;
 
-#import "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/GIDAuthorizationFlowProcessor.h"
+#import "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/API/GIDAuthorizationFlowProcessor.h"
+#import "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.h"
 #import "GoogleSignIn/Sources/GIDEMMSupport.h"
 #import "GoogleSignIn/Sources/GIDGoogleUser_Private.h"
 #import "GoogleSignIn/Sources/GIDSignIn_Private.h"
@@ -37,7 +38,6 @@
 #import "GoogleSignIn/Sources/GIDProfileDataFetcher/API/GIDProfileDataFetcher.h"
 #import "GoogleSignIn/Sources/GIDProfileDataFetcher/Implementations/Fakes/GIDFakeProfileDataFetcher.h"
 
-
 #if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
 #import "GoogleSignIn/Sources/GIDEMMErrorHandler.h"
 #endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
@@ -104,9 +104,7 @@ static NSString * const kFakeUserGivenName = @"fake";
 static NSString * const kFakeUserFamilyName = @"username";
 static NSString * const kFakeUserPictureURL = @"fake_user_picture_url";
 
-static NSString * const kContinueURL = @"com.google.UnitTests:/oauth2callback";
-static NSString * const kContinueURLWithClientID = @"FakeClientID:/oauth2callback";
-static NSString * const kWrongSchemeURL = @"wrong.app:/oauth2callback";
+static NSString * const kRightPathURL = @"com.google.UnitTests:/oauth2callback";
 static NSString * const kWrongPathURL = @"com.google.UnitTests:/wrong_path";
 
 static NSString * const kEMMRestartAuthURL =
@@ -193,6 +191,9 @@ static NSString *const kNewScope = @"newScope";
   // Fake for `GIDHTTPFetcher`.
   GIDFakeHTTPFetcher *_httpFetcher;
   
+  // Fake for `GIDAuthorizationFlowProcessor`.
+  GIDFakeAuthorizationFlowProcessor *_authorizationFlowProcessor;
+
   // Fake for `GIDProfileDataFetcher`.
   GIDFakeProfileDataFetcher *_profileDataFetcher;
   
@@ -225,23 +226,9 @@ static NSString *const kNewScope = @"newScope";
   // The configuration to be used when testing `GIDSignIn`.
   GIDConfiguration *_configuration;
 
-  // The login hint to be used when testing `GIDSignIn`.
-  NSString *_hint;
-
   // The completion to be used when testing `GIDSignIn`.
   GIDSignInCompletion _completion;
 
-#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
-  // The saved presentingViewController from the authorization request.
-  UIViewController *_savedPresentingViewController;
-#elif TARGET_OS_OSX
-  // The saved presentingWindow from the authorization request.
-  NSWindow *_savedPresentingWindow;
-#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
-
-  // The saved authorization callback.
-  OIDAuthorizationCallback _savedAuthorizationCallback;
-
   // The saved token request.
   OIDTokenRequest *_savedTokenRequest;
 
@@ -279,14 +266,6 @@ static NSString *const kNewScope = @"newScope";
   OCMStub([_authorization initWithAuthState:OCMOCK_ANY]).andReturn(_authorization);
   _user = OCMStrictClassMock([GIDGoogleUser class]);
   _oidAuthorizationService = OCMStrictClassMock([OIDAuthorizationService class]);
-  OCMStub([_oidAuthorizationService
-      presentAuthorizationRequest:OCMOCK_ANY
-#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
-         presentingViewController:SAVE_TO_ARG_BLOCK(self->_savedPresentingViewController)
-#elif TARGET_OS_OSX
-                 presentingWindow:SAVE_TO_ARG_BLOCK(self->_savedPresentingWindow)
-#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
-                         callback:COPY_TO_ARG_BLOCK(self->_savedAuthorizationCallback)]);
   OCMStub([self->_oidAuthorizationService
       performTokenRequest:SAVE_TO_ARG_BLOCK(self->_savedTokenRequest)
                  callback:COPY_TO_ARG_BLOCK(self->_savedTokenCallback)]);
@@ -303,18 +282,15 @@ static NSString *const kNewScope = @"newScope";
   _keychainHandler = [[GIDFakeKeychainHandler alloc] init];
   
   _httpFetcher = [[GIDFakeHTTPFetcher alloc] init];
-  
+
   _profileDataFetcher = [[GIDFakeProfileDataFetcher alloc] init];
   
-  GIDAuthorizationFlowProcessor * authorizationFlowProcessor =
-      [[GIDAuthorizationFlowProcessor alloc] init];
+  _authorizationFlowProcessor = [[GIDFakeAuthorizationFlowProcessor alloc] init];
   
   _signIn = [[GIDSignIn alloc] initWithKeychainHandler:_keychainHandler
                                            httpFetcher:_httpFetcher
                                     profileDataFetcher:_profileDataFetcher
-                            authorizationFlowProcessor:authorizationFlowProcessor];
-
-  _hint = nil;
+                            authorizationFlowProcessor:_authorizationFlowProcessor];
 
   __weak GIDSignInTest *weakSelf = self;
   _completion = ^(GIDSignInResult *_Nullable signInResult, NSError * _Nullable error) {
@@ -594,9 +570,8 @@ static NSString *const kNewScope = @"newScope";
   XCTAssertNil([_keychainHandler loadAuthState]);
 }
 
-- (void)testNotHandleWrongScheme {
-  XCTAssertFalse([_signIn handleURL:[NSURL URLWithString:kWrongSchemeURL]],
-                 @"should not handle URL");
+- (void)testHandleRightPath {
+  XCTAssertTrue([_signIn handleURL:[NSURL URLWithString:kRightPathURL]]);
   XCTAssertFalse(_completionCalled, @"should not call delegate");
 }
 
@@ -784,7 +759,7 @@ static NSString *const kNewScope = @"newScope";
 #elif TARGET_OS_OSX
   XCTAssertThrows([_signIn signInWithPresentingWindow:_presentingWindow
 #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
-                                                 hint:_hint
+                                                 hint:nil
                                            completion:_completion]);
 }
 
@@ -819,7 +794,7 @@ static NSString *const kNewScope = @"newScope";
 #elif TARGET_OS_OSX
     [_signIn signInWithPresentingWindow:_presentingWindow
 #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
-                                   hint:_hint
+                                   hint:nil
                              completion:_completion];
   } @catch (NSException *exception) {
     threw = YES;
@@ -1038,17 +1013,35 @@ static NSString *const kNewScope = @"newScope";
                codeVerifier:nil
        additionalParameters:tokenResponse.request.additionalParameters];
   
-  // Set the response for `GIDProfileDataFetcher`.
-    GIDProfileDataFetcherTestBlock testBlock = ^(GIDProfileDataFetcherFakeResponseProvider
-                                                 responseProvider) {
-      GIDProfileData *profileData = [GIDProfileData testInstance];
-      responseProvider(profileData, nil);
+  // Set the response for the auth endpoint.
+  GIDAuthorizationFlowProcessorTestBlock authorizationFlowTestBlock;
+  if (modalCancel) {
+    NSError *error = [NSError errorWithDomain:OIDGeneralErrorDomain
+                                         code:OIDErrorCodeUserCanceledAuthorizationFlow
+                                     userInfo:nil];
+    authorizationFlowTestBlock =
+        ^(GIDAuthorizationFlowProcessorFakeResponseProviderBlock responseProvider) {
+      responseProvider(nil, error);
+    };
+  } else {
+    authorizationFlowTestBlock =
+        ^(GIDAuthorizationFlowProcessorFakeResponseProviderBlock responseProvider) {
+      responseProvider(authResponse, nil);
     };
+  }
+  _authorizationFlowProcessor.testBlock = authorizationFlowTestBlock;
+  
+  // Set the response for `GIDProfileDataFetcher`.
+  GIDProfileDataFetcherTestBlock profileDataFetcherTestBlock =
+      ^(GIDProfileDataFetcherFakeResponseProvider responseProvider) {
+    GIDProfileData *profileData = [GIDProfileData testInstance];
+    responseProvider(profileData, nil);
+  };
     
-    _profileDataFetcher.testBlock = testBlock;
+  _profileDataFetcher.testBlock = profileDataFetcherTestBlock;
 
   if (restoredSignIn) {
-    // maybeFetchToken
+    // Mock `maybeFetchToken:` method in `restorePreviousSignIn:` flow.
     [[[_authState expect] andReturn:tokenResponse] lastTokenResponse];
     [[[_authState expect] andReturn:tokenResponse] lastTokenResponse];
     if (oldAccessToken) {
@@ -1084,49 +1077,31 @@ static NSString *const kNewScope = @"newScope";
 #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
               completion:completion];
     } else {
+      // Mock `maybeFetchToken:` method in Sign in flow.
+      if (!(authError || modalCancel)) {
+        [[[_authState expect] andReturn:nil] lastTokenResponse];
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
+        // Corresponds to EMM support
+        [[[_authState expect] andReturn:authResponse] lastAuthorizationResponse];
+#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
+        [[[_authState expect] andReturn:nil] lastTokenResponse];
+        [[[_authState expect] andReturn:authResponse] lastAuthorizationResponse];
+        [[[_authState expect] andReturn:authResponse] lastAuthorizationResponse];
+      }
+      
 #if TARGET_OS_IOS || TARGET_OS_MACCATALYST
       [_signIn signInWithPresentingViewController:_presentingViewController
 #elif TARGET_OS_OSX
       [_signIn signInWithPresentingWindow:_presentingWindow
 #endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
-                                     hint:_hint
+                                     hint:nil
                                completion:completion];
     }
-
-    [_authState verify];
     
-    XCTAssertNotNil(_savedAuthorizationCallback);
-#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
-    XCTAssertEqual(_savedPresentingViewController, _presentingViewController);
-#elif TARGET_OS_OSX
-    XCTAssertEqual(_savedPresentingWindow, _presentingWindow);
-#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
-
-    // maybeFetchToken
-    if (!(authError || modalCancel)) {
-      [[[_authState expect] andReturn:nil] lastTokenResponse];
-#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
-      // Corresponds to EMM support
-      [[[_authState expect] andReturn:authResponse] lastAuthorizationResponse];
-#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST
-      [[[_authState expect] andReturn:nil] lastTokenResponse];
-      [[[_authState expect] andReturn:authResponse] lastAuthorizationResponse];
-      [[[_authState expect] andReturn:authResponse] lastAuthorizationResponse];
-    }
-
-    // Simulate auth endpoint response
-    if (modalCancel) {
-      NSError *error = [NSError errorWithDomain:OIDGeneralErrorDomain
-                                           code:OIDErrorCodeUserCanceledAuthorizationFlow
-                                       userInfo:nil];
-      _savedAuthorizationCallback(nil, error);
-    } else {
-      _savedAuthorizationCallback(authResponse, nil);
-    }
-
     if (authError || modalCancel) {
       return;
     }
+    
     [_authState verify];
   }
 

+ 3 - 3
Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayUITests(iOS)/DaysUntilBirthdayUITests_iOS.swift

@@ -141,16 +141,16 @@ extension DaysUntilBirthdayUITests_iOS {
     guard sampleApp
             .keyboards
             .element
-            .buttons["go"]
+            .buttons["return"]
             .waitForExistence(timeout: timeout) else {
-      XCTFail("Failed to find 'go' button")
+      XCTFail("Failed to find 'return' button")
       return false
     }
 
     sampleApp
       .secureTextFields["Enter your password"]
       .typeText(Credential.password.rawValue)
-    sampleApp.keyboards.element.buttons["go"].tap()
+    sampleApp.keyboards.element.buttons["return"].tap()
 
     return true
   }