From 7552ca22471890326a53fc167b9b466bba3020c6 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 10:50:43 -0400 Subject: [PATCH 1/7] Duplicate default method channel files exactly --- .../lib/method_channel_google_sign_in.dart | 91 +++++++++++ .../google_sign_in_android/lib/src/utils.dart | 28 ++++ .../method_channel_google_sign_in_test.dart | 141 ++++++++++++++++++ .../lib/method_channel_google_sign_in.dart | 91 +++++++++++ .../google_sign_in_ios/lib/src/utils.dart | 28 ++++ .../method_channel_google_sign_in_test.dart | 141 ++++++++++++++++++ 6 files changed, 520 insertions(+) create mode 100644 packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart create mode 100644 packages/google_sign_in/google_sign_in_android/lib/src/utils.dart create mode 100644 packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart create mode 100644 packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart create mode 100644 packages/google_sign_in/google_sign_in_ios/lib/src/utils.dart create mode 100644 packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart diff --git a/packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart new file mode 100644 index 000000000000..1abda09fa99f --- /dev/null +++ b/packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart' show visibleForTesting; +import 'package:flutter/services.dart'; + +import '../google_sign_in_platform_interface.dart'; +import 'types.dart'; +import 'utils.dart'; + +/// An implementation of [GoogleSignInPlatform] that uses method channels. +class MethodChannelGoogleSignIn extends GoogleSignInPlatform { + /// This is only exposed for test purposes. It shouldn't be used by clients of + /// the plugin as it may break or change at any time. + @visibleForTesting + MethodChannel channel = + const MethodChannel('plugins.flutter.io/google_sign_in'); + + @override + Future init({ + List scopes = const [], + SignInOption signInOption = SignInOption.standard, + String? hostedDomain, + String? clientId, + }) { + return channel.invokeMethod('init', { + 'signInOption': signInOption.toString(), + 'scopes': scopes, + 'hostedDomain': hostedDomain, + 'clientId': clientId, + }); + } + + @override + Future signInSilently() { + return channel + .invokeMapMethod('signInSilently') + .then(getUserDataFromMap); + } + + @override + Future signIn() { + return channel + .invokeMapMethod('signIn') + .then(getUserDataFromMap); + } + + @override + Future getTokens( + {required String email, bool? shouldRecoverAuth = true}) { + return channel + .invokeMapMethod('getTokens', { + 'email': email, + 'shouldRecoverAuth': shouldRecoverAuth, + }).then((Map? result) => getTokenDataFromMap(result!)); + } + + @override + Future signOut() { + return channel.invokeMapMethod('signOut'); + } + + @override + Future disconnect() { + return channel.invokeMapMethod('disconnect'); + } + + @override + Future isSignedIn() async { + return (await channel.invokeMethod('isSignedIn'))!; + } + + @override + Future clearAuthCache({String? token}) { + return channel.invokeMethod( + 'clearAuthCache', + {'token': token}, + ); + } + + @override + Future requestScopes(List scopes) async { + return (await channel.invokeMethod( + 'requestScopes', + >{'scopes': scopes}, + ))!; + } +} diff --git a/packages/google_sign_in/google_sign_in_android/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_android/lib/src/utils.dart new file mode 100644 index 000000000000..5cd7c20b829a --- /dev/null +++ b/packages/google_sign_in/google_sign_in_android/lib/src/utils.dart @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; + +/// Converts user data coming from native code into the proper platform interface type. +GoogleSignInUserData? getUserDataFromMap(Map? data) { + if (data == null) { + return null; + } + return GoogleSignInUserData( + email: data['email']! as String, + id: data['id']! as String, + displayName: data['displayName'] as String?, + photoUrl: data['photoUrl'] as String?, + idToken: data['idToken'] as String?, + serverAuthCode: data['serverAuthCode'] as String?); +} + +/// Converts token data coming from native code into the proper platform interface type. +GoogleSignInTokenData getTokenDataFromMap(Map data) { + return GoogleSignInTokenData( + idToken: data['idToken'] as String?, + accessToken: data['accessToken'] as String?, + serverAuthCode: data['serverAuthCode'] as String?, + ); +} diff --git a/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart new file mode 100644 index 000000000000..a1d83c3f05e6 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart @@ -0,0 +1,141 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; +import 'package:google_sign_in_platform_interface/src/types.dart'; +import 'package:google_sign_in_platform_interface/src/utils.dart'; + +const Map kUserData = { + 'email': 'john.doe@gmail.com', + 'id': '8162538176523816253123', + 'photoUrl': 'https://lh5.googleusercontent.com/photo.jpg', + 'displayName': 'John Doe', + 'idToken': '123', + 'serverAuthCode': '789', +}; + +const Map kTokenData = { + 'idToken': '123', + 'accessToken': '456', + 'serverAuthCode': '789', +}; + +const Map kDefaultResponses = { + 'init': null, + 'signInSilently': kUserData, + 'signIn': kUserData, + 'signOut': null, + 'disconnect': null, + 'isSignedIn': true, + 'getTokens': kTokenData, + 'requestScopes': true, +}; + +final GoogleSignInUserData? kUser = getUserDataFromMap(kUserData); +final GoogleSignInTokenData kToken = + getTokenDataFromMap(kTokenData as Map); + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$MethodChannelGoogleSignIn', () { + final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final MethodChannel channel = googleSignIn.channel; + + final List log = []; + late Map + responses; // Some tests mutate some kDefaultResponses + + setUp(() { + responses = Map.from(kDefaultResponses); + channel.setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + final dynamic response = responses[methodCall.method]; + if (response != null && response is Exception) { + return Future.error('$response'); + } + return Future.value(response); + }); + log.clear(); + }); + + test('signInSilently transforms platform data to GoogleSignInUserData', + () async { + final dynamic response = await googleSignIn.signInSilently(); + expect(response, kUser); + }); + test('signInSilently Exceptions -> throws', () async { + responses['signInSilently'] = Exception('Not a user'); + expect(googleSignIn.signInSilently(), + throwsA(isInstanceOf())); + }); + + test('signIn transforms platform data to GoogleSignInUserData', () async { + final dynamic response = await googleSignIn.signIn(); + expect(response, kUser); + }); + test('signIn Exceptions -> throws', () async { + responses['signIn'] = Exception('Not a user'); + expect(googleSignIn.signIn(), throwsA(isInstanceOf())); + }); + + test('getTokens transforms platform data to GoogleSignInTokenData', + () async { + final dynamic response = await googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + expect(response, kToken); + expect( + log[0], + isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + })); + }); + + test('Other functions pass through arguments to the channel', () async { + final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + signInOption: SignInOption.games, + clientId: 'fakeClientId'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'signInOption': 'SignInOption.games', + 'clientId': 'fakeClientId', + }), + () { + googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + }: isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + }), + () { + googleSignIn.clearAuthCache(token: 'abc'); + }: isMethodCall('clearAuthCache', arguments: { + 'token': 'abc', + }), + () { + googleSignIn.requestScopes(['newScope', 'anotherScope']); + }: isMethodCall('requestScopes', arguments: { + 'scopes': ['newScope', 'anotherScope'], + }), + googleSignIn.signOut: isMethodCall('signOut', arguments: null), + googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), + googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), + }; + + for (final Function f in tests.keys) { + f(); + } + + expect(log, tests.values); + }); + }); +} diff --git a/packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart new file mode 100644 index 000000000000..1abda09fa99f --- /dev/null +++ b/packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart' show visibleForTesting; +import 'package:flutter/services.dart'; + +import '../google_sign_in_platform_interface.dart'; +import 'types.dart'; +import 'utils.dart'; + +/// An implementation of [GoogleSignInPlatform] that uses method channels. +class MethodChannelGoogleSignIn extends GoogleSignInPlatform { + /// This is only exposed for test purposes. It shouldn't be used by clients of + /// the plugin as it may break or change at any time. + @visibleForTesting + MethodChannel channel = + const MethodChannel('plugins.flutter.io/google_sign_in'); + + @override + Future init({ + List scopes = const [], + SignInOption signInOption = SignInOption.standard, + String? hostedDomain, + String? clientId, + }) { + return channel.invokeMethod('init', { + 'signInOption': signInOption.toString(), + 'scopes': scopes, + 'hostedDomain': hostedDomain, + 'clientId': clientId, + }); + } + + @override + Future signInSilently() { + return channel + .invokeMapMethod('signInSilently') + .then(getUserDataFromMap); + } + + @override + Future signIn() { + return channel + .invokeMapMethod('signIn') + .then(getUserDataFromMap); + } + + @override + Future getTokens( + {required String email, bool? shouldRecoverAuth = true}) { + return channel + .invokeMapMethod('getTokens', { + 'email': email, + 'shouldRecoverAuth': shouldRecoverAuth, + }).then((Map? result) => getTokenDataFromMap(result!)); + } + + @override + Future signOut() { + return channel.invokeMapMethod('signOut'); + } + + @override + Future disconnect() { + return channel.invokeMapMethod('disconnect'); + } + + @override + Future isSignedIn() async { + return (await channel.invokeMethod('isSignedIn'))!; + } + + @override + Future clearAuthCache({String? token}) { + return channel.invokeMethod( + 'clearAuthCache', + {'token': token}, + ); + } + + @override + Future requestScopes(List scopes) async { + return (await channel.invokeMethod( + 'requestScopes', + >{'scopes': scopes}, + ))!; + } +} diff --git a/packages/google_sign_in/google_sign_in_ios/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_ios/lib/src/utils.dart new file mode 100644 index 000000000000..5cd7c20b829a --- /dev/null +++ b/packages/google_sign_in/google_sign_in_ios/lib/src/utils.dart @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; + +/// Converts user data coming from native code into the proper platform interface type. +GoogleSignInUserData? getUserDataFromMap(Map? data) { + if (data == null) { + return null; + } + return GoogleSignInUserData( + email: data['email']! as String, + id: data['id']! as String, + displayName: data['displayName'] as String?, + photoUrl: data['photoUrl'] as String?, + idToken: data['idToken'] as String?, + serverAuthCode: data['serverAuthCode'] as String?); +} + +/// Converts token data coming from native code into the proper platform interface type. +GoogleSignInTokenData getTokenDataFromMap(Map data) { + return GoogleSignInTokenData( + idToken: data['idToken'] as String?, + accessToken: data['accessToken'] as String?, + serverAuthCode: data['serverAuthCode'] as String?, + ); +} diff --git a/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart new file mode 100644 index 000000000000..a1d83c3f05e6 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart @@ -0,0 +1,141 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; +import 'package:google_sign_in_platform_interface/src/types.dart'; +import 'package:google_sign_in_platform_interface/src/utils.dart'; + +const Map kUserData = { + 'email': 'john.doe@gmail.com', + 'id': '8162538176523816253123', + 'photoUrl': 'https://lh5.googleusercontent.com/photo.jpg', + 'displayName': 'John Doe', + 'idToken': '123', + 'serverAuthCode': '789', +}; + +const Map kTokenData = { + 'idToken': '123', + 'accessToken': '456', + 'serverAuthCode': '789', +}; + +const Map kDefaultResponses = { + 'init': null, + 'signInSilently': kUserData, + 'signIn': kUserData, + 'signOut': null, + 'disconnect': null, + 'isSignedIn': true, + 'getTokens': kTokenData, + 'requestScopes': true, +}; + +final GoogleSignInUserData? kUser = getUserDataFromMap(kUserData); +final GoogleSignInTokenData kToken = + getTokenDataFromMap(kTokenData as Map); + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$MethodChannelGoogleSignIn', () { + final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final MethodChannel channel = googleSignIn.channel; + + final List log = []; + late Map + responses; // Some tests mutate some kDefaultResponses + + setUp(() { + responses = Map.from(kDefaultResponses); + channel.setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + final dynamic response = responses[methodCall.method]; + if (response != null && response is Exception) { + return Future.error('$response'); + } + return Future.value(response); + }); + log.clear(); + }); + + test('signInSilently transforms platform data to GoogleSignInUserData', + () async { + final dynamic response = await googleSignIn.signInSilently(); + expect(response, kUser); + }); + test('signInSilently Exceptions -> throws', () async { + responses['signInSilently'] = Exception('Not a user'); + expect(googleSignIn.signInSilently(), + throwsA(isInstanceOf())); + }); + + test('signIn transforms platform data to GoogleSignInUserData', () async { + final dynamic response = await googleSignIn.signIn(); + expect(response, kUser); + }); + test('signIn Exceptions -> throws', () async { + responses['signIn'] = Exception('Not a user'); + expect(googleSignIn.signIn(), throwsA(isInstanceOf())); + }); + + test('getTokens transforms platform data to GoogleSignInTokenData', + () async { + final dynamic response = await googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + expect(response, kToken); + expect( + log[0], + isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + })); + }); + + test('Other functions pass through arguments to the channel', () async { + final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + signInOption: SignInOption.games, + clientId: 'fakeClientId'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'signInOption': 'SignInOption.games', + 'clientId': 'fakeClientId', + }), + () { + googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + }: isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + }), + () { + googleSignIn.clearAuthCache(token: 'abc'); + }: isMethodCall('clearAuthCache', arguments: { + 'token': 'abc', + }), + () { + googleSignIn.requestScopes(['newScope', 'anotherScope']); + }: isMethodCall('requestScopes', arguments: { + 'scopes': ['newScope', 'anotherScope'], + }), + googleSignIn.signOut: isMethodCall('signOut', arguments: null), + googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), + googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), + }; + + for (final Function f in tests.keys) { + f(); + } + + expect(log, tests.values); + }); + }); +} From 6928fa1ff2b1d957388f75381e6b66693ad303be Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 10:54:38 -0400 Subject: [PATCH 2/7] Remove unnecessary test group --- .../method_channel_google_sign_in_test.dart | 170 +++++++++--------- .../method_channel_google_sign_in_test.dart | 170 +++++++++--------- 2 files changed, 166 insertions(+), 174 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart index a1d83c3f05e6..7ee470a32cba 100644 --- a/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; -import 'package:google_sign_in_platform_interface/src/types.dart'; import 'package:google_sign_in_platform_interface/src/utils.dart'; const Map kUserData = { @@ -41,101 +40,98 @@ final GoogleSignInTokenData kToken = void main() { TestWidgetsFlutterBinding.ensureInitialized(); - group('$MethodChannelGoogleSignIn', () { - final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); - final MethodChannel channel = googleSignIn.channel; + final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final MethodChannel channel = googleSignIn.channel; - final List log = []; - late Map - responses; // Some tests mutate some kDefaultResponses + final List log = []; + late Map + responses; // Some tests mutate some kDefaultResponses - setUp(() { - responses = Map.from(kDefaultResponses); - channel.setMockMethodCallHandler((MethodCall methodCall) { - log.add(methodCall); - final dynamic response = responses[methodCall.method]; - if (response != null && response is Exception) { - return Future.error('$response'); - } - return Future.value(response); - }); - log.clear(); - }); - - test('signInSilently transforms platform data to GoogleSignInUserData', - () async { - final dynamic response = await googleSignIn.signInSilently(); - expect(response, kUser); - }); - test('signInSilently Exceptions -> throws', () async { - responses['signInSilently'] = Exception('Not a user'); - expect(googleSignIn.signInSilently(), - throwsA(isInstanceOf())); + setUp(() { + responses = Map.from(kDefaultResponses); + channel.setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + final dynamic response = responses[methodCall.method]; + if (response != null && response is Exception) { + return Future.error('$response'); + } + return Future.value(response); }); + log.clear(); + }); - test('signIn transforms platform data to GoogleSignInUserData', () async { - final dynamic response = await googleSignIn.signIn(); - expect(response, kUser); - }); - test('signIn Exceptions -> throws', () async { - responses['signIn'] = Exception('Not a user'); - expect(googleSignIn.signIn(), throwsA(isInstanceOf())); - }); + test('signInSilently transforms platform data to GoogleSignInUserData', + () async { + final dynamic response = await googleSignIn.signInSilently(); + expect(response, kUser); + }); + test('signInSilently Exceptions -> throws', () async { + responses['signInSilently'] = Exception('Not a user'); + expect(googleSignIn.signInSilently(), + throwsA(isInstanceOf())); + }); - test('getTokens transforms platform data to GoogleSignInTokenData', - () async { - final dynamic response = await googleSignIn.getTokens( - email: 'example@example.com', shouldRecoverAuth: false); - expect(response, kToken); - expect( - log[0], - isMethodCall('getTokens', arguments: { - 'email': 'example@example.com', - 'shouldRecoverAuth': false, - })); - }); + test('signIn transforms platform data to GoogleSignInUserData', () async { + final dynamic response = await googleSignIn.signIn(); + expect(response, kUser); + }); + test('signIn Exceptions -> throws', () async { + responses['signIn'] = Exception('Not a user'); + expect(googleSignIn.signIn(), throwsA(isInstanceOf())); + }); - test('Other functions pass through arguments to the channel', () async { - final Map tests = { - () { - googleSignIn.init( - hostedDomain: 'example.com', - scopes: ['two', 'scopes'], - signInOption: SignInOption.games, - clientId: 'fakeClientId'); - }: isMethodCall('init', arguments: { - 'hostedDomain': 'example.com', - 'scopes': ['two', 'scopes'], - 'signInOption': 'SignInOption.games', - 'clientId': 'fakeClientId', - }), - () { - googleSignIn.getTokens( - email: 'example@example.com', shouldRecoverAuth: false); - }: isMethodCall('getTokens', arguments: { + test('getTokens transforms platform data to GoogleSignInTokenData', () async { + final dynamic response = await googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + expect(response, kToken); + expect( + log[0], + isMethodCall('getTokens', arguments: { 'email': 'example@example.com', 'shouldRecoverAuth': false, - }), - () { - googleSignIn.clearAuthCache(token: 'abc'); - }: isMethodCall('clearAuthCache', arguments: { - 'token': 'abc', - }), - () { - googleSignIn.requestScopes(['newScope', 'anotherScope']); - }: isMethodCall('requestScopes', arguments: { - 'scopes': ['newScope', 'anotherScope'], - }), - googleSignIn.signOut: isMethodCall('signOut', arguments: null), - googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), - googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), - }; + })); + }); - for (final Function f in tests.keys) { - f(); - } + test('Other functions pass through arguments to the channel', () async { + final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + signInOption: SignInOption.games, + clientId: 'fakeClientId'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'signInOption': 'SignInOption.games', + 'clientId': 'fakeClientId', + }), + () { + googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + }: isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + }), + () { + googleSignIn.clearAuthCache(token: 'abc'); + }: isMethodCall('clearAuthCache', arguments: { + 'token': 'abc', + }), + () { + googleSignIn.requestScopes(['newScope', 'anotherScope']); + }: isMethodCall('requestScopes', arguments: { + 'scopes': ['newScope', 'anotherScope'], + }), + googleSignIn.signOut: isMethodCall('signOut', arguments: null), + googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), + googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), + }; - expect(log, tests.values); - }); + for (final Function f in tests.keys) { + f(); + } + + expect(log, tests.values); }); } diff --git a/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart index a1d83c3f05e6..7ee470a32cba 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; -import 'package:google_sign_in_platform_interface/src/types.dart'; import 'package:google_sign_in_platform_interface/src/utils.dart'; const Map kUserData = { @@ -41,101 +40,98 @@ final GoogleSignInTokenData kToken = void main() { TestWidgetsFlutterBinding.ensureInitialized(); - group('$MethodChannelGoogleSignIn', () { - final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); - final MethodChannel channel = googleSignIn.channel; + final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final MethodChannel channel = googleSignIn.channel; - final List log = []; - late Map - responses; // Some tests mutate some kDefaultResponses + final List log = []; + late Map + responses; // Some tests mutate some kDefaultResponses - setUp(() { - responses = Map.from(kDefaultResponses); - channel.setMockMethodCallHandler((MethodCall methodCall) { - log.add(methodCall); - final dynamic response = responses[methodCall.method]; - if (response != null && response is Exception) { - return Future.error('$response'); - } - return Future.value(response); - }); - log.clear(); - }); - - test('signInSilently transforms platform data to GoogleSignInUserData', - () async { - final dynamic response = await googleSignIn.signInSilently(); - expect(response, kUser); - }); - test('signInSilently Exceptions -> throws', () async { - responses['signInSilently'] = Exception('Not a user'); - expect(googleSignIn.signInSilently(), - throwsA(isInstanceOf())); + setUp(() { + responses = Map.from(kDefaultResponses); + channel.setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall); + final dynamic response = responses[methodCall.method]; + if (response != null && response is Exception) { + return Future.error('$response'); + } + return Future.value(response); }); + log.clear(); + }); - test('signIn transforms platform data to GoogleSignInUserData', () async { - final dynamic response = await googleSignIn.signIn(); - expect(response, kUser); - }); - test('signIn Exceptions -> throws', () async { - responses['signIn'] = Exception('Not a user'); - expect(googleSignIn.signIn(), throwsA(isInstanceOf())); - }); + test('signInSilently transforms platform data to GoogleSignInUserData', + () async { + final dynamic response = await googleSignIn.signInSilently(); + expect(response, kUser); + }); + test('signInSilently Exceptions -> throws', () async { + responses['signInSilently'] = Exception('Not a user'); + expect(googleSignIn.signInSilently(), + throwsA(isInstanceOf())); + }); - test('getTokens transforms platform data to GoogleSignInTokenData', - () async { - final dynamic response = await googleSignIn.getTokens( - email: 'example@example.com', shouldRecoverAuth: false); - expect(response, kToken); - expect( - log[0], - isMethodCall('getTokens', arguments: { - 'email': 'example@example.com', - 'shouldRecoverAuth': false, - })); - }); + test('signIn transforms platform data to GoogleSignInUserData', () async { + final dynamic response = await googleSignIn.signIn(); + expect(response, kUser); + }); + test('signIn Exceptions -> throws', () async { + responses['signIn'] = Exception('Not a user'); + expect(googleSignIn.signIn(), throwsA(isInstanceOf())); + }); - test('Other functions pass through arguments to the channel', () async { - final Map tests = { - () { - googleSignIn.init( - hostedDomain: 'example.com', - scopes: ['two', 'scopes'], - signInOption: SignInOption.games, - clientId: 'fakeClientId'); - }: isMethodCall('init', arguments: { - 'hostedDomain': 'example.com', - 'scopes': ['two', 'scopes'], - 'signInOption': 'SignInOption.games', - 'clientId': 'fakeClientId', - }), - () { - googleSignIn.getTokens( - email: 'example@example.com', shouldRecoverAuth: false); - }: isMethodCall('getTokens', arguments: { + test('getTokens transforms platform data to GoogleSignInTokenData', () async { + final dynamic response = await googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + expect(response, kToken); + expect( + log[0], + isMethodCall('getTokens', arguments: { 'email': 'example@example.com', 'shouldRecoverAuth': false, - }), - () { - googleSignIn.clearAuthCache(token: 'abc'); - }: isMethodCall('clearAuthCache', arguments: { - 'token': 'abc', - }), - () { - googleSignIn.requestScopes(['newScope', 'anotherScope']); - }: isMethodCall('requestScopes', arguments: { - 'scopes': ['newScope', 'anotherScope'], - }), - googleSignIn.signOut: isMethodCall('signOut', arguments: null), - googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), - googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), - }; + })); + }); - for (final Function f in tests.keys) { - f(); - } + test('Other functions pass through arguments to the channel', () async { + final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + signInOption: SignInOption.games, + clientId: 'fakeClientId'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'signInOption': 'SignInOption.games', + 'clientId': 'fakeClientId', + }), + () { + googleSignIn.getTokens( + email: 'example@example.com', shouldRecoverAuth: false); + }: isMethodCall('getTokens', arguments: { + 'email': 'example@example.com', + 'shouldRecoverAuth': false, + }), + () { + googleSignIn.clearAuthCache(token: 'abc'); + }: isMethodCall('clearAuthCache', arguments: { + 'token': 'abc', + }), + () { + googleSignIn.requestScopes(['newScope', 'anotherScope']); + }: isMethodCall('requestScopes', arguments: { + 'scopes': ['newScope', 'anotherScope'], + }), + googleSignIn.signOut: isMethodCall('signOut', arguments: null), + googleSignIn.disconnect: isMethodCall('disconnect', arguments: null), + googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null), + }; - expect(log, tests.values); - }); + for (final Function f in tests.keys) { + f(); + } + + expect(log, tests.values); }); } From 60bcaec692f35db765c220ec10b661c4f72c295e Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 12:01:48 -0400 Subject: [PATCH 3/7] Adjust copies to be internal implentations --- .../plugins/googlesignin/GoogleSignInPlugin.java | 2 +- .../lib/google_sign_in_android.dart} | 16 ++++++++++------ .../google_sign_in_android/pubspec.yaml | 1 + .../test/google_sign_in_android_test.dart} | 10 ++++++++-- .../ios/Classes/FLTGoogleSignInPlugin.m | 2 +- .../lib/google_sign_in_ios.dart} | 16 ++++++++++------ .../google_sign_in_ios/pubspec.yaml | 1 + .../test/google_sign_in_ios_test.dart} | 10 ++++++++-- 8 files changed, 40 insertions(+), 18 deletions(-) rename packages/google_sign_in/{google_sign_in_ios/lib/method_channel_google_sign_in.dart => google_sign_in_android/lib/google_sign_in_android.dart} (83%) rename packages/google_sign_in/{google_sign_in_ios/test/method_channel_google_sign_in_test.dart => google_sign_in_android/test/google_sign_in_android_test.dart} (93%) rename packages/google_sign_in/{google_sign_in_android/lib/method_channel_google_sign_in.dart => google_sign_in_ios/lib/google_sign_in_ios.dart} (83%) rename packages/google_sign_in/{google_sign_in_android/test/method_channel_google_sign_in_test.dart => google_sign_in_ios/test/google_sign_in_ios_test.dart} (93%) diff --git a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 1be023c678bb..a1237f0013a1 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -44,7 +44,7 @@ /** Google sign-in plugin for Flutter. */ public class GoogleSignInPlugin implements MethodCallHandler, FlutterPlugin, ActivityAware { - private static final String CHANNEL_NAME = "plugins.flutter.io/google_sign_in"; + private static final String CHANNEL_NAME = "plugins.flutter.io/google_sign_in_android"; private static final String METHOD_INIT = "init"; private static final String METHOD_SIGN_IN_SILENTLY = "signInSilently"; diff --git a/packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart similarity index 83% rename from packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart rename to packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart index 1abda09fa99f..d96328de695a 100644 --- a/packages/google_sign_in/google_sign_in_ios/lib/method_channel_google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart @@ -6,18 +6,22 @@ import 'dart:async'; import 'package:flutter/foundation.dart' show visibleForTesting; import 'package:flutter/services.dart'; +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; -import '../google_sign_in_platform_interface.dart'; -import 'types.dart'; -import 'utils.dart'; +import 'src/utils.dart'; -/// An implementation of [GoogleSignInPlatform] that uses method channels. -class MethodChannelGoogleSignIn extends GoogleSignInPlatform { +/// Android implementation of [GoogleSignInPlatform]. +class GoogleSignInAndroid extends GoogleSignInPlatform { /// This is only exposed for test purposes. It shouldn't be used by clients of /// the plugin as it may break or change at any time. @visibleForTesting MethodChannel channel = - const MethodChannel('plugins.flutter.io/google_sign_in'); + const MethodChannel('plugins.flutter.io/google_sign_in_android'); + + /// Registers this class as the default instance of [GoogleSignInPlatform]. + static void registerWith() { + GoogleSignInPlatform.instance = GoogleSignInAndroid(); + } @override Future init({ diff --git a/packages/google_sign_in/google_sign_in_android/pubspec.yaml b/packages/google_sign_in/google_sign_in_android/pubspec.yaml index efd679ca399b..7ba1f0f2586e 100644 --- a/packages/google_sign_in/google_sign_in_android/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_android/pubspec.yaml @@ -13,6 +13,7 @@ flutter: implements: google_sign_in platforms: android: + dartPluginClass: GoogleSignInAndroid package: io.flutter.plugins.googlesignin pluginClass: GoogleSignInPlugin diff --git a/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart similarity index 93% rename from packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart rename to packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart index 7ee470a32cba..7d39ae5f0232 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart @@ -4,8 +4,9 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:google_sign_in_android/google_sign_in_android.dart'; +import 'package:google_sign_in_android/src/utils.dart'; import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; -import 'package:google_sign_in_platform_interface/src/utils.dart'; const Map kUserData = { 'email': 'john.doe@gmail.com', @@ -40,7 +41,7 @@ final GoogleSignInTokenData kToken = void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final GoogleSignInAndroid googleSignIn = GoogleSignInAndroid(); final MethodChannel channel = googleSignIn.channel; final List log = []; @@ -60,6 +61,11 @@ void main() { log.clear(); }); + test('registered instance', () { + GoogleSignInAndroid.registerWith(); + expect(GoogleSignInPlatform.instance, isA()); + }); + test('signInSilently transforms platform data to GoogleSignInUserData', () async { final dynamic response = await googleSignIn.signInSilently(); diff --git a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m index d13d64d2ba04..6ba82c3c1a10 100644 --- a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m @@ -50,7 +50,7 @@ @implementation FLTGoogleSignInPlugin { + (void)registerWithRegistrar:(NSObject *)registrar { FlutterMethodChannel *channel = - [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/google_sign_in" + [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/google_sign_in_ios" binaryMessenger:[registrar messenger]]; FLTGoogleSignInPlugin *instance = [[FLTGoogleSignInPlugin alloc] init]; [registrar addApplicationDelegate:instance]; diff --git a/packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart similarity index 83% rename from packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart rename to packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart index 1abda09fa99f..7c9e91d8face 100644 --- a/packages/google_sign_in/google_sign_in_android/lib/method_channel_google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart @@ -6,18 +6,22 @@ import 'dart:async'; import 'package:flutter/foundation.dart' show visibleForTesting; import 'package:flutter/services.dart'; +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; -import '../google_sign_in_platform_interface.dart'; -import 'types.dart'; -import 'utils.dart'; +import 'src/utils.dart'; -/// An implementation of [GoogleSignInPlatform] that uses method channels. -class MethodChannelGoogleSignIn extends GoogleSignInPlatform { +/// iOS implementation of [GoogleSignInPlatform]. +class GoogleSignInIOS extends GoogleSignInPlatform { /// This is only exposed for test purposes. It shouldn't be used by clients of /// the plugin as it may break or change at any time. @visibleForTesting MethodChannel channel = - const MethodChannel('plugins.flutter.io/google_sign_in'); + const MethodChannel('plugins.flutter.io/google_sign_in_ios'); + + /// Registers this class as the default instance of [GoogleSignInPlatform]. + static void registerWith() { + GoogleSignInPlatform.instance = GoogleSignInIOS(); + } @override Future init({ diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index 52c4f77feb4b..9bdc1a54bd8d 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -13,6 +13,7 @@ flutter: implements: google_sign_in platforms: ios: + dartPluginClass: GoogleSignInIOS pluginClass: FLTGoogleSignInPlugin dependencies: diff --git a/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart similarity index 93% rename from packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart rename to packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart index 7ee470a32cba..7748e14b56f0 100644 --- a/packages/google_sign_in/google_sign_in_android/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart @@ -4,8 +4,9 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:google_sign_in_ios/google_sign_in_ios.dart'; +import 'package:google_sign_in_ios/src/utils.dart'; import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; -import 'package:google_sign_in_platform_interface/src/utils.dart'; const Map kUserData = { 'email': 'john.doe@gmail.com', @@ -40,7 +41,7 @@ final GoogleSignInTokenData kToken = void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final MethodChannelGoogleSignIn googleSignIn = MethodChannelGoogleSignIn(); + final GoogleSignInIOS googleSignIn = GoogleSignInIOS(); final MethodChannel channel = googleSignIn.channel; final List log = []; @@ -60,6 +61,11 @@ void main() { log.clear(); }); + test('registered instance', () { + GoogleSignInIOS.registerWith(); + expect(GoogleSignInPlatform.instance, isA()); + }); + test('signInSilently transforms platform data to GoogleSignInUserData', () async { final dynamic response = await googleSignIn.signInSilently(); From e033ea1b174a627caf5e68fb9cd4e885904c5ef6 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 10:52:26 -0400 Subject: [PATCH 4/7] Version bumps --- packages/google_sign_in/google_sign_in_android/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in_android/pubspec.yaml | 4 ++-- packages/google_sign_in/google_sign_in_ios/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in_ios/pubspec.yaml | 4 ++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md index e7c6847e7750..3ffa6b5b7d6b 100644 --- a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.2.6 + +* Switches to an internal method channel, rather than the default. + ## 5.2.5 * Splits from `video_player` as a federated implementation. diff --git a/packages/google_sign_in/google_sign_in_android/pubspec.yaml b/packages/google_sign_in/google_sign_in_android/pubspec.yaml index 7ba1f0f2586e..fa3dc1489b26 100644 --- a/packages/google_sign_in/google_sign_in_android/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_android/pubspec.yaml @@ -2,11 +2,11 @@ name: google_sign_in_android description: Android implementation of the google_sign_in plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 5.2.5 +version: 5.2.6 environment: sdk: ">=2.14.0 <3.0.0" - flutter: ">=2.5.0" + flutter: ">=2.8.0" flutter: plugin: diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md index e7c6847e7750..3ffa6b5b7d6b 100644 --- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.2.6 + +* Switches to an internal method channel, rather than the default. + ## 5.2.5 * Splits from `video_player` as a federated implementation. diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index 9bdc1a54bd8d..e5ef3832ff0e 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -2,11 +2,11 @@ name: google_sign_in_ios description: Android implementation of the google_sign_in plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 5.2.5 +version: 5.2.6 environment: sdk: ">=2.14.0 <3.0.0" - flutter: ">=2.5.0" + flutter: ">=2.8.0" flutter: plugin: From a605ef95f33d3c21f6e07e19b05cda88cbcd0dc3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 13:12:39 -0400 Subject: [PATCH 5/7] Move a small amount of iOS logic to Dart side --- .../ios/Classes/FLTGoogleSignInPlugin.m | 54 ++++++++----------- .../lib/google_sign_in_ios.dart | 14 ++--- .../test/google_sign_in_ios_test.dart | 26 +++++---- 3 files changed, 46 insertions(+), 48 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m index 6ba82c3c1a10..5ad69e2ad052 100644 --- a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m @@ -78,38 +78,30 @@ - (instancetype)initWithSignIn:(GIDSignIn *)signIn { - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if ([call.method isEqualToString:@"init"]) { - NSString *signInOption = call.arguments[@"signInOption"]; - if ([signInOption isEqualToString:@"SignInOption.games"]) { - result([FlutterError errorWithCode:@"unsupported-options" - message:@"Games sign in is not supported on iOS" - details:nil]); - } else { - NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" - ofType:@"plist"]; - if (path) { - NSMutableDictionary *plist = - [[NSMutableDictionary alloc] initWithContentsOfFile:path]; - BOOL hasDynamicClientId = [call.arguments[@"clientId"] isKindOfClass:[NSString class]]; - - if (hasDynamicClientId) { - self.signIn.clientID = call.arguments[@"clientId"]; - } else { - self.signIn.clientID = plist[kClientIdKey]; - } + NSString *path = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; + if (path) { + NSMutableDictionary *plist = + [[NSMutableDictionary alloc] initWithContentsOfFile:path]; + BOOL hasDynamicClientId = [call.arguments[@"clientId"] isKindOfClass:[NSString class]]; + + if (hasDynamicClientId) { + self.signIn.clientID = call.arguments[@"clientId"]; + } else { + self.signIn.clientID = plist[kClientIdKey]; + } - self.signIn.serverClientID = plist[kServerClientIdKey]; - self.signIn.scopes = call.arguments[@"scopes"]; - if (call.arguments[@"hostedDomain"] == [NSNull null]) { - self.signIn.hostedDomain = nil; - } else { - self.signIn.hostedDomain = call.arguments[@"hostedDomain"]; - } - result(nil); + self.signIn.serverClientID = plist[kServerClientIdKey]; + self.signIn.scopes = call.arguments[@"scopes"]; + if (call.arguments[@"hostedDomain"] == [NSNull null]) { + self.signIn.hostedDomain = nil; } else { - result([FlutterError errorWithCode:@"missing-config" - message:@"GoogleService-Info.plist file not found" - details:nil]); + self.signIn.hostedDomain = call.arguments[@"hostedDomain"]; } + result(nil); + } else { + result([FlutterError errorWithCode:@"missing-config" + message:@"GoogleService-Info.plist file not found" + details:nil]); } } else if ([call.method isEqualToString:@"signInSilently"]) { if ([self setAccountRequest:result]) { @@ -144,10 +136,6 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result if ([self setAccountRequest:result]) { [self.signIn disconnect]; } - } else if ([call.method isEqualToString:@"clearAuthCache"]) { - // There's nothing to be done here on iOS since the expired/invalid - // tokens are refreshed automatically by getTokensWithHandler. - result(nil); } else if ([call.method isEqualToString:@"requestScopes"]) { GIDGoogleUser *user = self.signIn.currentUser; if (user == nil) { diff --git a/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart index 7c9e91d8face..ce8865664507 100644 --- a/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart +++ b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart @@ -30,8 +30,12 @@ class GoogleSignInIOS extends GoogleSignInPlatform { String? hostedDomain, String? clientId, }) { + if (signInOption == SignInOption.games) { + throw PlatformException( + code: 'unsupported-options', + message: 'Games sign in is not supported on iOS'); + } return channel.invokeMethod('init', { - 'signInOption': signInOption.toString(), 'scopes': scopes, 'hostedDomain': hostedDomain, 'clientId': clientId, @@ -78,11 +82,9 @@ class GoogleSignInIOS extends GoogleSignInPlatform { } @override - Future clearAuthCache({String? token}) { - return channel.invokeMethod( - 'clearAuthCache', - {'token': token}, - ); + Future clearAuthCache({String? token}) async { + // There's nothing to be done here on iOS since the expired/invalid + // tokens are refreshed automatically by getTokens. } @override diff --git a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart index 7748e14b56f0..92637e938fd9 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart @@ -44,12 +44,13 @@ void main() { final GoogleSignInIOS googleSignIn = GoogleSignInIOS(); final MethodChannel channel = googleSignIn.channel; - final List log = []; + late List log; late Map responses; // Some tests mutate some kDefaultResponses setUp(() { responses = Map.from(kDefaultResponses); + log = []; channel.setMockMethodCallHandler((MethodCall methodCall) { log.add(methodCall); final dynamic response = responses[methodCall.method]; @@ -58,7 +59,6 @@ void main() { } return Future.value(response); }); - log.clear(); }); test('registered instance', () { @@ -66,6 +66,16 @@ void main() { expect(GoogleSignInPlatform.instance, isA()); }); + test('init throws for SignInOptions.games', () async { + expect( + () => googleSignIn.init( + hostedDomain: 'example.com', + signInOption: SignInOption.games, + clientId: 'fakeClientId'), + throwsA(isInstanceOf().having( + (PlatformException e) => e.code, 'code', 'unsupported-options'))); + }); + test('signInSilently transforms platform data to GoogleSignInUserData', () async { final dynamic response = await googleSignIn.signInSilently(); @@ -98,18 +108,21 @@ void main() { })); }); + test('clearAuthCache is a no-op', () async { + await googleSignIn.clearAuthCache(token: 'abc'); + expect(log.isEmpty, true); + }); + test('Other functions pass through arguments to the channel', () async { final Map tests = { () { googleSignIn.init( hostedDomain: 'example.com', scopes: ['two', 'scopes'], - signInOption: SignInOption.games, clientId: 'fakeClientId'); }: isMethodCall('init', arguments: { 'hostedDomain': 'example.com', 'scopes': ['two', 'scopes'], - 'signInOption': 'SignInOption.games', 'clientId': 'fakeClientId', }), () { @@ -119,11 +132,6 @@ void main() { 'email': 'example@example.com', 'shouldRecoverAuth': false, }), - () { - googleSignIn.clearAuthCache(token: 'abc'); - }: isMethodCall('clearAuthCache', arguments: { - 'token': 'abc', - }), () { googleSignIn.requestScopes(['newScope', 'anotherScope']); }: isMethodCall('requestScopes', arguments: { From 782240e12076f557030a4b212625c4d71541ab4e Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 13:18:19 -0400 Subject: [PATCH 6/7] Add tests that the method handlers are correct --- .../example/integration_test/google_sign_in_test.dart | 8 ++++++++ .../example/integration_test/google_sign_in_test.dart | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/packages/google_sign_in/google_sign_in_android/example/integration_test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_android/example/integration_test/google_sign_in_test.dart index d4631f6a6fd3..f1388ce86d67 100644 --- a/packages/google_sign_in/google_sign_in_android/example/integration_test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_android/example/integration_test/google_sign_in_test.dart @@ -13,4 +13,12 @@ void main() { final GoogleSignInPlatform signIn = GoogleSignInPlatform.instance; expect(signIn, isNotNull); }); + + testWidgets('Method channel handler is present', (WidgetTester tester) async { + // isSignedIn can be called without initialization, so use it to validate + // that the native method handler is present (e.g., that the channel name + // is correct). + final GoogleSignInPlatform signIn = GoogleSignInPlatform.instance; + await expectLater(signIn.isSignedIn(), completes); + }); } diff --git a/packages/google_sign_in/google_sign_in_ios/example/integration_test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_ios/example/integration_test/google_sign_in_test.dart index d4631f6a6fd3..f1388ce86d67 100644 --- a/packages/google_sign_in/google_sign_in_ios/example/integration_test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/example/integration_test/google_sign_in_test.dart @@ -13,4 +13,12 @@ void main() { final GoogleSignInPlatform signIn = GoogleSignInPlatform.instance; expect(signIn, isNotNull); }); + + testWidgets('Method channel handler is present', (WidgetTester tester) async { + // isSignedIn can be called without initialization, so use it to validate + // that the native method handler is present (e.g., that the channel name + // is correct). + final GoogleSignInPlatform signIn = GoogleSignInPlatform.instance; + await expectLater(signIn.isSignedIn(), completes); + }); } From 4b505de6fe9c57e62c924804a414bd5ccd805827 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 26 Apr 2022 13:33:35 -0400 Subject: [PATCH 7/7] Remove iOS native unit tests of moved functionality --- .../ios/RunnerTests/GoogleSignInTests.m | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m b/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m index dbbd65397ac5..3bc08d18604a 100644 --- a/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m +++ b/packages/google_sign_in/google_sign_in_ios/example/ios/RunnerTests/GoogleSignInTests.m @@ -73,35 +73,8 @@ - (void)testDisconnect { OCMVerify([self.mockSignIn disconnect]); } -- (void)testClearAuthCache { - FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"clearAuthCache" - arguments:nil]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; - [self.plugin handleMethodCall:methodCall - result:^(id result) { - XCTAssertNil(result); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - #pragma mark - Init -- (void)testInitGamesSignInUnsupported { - FlutterMethodCall *methodCall = - [FlutterMethodCall methodCallWithMethodName:@"init" - arguments:@{@"signInOption" : @"SignInOption.games"}]; - - XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; - [self.plugin handleMethodCall:methodCall - result:^(FlutterError *result) { - XCTAssertEqualObjects(result.code, @"unsupported-options"); - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; -} - - (void)testInitGoogleServiceInfoPlist { FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"init"