diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 09b1d6f6..221650b3 100644 --- a/.github/workflows/unit_tests.yml +++ b/.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' diff --git a/GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.h b/GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.h new file mode 100644 index 00000000..f8ce6128 --- /dev/null +++ b/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 + +#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 + +/// The test block which provides the response value. +@property(nonatomic) GIDAuthorizationFlowProcessorTestBlock testBlock; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.m b/GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/Fakes/GIDFakeAuthorizationFlowProcessor.m new file mode 100644 index 00000000..7077fd44 --- /dev/null +++ b/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 +#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 YES; +} + +- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)url { + return YES; +} + +- (void)cancelAuthenticationFlow { + NSAssert(NO, @"Not implemented."); +} + +@end diff --git a/GoogleSignIn/Tests/Unit/GIDSignInTest.m b/GoogleSignIn/Tests/Unit/GIDSignInTest.m index dd328dac..96256288 100644 --- a/GoogleSignIn/Tests/Unit/GIDSignInTest.m +++ b/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 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 @@ @interface GIDSignInTest : XCTestCase { // Fake for `GIDHTTPFetcher`. GIDFakeHTTPFetcher *_httpFetcher; + // Fake for `GIDAuthorizationFlowProcessor`. + GIDFakeAuthorizationFlowProcessor *_authorizationFlowProcessor; + // Fake for `GIDProfileDataFetcher`. GIDFakeProfileDataFetcher *_profileDataFetcher; @@ -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; @@ -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)]); @@ -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) { @@ -594,9 +570,8 @@ - (void)testSignOut { 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 @@ - (void)testPresentingViewControllerException { #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 @@ - (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; @@ -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) { @@ -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 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]; } diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayUITests(iOS)/DaysUntilBirthdayUITests_iOS.swift b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayUITests(iOS)/DaysUntilBirthdayUITests_iOS.swift index 607acbcb..6644e786 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayUITests(iOS)/DaysUntilBirthdayUITests_iOS.swift +++ b/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 }