diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md index ae8b554ddeb8..9a8fa677fe0f 100644 --- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.2.5 + +* Updates native header visibility for Swift testing. + ## 6.2.4 * Updates to Pigeon 26. diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.m b/packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.m deleted file mode 100644 index 87bf2777c2c9..000000000000 --- a/packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.m +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#if TARGET_OS_OSX -@import FlutterMacOS; -#else -@import Flutter; -#endif - -@import XCTest; -@import google_sign_in_ios; -#if __has_include() -@import google_sign_in_ios.Test; -#endif -@import GoogleSignIn; - -/// Test implementation of @c FSIViewProvider. -@interface TestViewProvider : NSObject -#if TARGET_OS_OSX -/// The view containing the Flutter content. -@property(nonatomic, nullable) NSView *view; -#else -/// The view controller containing the Flutter content. -@property(nonatomic, nullable) UIViewController *viewController; -#endif -@end - -@implementation TestViewProvider -@end - -/// Test implementation of @c FSIGIDSignIn. -@interface TestSignIn : NSObject - -// To cause methods to throw an exception. -@property(nonatomic, nullable) NSException *exception; - -// Results to use in completion callbacks. -@property(nonatomic, nullable) NSObject *user; -@property(nonatomic, nullable) NSError *error; -@property(nonatomic, nullable) NSObject *signInResult; - -// Passed parameters. -@property(nonatomic, copy, nullable) NSString *hint; -@property(nonatomic, copy, nullable) NSArray *additionalScopes; -@property(nonatomic, copy, nullable) NSString *nonce; -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST -@property(nonatomic, nullable) UIViewController *presentingViewController; -#else -@property(nonatomic, nullable) NSWindow *presentingWindow; -#endif - -/// Whether @c signOut was called. -@property(nonatomic) BOOL signOutCalled; - -@end - -@implementation TestSignIn -@synthesize configuration; - -- (BOOL)handleURL:(NSURL *)url { - return YES; -} - -- (void)restorePreviousSignInWithCompletion: - (nullable void (^)(NSObject *_Nullable user, - NSError *_Nullable error))completion { - if (self.exception) { - @throw self.exception; - } - if (completion) { - completion(self.user, self.user ? nil : self.error); - } -} - -- (void)signOut { - self.signOutCalled = YES; -} - -- (void)disconnectWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { - if (self.exception) { - @throw self.exception; - } - if (completion) { - completion(self.error); - } -} - -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST -- (void)signInWithPresentingViewController:(UIViewController *)presentingViewController - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - nonce:(nullable NSString *)nonce - completion:(nullable void (^)( - NSObject *_Nullable signInResult, - NSError *_Nullable error))completion { - if (self.exception) { - @throw self.exception; - } - self.presentingViewController = presentingViewController; - self.hint = hint; - self.additionalScopes = additionalScopes; - self.nonce = nonce; - if (completion) { - completion(self.signInResult, self.signInResult ? nil : self.error); - } -} -#else -- (void)signInWithPresentingWindow:(NSWindow *)presentingWindow - hint:(nullable NSString *)hint - additionalScopes:(nullable NSArray *)additionalScopes - nonce:(nullable NSString *)nonce - completion: - (nullable void (^)(NSObject *_Nullable signInResult, - NSError *_Nullable error))completion { - if (self.exception) { - @throw self.exception; - } - self.presentingWindow = presentingWindow; - self.hint = hint; - self.additionalScopes = additionalScopes; - self.nonce = nonce; - if (completion) { - completion(self.signInResult, self.signInResult ? nil : self.error); - } -} -#endif - -@end - -/// Test implementation of @c FSIGIDProfileData. -@interface TestProfileData : NSObject -@property(nonatomic, readwrite) NSString *email; -@property(nonatomic, readwrite) NSString *name; -/// A URL to return from imageURLWithDimension:. -@property(nonatomic) NSURL *imageURL; -@end - -@implementation TestProfileData { -} - -- (BOOL)hasImage { - return self.imageURL != nil; -} - -- (NSURL *)imageURLWithDimension:(NSUInteger)dimension { - return self.imageURL; -} -@end - -/// Test implementation of @c FSIGIDToken. -@interface TestToken : NSObject -@property(nonatomic, readwrite) NSString *tokenString; -@property(nonatomic, readwrite) NSDate *expirationDate; -@end - -@implementation TestToken -@end - -/// Test implementation of @c FSIGIDSignInResult. -@interface TestSignInResult : NSObject -@property(nonatomic, readwrite) NSObject *user; -@property(nonatomic, readwrite, nullable) NSString *serverAuthCode; -@end - -@implementation TestSignInResult -@end - -/// Test implementation of @c FSIGIDGoogleUser. -@interface TestGoogleUser : NSObject -@property(nonatomic, readwrite, nullable) NSString *userID; -@property(nonatomic, readwrite, nullable) NSObject *profile; -@property(nonatomic, readwrite, nullable) NSArray *grantedScopes; -@property(nonatomic, readwrite) NSObject *accessToken; -@property(nonatomic, readwrite) NSObject *refreshToken; -@property(nonatomic, readwrite, nullable) NSObject *idToken; - -/// An exception to throw from methods. -@property(nonatomic, nullable) NSException *exception; - -/// The result to return from addScopes:presentingViewController:completion:. -@property(nonatomic, nullable) NSObject *result; - -/// The error to return from methods. -@property(nonatomic, nullable) NSError *error; - -// Values passed as parameters. -@property(nonatomic, copy, nullable) NSArray *requestedScopes; -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST -@property(nonatomic, nullable) UIViewController *presentingViewController; -#else -@property(nonatomic, nullable) NSWindow *presentingWindow; -#endif -@end - -@implementation TestGoogleUser - -- (void)refreshTokensIfNeededWithCompletion:(void (^)(NSObject *_Nullable user, - NSError *_Nullable error))completion { - if (self.exception) { - @throw self.exception; - } - if (completion) { - completion(self.error ? nil : self, self.error); - } -} - -#if TARGET_OS_IOS || TARGET_OS_MACCATALYST - -- (void)addScopes:(NSArray *)scopes - presentingViewController:(UIViewController *)presentingViewController - completion:(nullable void (^)(NSObject *_Nullable result, - NSError *_Nullable error))completion { - self.requestedScopes = scopes; - self.presentingViewController = presentingViewController; - if (self.exception) { - @throw self.exception; - } - if (completion) { - completion(self.error ? nil : self.result, self.error); - } -} - -#elif TARGET_OS_OSX - -- (void)addScopes:(NSArray *)scopes - presentingWindow:(NSWindow *)presentingWindow - completion:(nullable void (^)(NSObject *_Nullable result, - NSError *_Nullable error))completion { - self.requestedScopes = scopes; - self.presentingWindow = presentingWindow; - if (self.exception) { - @throw self.exception; - } - if (completion) { - completion(self.error ? nil : self.result, self.error); - } -} - -#endif - -@end - -#pragma mark - - -@interface FLTGoogleSignInPluginTest : XCTestCase - -@property(nonatomic) TestViewProvider *viewProvider; -@property(nonatomic) FLTGoogleSignInPlugin *plugin; -@property(nonatomic) TestSignIn *fakeSignIn; -@property(nonatomic, copy) NSDictionary *googleServiceInfo; - -@end - -@implementation FLTGoogleSignInPluginTest - -- (void)setUp { - [super setUp]; - self.viewProvider = [[TestViewProvider alloc] init]; - - self.fakeSignIn = [[TestSignIn alloc] init]; - - self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:self.fakeSignIn - viewProvider:self.viewProvider]; - - NSString *plistPath = - [[NSBundle bundleForClass:[self class]] pathForResource:@"GoogleService-Info" - ofType:@"plist"]; - if (plistPath) { - self.googleServiceInfo = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; - } -} - -- (void)testSignOut { - FlutterError *error; - [self.plugin signOutWithError:&error]; - XCTAssertTrue(self.fakeSignIn.signOutCalled); - XCTAssertNil(error); -} - -- (void)testDisconnect { - XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; - [self.plugin disconnectWithCompletion:^(FlutterError *error) { - XCTAssertNil(error); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -#pragma mark - Configure - -- (void)testInitNoClientIdNoError { - // Init plugin without GoogleService-Info.plist. - self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:self.fakeSignIn - viewProvider:self.viewProvider - googleServiceProperties:nil]; - - // init call does not provide a clientId. - FSIPlatformConfigurationParams *params = [FSIPlatformConfigurationParams makeWithClientId:nil - serverClientId:nil - hostedDomain:nil]; - - FlutterError *error; - [self.plugin configureWithParameters:params error:&error]; - XCTAssertNil(error); -} - -- (void)testInitGoogleServiceInfoPlist { - self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:self.fakeSignIn - viewProvider:self.viewProvider - googleServiceProperties:self.googleServiceInfo]; - FSIPlatformConfigurationParams *params = - [FSIPlatformConfigurationParams makeWithClientId:nil - serverClientId:nil - hostedDomain:@"example.com"]; - - FlutterError *error; - [self.plugin configureWithParameters:params error:&error]; - XCTAssertNil(error); - XCTAssertEqualObjects(self.fakeSignIn.configuration.hostedDomain, @"example.com"); - // Set in example app GoogleService-Info.plist. - XCTAssertEqualObjects( - self.fakeSignIn.configuration.clientID, - @"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"); - XCTAssertEqualObjects(self.fakeSignIn.configuration.serverClientID, @"YOUR_SERVER_CLIENT_ID"); -} - -- (void)testInitDynamicClientIdNullDomain { - // Init plugin without GoogleService-Info.plist. - self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:self.fakeSignIn - viewProvider:self.viewProvider - googleServiceProperties:nil]; - - FSIPlatformConfigurationParams *params = - [FSIPlatformConfigurationParams makeWithClientId:@"mockClientId" - serverClientId:nil - hostedDomain:nil]; - - FlutterError *error; - [self.plugin configureWithParameters:params error:&error]; - XCTAssertNil(error); - XCTAssertNil(self.fakeSignIn.configuration.hostedDomain); - XCTAssertEqualObjects(self.fakeSignIn.configuration.clientID, @"mockClientId"); - XCTAssertNil(self.fakeSignIn.configuration.serverClientID); -} - -- (void)testInitDynamicServerClientIdNullDomain { - self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:self.fakeSignIn - viewProvider:self.viewProvider - googleServiceProperties:self.googleServiceInfo]; - FSIPlatformConfigurationParams *params = - [FSIPlatformConfigurationParams makeWithClientId:nil - serverClientId:@"mockServerClientId" - hostedDomain:nil]; - - FlutterError *error; - [self.plugin configureWithParameters:params error:&error]; - XCTAssertNil(error); - XCTAssertNil(self.fakeSignIn.configuration.hostedDomain); - // Set in example app GoogleService-Info.plist. - XCTAssertEqualObjects( - self.fakeSignIn.configuration.clientID, - @"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"); - // Overridden by params. - XCTAssertEqualObjects(self.fakeSignIn.configuration.serverClientID, @"mockServerClientId"); -} - -- (void)testInitInfoPlist { - FSIPlatformConfigurationParams *params = - [FSIPlatformConfigurationParams makeWithClientId:nil - serverClientId:nil - hostedDomain:@"example.com"]; - - FlutterError *error; - [self.plugin configureWithParameters:params error:&error]; - XCTAssertNil(error); - // No configuration should be set, allowing the SDK to use its default behavior - // (which is to load configuration information from Info.plist). - XCTAssertNil(self.fakeSignIn.configuration); -} - -#pragma mark - restorePreviousSignIn - -- (void)testSignInSilently { - TestGoogleUser *fakeUser = [[TestGoogleUser alloc] init]; - fakeUser.userID = @"mockID"; - self.fakeSignIn.user = fakeUser; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin restorePreviousSignInWithCompletion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.error); - XCTAssertNotNil(result.success); - FSIUserData *user = result.success.user; - XCTAssertNil(user.displayName); - XCTAssertNil(user.email); - XCTAssertEqualObjects(user.userId, @"mockID"); - XCTAssertNil(user.photoUrl); - XCTAssertNil(result.success.accessToken); - XCTAssertNil(result.success.serverAuthCode); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRestorePreviousSignInWithError { - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeHasNoAuthInKeychain - userInfo:nil]; - self.fakeSignIn.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin restorePreviousSignInWithCompletion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, FSIGoogleSignInErrorCodeNoAuthInKeychain); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -#pragma mark - signIn - -- (void)testSignIn { - self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:self.fakeSignIn - viewProvider:self.viewProvider - googleServiceProperties:self.googleServiceInfo]; - TestGoogleUser *fakeUser = [[TestGoogleUser alloc] init]; - fakeUser.userID = @"mockID"; - TestProfileData *fakeUserProfile = [[TestProfileData alloc] init]; - fakeUserProfile.name = @"mockDisplay"; - fakeUserProfile.email = @"mock@example.com"; - fakeUserProfile.imageURL = [NSURL URLWithString:@"https://example.com/profile.png"]; - - NSString *accessToken = @"mockAccessToken"; - NSString *serverAuthCode = @"mockAuthCode"; - fakeUser.profile = fakeUserProfile; - TestToken *fakeAccessToken = [[TestToken alloc] init]; - fakeAccessToken.tokenString = accessToken; - fakeUser.accessToken = fakeAccessToken; - - TestSignInResult *fakeSignInResult = [[TestSignInResult alloc] init]; - fakeSignInResult.user = fakeUser; - fakeSignInResult.serverAuthCode = serverAuthCode; - - self.fakeSignIn.signInResult = fakeSignInResult; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin signInWithScopeHint:@[] - nonce:nil - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - FSIUserData *user = result.success.user; - XCTAssertEqualObjects(user.displayName, @"mockDisplay"); - XCTAssertEqualObjects(user.email, @"mock@example.com"); - XCTAssertEqualObjects(user.userId, @"mockID"); - XCTAssertEqualObjects(user.photoUrl, @"https://example.com/profile.png"); - XCTAssertEqualObjects(result.success.accessToken, accessToken); - XCTAssertEqualObjects(result.success.serverAuthCode, serverAuthCode); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testSignInWithScopeHint { - FlutterError *initializationError; - [self.plugin configureWithParameters:[FSIPlatformConfigurationParams makeWithClientId:nil - serverClientId:nil - hostedDomain:nil] - error:&initializationError]; - XCTAssertNil(initializationError); - - TestGoogleUser *fakeUser = [[TestGoogleUser alloc] init]; - fakeUser.userID = @"mockID"; - TestSignInResult *fakeSignInResult = [[TestSignInResult alloc] init]; - fakeSignInResult.user = fakeUser; - - NSArray *requestedScopes = @[ @"scope1", @"scope2" ]; - self.fakeSignIn.signInResult = fakeSignInResult; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin signInWithScopeHint:requestedScopes - nonce:nil - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.error); - XCTAssertEqualObjects(result.success.user.userId, @"mockID"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; - - XCTAssertTrue([[NSSet setWithArray:self.fakeSignIn.additionalScopes] - isEqualToSet:[NSSet setWithArray:requestedScopes]]); -} - -- (void)testSignInWithNonce { - FlutterError *initializationError; - [self.plugin configureWithParameters:[FSIPlatformConfigurationParams makeWithClientId:nil - serverClientId:nil - hostedDomain:nil] - error:&initializationError]; - XCTAssertNil(initializationError); - - TestGoogleUser *fakeUser = [[TestGoogleUser alloc] init]; - fakeUser.userID = @"mockID"; - TestSignInResult *fakeSignInResult = [[TestSignInResult alloc] init]; - fakeSignInResult.user = fakeUser; - - NSString *nonce = @"A nonce"; - self.fakeSignIn.signInResult = fakeSignInResult; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin signInWithScopeHint:@[] - nonce:nonce - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.error); - XCTAssertEqualObjects(result.success.user.userId, @"mockID"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; - - XCTAssertEqualObjects(self.fakeSignIn.nonce, nonce); -} - -- (void)testSignInAlreadyGranted { - TestGoogleUser *fakeUser = [[TestGoogleUser alloc] init]; - fakeUser.userID = @"mockID"; - TestSignInResult *fakeSignInResult = [[TestSignInResult alloc] init]; - fakeSignInResult.user = fakeUser; - - self.fakeSignIn.signInResult = fakeSignInResult; - - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeScopesAlreadyGranted - userInfo:nil]; - self.fakeSignIn.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin signInWithScopeHint:@[] - nonce:nil - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.error); - XCTAssertEqualObjects(result.success.user.userId, @"mockID"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testSignInError { - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeCanceled - userInfo:nil]; - self.fakeSignIn.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin signInWithScopeHint:@[] - nonce:nil - completion:^(FSISignInResult *result, FlutterError *error) { - // Known errors from the SDK are returned as structured data, not - // FlutterError. - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, FSIGoogleSignInErrorCodeCanceled); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testSignInExceptionReturnsError { - self.fakeSignIn.exception = [NSException exceptionWithName:@"MockName" - reason:@"MockReason" - userInfo:nil]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin signInWithScopeHint:@[] - nonce:nil - completion:^(FSISignInResult *result, FlutterError *error) { - // Unexpected errors, such as runtime exceptions, are returned as - // FlutterError. - XCTAssertNil(result); - XCTAssertEqualObjects(error.code, @"google_sign_in"); - XCTAssertEqualObjects(error.message, @"MockReason"); - XCTAssertEqualObjects(error.details, @"MockName"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -#pragma mark - refreshedAuthorizationTokens - -- (void)testRefreshTokens { - TestGoogleUser *fakeUser = [self addSignedInUser]; - // TestGoogleUser passes itself as the result's user property, so set the - // fake result data on this object. - TestToken *fakeIDToken = [[TestToken alloc] init]; - fakeIDToken.tokenString = @"mockIdToken"; - fakeUser.idToken = fakeIDToken; - - TestToken *fakeAccessToken = [[TestToken alloc] init]; - fakeAccessToken.tokenString = @"mockAccessToken"; - fakeUser.accessToken = fakeAccessToken; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin - refreshedAuthorizationTokensForUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.error); - XCTAssertEqualObjects(result.success.user.idToken, @"mockIdToken"); - XCTAssertEqualObjects(result.success.accessToken, - @"mockAccessToken"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRefreshTokensUnkownUser { - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin - refreshedAuthorizationTokensForUser:@"unknownUser" - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, - FSIGoogleSignInErrorCodeUserMismatch); - XCTAssertEqualObjects(result.error.message, - @"The user is no longer signed in."); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRefreshTokensNoAuthKeychainError { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeHasNoAuthInKeychain - userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin refreshedAuthorizationTokensForUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, - FSIGoogleSignInErrorCodeNoAuthInKeychain); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRefreshTokensCancelledError { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeCanceled - userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin refreshedAuthorizationTokensForUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, - FSIGoogleSignInErrorCodeCanceled); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRefreshTokensURLError { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:NSURLErrorDomain - code:NSURLErrorTimedOut - userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin refreshedAuthorizationTokensForUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(result.error); - XCTAssertNil(result.success); - NSString *expectedCode = [NSString - stringWithFormat:@"%@: %ld", NSURLErrorDomain, - NSURLErrorTimedOut]; - XCTAssertEqualObjects(error.code, expectedCode); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRefreshTokensUnknownError { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:@"BogusDomain" code:42 userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin refreshedAuthorizationTokensForUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(result.success); - XCTAssertEqualObjects(error.code, @"BogusDomain: 42"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -#pragma mark - addScopes - -- (void)testRequestScopesPassesScopes { - TestGoogleUser *fakeUser = [self addSignedInUser]; - // Create a different instance to return in the result, to avoid a retain cycle. - TestGoogleUser *fakeResultUser = [[TestGoogleUser alloc] init]; - fakeResultUser.userID = fakeUser.userID; - TestSignInResult *fakeSignInResult = [[TestSignInResult alloc] init]; - fakeSignInResult.user = fakeResultUser; - fakeUser.result = fakeSignInResult; - - NSArray *scopes = @[ @"mockScope1" ]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin addScopes:@[ @"mockScope1" ] - forUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNotNil(result.success); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; - XCTAssertEqual(fakeUser.requestedScopes.firstObject, scopes.firstObject); -} - -- (void)testRequestScopesResultErrorIfNotSignedIn { - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin addScopes:@[ @"mockScope1" ] - forUser:@"unknownUser" - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, FSIGoogleSignInErrorCodeUserMismatch); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRequestScopesIfNoMissingScope { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeScopesAlreadyGranted - userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin addScopes:@[ @"mockScope1" ] - forUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, FSIGoogleSignInErrorCodeScopesAlreadyGranted); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRequestScopesResultErrorIfMismatchingUser { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:kGIDSignInErrorDomain - code:kGIDSignInErrorCodeMismatchWithCurrentUser - userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin addScopes:@[ @"mockScope1" ] - forUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(error); - XCTAssertNil(result.success); - XCTAssertEqual(result.error.type, FSIGoogleSignInErrorCodeUserMismatch); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRequestScopesWithUnknownError { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - NSError *sdkError = [NSError errorWithDomain:@"BogusDomain" code:42 userInfo:nil]; - fakeUser.error = sdkError; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin addScopes:@[ @"mockScope1" ] - forUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(result); - XCTAssertEqualObjects(error.code, @"BogusDomain: 42"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -- (void)testRequestScopesException { - TestGoogleUser *fakeUser = [self addSignedInUser]; - - fakeUser.exception = [NSException exceptionWithName:@"MockName" - reason:@"MockReason" - userInfo:nil]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"completion called"]; - [self.plugin addScopes:@[] - forUser:fakeUser.userID - completion:^(FSISignInResult *result, FlutterError *error) { - XCTAssertNil(result); - XCTAssertEqualObjects(error.code, @"request_scopes"); - XCTAssertEqualObjects(error.message, @"MockReason"); - XCTAssertEqualObjects(error.details, @"MockName"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - -#pragma mark - Utils - -- (TestGoogleUser *)addSignedInUser { - NSString *identifier = @"fakeID"; - TestGoogleUser *user = [[TestGoogleUser alloc] init]; - user.userID = identifier; - self.plugin.usersByIdentifier[identifier] = user; - return user; -} - -@end diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.swift b/packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.swift new file mode 100644 index 000000000000..d83753726cf0 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_ios/darwin/Tests/GoogleSignInTests.swift @@ -0,0 +1,724 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import GoogleSignIn +import Testing + +@testable import google_sign_in_ios + +#if os(OSX) + import FlutterMacOS +#else + import Flutter +#endif + +// Test implementation of FSIViewProvider. +class TestViewProvider: NSObject, FSIViewProvider { + #if os(OSX) + // The view containing the Flutter content. + var view: NSView? + #else + // The view controller containing the Flutter content. + var viewController: UIViewController? + #endif +} + +// Test implementation of FSIGIDSignIn. +class TestSignIn: NSObject, FSIGIDSignIn { + var configuration: GIDConfiguration? + + // To cause methods to throw an exception. + var exception: NSException? + + // Results to use in completion callbacks. + var user: (any FSIGIDGoogleUser)? + var error: Error? + var signInResult: (any FSIGIDSignInResult)? + + // Passed parameters. + var hint: String? + var additionalScopes: [String]? + var nonce: String? + #if os(iOS) || targetEnvironment(macCatalyst) + var presentingViewController: UIViewController? + #else + var presentingWindow: NSWindow? + #endif + + // Whether signOut was called. + var signOutCalled = false + + func handle(_ url: URL) -> Bool { + return true + } + + func restorePreviousSignIn(completion: (((any FSIGIDGoogleUser)?, Error?) -> Void)?) { + if let exception = exception { + exception.raise() + } + if let user { + completion?(user, nil) + } else { + completion?(nil, error) + } + } + + func signOut() { + signOutCalled = true + } + + func disconnect(completion: ((Error?) -> Void)?) { + if let exception = exception { + exception.raise() + } + completion?(error) + } + + #if os(iOS) || targetEnvironment(macCatalyst) + func signIn( + withPresenting presentingViewController: UIViewController, + hint: String?, + additionalScopes: [String]?, + nonce: String?, + completion: ((FSIGIDSignInResult?, Error?) -> Void)? + ) { + if let exception = exception { + exception.raise() + } + self.presentingViewController = presentingViewController + self.hint = hint + self.additionalScopes = additionalScopes + self.nonce = nonce + if let signInResult { + completion?(signInResult, nil) + } else { + completion?(nil, error) + } + } + #else + func signIn( + withPresenting presentingWindow: NSWindow, + hint: String?, + additionalScopes: [String]?, + nonce: String?, + completion: (((any FSIGIDSignInResult)?, Error?) -> Void)? + ) { + if let exception = exception { + exception.raise() + } + self.presentingWindow = presentingWindow + self.hint = hint + self.additionalScopes = additionalScopes + self.nonce = nonce + if let signInResult { + completion?(signInResult, nil) + } else { + completion?(nil, error) + } + } + #endif +} + +// Test implementation of FSIGIDProfileData. +class TestProfileData: NSObject, FSIGIDProfileData { + var email: String + var name: String + // A URL to return from imageURLWithDimension:. + var imageURL: URL? + + init(name: String, email: String, imageURL: URL?) { + self.name = name + self.email = email + self.imageURL = imageURL + } + + var hasImage: Bool { + return imageURL != nil + } + + func imageURL(withDimension dimension: UInt) -> URL? { + return imageURL + } +} + +// Test implementation of FSIGIDToken. +final class TestToken: NSObject, FSIGIDToken { + let tokenString: String + let expirationDate: Date? + + init(_ token: String, expiration: Date? = nil) { + tokenString = token + expirationDate = expiration + } +} + +// Test implementation of FSIGIDSignInResult. +class TestSignInResult: NSObject, FSIGIDSignInResult { + var user: any FSIGIDGoogleUser + var serverAuthCode: String? + + init(user: any FSIGIDGoogleUser, serverAuthCode: String? = nil) { + self.user = user + self.serverAuthCode = serverAuthCode + } +} + +// Test implementation of FSIGIDGoogleUser. +class TestGoogleUser: NSObject, FSIGIDGoogleUser { + var userID: String? + var profile: (any FSIGIDProfileData)? + var grantedScopes: [String]? + var accessToken: any FSIGIDToken = TestToken("Access") + var refreshToken: any FSIGIDToken = TestToken("Refresh") + var idToken: (any FSIGIDToken)? + + // An exception to throw from methods. + var exception: NSException? + + // The result to return from addScopes:presentingViewController:completion:. + var result: (any FSIGIDSignInResult)? + + // The error to return from methods. + var error: Error? + + // Values passed as parameters. + var requestedScopes: [String]? + #if os(iOS) || targetEnvironment(macCatalyst) + var presentingViewController: UIViewController? + #else + var presentingWindow: NSWindow? + #endif + + init(_ userIdentifier: String) { + userID = userIdentifier + } + + func refreshTokensIfNeeded(completion: @escaping ((any FSIGIDGoogleUser)?, Error?) -> Void) { + if let exception = exception { + exception.raise() + } + completion(self.error == nil ? self : nil, self.error) + } + + #if os(iOS) || targetEnvironment(macCatalyst) + func addScopes( + _ scopes: [String], + presenting presentingViewController: UIViewController, + completion: (((any FSIGIDSignInResult)?, Error?) -> Void)? + ) { + self.requestedScopes = scopes + self.presentingViewController = presentingViewController + if let exception = exception { + exception.raise() + } + completion?(self.error == nil ? self.result : nil, self.error) + } + #elseif os(OSX) + func addScopes( + _ scopes: [String], + presenting presentingWindow: NSWindow, + completion: (((any FSIGIDSignInResult)?, Error?) -> Void)? + ) { + self.requestedScopes = scopes + self.presentingWindow = presentingWindow + if let exception = exception { + exception.raise() + } + completion?(self.error == nil ? self.result : nil, self.error) + } + #endif +} + +struct GoogleSignInPluginTests { + @Test func signOut() { + let (plugin, fakeSignIn) = createTestPlugin() + var error: FlutterError? + plugin.signOutWithError(&error) + #expect(fakeSignIn.signOutCalled == true) + #expect(error == nil) + } + + @Test func disconnect() async { + let (plugin, _) = createTestPlugin() + await confirmation("expect result returns true") { confirmed in + plugin.disconnect { error in + #expect(error == nil) + confirmed() + } + } + } + + @Suite("configure") struct ConfigureTests { + @Test func configureFromAppInfoPlist() { + let (plugin, fakeSignIn) = createTestPlugin() + let params = FSIPlatformConfigurationParams.make( + withClientId: nil, + serverClientId: nil, + hostedDomain: "example.com") + + var error: FlutterError? + plugin.configure(withParameters: params, error: &error) + #expect(error == nil) + // No configuration should be set, allowing the SDK to use its default behavior + // (which is to load configuration information from the app's Info.plist). + #expect(fakeSignIn.configuration == nil) + } + + @Test( + arguments: [ + // Use GoogleService-Info.plist, but add a domain. + (nil, nil, "example.com", true), + // Use GoogleService-Info.plist, but override the server client ID. + (nil, "overridingServerClientId", nil, true), + // No plist, providing only some values. + ("runtimeClientId", nil, nil, false), + ("runtimeClientId", "runtimeSeverClientId", nil, false), + ] as [(String?, String?, String?, Bool)]) func configureFromExplicitValues( + dynamicClientId: String?, + dynamicServerClientId: String?, + dynamicHostedDomain: String?, + useGoogleServiceInfoPlist: Bool + ) + { + let (plugin, fakeSignIn) = createTestPlugin( + googleServiceProperties: useGoogleServiceInfoPlist ? loadGoogleServiceInfo() : nil) + let params = FSIPlatformConfigurationParams.make( + withClientId: dynamicClientId, + serverClientId: dynamicServerClientId, + hostedDomain: dynamicHostedDomain) + + // Default configuration values are nil, or the values from GoogleService-Info.plist if + // that's being used. + var expectedClientId: String? = + useGoogleServiceInfoPlist + ? "479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com" : nil + var expectedServerClientId: String? = + useGoogleServiceInfoPlist ? "YOUR_SERVER_CLIENT_ID" : nil + var expectedDomain: String? = nil + // Any value passed in at runtime should override the default. + if let dynamicClientId { + expectedClientId = dynamicClientId + } + if let dynamicServerClientId { + expectedServerClientId = dynamicServerClientId + } + if let dynamicHostedDomain { + expectedDomain = dynamicHostedDomain + } + + var error: FlutterError? + plugin.configure(withParameters: params, error: &error) + #expect(error == nil) + #expect( + fakeSignIn.configuration?.clientID + == expectedClientId) + #expect(fakeSignIn.configuration?.serverClientID == expectedServerClientId) + #expect(fakeSignIn.configuration?.hostedDomain == expectedDomain) + } + } + + @Suite("restorePreviousSignIn") struct RestorePreviousSignInTests { + @Test func restorePreviousSignInSuccess() async { + let (plugin, fakeSignIn) = createTestPlugin() + let userID = "mockID" + let fakeUser = TestGoogleUser(userID) + let accessToken = fakeUser.accessToken.tokenString + let name = "mockDislayName" + let email = "mock@example.com" + let imageURLString = "https://example.com/profile.png" + fakeUser.profile = TestProfileData( + name: name, email: email, + imageURL: URL(string: imageURLString)) + fakeSignIn.user = fakeUser + + await confirmation("completion called") { confirmed in + plugin.restorePreviousSignIn { result, error in + #expect(error == nil) + #expect(result?.error == nil) + #expect(result?.success != nil) + #expect(result?.success?.user.displayName == name) + #expect(result?.success?.user.email == email) + #expect(result?.success?.user.userId == userID) + #expect(result?.success?.user.photoUrl == imageURLString) + #expect(result?.success?.accessToken == accessToken) + #expect(result?.success?.serverAuthCode == nil) + confirmed() + } + } + } + + @Test func restorePreviousSignInError() async { + let (plugin, fakeSignIn) = createTestPlugin() + let sdkError = NSError( + domain: kGIDSignInErrorDomain, code: GIDSignInError.hasNoAuthInKeychain.rawValue, + userInfo: nil) + fakeSignIn.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.restorePreviousSignIn { result, error in + #expect(error == nil) + #expect(result?.success == nil) + #expect(result?.error?.type == FSIGoogleSignInErrorCode.noAuthInKeychain) + confirmed() + } + } + } + } + + @Suite("signIn") struct SignInTests { + @Test func signInWithoutParameters() async { + let (plugin, fakeSignIn) = createTestPlugin() + let fakeUser = TestGoogleUser("mockID") + let fakeUserProfile = TestProfileData( + name: "mockDisplay", email: "mock@example.com", + imageURL: URL(string: "https://example.com/profile.png")) + + let accessToken = "mockAccessToken" + let serverAuthCode = "mockAuthCode" + fakeUser.profile = fakeUserProfile + fakeUser.accessToken = TestToken(accessToken) + + let fakeSignInResult = TestSignInResult(user: fakeUser, serverAuthCode: serverAuthCode) + + fakeSignIn.signInResult = fakeSignInResult + + await confirmation("completion called") { confirmed in + plugin.signIn(withScopeHint: [], nonce: nil) { result, error in + #expect(error == nil) + #expect(result?.success?.user.displayName == "mockDisplay") + #expect(result?.success?.user.email == "mock@example.com") + #expect(result?.success?.user.userId == "mockID") + #expect(result?.success?.user.photoUrl == "https://example.com/profile.png") + #expect(result?.success?.accessToken == accessToken) + #expect(result?.success?.serverAuthCode == serverAuthCode) + confirmed() + } + } + } + + @Test func signInWithScopeHint() async { + let (plugin, fakeSignIn) = createTestPlugin() + var initializationError: FlutterError? + plugin.configure( + withParameters: FSIPlatformConfigurationParams.make( + withClientId: nil, + serverClientId: nil, + hostedDomain: nil), + error: &initializationError) + #expect(initializationError == nil) + + let fakeUser = TestGoogleUser("mockID") + let fakeSignInResult = TestSignInResult(user: fakeUser) + + let requestedScopes = ["scope1", "scope2"] + fakeSignIn.signInResult = fakeSignInResult + + await confirmation("completion called") { confirmed in + plugin.signIn(withScopeHint: requestedScopes, nonce: nil) { result, error in + #expect(error == nil) + #expect(result?.error == nil) + #expect(result?.success?.user.userId == "mockID") + confirmed() + } + } + + #expect(Set(fakeSignIn.additionalScopes ?? []) == Set(requestedScopes)) + } + + @Test func signInWithNonce() async { + let (plugin, fakeSignIn) = createTestPlugin() + var initializationError: FlutterError? + plugin.configure( + withParameters: FSIPlatformConfigurationParams.make( + withClientId: nil, + serverClientId: nil, + hostedDomain: nil), + error: &initializationError) + #expect(initializationError == nil) + + let fakeUser = TestGoogleUser("mockID") + let fakeSignInResult = TestSignInResult(user: fakeUser) + + let nonce = "A nonce" + fakeSignIn.signInResult = fakeSignInResult + + await confirmation("completion called") { confirmed in + plugin.signIn(withScopeHint: [], nonce: nonce) { result, error in + #expect(error == nil) + #expect(result?.error == nil) + #expect(result?.success?.user.userId == "mockID") + confirmed() + } + } + + #expect(fakeSignIn.nonce == nonce) + } + + @Test func signInAlreadyGranted() async { + let (plugin, fakeSignIn) = createTestPlugin() + let fakeUser = TestGoogleUser("mockID") + let fakeSignInResult = TestSignInResult(user: fakeUser) + + fakeSignIn.signInResult = fakeSignInResult + + let sdkError = NSError( + domain: kGIDSignInErrorDomain, code: GIDSignInError.scopesAlreadyGranted.rawValue, + userInfo: nil) + fakeSignIn.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.signIn(withScopeHint: [], nonce: nil) { result, error in + #expect(error == nil) + #expect(result?.error == nil) + #expect(result?.success?.user.userId == "mockID") + confirmed() + } + } + } + + @Test func signInCanceled() async { + let (plugin, fakeSignIn) = createTestPlugin() + let sdkError = NSError( + domain: kGIDSignInErrorDomain, code: GIDSignInError.canceled.rawValue, userInfo: nil) + fakeSignIn.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.signIn(withScopeHint: [], nonce: nil) { result, error in + // Known errors from the SDK are returned as structured data, not + // FlutterError. + #expect(error == nil) + #expect(result?.success == nil) + #expect(result?.error?.type == .canceled) + confirmed() + } + } + } + + @Test func signInExceptionReturnsError() async { + let (plugin, fakeSignIn) = createTestPlugin() + fakeSignIn.exception = NSException( + name: NSExceptionName(rawValue: "MockName"), + reason: "MockReason", + userInfo: nil) + + await confirmation("completion called") { confirmed in + plugin.signIn(withScopeHint: [], nonce: nil) { result, error in + // Unexpected errors, such as runtime exceptions, are returned as + // FlutterError. + #expect(result == nil) + #expect(error?.code == "google_sign_in") + #expect(error?.message == "MockReason") + #expect(error?.details as? String == "MockName") + confirmed() + } + } + } + } + + @Suite("refreshedAuthorizationTokens") struct RefreshTests { + @Test func refreshTokensSuccess() async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + // TestGoogleUser passes itself as the result's user property, so set the + // fake result data on this object. + fakeUser.idToken = TestToken("mockIdToken") + fakeUser.accessToken = TestToken("mockAccessToken") + + await confirmation("completion called") { confirmed in + plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in + #expect(error == nil) + #expect(result?.error == nil) + #expect(result?.success?.user.idToken == "mockIdToken") + #expect(result?.success?.accessToken == "mockAccessToken") + confirmed() + } + } + } + + @Test func refreshTokensUnkownUser() async { + let (plugin, _) = createTestPlugin() + await confirmation("completion called") { confirmed in + plugin.refreshedAuthorizationTokens(forUser: "unknownUser") { result, error in + #expect(error == nil) + #expect(result?.success == nil) + #expect(result?.error?.type == .userMismatch) + #expect(result?.error?.message == "The user is no longer signed in.") + confirmed() + } + } + } + + @Test(arguments: [ + (GIDSignInError.hasNoAuthInKeychain.rawValue, FSIGoogleSignInErrorCode.noAuthInKeychain), + (GIDSignInError.canceled.rawValue, .canceled), + ]) func refreshTokensGIDSignInErrorDomainErrors( + signInSDKErrorCode: Int, + expectedPigeonErrorCode: FSIGoogleSignInErrorCode + ) async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + + let sdkError = NSError( + domain: kGIDSignInErrorDomain, code: signInSDKErrorCode, + userInfo: nil) + fakeUser.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in + #expect(error == nil) + #expect(result?.success == nil) + #expect(result?.error?.type == expectedPigeonErrorCode) + confirmed() + } + } + } + + @Test(arguments: [ + (NSURLErrorDomain, NSURLErrorTimedOut), + ("BogusDomain", 42), + ]) func refreshTokensOtherDomainErrors( + errorDomain: String, + errorCode: Int + ) async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + + let sdkError = NSError(domain: errorDomain, code: errorCode, userInfo: nil) + fakeUser.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.refreshedAuthorizationTokens(forUser: fakeUser.userID!) { result, error in + #expect(result?.error == nil) + #expect(result?.success == nil) + let expectedCode = "\(errorDomain): \(errorCode)" + #expect(error?.code == expectedCode) + confirmed() + } + } + } + } + + @Suite("addScopes") struct AddScopesTests { + @Test func addScopesPassesScopes() async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + // Create a different instance to return in the result, to avoid a retain cycle. + let fakeResultUser = TestGoogleUser(fakeUser.userID!) + let fakeSignInResult = TestSignInResult(user: fakeResultUser) + fakeUser.result = fakeSignInResult + + let scopes = ["mockScope1"] + + await confirmation("completion called") { confirmed in + plugin.addScopes(scopes, forUser: fakeUser.userID!) { result, error in + #expect(error == nil) + #expect(result?.success != nil) + confirmed() + } + } + #expect(fakeUser.requestedScopes?.first == scopes.first) + } + + @Test func addScopesErrorsIfNotSignedIn() async { + let (plugin, _) = createTestPlugin() + await confirmation("completion called") { confirmed in + plugin.addScopes(["mockScope1"], forUser: "unknownUser") { result, error in + #expect(error == nil) + #expect(result?.success == nil) + #expect(result?.error?.type == .userMismatch) + confirmed() + } + } + } + + @Test(arguments: [ + (GIDSignInError.scopesAlreadyGranted.rawValue, FSIGoogleSignInErrorCode.scopesAlreadyGranted), + (GIDSignInError.mismatchWithCurrentUser.rawValue, FSIGoogleSignInErrorCode.userMismatch), + ]) func addScopesGIDSignInErrorDomainErrors( + signInSDKErrorCode: Int, + expectedPigeonErrorCode: FSIGoogleSignInErrorCode + ) async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + + let sdkError = NSError( + domain: kGIDSignInErrorDomain, code: signInSDKErrorCode, + userInfo: nil) + fakeUser.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.addScopes(["mockScope1"], forUser: fakeUser.userID!) { result, error in + #expect(error == nil) + #expect(result?.success == nil) + #expect(result?.error?.type == expectedPigeonErrorCode) + confirmed() + } + } + } + + @Test func addScopesUnknownError() async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + + let sdkError = NSError(domain: "BogusDomain", code: 42, userInfo: nil) + fakeUser.error = sdkError + + await confirmation("completion called") { confirmed in + plugin.addScopes(["mockScope1"], forUser: fakeUser.userID!) { result, error in + #expect(result == nil) + #expect(error?.code == "BogusDomain: 42") + confirmed() + } + } + } + + @Test func addScopesException() async { + let (plugin, _) = createTestPlugin() + let fakeUser = addSignedInUser(to: plugin) + + fakeUser.exception = NSException( + name: NSExceptionName(rawValue: "MockName"), + reason: "MockReason", + userInfo: nil) + + await confirmation("completion called") { confirmed in + plugin.addScopes([], forUser: fakeUser.userID!) { result, error in + #expect(result == nil) + #expect(error?.code == "request_scopes") + #expect(error?.message == "MockReason") + #expect(error?.details as? String == "MockName") + confirmed() + } + } + } + } +} + +func loadGoogleServiceInfo() -> [String: Any]? { + if let plistPath = Bundle(for: TestSignIn.self).path( + forResource: "GoogleService-Info", ofType: "plist") + { + return NSDictionary(contentsOfFile: plistPath) as? [String: Any] + } + return nil +} + +func createTestPlugin( + viewProvider: TestViewProvider = TestViewProvider(), + googleServiceProperties: [String: Any]? = nil +) -> (FLTGoogleSignInPlugin, TestSignIn) { + let fakeSignIn = TestSignIn() + return ( + FLTGoogleSignInPlugin( + signIn: fakeSignIn, viewProvider: viewProvider, + googleServiceProperties: googleServiceProperties), fakeSignIn + ) +} + +func addSignedInUser(to plugin: FLTGoogleSignInPlugin) -> TestGoogleUser { + let identifier = "fakeID" + let user = TestGoogleUser(identifier) + plugin.usersByIdentifier[identifier] = user + return user +} diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios.podspec b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios.podspec index 1c236caaa292..9adb77fbe6a5 100644 --- a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios.podspec +++ b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios.podspec @@ -14,7 +14,6 @@ Enables Google Sign-In in Flutter apps. s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_ios' } s.source_files = 'google_sign_in_ios/Sources/google_sign_in_ios/**/*.{h,m}' s.public_header_files = 'google_sign_in_ios/Sources/google_sign_in_ios/include/**/*.h' - s.module_map = 'google_sign_in_ios/Sources/google_sign_in_ios/include/FLTGoogleSignInPlugin.modulemap' # GTMSessionFetcher is a GoogleSignIn transitive dependency, added here as a # direct dependency to ensure a version which defines modules. diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Package.swift b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Package.swift index 10e0d4ca6c90..7b37176cecb5 100644 --- a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Package.swift +++ b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Package.swift @@ -26,9 +26,6 @@ let package = Package( dependencies: [ .product(name: "GoogleSignIn", package: "GoogleSignIn-iOS") ], - exclude: [ - "include/google_sign_in_ios-umbrella.h", "include/FLTGoogleSignInPlugin.modulemap", - ], resources: [ .process("Resources") ], diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/FLTGoogleSignInPlugin.modulemap b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/FLTGoogleSignInPlugin.modulemap deleted file mode 100644 index 31e30d93c582..000000000000 --- a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/FLTGoogleSignInPlugin.modulemap +++ /dev/null @@ -1,10 +0,0 @@ -framework module google_sign_in_ios { - umbrella header "google_sign_in_ios-umbrella.h" - - export * - module * { export * } - - explicit module Test { - header "FLTGoogleSignInPlugin_Test.h" - } -} diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios-umbrella.h b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios-umbrella.h deleted file mode 100644 index 4e914272c0e2..000000000000 --- a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios-umbrella.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import -#import -#import - -FOUNDATION_EXPORT double google_sign_inVersionNumber; -FOUNDATION_EXPORT const unsigned char google_sign_inVersionString[]; diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin.h b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin.h index 2044ead34e3e..9e74136a26f5 100644 --- a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin.h +++ b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin.h @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@import Foundation; + #if TARGET_OS_OSX #import #else diff --git a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin_Test.h b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin_Test.h index 7e0f6017dfa5..8e3a3d339cd7 100644 --- a/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin_Test.h +++ b/packages/google_sign_in/google_sign_in_ios/darwin/google_sign_in_ios/Sources/google_sign_in_ios/include/google_sign_in_ios/FLTGoogleSignInPlugin_Test.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This header is available in the Test module. Import via "@import google_sign_in.Test;" - #import +@import Foundation; + #import #import "FSIGoogleSignInProtocols.h" diff --git a/packages/google_sign_in/google_sign_in_ios/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_sign_in/google_sign_in_ios/example/ios/Flutter/AppFrameworkInfo.plist index 1f6b98f117b2..6fe4034356ac 100644 --- a/packages/google_sign_in/google_sign_in_ios/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/google_sign_in/google_sign_in_ios/example/ios/Flutter/AppFrameworkInfo.plist @@ -24,7 +24,5 @@ arm64 - MinimumOSVersion - 13.0 diff --git a/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj index 6c78727f6d7c..f262e2f80887 100644 --- a/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_sign_in/google_sign_in_ios/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 60; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -18,7 +18,7 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; C2FB9CBA01DB0A2DE5F31E12 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */; }; C56D3B06A42F3B35C1F47A43 /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18AD6475292B9C45B529DDC9 /* libPods-RunnerTests.a */; }; - F76AC1A52666D0540040C8BC /* GoogleSignInTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F76AC1A42666D0540040C8BC /* GoogleSignInTests.m */; }; + F76AC1A52666D0540040C8BC /* GoogleSignInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76AC1A42666D0540040C8BC /* GoogleSignInTests.swift */; }; F76AC1B32666D0610040C8BC /* GoogleSignInUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F76AC1B22666D0610040C8BC /* GoogleSignInUITests.m */; }; /* End PBXBuildFile section */ @@ -60,6 +60,7 @@ 5A76713E622F06379AEDEBFA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 5C6F5A6C1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../darwin/Tests/GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; }; 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -75,7 +76,7 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F582639B44581540871D9BB0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; F76AC1A22666D0540040C8BC /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - F76AC1A42666D0540040C8BC /* GoogleSignInTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GoogleSignInTests.m; path = ../../darwin/Tests/GoogleSignInTests.m; sourceTree = SOURCE_ROOT; }; + F76AC1A42666D0540040C8BC /* GoogleSignInTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GoogleSignInTests.swift; path = ../../darwin/Tests/GoogleSignInTests.swift; sourceTree = SOURCE_ROOT; }; F76AC1A62666D0540040C8BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F76AC1B02666D0610040C8BC /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F76AC1B22666D0610040C8BC /* GoogleSignInUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleSignInUITests.m; sourceTree = ""; }; @@ -124,6 +125,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -192,7 +194,7 @@ isa = PBXGroup; children = ( 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */, - F76AC1A42666D0540040C8BC /* GoogleSignInTests.m */, + F76AC1A42666D0540040C8BC /* GoogleSignInTests.swift */, F76AC1A62666D0540040C8BC /* Info.plist */, ); path = RunnerTests; @@ -305,7 +307,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -436,7 +438,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F76AC1A52666D0540040C8BC /* GoogleSignInTests.m in Sources */, + F76AC1A52666D0540040C8BC /* GoogleSignInTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -651,6 +653,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 6.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; }; name = Debug; @@ -669,6 +672,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 6.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; }; name = Release; @@ -747,7 +751,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/google_sign_in/google_sign_in_ios/example/macos/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in_ios/example/macos/Runner.xcodeproj/project.pbxproj index 99e3f601ab4f..e19d4819efb0 100644 --- a/packages/google_sign_in/google_sign_in_ios/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/google_sign_in/google_sign_in_ios/example/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 60; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -22,7 +22,7 @@ /* Begin PBXBuildFile section */ 330B3F8D2B1E2A5800E6DC3F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 330B3F8C2B1E2A5800E6DC3F /* GoogleService-Info.plist */; }; - 331C80D8294CF71000263BE5 /* GoogleSignInTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* GoogleSignInTests.m */; }; + 331C80D8294CF71000263BE5 /* GoogleSignInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* GoogleSignInTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; @@ -68,7 +68,7 @@ 0E1002C336EBB758B6DD1BE4 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 330B3F8C2B1E2A5800E6DC3F /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../darwin/Tests/GoogleService-Info.plist"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* GoogleSignInTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GoogleSignInTests.m; path = ../../darwin/Tests/GoogleSignInTests.m; sourceTree = SOURCE_ROOT; }; + 331C80D7294CF71000263BE5 /* GoogleSignInTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GoogleSignInTests.swift; path = ../../darwin/Tests/GoogleSignInTests.swift; sourceTree = SOURCE_ROOT; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* google_sign_in_ios_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = google_sign_in_ios_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -84,6 +84,7 @@ 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 4626AA70E7BDF77ABE2E7DB0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 8403A54CFF539C6D4BFB2536 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; @@ -118,7 +119,7 @@ isa = PBXGroup; children = ( 330B3F8C2B1E2A5800E6DC3F /* GoogleService-Info.plist */, - 331C80D7294CF71000263BE5 /* GoogleSignInTests.m */, + 331C80D7294CF71000263BE5 /* GoogleSignInTests.swift */, ); name = RunnerTests; path = Runner; @@ -170,6 +171,7 @@ 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, @@ -424,7 +426,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 331C80D8294CF71000263BE5 /* GoogleSignInTests.m in Sources */, + 331C80D8294CF71000263BE5 /* GoogleSignInTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -476,7 +478,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleSignInIosExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/google_sign_in_ios_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/google_sign_in_ios_example"; }; name = Debug; @@ -491,7 +493,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleSignInIosExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/google_sign_in_ios_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/google_sign_in_ios_example"; }; name = Release; @@ -506,7 +508,7 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleSignInIosExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/google_sign_in_ios_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/google_sign_in_ios_example"; }; name = Profile; diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index d382b5147a2c..0cf613cce834 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_ios description: iOS implementation of the google_sign_in plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 6.2.4 +version: 6.2.5 environment: sdk: ^3.9.0 @@ -40,7 +40,7 @@ topics: # The example deliberately includes limited-use secrets. false_secrets: - /darwin/Tests/GoogleService-Info.plist - - /darwin/Tests/GoogleSignInTests.m + - /darwin/Tests/GoogleSignInTests.swift - /example/ios/Runner/Info.plist - /example/lib/main.dart - /example/macos/Runner/Info.plist