Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[google_sign_in] Add iOS unit tests #4157

Merged
merged 8 commits into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion packages/google_sign_in/google_sign_in/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
## 5.0.5

* Add iOS unit and UI integration test targets.
* Add iOS unit test module map.
* Exclude arm64 simulators in example app.

## 5.0.4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>9.0</string>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automatic from flutter/flutter#85174

</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automatic from flutter/flutter#85174

MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -589,7 +589,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// found in the LICENSE file.

#import "FLTGoogleSignInPlugin.h"
#import "FLTGoogleSignInPlugin_Test.h"

#import <GoogleSignIn/GoogleSignIn.h>

// The key within `GoogleService-Info.plist` used to hold the application's
Expand Down Expand Up @@ -35,11 +37,15 @@
}

@interface FLTGoogleSignInPlugin () <GIDSignInDelegate>
@property(strong, readonly) GIDSignIn *signIn;

// Redeclared as not a designated initializer.
- (instancetype)init;
@end

@implementation FLTGoogleSignInPlugin {
FlutterResult _accountRequest;
NSArray *_additionalScopesRequest;
NSArray<NSString *> *_additionalScopesRequest;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
Expand All @@ -52,9 +58,14 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
}

- (instancetype)init {
return [self initWithSignIn:GIDSignIn.sharedInstance];
}

