Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fake for GIDAuthorizationFlowProcessor #287

Open
wants to merge 16 commits into
base: refactorGSI
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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.");
Alex-4-Git marked this conversation as resolved.
Show resolved Hide resolved

self.testBlock(^(OIDAuthorizationResponse *authorizationResponse, NSError *error) {
completion(authorizationResponse, error);
});
}

- (BOOL)isStarted {
NSAssert(NO, @"Not implemented.");
return YES;
}

- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)url {
return YES;
}

- (void)cancelAuthenticationFlow {
NSAssert(NO, @"Not implemented.");
}

@end
131 changes: 53 additions & 78 deletions GoogleSignIn/Tests/Unit/GIDSignInTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -104,9 +104,7 @@
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 =
Expand Down Expand Up @@ -193,6 +191,9 @@ @interface GIDSignInTest : XCTestCase {
// Fake for `GIDHTTPFetcher`.
GIDFakeHTTPFetcher *_httpFetcher;

// Fake for `GIDAuthorizationFlowProcessor`.
GIDFakeAuthorizationFlowProcessor *_authorizationFlowProcessor;
Alex-4-Git marked this conversation as resolved.
Show resolved Hide resolved

// Fake for `GIDProfileDataFetcher`.
GIDFakeProfileDataFetcher *_profileDataFetcher;

Expand Down Expand Up @@ -225,23 +226,9 @@ @interface GIDSignInTest : XCTestCase {
// 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;

Expand Down Expand Up @@ -279,14 +266,6 @@ - (void)setUp {
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)]);
Expand All @@ -304,17 +283,14 @@ - (void)setUp {

_httpFetcher = [[GIDFakeHTTPFetcher alloc] init];

_profileDataFetcher = [[GIDFakeProfileDataFetcher alloc] init];
_authorizationFlowProcessor = [[GIDFakeAuthorizationFlowProcessor alloc] init];

GIDAuthorizationFlowProcessor * authorizationFlowProcessor =
[[GIDAuthorizationFlowProcessor alloc] init];
_profileDataFetcher = [[GIDFakeProfileDataFetcher 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) {
Expand All @@ -333,7 +309,7 @@ - (void)tearDown {
OCMVerifyAll(_tokenResponse);
OCMVerifyAll(_tokenRequest);
OCMVerifyAll(_user);
OCMVerifyAll(_oidAuthorizationService);
// OCMVerifyAll(_oidAuthorizationService);

#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
OCMVerifyAll(_presentingViewController);
Expand Down Expand Up @@ -594,9 +570,8 @@ - (void)testSignOut {
XCTAssertNil([_keychainHandler loadAuthState]);
}

- (void)testNotHandleWrongScheme {
Alex-4-Git marked this conversation as resolved.
Show resolved Hide resolved
XCTAssertFalse([_signIn handleURL:[NSURL URLWithString:kWrongSchemeURL]],
@"should not handle URL");
- (void)testHandleRightPath {
XCTAssertTrue([_signIn handleURL:[NSURL URLWithString:kRightPathURL]]);
XCTAssertFalse(_completionCalled, @"should not call delegate");
}

Expand Down Expand Up @@ -784,7 +759,7 @@ - (void)testPresentingViewControllerException {
#elif TARGET_OS_OSX
XCTAssertThrows([_signIn signInWithPresentingWindow:_presentingWindow
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
hint:_hint
hint:nil
completion:_completion]);
}

Expand Down Expand Up @@ -819,7 +794,7 @@ - (void)testSchemesNotSupportedException {
#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;
Expand Down Expand Up @@ -1038,17 +1013,35 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
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) {
Expand Down Expand Up @@ -1084,49 +1077,31 @@ - (void)OAuthLoginWithAddScopesFlow:(BOOL)addScopesFlow
#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
Alex-4-Git marked this conversation as resolved.
Show resolved Hide resolved
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];
}

Expand Down