From 3a2932e7b2b2d102a8b98f003e18727d2b0c6e5b Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Mon, 10 Feb 2020 09:52:28 -0800 Subject: [PATCH 01/23] Add scope handling methods to google_sign_in_web. --- .../lib/google_sign_in_web.dart | 25 +++++++++++++++++++ .../google_sign_in_web/test/auth2_test.dart | 12 +++++++++ .../test/gapi_mocks/src/google_user.dart | 2 ++ 3 files changed, 39 insertions(+) diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart index 4004d47d5551..cbef3c40892f 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart @@ -176,4 +176,29 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { return auth2.getAuthInstance().disconnect(); } + + @override + Future hasGrantedScope(String scope) async { + await initialized; + + return auth2 + .getAuthInstance() + ?.currentUser + ?.get() + ?.getGrantedScopes() + ?.contains(scope) ?? + false; + } + + @override + Future requestScope(String scope) async { + await initialized; + + return auth2 + .getAuthInstance() + ?.currentUser + ?.get() + ?.grant(auth2.SigninOptions(scope: scope)) ?? + false; + } } diff --git a/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart b/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart index 7a3a01227169..2ba01dc8801a 100644 --- a/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart +++ b/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart @@ -73,5 +73,17 @@ void main() { expect(actualToken, expectedTokenData); }); + + test('hasGrantedScope', () async { + bool hasScope = await plugin.hasGrantedScope('scope'); + + expect(hasScope, isTrue); + }); + + test('requestScope', () async { + bool scopeGranted = await plugin.requestScope('newScope'); + + expect(scopeGranted, isTrue); + }); }); } diff --git a/packages/google_sign_in/google_sign_in_web/test/gapi_mocks/src/google_user.dart b/packages/google_sign_in/google_sign_in_web/test/gapi_mocks/src/google_user.dart index 9f2b7b9bf6fa..15993bb56d8a 100644 --- a/packages/google_sign_in/google_sign_in_web/test/gapi_mocks/src/google_user.dart +++ b/packages/google_sign_in/google_sign_in_web/test/gapi_mocks/src/google_user.dart @@ -21,5 +21,7 @@ String googleUser(GoogleSignInUserData data) => ''' access_token: 'access_${data.idToken}', } }, + getGrantedScopes: () => 'some scope', + grant: () => true, } '''; From f22a3e19bc55f7c16738df3b8d609b2316b4fe68 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Mon, 10 Feb 2020 10:30:58 -0800 Subject: [PATCH 02/23] Update version and changelog for web plugin. --- packages/google_sign_in/google_sign_in_web/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in_web/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md index 1b1492b35c56..6f186fddd704 100644 --- a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.0 + +* Add support for methods introduced in `google_sign_in_platform_interface` 1.1.0. + ## 0.8.4 * Remove all `fakeConstructor$` from the generated facade. JS interop classes do not support non-external constructors. diff --git a/packages/google_sign_in/google_sign_in_web/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/pubspec.yaml index 574cd95f3cca..9f2ce2636b21 100644 --- a/packages/google_sign_in/google_sign_in_web/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_web/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_web description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android, iOS and Web. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_web -version: 0.8.4 +version: 0.9.0 flutter: plugin: @@ -12,7 +12,7 @@ flutter: fileName: google_sign_in_web.dart dependencies: - google_sign_in_platform_interface: ^1.0.0 + google_sign_in_platform_interface: ^1.1.0 flutter: sdk: flutter flutter_web_plugins: From f985b85367c2e8c4678ddcc1c8d0955a29c1bbf3 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Mon, 10 Feb 2020 09:54:03 -0800 Subject: [PATCH 03/23] Add scope handling methods to google_sign_in. --- .../googlesignin/GoogleSignInPlugin.java | 41 +++++++++++++++++ .../ios/Classes/FLTGoogleSignInPlugin.m | 10 +++++ .../google_sign_in/lib/google_sign_in.dart | 12 +++++ .../test/google_sign_in_test.dart | 44 +++++++++++++++++++ 4 files changed, 107 insertions(+) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 6c9bedde1038..2407f794c21d 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -46,6 +46,8 @@ public class GoogleSignInPlugin implements MethodCallHandler { private static final String METHOD_DISCONNECT = "disconnect"; private static final String METHOD_IS_SIGNED_IN = "isSignedIn"; private static final String METHOD_CLEAR_AUTH_CACHE = "clearAuthCache"; + private static final String METHOD_HAS_GRANTED_SCOPE = "hasGrantedScope"; + private static final String METHOD_REQUEST_SCOPE = "requestScope"; private final IDelegate delegate; @@ -100,6 +102,16 @@ public void onMethodCall(MethodCall call, Result result) { delegate.isSignedIn(result); break; + case METHOD_HAS_GRANTED_SCOPE: + String scope = call.argument("scope"); + delegate.hasGrantedScope(result, scope); + break; + + case METHOD_REQUEST_SCOPE: + scope = call.argument("scope"); + delegate.requestScope(result, scope); + break; + default: result.notImplemented(); } @@ -153,6 +165,12 @@ public void init( /** Checks if there is a signed in user. */ public void isSignedIn(Result result); + + /** Checks to see if the passed Oauth scope has been granted by the user. */ + public void hasGrantedScope(final Result result, final String scope); + + /** Prompts the user to grant an additional Oauth scope. */ + public void requestScope(final Result result, final String scope); } /** @@ -167,6 +185,7 @@ public void init( public static final class Delegate implements IDelegate, PluginRegistry.ActivityResultListener { private static final int REQUEST_CODE_SIGNIN = 53293; private static final int REQUEST_CODE_RECOVER_AUTH = 53294; + private static final int REQUEST_CODE_REQUEST_SCOPE = 53295; private static final String ERROR_REASON_EXCEPTION = "exception"; private static final String ERROR_REASON_STATUS = "status"; @@ -343,6 +362,25 @@ public void isSignedIn(final Result result) { result.success(value); } + @Override + public void hasGrantedScope(Result result, String scope) { + GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); + boolean value = account != null && GoogleSignIn.hasPermissions(account, new Scope(scope)); + result.success(value); + } + + @Override + public void requestScope(Result result, String scope) { + GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); + if (account != null) { + GoogleSignIn.requestPermissions( + registrar.activity(), + REQUEST_CODE_REQUEST_SCOPE, + account, + new Scope(scope)); + } + } + private void onSignInResult(Task completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); @@ -527,6 +565,9 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { finishWithError(ERROR_REASON_SIGN_IN_FAILED, "Signin failed"); } return true; + case REQUEST_CODE_REQUEST_SCOPE: + pendingOperation.result.success(resultCode == Activity.RESULT_OK); + return true; default: return false; } diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 0790c1b8cf65..5f31c5230efc 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -121,6 +121,16 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result // 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:@"hasGrantedScope"]) { + GIDGoogleUser *user = [GIDSignIn sharedInstance].currentUser; + NSString *scope = call.arguments[@"scope"]; + bool success = [user.grantedScopes containsObject:scope]; + result(@(success)); + } else if ([call.method isEqualToString:@"requestScope"]) { + NSArray *currentScopes = [GIDSignIn sharedInstance].scopes; + NSString *scope = call.arguments[@"scope"]; + [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObject:scope]; + [[GIDSignIn sharedInstance] signIn]; } else { result(FlutterMethodNotImplemented); } diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 09753377ac76..0585115e6e89 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -367,4 +367,16 @@ class GoogleSignIn { /// authentication. Future disconnect() => _addMethodCall(GoogleSignInPlatform.instance.disconnect); + + /// Indicates whether this Oauth [scope] has been granted. + Future hasGrantedScope(String scope) async { + await _ensureInitialized(); + return GoogleSignInPlatform.instance.hasGrantedScope(scope); + } + + /// Requests the user grant an additional Oauth [scope]. + Future requestScope(String scope) async { + await _ensureInitialized(); + return GoogleSignInPlatform.instance.requestScope(scope); + } } diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index a85fb0f27e42..f0bc49f0f3f5 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -32,6 +32,8 @@ void main() { 'signOut': null, 'disconnect': null, 'isSignedIn': true, + 'hasGrantedScope': true, + 'requestScope': true, 'getTokens': { 'idToken': '123', 'accessToken': '456', @@ -379,6 +381,48 @@ void main() { ], ); }); + + test('hasGrantedScope returns true if scope is granted', () async { + await googleSignIn.signIn(); + final result = await googleSignIn.hasGrantedScope('testScope'); + + expect(result, isTrue); + expect( + log, + [ + isMethodCall('init', arguments: { + 'signInOption': 'SignInOption.standard', + 'scopes': [], + 'hostedDomain': null, + }), + isMethodCall('signIn', arguments: null), + isMethodCall('hasGrantedScope', arguments: { + 'scope': 'testScope', + }), + ], + ); + }); + + test('requestScope returns true once new scope is granted', () async { + await googleSignIn.signIn(); + final result = await googleSignIn.requestScope('testScope'); + + expect(result, isTrue); + expect( + log, + [ + isMethodCall('init', arguments: { + 'signInOption': 'SignInOption.standard', + 'scopes': [], + 'hostedDomain': null, + }), + isMethodCall('signIn', arguments: null), + isMethodCall('requestScope', arguments: { + 'scope': 'testScope', + }), + ], + ); + }); }); group('GoogleSignIn with fake backend', () { From 862fa74d64e400b1a5fcf4c73d676765ffee23fa Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Mon, 10 Feb 2020 10:31:22 -0800 Subject: [PATCH 04/23] Update version for main plugin. --- packages/google_sign_in/google_sign_in/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 8a9743f10702..a17b384666f4 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.3.0 + +* Add support for method introduced in `google_sign_in_platform_interface` 1.1.0. + ## 4.2.0 * Migrate to AndroidX. diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index 5ef91f743142..860369da8c40 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 4.2.0 +version: 4.3.0 flutter: plugin: @@ -16,7 +16,7 @@ flutter: default_package: google_sign_in_web dependencies: - google_sign_in_platform_interface: ^1.0.0 + google_sign_in_platform_interface: ^1.1.0 flutter: sdk: flutter meta: ^1.0.4 From 773276c399f0e68cef6857b129abf8824abe8e48 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Thu, 27 Feb 2020 08:34:11 -0800 Subject: [PATCH 05/23] Fix GoogleSignInPlugin.java formatting. --- .../io/flutter/plugins/googlesignin/GoogleSignInPlugin.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 2407f794c21d..17445df0e6d4 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -374,10 +374,7 @@ public void requestScope(Result result, String scope) { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); if (account != null) { GoogleSignIn.requestPermissions( - registrar.activity(), - REQUEST_CODE_REQUEST_SCOPE, - account, - new Scope(scope)); + registrar.activity(), REQUEST_CODE_REQUEST_SCOPE, account, new Scope(scope)); } } From 9e4deca4fcc4d17ca316c6d021db188dbfb36b5d Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Thu, 27 Feb 2020 13:45:24 -0800 Subject: [PATCH 06/23] Implement requesting multiple scopes on all platforms. --- .../googlesignin/GoogleSignInPlugin.java | 17 +++++++++++------ .../ios/Classes/FLTGoogleSignInPlugin.m | 6 +++--- .../google_sign_in/lib/google_sign_in.dart | 4 ++-- .../test/google_sign_in_test.dart | 4 ++-- .../lib/google_sign_in_web.dart | 4 ++-- .../google_sign_in_web/test/auth2_test.dart | 2 +- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 17445df0e6d4..bda0f5da8d02 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -108,8 +108,8 @@ public void onMethodCall(MethodCall call, Result result) { break; case METHOD_REQUEST_SCOPE: - scope = call.argument("scope"); - delegate.requestScope(result, scope); + List scopes = call.argument("scope"); + delegate.requestScopes(result, scopes); break; default: @@ -169,8 +169,8 @@ public void init( /** Checks to see if the passed Oauth scope has been granted by the user. */ public void hasGrantedScope(final Result result, final String scope); - /** Prompts the user to grant an additional Oauth scope. */ - public void requestScope(final Result result, final String scope); + /** Prompts the user to grant an additional Oauth scopes. */ + public void requestScopes(final Result result, final List scopes); } /** @@ -370,11 +370,16 @@ public void hasGrantedScope(Result result, String scope) { } @Override - public void requestScope(Result result, String scope) { + public void requestScopes(Result result, List scopes) { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); if (account != null) { + Scope[] wrappedScopes = new Scope[scopes.size()]; + for (int i = 0; i < scopes.size(); i++) { + wrappedScopes[i] = new Scope(scopes.get(i)); + } + GoogleSignIn.requestPermissions( - registrar.activity(), REQUEST_CODE_REQUEST_SCOPE, account, new Scope(scope)); + registrar.activity(), REQUEST_CODE_REQUEST_SCOPE, account, wrappedScopes); } } diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 5f31c5230efc..b107122ab83c 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -126,10 +126,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result NSString *scope = call.arguments[@"scope"]; bool success = [user.grantedScopes containsObject:scope]; result(@(success)); - } else if ([call.method isEqualToString:@"requestScope"]) { + } else if ([call.method isEqualToString:@"requestScopes"]) { NSArray *currentScopes = [GIDSignIn sharedInstance].scopes; - NSString *scope = call.arguments[@"scope"]; - [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObject:scope]; + NSArray *scope = call.arguments[@"scopes"]; + [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObjectsFromArray:scopes]; [[GIDSignIn sharedInstance] signIn]; } else { result(FlutterMethodNotImplemented); diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 0585115e6e89..99d818525f7c 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -375,8 +375,8 @@ class GoogleSignIn { } /// Requests the user grant an additional Oauth [scope]. - Future requestScope(String scope) async { + Future requestScopes(List scopes) async { await _ensureInitialized(); - return GoogleSignInPlatform.instance.requestScope(scope); + return GoogleSignInPlatform.instance.requestScopes(scopes); } } diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index f0bc49f0f3f5..f43b8aa41f6f 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -405,7 +405,7 @@ void main() { test('requestScope returns true once new scope is granted', () async { await googleSignIn.signIn(); - final result = await googleSignIn.requestScope('testScope'); + final result = await googleSignIn.requestScopes(['testScope']); expect(result, isTrue); expect( @@ -418,7 +418,7 @@ void main() { }), isMethodCall('signIn', arguments: null), isMethodCall('requestScope', arguments: { - 'scope': 'testScope', + 'scopes': ['testScope'], }), ], ); diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart index cbef3c40892f..3034e9eaf4b8 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart @@ -191,14 +191,14 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { } @override - Future requestScope(String scope) async { + Future requestScopes(List scopes) async { await initialized; return auth2 .getAuthInstance() ?.currentUser ?.get() - ?.grant(auth2.SigninOptions(scope: scope)) ?? + ?.grant(auth2.SigninOptions(scope: scopes.join(" "))) ?? false; } } diff --git a/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart b/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart index 2ba01dc8801a..f2db090b6434 100644 --- a/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart +++ b/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart @@ -81,7 +81,7 @@ void main() { }); test('requestScope', () async { - bool scopeGranted = await plugin.requestScope('newScope'); + bool scopeGranted = await plugin.requestScopes(['newScope']); expect(scopeGranted, isTrue); }); From d77cb0317bee428455cd46761a0e57dff512fd69 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Fri, 28 Feb 2020 13:13:24 -0800 Subject: [PATCH 07/23] Remove listMissingScopes from implementations. --- .../googlesignin/GoogleSignInPlugin.java | 51 ++++++++++--------- .../ios/Classes/FLTGoogleSignInPlugin.m | 14 ++--- .../google_sign_in/lib/google_sign_in.dart | 8 +-- .../test/google_sign_in_test.dart | 28 ++-------- .../lib/google_sign_in_web.dart | 28 ++++------ .../google_sign_in_web/test/auth2_test.dart | 8 +-- 6 files changed, 49 insertions(+), 88 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index bda0f5da8d02..bffc68465b7c 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -27,6 +27,7 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -46,8 +47,8 @@ public class GoogleSignInPlugin implements MethodCallHandler { private static final String METHOD_DISCONNECT = "disconnect"; private static final String METHOD_IS_SIGNED_IN = "isSignedIn"; private static final String METHOD_CLEAR_AUTH_CACHE = "clearAuthCache"; - private static final String METHOD_HAS_GRANTED_SCOPE = "hasGrantedScope"; - private static final String METHOD_REQUEST_SCOPE = "requestScope"; + private static final String METHOD_LIST_MISSING_SCOPES = "listMissingScopes"; + private static final String METHOD_REQUEST_SCOPES = "requestScopes"; private final IDelegate delegate; @@ -102,13 +103,8 @@ public void onMethodCall(MethodCall call, Result result) { delegate.isSignedIn(result); break; - case METHOD_HAS_GRANTED_SCOPE: - String scope = call.argument("scope"); - delegate.hasGrantedScope(result, scope); - break; - - case METHOD_REQUEST_SCOPE: - List scopes = call.argument("scope"); + case METHOD_REQUEST_SCOPES: + List scopes = call.argument("scopes"); delegate.requestScopes(result, scopes); break; @@ -166,9 +162,6 @@ public void init( /** Checks if there is a signed in user. */ public void isSignedIn(Result result); - /** Checks to see if the passed Oauth scope has been granted by the user. */ - public void hasGrantedScope(final Result result, final String scope); - /** Prompts the user to grant an additional Oauth scopes. */ public void requestScopes(final Result result, final List scopes); } @@ -362,25 +355,33 @@ public void isSignedIn(final Result result) { result.success(value); } - @Override - public void hasGrantedScope(Result result, String scope) { - GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); - boolean value = account != null && GoogleSignIn.hasPermissions(account, new Scope(scope)); - result.success(value); - } - @Override public void requestScopes(Result result, List scopes) { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); - if (account != null) { - Scope[] wrappedScopes = new Scope[scopes.size()]; - for (int i = 0; i < scopes.size(); i++) { - wrappedScopes[i] = new Scope(scopes.get(i)); + if (account == null) { + result.error(ERROR_REASON_SIGN_IN_REQUIRED, "No account to grant scopes.", null); + return; + } + + List wrappedScopes = new ArrayList<>(); + + for (String scope : scopes) { + Scope wrappedScope = new Scope(scope); + if (!GoogleSignIn.hasPermissions(account, wrappedScope)) { + wrappedScopes.add(wrappedScope); } + } - GoogleSignIn.requestPermissions( - registrar.activity(), REQUEST_CODE_REQUEST_SCOPE, account, wrappedScopes); + if (wrappedScopes.isEmpty()) { + result.success(true); + return; } + + GoogleSignIn.requestPermissions( + registrar.activity(), + REQUEST_CODE_REQUEST_SCOPE, + account, + wrappedScopes.toArray(new Scope[0])); } private void onSignInResult(Task completedTask) { diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index b107122ab83c..20e80c520f44 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -121,15 +121,15 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result // 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:@"hasGrantedScope"]) { - GIDGoogleUser *user = [GIDSignIn sharedInstance].currentUser; - NSString *scope = call.arguments[@"scope"]; - bool success = [user.grantedScopes containsObject:scope]; - result(@(success)); } else if ([call.method isEqualToString:@"requestScopes"]) { NSArray *currentScopes = [GIDSignIn sharedInstance].scopes; - NSArray *scope = call.arguments[@"scopes"]; - [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObjectsFromArray:scopes]; + NSArray *scopes = call.arguments[@"scopes"]; + NSArray *missingScopes = [scopes + filteredArrayUsingPredicate:[NSPredicate + predicateWithBlock:^BOOL(id scope, NSDictionary *bindings) { + return ![user.grantedScopes containsObject:scope]; + }]]; + [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes]; [[GIDSignIn sharedInstance] signIn]; } else { result(FlutterMethodNotImplemented); diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 99d818525f7c..7402c7a69816 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -368,13 +368,7 @@ class GoogleSignIn { Future disconnect() => _addMethodCall(GoogleSignInPlatform.instance.disconnect); - /// Indicates whether this Oauth [scope] has been granted. - Future hasGrantedScope(String scope) async { - await _ensureInitialized(); - return GoogleSignInPlatform.instance.hasGrantedScope(scope); - } - - /// Requests the user grant an additional Oauth [scope]. + /// Requests the user grants additional Oauth [scopes]. Future requestScopes(List scopes) async { await _ensureInitialized(); return GoogleSignInPlatform.instance.requestScopes(scopes); diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index f43b8aa41f6f..898c27fd9f7e 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -32,8 +32,7 @@ void main() { 'signOut': null, 'disconnect': null, 'isSignedIn': true, - 'hasGrantedScope': true, - 'requestScope': true, + 'requestScopes': true, 'getTokens': { 'idToken': '123', 'accessToken': '456', @@ -382,28 +381,7 @@ void main() { ); }); - test('hasGrantedScope returns true if scope is granted', () async { - await googleSignIn.signIn(); - final result = await googleSignIn.hasGrantedScope('testScope'); - - expect(result, isTrue); - expect( - log, - [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), - isMethodCall('signIn', arguments: null), - isMethodCall('hasGrantedScope', arguments: { - 'scope': 'testScope', - }), - ], - ); - }); - - test('requestScope returns true once new scope is granted', () async { + test('requestScopes returns true once new scope is granted', () async { await googleSignIn.signIn(); final result = await googleSignIn.requestScopes(['testScope']); @@ -417,7 +395,7 @@ void main() { 'hostedDomain': null, }), isMethodCall('signIn', arguments: null), - isMethodCall('requestScope', arguments: { + isMethodCall('requestScopes', arguments: { 'scopes': ['testScope'], }), ], diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart index 3034e9eaf4b8..bb43ba100c5d 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart @@ -178,27 +178,21 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { } @override - Future hasGrantedScope(String scope) async { + Future requestScopes(List scopes) async { await initialized; - return auth2 - .getAuthInstance() - ?.currentUser - ?.get() - ?.getGrantedScopes() - ?.contains(scope) ?? - false; - } + final currentUser = auth2.getAuthInstance()?.currentUser?.get(); - @override - Future requestScopes(List scopes) async { - await initialized; + if (currentUser == null) return false; + + final grantedScopes = currentUser.getGrantedScopes(); + final missingScopes = + scopes.where((scope) => !grantedScopes.contains(scope)); + + if (missingScopes.isEmpty) return true; - return auth2 - .getAuthInstance() - ?.currentUser - ?.get() - ?.grant(auth2.SigninOptions(scope: scopes.join(" "))) ?? + return currentUser + .grant(auth2.SigninOptions(scope: missingScopes.join(" "))) ?? false; } } diff --git a/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart b/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart index f2db090b6434..40bc8a404d06 100644 --- a/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart +++ b/packages/google_sign_in/google_sign_in_web/test/auth2_test.dart @@ -74,13 +74,7 @@ void main() { expect(actualToken, expectedTokenData); }); - test('hasGrantedScope', () async { - bool hasScope = await plugin.hasGrantedScope('scope'); - - expect(hasScope, isTrue); - }); - - test('requestScope', () async { + test('requestScopes', () async { bool scopeGranted = await plugin.requestScopes(['newScope']); expect(scopeGranted, isTrue); From f24a40fc4afeed7b363548da87b59dc8ff91a28f Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 11 Mar 2020 14:11:17 -0700 Subject: [PATCH 08/23] Remove unused constant. --- .../java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index bffc68465b7c..d531409d7b36 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -47,7 +47,6 @@ public class GoogleSignInPlugin implements MethodCallHandler { private static final String METHOD_DISCONNECT = "disconnect"; private static final String METHOD_IS_SIGNED_IN = "isSignedIn"; private static final String METHOD_CLEAR_AUTH_CACHE = "clearAuthCache"; - private static final String METHOD_LIST_MISSING_SCOPES = "listMissingScopes"; private static final String METHOD_REQUEST_SCOPES = "requestScopes"; private final IDelegate delegate; From 2c5577384ad94d4028777483c78ba9770bde69ea Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 11 Mar 2020 14:14:46 -0700 Subject: [PATCH 09/23] Complete sign-in loop on iOS. --- .../ios/Classes/FLTGoogleSignInPlugin.m | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 20e80c520f44..3183364b1537 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -37,6 +37,7 @@ @interface FLTGoogleSignInPlugin () @implementation FLTGoogleSignInPlugin { FlutterResult _accountRequest; + NSArray *_additionalScopesRequest; } + (void)registerWithRegistrar:(NSObject *)registrar { @@ -122,6 +123,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result // tokens are refreshed automatically by getTokensWithHandler. result(nil); } else if ([call.method isEqualToString:@"requestScopes"]) { + GIDGoogleUser *user = [GIDSignIn sharedInstance].currentUser; NSArray *currentScopes = [GIDSignIn sharedInstance].scopes; NSArray *scopes = call.arguments[@"scopes"]; NSArray *missingScopes = [scopes @@ -129,8 +131,23 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result predicateWithBlock:^BOOL(id scope, NSDictionary *bindings) { return ![user.grantedScopes containsObject:scope]; }]]; - [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes]; - [[GIDSignIn sharedInstance] signIn]; + + if (!missingScopes || !missingScopes.count) { + result(@(YES)); + return; + } + + if([self setAccountRequest:result]) { + _additionalScopesRequest = missingScopes; + [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes]; + [GIDSignIn sharedInstance].presentingViewController = [self topViewController]; + [GIDSignIn sharedInstance].loginHint = user.profile.email; + @try { + [[GIDSignIn sharedInstance] signIn]; + } @catch (NSException *e) { + result([FlutterError errorWithCode:@"request_scopes" message:e.reason details:e.name]); + } + } } else { result(FlutterMethodNotImplemented); } @@ -172,6 +189,20 @@ - (void)signIn:(GIDSignIn *)signIn // Forward all errors and let Dart side decide how to handle. [self respondWithAccount:nil error:error]; } else { + if(_additionalScopesRequest) { + bool granted = YES; + for(NSString *scope in _additionalScopesRequest) { + if(![user.grantedScopes containsObject:scope]) { + granted = NO; + break; + } + } + _accountRequest(@(granted)); + _accountRequest = nil; + _additionalScopesRequest = nil; + return; + } else { + NSURL *photoUrl; if (user.profile.hasImage) { // Placeholder that will be replaced by on the Dart side based on screen @@ -185,6 +216,7 @@ - (void)signIn:(GIDSignIn *)signIn @"photoUrl" : [photoUrl absoluteString] ?: [NSNull null], } error:nil]; + } } } From d6cbeb434c925b094e4b999cbeb2881f4104ac82 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 11 Mar 2020 14:22:21 -0700 Subject: [PATCH 10/23] Fix iOS plugin formatting. --- .../ios/Classes/FLTGoogleSignInPlugin.m | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 3183364b1537..ee7b2df00817 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -32,7 +32,7 @@ details:error.localizedDescription]; } -@interface FLTGoogleSignInPlugin () +@interface FLTGoogleSignInPlugin () @end @implementation FLTGoogleSignInPlugin { @@ -71,8 +71,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result message:@"Games sign in is not supported on iOS" details:nil]); } else { - NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" - ofType:@"plist"]; + NSString *path = + [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; if (path) { NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; [GIDSignIn sharedInstance].clientID = plist[kClientIdKey]; @@ -137,16 +137,17 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result return; } - if([self setAccountRequest:result]) { + if ([self setAccountRequest:result]) { _additionalScopesRequest = missingScopes; - [GIDSignIn sharedInstance].scopes = [currentScopes arrayByAddingObjectsFromArray:missingScopes]; + [GIDSignIn sharedInstance].scopes = + [currentScopes arrayByAddingObjectsFromArray:missingScopes]; [GIDSignIn sharedInstance].presentingViewController = [self topViewController]; [GIDSignIn sharedInstance].loginHint = user.profile.email; @try { [[GIDSignIn sharedInstance] signIn]; } @catch (NSException *e) { result([FlutterError errorWithCode:@"request_scopes" message:e.reason details:e.name]); - } + } } } else { result(FlutterMethodNotImplemented); @@ -189,10 +190,10 @@ - (void)signIn:(GIDSignIn *)signIn // Forward all errors and let Dart side decide how to handle. [self respondWithAccount:nil error:error]; } else { - if(_additionalScopesRequest) { + if (_additionalScopesRequest) { bool granted = YES; - for(NSString *scope in _additionalScopesRequest) { - if(![user.grantedScopes containsObject:scope]) { + for (NSString *scope in _additionalScopesRequest) { + if (![user.grantedScopes containsObject:scope]) { granted = NO; break; } @@ -202,20 +203,19 @@ - (void)signIn:(GIDSignIn *)signIn _additionalScopesRequest = nil; return; } else { - - NSURL *photoUrl; - if (user.profile.hasImage) { - // Placeholder that will be replaced by on the Dart side based on screen - // size - photoUrl = [user.profile imageURLWithDimension:1337]; - } - [self respondWithAccount:@{ - @"displayName" : user.profile.name ?: [NSNull null], - @"email" : user.profile.email ?: [NSNull null], - @"id" : user.userID ?: [NSNull null], - @"photoUrl" : [photoUrl absoluteString] ?: [NSNull null], - } - error:nil]; + NSURL *photoUrl; + if (user.profile.hasImage) { + // Placeholder that will be replaced by on the Dart side based on screen + // size + photoUrl = [user.profile imageURLWithDimension:1337]; + } + [self respondWithAccount:@{ + @"displayName" : user.profile.name ?: [NSNull null], + @"email" : user.profile.email ?: [NSNull null], + @"id" : user.userID ?: [NSNull null], + @"photoUrl" : [photoUrl absoluteString] ?: [NSNull null], + } + error:nil]; } } } From 64e52fd7f35e6fe3fbab94c95f8887b6e17c4e73 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 11 Mar 2020 14:31:10 -0700 Subject: [PATCH 11/23] Fix iOS formatting. --- .../google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index ee7b2df00817..31dfe35fc845 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -32,7 +32,7 @@ details:error.localizedDescription]; } -@interface FLTGoogleSignInPlugin () +@interface FLTGoogleSignInPlugin () @end @implementation FLTGoogleSignInPlugin { @@ -71,8 +71,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result message:@"Games sign in is not supported on iOS" details:nil]); } else { - NSString *path = - [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; + NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" + ofType:@"plist"]; if (path) { NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; [GIDSignIn sharedInstance].clientID = plist[kClientIdKey]; From 0002d12284fb01c84090148ba3528a5563aa28e3 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 10:02:01 -0700 Subject: [PATCH 12/23] ios unit tests --- .../ios/GoogleSignInExampleTests/Info.plist | 22 ++++++++ .../ios/Tests/GoogleSignInExampleTests.m | 54 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 packages/google_sign_in/google_sign_in/example/ios/GoogleSignInExampleTests/Info.plist create mode 100644 packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m diff --git a/packages/google_sign_in/google_sign_in/example/ios/GoogleSignInExampleTests/Info.plist b/packages/google_sign_in/google_sign_in/example/ios/GoogleSignInExampleTests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/example/ios/GoogleSignInExampleTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m new file mode 100644 index 000000000000..296b5e044644 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m @@ -0,0 +1,54 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; + +@import XCTest; +@import google_sign_in; +@import GoogleSignIn; +@import OCMock; + +@interface FLTGoogleSignInPluginTest : XCTestCase + +@property(strong, nonatomic) NSObject *mockBinaryMessenger; +@property(strong, nonatomic) NSObject *mockPluginRegistrar; +@property(strong, nonatomic) FLTGoogleSignInPlugin *plugin; +@property(strong, nonatomic) GIDSignIn *mockSharedInstance; + +@end + +@implementation FLTGoogleSignInPluginTest + +- (void)setUp { + [super setUp]; + self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + self.mockSharedInstance = [OCMockObject partialMockForObject:[GIDSignIn sharedInstance]]; + OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger); + self.plugin = [[FLTGoogleSignInPlugin alloc] init]; + [FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar]; +} + +- (void)testRequestScopesIfNoMissingScope { + // Mock Google Signin internal calls + GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); + OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); + NSArray *currentScopes = @[@"mockScope1"]; + OCMStub(mockUser.grantedScopes).andReturn(currentScopes); + FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"requestScopes" arguments:@{@"scopes":currentScopes}]; + + XCTestExpectation* expectation = + [self expectationWithDescription:@"expect result returns true"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertTrue([result boolValue]); + +} + +@end From 8dc89d589adc29b8d23a6e587d8c20648d83f4b4 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 10:02:14 -0700 Subject: [PATCH 13/23] podspec adding ocmock --- .../google_sign_in/google_sign_in/ios/google_sign_in.podspec | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec b/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec index 73533c6a0db6..0468c5a24807 100755 --- a/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec +++ b/packages/google_sign_in/google_sign_in/ios/google_sign_in.podspec @@ -20,4 +20,9 @@ Enables Google Sign-In in Flutter apps. s.platform = :ios, '8.0' s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + + s.test_spec 'Tests' do |test_spec| + test_spec.source_files = 'Tests/**/*' + test_spec.dependency 'OCMock','3.5' + end end From 34cdbaa65170139ddd4694c8469537d271456c22 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Tue, 17 Mar 2020 14:26:10 -0700 Subject: [PATCH 14/23] Add iOS tests for requestScopes. --- .../ios/Tests/GoogleSignInExampleTests.m | 54 ------- .../ios/Tests/GoogleSignInPluginTest.m | 136 ++++++++++++++++++ 2 files changed, 136 insertions(+), 54 deletions(-) delete mode 100644 packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m create mode 100644 packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m deleted file mode 100644 index 296b5e044644..000000000000 --- a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import Flutter; - -@import XCTest; -@import google_sign_in; -@import GoogleSignIn; -@import OCMock; - -@interface FLTGoogleSignInPluginTest : XCTestCase - -@property(strong, nonatomic) NSObject *mockBinaryMessenger; -@property(strong, nonatomic) NSObject *mockPluginRegistrar; -@property(strong, nonatomic) FLTGoogleSignInPlugin *plugin; -@property(strong, nonatomic) GIDSignIn *mockSharedInstance; - -@end - -@implementation FLTGoogleSignInPluginTest - -- (void)setUp { - [super setUp]; - self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); - self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); - self.mockSharedInstance = [OCMockObject partialMockForObject:[GIDSignIn sharedInstance]]; - OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger); - self.plugin = [[FLTGoogleSignInPlugin alloc] init]; - [FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar]; -} - -- (void)testRequestScopesIfNoMissingScope { - // Mock Google Signin internal calls - GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); - OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); - NSArray *currentScopes = @[@"mockScope1"]; - OCMStub(mockUser.grantedScopes).andReturn(currentScopes); - FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"requestScopes" arguments:@{@"scopes":currentScopes}]; - - XCTestExpectation* expectation = - [self expectationWithDescription:@"expect result returns true"]; - __block id result; - [self.plugin handleMethodCall:methodCall - result:^(id r) { - [expectation fulfill]; - result = r; - }]; - [self waitForExpectations:@[ expectation ] timeout:5]; - XCTAssertTrue([result boolValue]); - -} - -@end diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m new file mode 100644 index 000000000000..4a99c59b97b4 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m @@ -0,0 +1,136 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; + +@import XCTest; +@import google_sign_in; +@import GoogleSignIn; +@import OCMock; + +@interface FLTGoogleSignInPluginTest : XCTestCase + +@property(strong, nonatomic) NSObject *mockBinaryMessenger; +@property(strong, nonatomic) NSObject *mockPluginRegistrar; +@property(strong, nonatomic) FLTGoogleSignInPlugin *plugin; +@property(strong, nonatomic) GIDSignIn *mockSharedInstance; + +@end + +@implementation FLTGoogleSignInPluginTest + +- (void)setUp { + [super setUp]; + self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + self.mockSharedInstance = [OCMockObject partialMockForObject:[GIDSignIn sharedInstance]]; + OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger); + self.plugin = [[FLTGoogleSignInPlugin alloc] init]; + [FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar]; +} + +- (void)tearDown { + [((OCMockObject *)self.mockSharedInstance) stopMocking]; + [super tearDown]; +} + +- (void)testRequestScopesIfNoMissingScope { + // Mock Google Signin internal calls + GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); + OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); + NSArray *requestedScopes = @[ @"mockScope1" ]; + OCMStub(mockUser.grantedScopes).andReturn(requestedScopes); + FlutterMethodCall *methodCall = + [FlutterMethodCall methodCallWithMethodName:@"requestScopes" + arguments:@{@"scopes" : requestedScopes}]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertTrue([result boolValue]); +} + +- (void)testRequestScopesRequestsIfNotGranted { + // Mock Google Signin internal calls + GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); + OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); + NSArray *requestedScopes = @[ @"mockScope1" ]; + OCMStub(mockUser.grantedScopes).andReturn(@[]); + + FlutterMethodCall *methodCall = + [FlutterMethodCall methodCallWithMethodName:@"requestScopes" + arguments:@{@"scopes" : requestedScopes}]; + + [self.plugin handleMethodCall:methodCall + result:^(id r){ + }]; + + XCTAssertTrue([self.mockSharedInstance.scopes containsObject:@"mockScope1"]); + OCMVerify([self.mockSharedInstance signIn]); +} + +- (void)testRequestScopesReturnsFalseIfNotGranted { + // Mock Google Signin internal calls + GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); + OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); + NSArray *requestedScopes = @[ @"mockScope1" ]; + OCMStub(mockUser.grantedScopes).andReturn(@[]); + + OCMStub([self.mockSharedInstance signIn]).andDo(^(NSInvocation *invocation) { + [((NSObject *)self.plugin) signIn:self.mockSharedInstance + didSignInForUser:mockUser + withError:nil]; + }); + + FlutterMethodCall *methodCall = + [FlutterMethodCall methodCallWithMethodName:@"requestScopes" + arguments:@{@"scopes" : requestedScopes}]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns false"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertFalse([result boolValue]); +} + +- (void)testRequestScopesReturnsTrueIfGranted { + // Mock Google Signin internal calls + GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); + OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); + NSArray *requestedScopes = @[ @"mockScope1" ]; + NSMutableArray *availableScopes = [NSMutableArray new]; + OCMStub(mockUser.grantedScopes).andReturn(availableScopes); + + OCMStub([self.mockSharedInstance signIn]).andDo(^(NSInvocation *invocation) { + [availableScopes addObject:@"mockScope1"]; + [((NSObject *)self.plugin) signIn:self.mockSharedInstance + didSignInForUser:mockUser + withError:nil]; + }); + + FlutterMethodCall *methodCall = + [FlutterMethodCall methodCallWithMethodName:@"requestScopes" + arguments:@{@"scopes" : requestedScopes}]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertTrue([result boolValue]); +} + +@end From eb042ff4ebf68148336b6d4dff19045f328590cc Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 10:02:01 -0700 Subject: [PATCH 15/23] ios unit tests --- .../ios/Tests/GoogleSignInExampleTests.m | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m new file mode 100644 index 000000000000..296b5e044644 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m @@ -0,0 +1,54 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; + +@import XCTest; +@import google_sign_in; +@import GoogleSignIn; +@import OCMock; + +@interface FLTGoogleSignInPluginTest : XCTestCase + +@property(strong, nonatomic) NSObject *mockBinaryMessenger; +@property(strong, nonatomic) NSObject *mockPluginRegistrar; +@property(strong, nonatomic) FLTGoogleSignInPlugin *plugin; +@property(strong, nonatomic) GIDSignIn *mockSharedInstance; + +@end + +@implementation FLTGoogleSignInPluginTest + +- (void)setUp { + [super setUp]; + self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + self.mockSharedInstance = [OCMockObject partialMockForObject:[GIDSignIn sharedInstance]]; + OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger); + self.plugin = [[FLTGoogleSignInPlugin alloc] init]; + [FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar]; +} + +- (void)testRequestScopesIfNoMissingScope { + // Mock Google Signin internal calls + GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); + OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); + NSArray *currentScopes = @[@"mockScope1"]; + OCMStub(mockUser.grantedScopes).andReturn(currentScopes); + FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"requestScopes" arguments:@{@"scopes":currentScopes}]; + + XCTestExpectation* expectation = + [self expectationWithDescription:@"expect result returns true"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertTrue([result boolValue]); + +} + +@end From 815f673bbe4e9aae6f678a16c7169b3583287080 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 10:32:42 -0700 Subject: [PATCH 16/23] init setup for java --- .../google_sign_in/android/build.gradle | 2 + .../googlesignin/GoogleSignInPluginTests.java | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java diff --git a/packages/google_sign_in/google_sign_in/android/build.gradle b/packages/google_sign_in/google_sign_in/android/build.gradle index 144739559b5c..1380beb89a48 100755 --- a/packages/google_sign_in/google_sign_in/android/build.gradle +++ b/packages/google_sign_in/google_sign_in/android/build.gradle @@ -36,4 +36,6 @@ android { dependencies { implementation 'com.google.android.gms:play-services-auth:16.0.1' implementation 'com.google.guava:guava:20.0' + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:2.17.0' } diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java new file mode 100644 index 000000000000..df3f17dcc99f --- /dev/null +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java @@ -0,0 +1,40 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlesignin; + +import static org.mockito.Mockito.when; +// +//import android.app.Activity; +//import android.app.Application; +//import android.content.Context; +//import io.flutter.plugin.common.BinaryMessenger; +//import io.flutter.plugin.common.PluginRegistry; +//import org.junit.Before; +//import org.junit.Test; +//import org.mockito.Mock; +//import org.mockito.MockitoAnnotations; + +public class GoogleSignInPluginTests { +// @Mock Activity activity; +// @Mock Context context; +// @Mock PluginRegistry.Registrar mockRegistrar; // For v1 embedding +// @Mock BinaryMessenger mockMessenger; +// @Mock Application mockApplication; +// +// @Before +// public void setUp() { +// MockitoAnnotations.initMocks(this); +// when(mockRegistrar.activity()).thenReturn(activity); +// when(mockRegistrar.messenger()).thenReturn(mockMessenger); +// when(mockRegistrar.context()).thenReturn(context); +// } +// +// @Test +// public void registerWith_doNotCrashWhenRegisterContextIsActivity_V1Embedding() { +// when(mockRegistrar.context()).thenReturn(activity); +// when(activity.getApplicationContext()).thenReturn(mockApplication); +// InAppPurchasePlugin.registerWith(mockRegistrar); +// } +} \ No newline at end of file From 8d5b4dff20f893b95826f8e908ffa2b0109c3948 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 11:48:41 -0700 Subject: [PATCH 17/23] update --- .../google_sign_in/android/build.gradle | 4 +- .../googlesignin/GoogleSignInPluginTests.java | 40 ------------------ .../GoogleSignInPluginTests.java | 41 +++++++++++++++++++ 3 files changed, 43 insertions(+), 42 deletions(-) delete mode 100644 packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java create mode 100644 packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java diff --git a/packages/google_sign_in/google_sign_in/android/build.gradle b/packages/google_sign_in/google_sign_in/android/build.gradle index 1380beb89a48..9730af9eefbd 100755 --- a/packages/google_sign_in/google_sign_in/android/build.gradle +++ b/packages/google_sign_in/google_sign_in/android/build.gradle @@ -36,6 +36,6 @@ android { dependencies { implementation 'com.google.android.gms:play-services-auth:16.0.1' implementation 'com.google.guava:guava:20.0' - testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.17.0' + testCompile 'junit:junit:4.12' + testCompile 'org.mockito:mockito-core:2.17.0' } diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java deleted file mode 100644 index df3f17dcc99f..000000000000 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.googlesignin; - -import static org.mockito.Mockito.when; -// -//import android.app.Activity; -//import android.app.Application; -//import android.content.Context; -//import io.flutter.plugin.common.BinaryMessenger; -//import io.flutter.plugin.common.PluginRegistry; -//import org.junit.Before; -//import org.junit.Test; -//import org.mockito.Mock; -//import org.mockito.MockitoAnnotations; - -public class GoogleSignInPluginTests { -// @Mock Activity activity; -// @Mock Context context; -// @Mock PluginRegistry.Registrar mockRegistrar; // For v1 embedding -// @Mock BinaryMessenger mockMessenger; -// @Mock Application mockApplication; -// -// @Before -// public void setUp() { -// MockitoAnnotations.initMocks(this); -// when(mockRegistrar.activity()).thenReturn(activity); -// when(mockRegistrar.messenger()).thenReturn(mockMessenger); -// when(mockRegistrar.context()).thenReturn(context); -// } -// -// @Test -// public void registerWith_doNotCrashWhenRegisterContextIsActivity_V1Embedding() { -// when(mockRegistrar.context()).thenReturn(activity); -// when(activity.getApplicationContext()).thenReturn(mockApplication); -// InAppPurchasePlugin.registerWith(mockRegistrar); -// } -} \ No newline at end of file diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java new file mode 100644 index 000000000000..11cc6afcd338 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java @@ -0,0 +1,41 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlesignintests; + +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.PluginRegistry; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class GoogleSignInPluginTests { + + @Mock Activity activity; + @Mock Context context; + @Mock PluginRegistry.Registrar mockRegistrar; + @Mock BinaryMessenger mockMessenger; + @Mock Application mockApplication; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mockRegistrar.activity()).thenReturn(activity); + when(mockRegistrar.messenger()).thenReturn(mockMessenger); + when(mockRegistrar.context()).thenReturn(context); + } +// +// @Test +// public void registerWith_doNotCrashWhenRegisterContextIsActivity_V1Embedding() { +// when(mockRegistrar.context()).thenReturn(activity); +// when(activity.getApplicationContext()).thenReturn(mockApplication); +// InAppPurchasePlugin.registerWith(mockRegistrar); +// } +} \ No newline at end of file From 1f0ea7abd1a9dc6c42ecd4175b04c98bc01d84d6 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 16:47:19 -0700 Subject: [PATCH 18/23] setup java test --- .../google_sign_in/android/build.gradle | 27 ++++++++++- .../googlesignin/GoogleSignInPlugin.java | 30 ++++++++++-- .../example/android/app/build.gradle | 6 +++ .../googlesignin/GoogleSignInPluginTests.java | 46 +++++++++++++++++++ .../GoogleSignInPluginTests.java | 41 ----------------- 5 files changed, 102 insertions(+), 48 deletions(-) create mode 100644 packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java delete mode 100644 packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java diff --git a/packages/google_sign_in/google_sign_in/android/build.gradle b/packages/google_sign_in/google_sign_in/android/build.gradle index 9730af9eefbd..d758fa8b2a55 100755 --- a/packages/google_sign_in/google_sign_in/android/build.gradle +++ b/packages/google_sign_in/google_sign_in/android/build.gradle @@ -36,6 +36,29 @@ android { dependencies { implementation 'com.google.android.gms:play-services-auth:16.0.1' implementation 'com.google.guava:guava:20.0' - testCompile 'junit:junit:4.12' - testCompile 'org.mockito:mockito-core:2.17.0' } + +afterEvaluate { + def containsEmbeddingDependencies = false + for (def configuration : configurations.all) { + for (def dependency : configuration.dependencies) { + if (dependency.group == 'io.flutter' && + dependency.name.startsWith('flutter_embedding') && + dependency.isTransitive()) + { + containsEmbeddingDependencies = true + break + } + } + } + if (!containsEmbeddingDependencies) { + android { + dependencies { + def lifecycle_version = "1.1.1" + compileOnly "android.arch.lifecycle:runtime:$lifecycle_version" + compileOnly "android.arch.lifecycle:common:$lifecycle_version" + compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version" + } + } + } +} \ No newline at end of file diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index d531409d7b36..30526093b028 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -6,7 +6,10 @@ import android.accounts.Account; import android.app.Activity; +import android.content.Context; import android.content.Intent; +import android.support.annotation.VisibleForTesting; + import com.google.android.gms.auth.GoogleAuthUtil; import com.google.android.gms.auth.UserRecoverableAuthException; import com.google.android.gms.auth.api.signin.GoogleSignIn; @@ -53,12 +56,12 @@ public class GoogleSignInPlugin implements MethodCallHandler { public static void registerWith(PluginRegistry.Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME); - final GoogleSignInPlugin instance = new GoogleSignInPlugin(registrar); + final GoogleSignInPlugin instance = new GoogleSignInPlugin(registrar, new GoogleSignInWrapper()); channel.setMethodCallHandler(instance); } - private GoogleSignInPlugin(PluginRegistry.Registrar registrar) { - delegate = new Delegate(registrar); + GoogleSignInPlugin(PluginRegistry.Registrar registrar, GoogleSignInWrapper googleSignInWrapper) { + delegate = new Delegate(registrar, googleSignInWrapper); } @Override @@ -194,13 +197,15 @@ public static final class Delegate implements IDelegate, PluginRegistry.Activity private final PluginRegistry.Registrar registrar; private final BackgroundTaskRunner backgroundTaskRunner = new BackgroundTaskRunner(1); + private final GoogleSignInWrapper googleSignInWrapper; private GoogleSignInClient signInClient; private List requestedScopes; private PendingOperation pendingOperation; - public Delegate(PluginRegistry.Registrar registrar) { + public Delegate(PluginRegistry.Registrar registrar, GoogleSignInWrapper googleSignInWrapper) { this.registrar = registrar; + this.googleSignInWrapper = googleSignInWrapper; registrar.addActivityResultListener(this); } @@ -356,7 +361,7 @@ public void isSignedIn(final Result result) { @Override public void requestScopes(Result result, List scopes) { - GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(registrar.context()); + GoogleSignInAccount account = googleSignInWrapper.getLastSignedInAccount(registrar.context()); if (account == null) { result.error(ERROR_REASON_SIGN_IN_REQUIRED, "No account to grant scopes.", null); return; @@ -576,3 +581,18 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { } } } + +/** + * A wrapper object that calls static method in GoogleSignIn. + * + * Because GoogleSignIn uses static method mostly, which is hard for unit testing. We use this wrapper + * class to use instance method which calls the corresponding GoogleSignIn static methods. + * + * Warning! This class should stay true that each method calls a GoogleSignIn static method with the same name and same parameters. + */ +class GoogleSignInWrapper { + + GoogleSignInAccount getLastSignedInAccount(Context context) { + return GoogleSignIn.getLastSignedInAccount(context); + } +} diff --git a/packages/google_sign_in/google_sign_in/example/android/app/build.gradle b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle index 5b1c5699d48d..722fd42419ff 100755 --- a/packages/google_sign_in/google_sign_in/example/android/app/build.gradle +++ b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle @@ -52,3 +52,9 @@ android { flutter { source '../..' } + +dependencies { + implementation 'com.google.android.gms:play-services-auth:16.0.1' + testImplementation'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:2.17.0' +} diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java new file mode 100644 index 000000000000..397d0b46afd7 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java @@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlesignin; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.PluginRegistry; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +public class GoogleSignInPluginTests { + + @Mock Context mockContext; + @Mock PluginRegistry.Registrar mockRegistrar; + @Mock BinaryMessenger mockMessenger; + @Spy MethodChannel.Result result; + @Mock GoogleSignInWrapper mockGoogleSignIn; + GoogleSignInPlugin plugin; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mockRegistrar.messenger()).thenReturn(mockMessenger); + when(mockRegistrar.context()).thenReturn(mockContext); + GoogleSignInPlugin.registerWith(mockRegistrar); + plugin = new GoogleSignInPlugin(mockRegistrar, mockGoogleSignIn); + } + + @Test + public void requestScopes_ResultErrorIfAccountIsNull() { + MethodCall methodCall = new MethodCall("requestScopes", null); + when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(null); + plugin.onMethodCall(methodCall, result); + verify(result).error("sign_in_required", "No account to grant scopes.", null); + } +} diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java deleted file mode 100644 index 11cc6afcd338..000000000000 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignintests/GoogleSignInPluginTests.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.googlesignintests; - -import static org.mockito.Mockito.when; - -import android.app.Activity; -import android.app.Application; -import android.content.Context; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.PluginRegistry; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -public class GoogleSignInPluginTests { - - @Mock Activity activity; - @Mock Context context; - @Mock PluginRegistry.Registrar mockRegistrar; - @Mock BinaryMessenger mockMessenger; - @Mock Application mockApplication; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - when(mockRegistrar.activity()).thenReturn(activity); - when(mockRegistrar.messenger()).thenReturn(mockMessenger); - when(mockRegistrar.context()).thenReturn(context); - } -// -// @Test -// public void registerWith_doNotCrashWhenRegisterContextIsActivity_V1Embedding() { -// when(mockRegistrar.context()).thenReturn(activity); -// when(activity.getApplicationContext()).thenReturn(mockApplication); -// InAppPurchasePlugin.registerWith(mockRegistrar); -// } -} \ No newline at end of file From e20566c374d6f981b6ba0c7eb70b99b4830985a7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 17 Mar 2020 16:49:40 -0700 Subject: [PATCH 19/23] revert gradle change --- .../google_sign_in/android/build.gradle | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/android/build.gradle b/packages/google_sign_in/google_sign_in/android/build.gradle index d758fa8b2a55..b900b12f5ae6 100755 --- a/packages/google_sign_in/google_sign_in/android/build.gradle +++ b/packages/google_sign_in/google_sign_in/android/build.gradle @@ -32,33 +32,3 @@ android { disable 'InvalidPackage' } } - -dependencies { - implementation 'com.google.android.gms:play-services-auth:16.0.1' - implementation 'com.google.guava:guava:20.0' -} - -afterEvaluate { - def containsEmbeddingDependencies = false - for (def configuration : configurations.all) { - for (def dependency : configuration.dependencies) { - if (dependency.group == 'io.flutter' && - dependency.name.startsWith('flutter_embedding') && - dependency.isTransitive()) - { - containsEmbeddingDependencies = true - break - } - } - } - if (!containsEmbeddingDependencies) { - android { - dependencies { - def lifecycle_version = "1.1.1" - compileOnly "android.arch.lifecycle:runtime:$lifecycle_version" - compileOnly "android.arch.lifecycle:common:$lifecycle_version" - compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version" - } - } - } -} \ No newline at end of file From b5ccc5af0d10e00b0b3f41014e717b62d1ecaf7d Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 18 Mar 2020 10:34:21 -0700 Subject: [PATCH 20/23] Add tests for requestsScopes Android implementation. --- .../google_sign_in/android/build.gradle | 5 ++ .../googlesignin/GoogleSignInPlugin.java | 18 +++- .../googlesignin/GoogleSignInPluginTests.java | 89 ++++++++++++++++++- .../org.mockito.plugins.MockMaker | 1 + 4 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 packages/google_sign_in/google_sign_in/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/packages/google_sign_in/google_sign_in/android/build.gradle b/packages/google_sign_in/google_sign_in/android/build.gradle index b900b12f5ae6..144739559b5c 100755 --- a/packages/google_sign_in/google_sign_in/android/build.gradle +++ b/packages/google_sign_in/google_sign_in/android/build.gradle @@ -32,3 +32,8 @@ android { disable 'InvalidPackage' } } + +dependencies { + implementation 'com.google.android.gms:play-services-auth:16.0.1' + implementation 'com.google.guava:guava:20.0' +} diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 30526093b028..2e67bc6e99cb 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -180,7 +180,7 @@ public void init( public static final class Delegate implements IDelegate, PluginRegistry.ActivityResultListener { private static final int REQUEST_CODE_SIGNIN = 53293; private static final int REQUEST_CODE_RECOVER_AUTH = 53294; - private static final int REQUEST_CODE_REQUEST_SCOPE = 53295; + @VisibleForTesting static final int REQUEST_CODE_REQUEST_SCOPE = 53295; private static final String ERROR_REASON_EXCEPTION = "exception"; private static final String ERROR_REASON_STATUS = "status"; @@ -361,6 +361,8 @@ public void isSignedIn(final Result result) { @Override public void requestScopes(Result result, List scopes) { + checkAndSetPendingOperation(METHOD_REQUEST_SCOPES, result); + GoogleSignInAccount account = googleSignInWrapper.getLastSignedInAccount(registrar.context()); if (account == null) { result.error(ERROR_REASON_SIGN_IN_REQUIRED, "No account to grant scopes.", null); @@ -371,7 +373,7 @@ public void requestScopes(Result result, List scopes) { for (String scope : scopes) { Scope wrappedScope = new Scope(scope); - if (!GoogleSignIn.hasPermissions(account, wrappedScope)) { + if (!googleSignInWrapper.hasPermissions(account, wrappedScope)) { wrappedScopes.add(wrappedScope); } } @@ -381,7 +383,7 @@ public void requestScopes(Result result, List scopes) { return; } - GoogleSignIn.requestPermissions( + googleSignInWrapper.requestPermissions( registrar.activity(), REQUEST_CODE_REQUEST_SCOPE, account, @@ -573,7 +575,7 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { } return true; case REQUEST_CODE_REQUEST_SCOPE: - pendingOperation.result.success(resultCode == Activity.RESULT_OK); + finishWithSuccess(resultCode == Activity.RESULT_OK); return true; default: return false; @@ -595,4 +597,12 @@ class GoogleSignInWrapper { GoogleSignInAccount getLastSignedInAccount(Context context) { return GoogleSignIn.getLastSignedInAccount(context); } + + boolean hasPermissions(GoogleSignInAccount account, Scope scope) { + return GoogleSignIn.hasPermissions(account, scope); + } + + void requestPermissions(Activity activity, int requestCode, GoogleSignInAccount account, Scope[] scopes) { + GoogleSignIn.requestPermissions(activity, requestCode, account, scopes); + } } diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java index 397d0b46afd7..ef66368e5d26 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java @@ -7,13 +7,23 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.content.Context; +import android.content.Intent; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.common.api.Scope; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugin.common.PluginRegistry.ActivityResultListener; +import io.flutter.plugins.googlesignin.GoogleSignInPlugin.Delegate; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -21,18 +31,20 @@ public class GoogleSignInPluginTests { @Mock Context mockContext; + @Mock Activity mockActivity; @Mock PluginRegistry.Registrar mockRegistrar; @Mock BinaryMessenger mockMessenger; @Spy MethodChannel.Result result; @Mock GoogleSignInWrapper mockGoogleSignIn; - GoogleSignInPlugin plugin; + @Mock GoogleSignInAccount account; + private GoogleSignInPlugin plugin; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mockRegistrar.messenger()).thenReturn(mockMessenger); when(mockRegistrar.context()).thenReturn(mockContext); - GoogleSignInPlugin.registerWith(mockRegistrar); + when(mockRegistrar.activity()).thenReturn(mockActivity); plugin = new GoogleSignInPlugin(mockRegistrar, mockGoogleSignIn); } @@ -43,4 +55,77 @@ public void requestScopes_ResultErrorIfAccountIsNull() { plugin.onMethodCall(methodCall, result); verify(result).error("sign_in_required", "No account to grant scopes.", null); } + + @Test + public void requestScopes_ResultTrueIfAlreadyGranted() { + HashMap> arguments = new HashMap<>(); + arguments.put("scopes", Collections.singletonList("requestedScope")); + + MethodCall methodCall = new MethodCall("requestScopes", arguments); + Scope requestedScope = new Scope("requestedScope"); + when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); + when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); + when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(true); + + plugin.onMethodCall(methodCall, result); + verify(result).success(true); + } + + @Test + public void requestScopes_RequestsPermissionIfNotGranted() { + HashMap> arguments = new HashMap<>(); + arguments.put("scopes", Collections.singletonList("requestedScope")); + MethodCall methodCall = new MethodCall("requestScopes", arguments); + Scope requestedScope = new Scope("requestedScope"); + + when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); + when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); + when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); + + plugin.onMethodCall(methodCall, result); + + verify(mockGoogleSignIn).requestPermissions(mockActivity, 53295, account, new Scope[] {requestedScope}); + } + + @Test + public void requestScopes_ReturnsFalseIfPermissionDenied() { + HashMap> arguments = new HashMap<>(); + arguments.put("scopes", Collections.singletonList("requestedScope")); + MethodCall methodCall = new MethodCall("requestScopes", arguments); + Scope requestedScope = new Scope("requestedScope"); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ActivityResultListener.class); + verify(mockRegistrar).addActivityResultListener(captor.capture()); + ActivityResultListener listener = captor.getValue(); + + when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); + when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); + when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); + + plugin.onMethodCall(methodCall, result); + listener.onActivityResult(Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_CANCELED, new Intent()); + + verify(result).success(false); + } + + @Test + public void requestScopes_ReturnsTrueIfPermissionGranted() { + HashMap> arguments = new HashMap<>(); + arguments.put("scopes", Collections.singletonList("requestedScope")); + MethodCall methodCall = new MethodCall("requestScopes", arguments); + Scope requestedScope = new Scope("requestedScope"); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ActivityResultListener.class); + verify(mockRegistrar).addActivityResultListener(captor.capture()); + ActivityResultListener listener = captor.getValue(); + + when(mockGoogleSignIn.getLastSignedInAccount(mockContext)).thenReturn(account); + when(account.getGrantedScopes()).thenReturn(Collections.singleton(requestedScope)); + when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); + + plugin.onMethodCall(methodCall, result); + listener.onActivityResult(Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); + + verify(result).success(true); + } } diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/packages/google_sign_in/google_sign_in/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000000..1f0955d450f0 --- /dev/null +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline From edf36ec374f996902c6b9c29aae2fe4272b755b8 Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 18 Mar 2020 11:55:49 -0700 Subject: [PATCH 21/23] Clean up iOS; add test case for absent account. --- .../Info.plist | 0 .../ios/Classes/FLTGoogleSignInPlugin.m | 5 ++ .../ios/Tests/GoogleSignInExampleTests.m | 54 ------------------- .../ios/Tests/GoogleSignInPluginTest.m | 18 +++++++ 4 files changed, 23 insertions(+), 54 deletions(-) rename packages/google_sign_in/google_sign_in/example/ios/{GoogleSignInExampleTests => GoogleSignInPluginTest}/Info.plist (100%) delete mode 100644 packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m diff --git a/packages/google_sign_in/google_sign_in/example/ios/GoogleSignInExampleTests/Info.plist b/packages/google_sign_in/google_sign_in/example/ios/GoogleSignInPluginTest/Info.plist similarity index 100% rename from packages/google_sign_in/google_sign_in/example/ios/GoogleSignInExampleTests/Info.plist rename to packages/google_sign_in/google_sign_in/example/ios/GoogleSignInPluginTest/Info.plist diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 31dfe35fc845..ceb93d05a0dc 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -124,6 +124,11 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result result(nil); } else if ([call.method isEqualToString:@"requestScopes"]) { GIDGoogleUser *user = [GIDSignIn sharedInstance].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 diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m deleted file mode 100644 index 296b5e044644..000000000000 --- a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInExampleTests.m +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import Flutter; - -@import XCTest; -@import google_sign_in; -@import GoogleSignIn; -@import OCMock; - -@interface FLTGoogleSignInPluginTest : XCTestCase - -@property(strong, nonatomic) NSObject *mockBinaryMessenger; -@property(strong, nonatomic) NSObject *mockPluginRegistrar; -@property(strong, nonatomic) FLTGoogleSignInPlugin *plugin; -@property(strong, nonatomic) GIDSignIn *mockSharedInstance; - -@end - -@implementation FLTGoogleSignInPluginTest - -- (void)setUp { - [super setUp]; - self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); - self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); - self.mockSharedInstance = [OCMockObject partialMockForObject:[GIDSignIn sharedInstance]]; - OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger); - self.plugin = [[FLTGoogleSignInPlugin alloc] init]; - [FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar]; -} - -- (void)testRequestScopesIfNoMissingScope { - // Mock Google Signin internal calls - GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); - OCMStub(self.mockSharedInstance.currentUser).andReturn(mockUser); - NSArray *currentScopes = @[@"mockScope1"]; - OCMStub(mockUser.grantedScopes).andReturn(currentScopes); - FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"requestScopes" arguments:@{@"scopes":currentScopes}]; - - XCTestExpectation* expectation = - [self expectationWithDescription:@"expect result returns true"]; - __block id result; - [self.plugin handleMethodCall:methodCall - result:^(id r) { - [expectation fulfill]; - result = r; - }]; - [self waitForExpectations:@[ expectation ] timeout:5]; - XCTAssertTrue([result boolValue]); - -} - -@end diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m index 4a99c59b97b4..00f6d831d4f6 100644 --- a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m @@ -35,6 +35,24 @@ - (void)tearDown { [super tearDown]; } +-(void)testRequestScopesResultErrorIfNotSignedIn { + OCMStub(self.mockSharedInstance.currentUser).andReturn(nil); + + FlutterMethodCall *methodCall = + [FlutterMethodCall methodCallWithMethodName:@"requestScopes" + arguments:@{@"scopes" : @[ @"mockScope1" ]}]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertEqualObjects([((FlutterError*) result) code], @"sign_in_required"); +} + - (void)testRequestScopesIfNoMissingScope { // Mock Google Signin internal calls GIDGoogleUser *mockUser = OCMClassMock(GIDGoogleUser.class); From d496ae21219f149527db18150f74df58f56d4ebd Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Wed, 18 Mar 2020 13:04:56 -0700 Subject: [PATCH 22/23] Format google_sign_in; fix Android tests. --- .../googlesignin/GoogleSignInPlugin.java | 14 ++++++---- .../example/android/app/build.gradle | 4 +++ .../googlesignin/GoogleSignInPluginTests.java | 15 ++++++---- .../ios/Classes/FLTGoogleSignInPlugin.m | 6 ++-- .../ios/Tests/GoogleSignInPluginTest.m | 28 +++++++++---------- 5 files changed, 40 insertions(+), 27 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 2e67bc6e99cb..fc83444e8172 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -9,7 +9,6 @@ import android.content.Context; import android.content.Intent; import android.support.annotation.VisibleForTesting; - import com.google.android.gms.auth.GoogleAuthUtil; import com.google.android.gms.auth.UserRecoverableAuthException; import com.google.android.gms.auth.api.signin.GoogleSignIn; @@ -56,7 +55,8 @@ public class GoogleSignInPlugin implements MethodCallHandler { public static void registerWith(PluginRegistry.Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME); - final GoogleSignInPlugin instance = new GoogleSignInPlugin(registrar, new GoogleSignInWrapper()); + final GoogleSignInPlugin instance = + new GoogleSignInPlugin(registrar, new GoogleSignInWrapper()); channel.setMethodCallHandler(instance); } @@ -587,10 +587,11 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { /** * A wrapper object that calls static method in GoogleSignIn. * - * Because GoogleSignIn uses static method mostly, which is hard for unit testing. We use this wrapper - * class to use instance method which calls the corresponding GoogleSignIn static methods. + *