- (instancetype)initWithSignIn:(GIDSignIn *)signIn {
self = [super init];
if (self) {
[GIDSignIn sharedInstance].delegate = self;
_signIn = signIn;
_signIn.delegate = self;

// On the iOS simulator, we get "Broken pipe" errors after sign-in for some
// unknown reason. We can avoid crashing the app by ignoring them.
Expand All @@ -76,22 +87,22 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info"
ofType:@"plist"];
if (path) {
NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
BOOL hasDynamicClientId =
[[call.arguments valueForKey:@"clientId"] isKindOfClass:[NSString class]];
NSMutableDictionary<NSString *, NSString *> *plist =
[[NSMutableDictionary alloc] initWithContentsOfFile:path];
BOOL hasDynamicClientId = [call.arguments[@"clientId"] isKindOfClass:[NSString class]];

if (hasDynamicClientId) {
[GIDSignIn sharedInstance].clientID = [call.arguments valueForKey:@"clientId"];
self.signIn.clientID = call.arguments[@"clientId"];
} else {
[GIDSignIn sharedInstance].clientID = plist[kClientIdKey];
self.signIn.clientID = plist[kClientIdKey];
}

[GIDSignIn sharedInstance].serverClientID = plist[kServerClientIdKey];
[GIDSignIn sharedInstance].scopes = call.arguments[@"scopes"];
self.signIn.serverClientID = plist[kServerClientIdKey];
self.signIn.scopes = call.arguments[@"scopes"];
if (call.arguments[@"hostedDomain"] == [NSNull null]) {
[GIDSignIn sharedInstance].hostedDomain = nil;
self.signIn.hostedDomain = nil;
} else {
[GIDSignIn sharedInstance].hostedDomain = call.arguments[@"hostedDomain"];
self.signIn.hostedDomain = call.arguments[@"hostedDomain"];
}
result(nil);
} else {
Expand All @@ -102,23 +113,23 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
}
} else if ([call.method isEqualToString:@"signInSilently"]) {
if ([self setAccountRequest:result]) {
[[GIDSignIn sharedInstance] restorePreviousSignIn];
[self.signIn restorePreviousSignIn];
}
} else if ([call.method isEqualToString:@"isSignedIn"]) {
result(@([[GIDSignIn sharedInstance] hasPreviousSignIn]));
result(@([self.signIn hasPreviousSignIn]));
} else if ([call.method isEqualToString:@"signIn"]) {
[GIDSignIn sharedInstance].presentingViewController = [self topViewController];
self.signIn.presentingViewController = [self topViewController];

if ([self setAccountRequest:result]) {
@try {
[[GIDSignIn sharedInstance] signIn];
[self.signIn signIn];
} @catch (NSException *e) {
result([FlutterError errorWithCode:@"google_sign_in" message:e.reason details:e.name]);
[e raise];
}
}
} else if ([call.method isEqualToString:@"getTokens"]) {
GIDGoogleUser *currentUser = [GIDSignIn sharedInstance].currentUser;
GIDGoogleUser *currentUser = self.signIn.currentUser;
GIDAuthentication *auth = currentUser.authentication;
[auth getTokensWithHandler:^void(GIDAuthentication *authentication, NSError *error) {
result(error != nil ? getFlutterError(error) : @{
Expand All @@ -127,28 +138,28 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
});
}];
} else if ([call.method isEqualToString:@"signOut"]) {
[[GIDSignIn sharedInstance] signOut];
[self.signIn signOut];
result(nil);
} else if ([call.method isEqualToString:@"disconnect"]) {
if ([self setAccountRequest:result]) {
[[GIDSignIn sharedInstance] disconnect];
[self.signIn disconnect];
}
} else if ([call.method isEqualToString:@"clearAuthCache"]) {
// There's nothing to be done here on iOS since the expired/invalid
// tokens are refreshed automatically by getTokensWithHandler.
result(nil);
} else if ([call.method isEqualToString:@"requestScopes"]) {
GIDGoogleUser *user = [GIDSignIn sharedInstance].currentUser;
GIDGoogleUser *user = self.signIn.currentUser;
if (user == nil) {
result([FlutterError errorWithCode:@"sign_in_required"
message:@"No account to grant scopes."
details:nil]);
return;
}

NSArray *currentScopes = [GIDSignIn sharedInstance].scopes;
NSArray *scopes = call.arguments[@"scopes"];
NSArray *missingScopes = [scopes
NSArray<NSString *> *currentScopes = self.signIn.scopes;
NSArray<NSString *> *scopes = call.arguments[@"scopes"];
NSArray<NSString *> *missingScopes = [scopes
filteredArrayUsingPredicate:[NSPredicate
predicateWithBlock:^BOOL(id scope, NSDictionary *bindings) {
return ![user.grantedScopes containsObject:scope];
Expand All @@ -161,12 +172,11 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result

if ([self setAccountRequest:result]) {
_additionalScopesRequest = missingScopes;
[GIDSignIn sharedInstance].scopes =
[currentScopes arrayByAddingObjectsFromArray:missingScopes];
[GIDSignIn sharedInstance].presentingViewController = [self topViewController];
[GIDSignIn sharedInstance].loginHint = user.profile.email;
self.signIn.scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes];
self.signIn.presentingViewController = [self topViewController];
self.signIn.loginHint = user.profile.email;
@try {
[[GIDSignIn sharedInstance] signIn];
[self.signIn signIn];
} @catch (NSException *e) {
result([FlutterError errorWithCode:@"request_scopes" message:e.reason details:e.name]);
}
Expand All @@ -187,8 +197,10 @@ - (BOOL)setAccountRequest:(FlutterResult)request {
return YES;
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
return [[GIDSignIn sharedInstance] handleURL:url];
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
return [self.signIn handleURL:url];
}

#pragma mark - <GIDSignInUIDelegate> protocol
Expand Down Expand Up @@ -251,7 +263,7 @@ - (void)signIn:(GIDSignIn *)signIn

#pragma mark - private methods

- (void)respondWithAccount:(id)account error:(NSError *)error {
- (void)respondWithAccount:(NSDictionary<NSString *, id> *)account error:(NSError *)error {
FlutterResult result = _accountRequest;
_accountRequest = nil;
result(error != nil ? getFlutterError(error) : account);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
framework module google_sign_in {
umbrella header "google_sign_in-umbrella.h"

export *
module * { export * }

explicit module Test {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a private module since there are some complications for Swift files not being able to import those.

Instead, this explicit module requires that google_sign_in.Test be imported to access FLTGoogleSignInPlugin_Test. So initWithSignIn: won't be available in the normal import google_sign_in case, won't auto-complete, etc.

header "FLTGoogleSignInPlugin_Test.h"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// 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 <google_sign_in/FLTGoogleSignInPlugin.h>

@class GIDSignIn;

/// Methods exposed for unit testing.
@interface FLTGoogleSignInPlugin ()

/// Inject @c GIDSignIn for testing.
- (instancetype)initWithSignIn:(GIDSignIn *)signIn NS_DESIGNATED_INITIALIZER;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file was previously generated by CocoaPods with the same name. Now we need to manage it manually and check it into the repo because we're defining a module map, which takes us out of the magical auto module world.

// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import <Foundation/Foundation.h>
#import <google_sign_in/FLTGoogleSignInPlugin.h>

FOUNDATION_EXPORT double google_sign_inVersionNumber;
FOUNDATION_EXPORT const unsigned char google_sign_inVersionString[];
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ Enables Google Sign-In in Flutter apps.
s.license = { :type => 'BSD', :file => '../LICENSE' }
s.author = { 'Flutter Team' => '[email protected]' }
s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/google_sign_in' }
s.source_files = 'Classes/**/*'
s.source_files = 'Classes/**/*.{h,m}'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modulemap shouldn't be included in the source files.

s.public_header_files = 'Classes/**/*.h'
s.module_map = 'Classes/FLTGoogleSignInPlugin.modulemap'
s.dependency 'Flutter'
s.dependency 'GoogleSignIn', '~> 5.0'
s.static_framework = true
Expand Down
2 changes: 1 addition & 1 deletion packages/google_sign_in/google_sign_in/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
for signing in with a Google account on Android and iOS.
repository: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22
version: 5.0.4
version: 5.0.5
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stuartmorgan with the module change this seems different enough to warrant a patch bump.


environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down