Because GoogleSignIn uses static method mostly, which is hard for unit testing. We use this + * wrapper class to use instance method which calls the corresponding GoogleSignIn static methods. * - * Warning! This class should stay true that each method calls a GoogleSignIn static method with the same name and same parameters. + *

Warning! This class should stay true that each method calls a GoogleSignIn static method with + * the same name and same parameters. */ class GoogleSignInWrapper { @@ -602,7 +603,8 @@ boolean hasPermissions(GoogleSignInAccount account, Scope scope) { return GoogleSignIn.hasPermissions(account, scope); } - void requestPermissions(Activity activity, int requestCode, GoogleSignInAccount account, Scope[] scopes) { + void requestPermissions( + Activity activity, int requestCode, GoogleSignInAccount account, Scope[] scopes) { GoogleSignIn.requestPermissions(activity, requestCode, account, scopes); } } diff --git a/packages/google_sign_in/google_sign_in/example/android/app/build.gradle b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle index 722fd42419ff..e6da1a0aebf5 100755 --- a/packages/google_sign_in/google_sign_in/example/android/app/build.gradle +++ b/packages/google_sign_in/google_sign_in/example/android/app/build.gradle @@ -47,6 +47,10 @@ android { signingConfig signingConfigs.debug } } + + testOptions { + unitTests.returnDefaultValues = true + } } flutter { diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java index ef66368e5d26..bd8e37ae3a28 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java @@ -84,7 +84,8 @@ public void requestScopes_RequestsPermissionIfNotGranted() { plugin.onMethodCall(methodCall, result); - verify(mockGoogleSignIn).requestPermissions(mockActivity, 53295, account, new Scope[] {requestedScope}); + verify(mockGoogleSignIn) + .requestPermissions(mockActivity, 53295, account, new Scope[] {requestedScope}); } @Test @@ -94,7 +95,8 @@ public void requestScopes_ReturnsFalseIfPermissionDenied() { MethodCall methodCall = new MethodCall("requestScopes", arguments); Scope requestedScope = new Scope("requestedScope"); - ArgumentCaptor captor = ArgumentCaptor.forClass(ActivityResultListener.class); + ArgumentCaptor captor = + ArgumentCaptor.forClass(ActivityResultListener.class); verify(mockRegistrar).addActivityResultListener(captor.capture()); ActivityResultListener listener = captor.getValue(); @@ -103,7 +105,8 @@ public void requestScopes_ReturnsFalseIfPermissionDenied() { when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); plugin.onMethodCall(methodCall, result); - listener.onActivityResult(Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_CANCELED, new Intent()); + listener.onActivityResult( + Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_CANCELED, new Intent()); verify(result).success(false); } @@ -115,7 +118,8 @@ public void requestScopes_ReturnsTrueIfPermissionGranted() { MethodCall methodCall = new MethodCall("requestScopes", arguments); Scope requestedScope = new Scope("requestedScope"); - ArgumentCaptor captor = ArgumentCaptor.forClass(ActivityResultListener.class); + ArgumentCaptor captor = + ArgumentCaptor.forClass(ActivityResultListener.class); verify(mockRegistrar).addActivityResultListener(captor.capture()); ActivityResultListener listener = captor.getValue(); @@ -124,7 +128,8 @@ public void requestScopes_ReturnsTrueIfPermissionGranted() { when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); plugin.onMethodCall(methodCall, result); - listener.onActivityResult(Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); + listener.onActivityResult( + Delegate.REQUEST_CODE_REQUEST_SCOPE, Activity.RESULT_OK, new Intent()); verify(result).success(true); } diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index ceb93d05a0dc..9049fcd62a33 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -124,8 +124,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result result(nil); } else if ([call.method isEqualToString:@"requestScopes"]) { GIDGoogleUser *user = [GIDSignIn sharedInstance].currentUser; - if(user == nil) { - result([FlutterError errorWithCode:@"sign_in_required" message:@"No account to grant scopes." details:nil]); + if (user == nil) { + result([FlutterError errorWithCode:@"sign_in_required" + message:@"No account to grant scopes." + details:nil]); return; } diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m index 00f6d831d4f6..ca1861431b86 100644 --- a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m @@ -35,22 +35,22 @@ - (void)tearDown { [super tearDown]; } --(void)testRequestScopesResultErrorIfNotSignedIn { +- (void)testRequestScopesResultErrorIfNotSignedIn { OCMStub(self.mockSharedInstance.currentUser).andReturn(nil); - FlutterMethodCall *methodCall = - [FlutterMethodCall methodCallWithMethodName:@"requestScopes" - arguments:@{@"scopes" : @[ @"mockScope1" ]}]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; - __block id result; - [self.plugin handleMethodCall:methodCall - result:^(id r) { - [expectation fulfill]; - result = r; - }]; - [self waitForExpectations:@[ expectation ] timeout:5]; - XCTAssertEqualObjects([((FlutterError*) result) code], @"sign_in_required"); + FlutterMethodCall *methodCall = + [FlutterMethodCall methodCallWithMethodName:@"requestScopes" + arguments:@{@"scopes" : @[ @"mockScope1" ]}]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; + __block id result; + [self.plugin handleMethodCall:methodCall + result:^(id r) { + [expectation fulfill]; + result = r; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertEqualObjects([((FlutterError *)result) code], @"sign_in_required"); } - (void)testRequestScopesIfNoMissingScope { From 0377f2cf198e997d89ee60f4f908b7ec1818010a Mon Sep 17 00:00:00 2001 From: Conner Kasten Date: Thu, 19 Mar 2020 14:53:11 -0700 Subject: [PATCH 23/23] Switch to AndroidX annotation. --- .../io/flutter/plugins/googlesignin/GoogleSignInPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index fc83444e8172..ebebfa0294ab 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -8,7 +8,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.VisibleForTesting; import com.google.android.gms.auth.GoogleAuthUtil; import com.google.android.gms.auth.UserRecoverableAuthException; import com.google.android.gms.auth.api.signin.GoogleSignIn;