| // 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 Flutter; |
| |
| @import XCTest; |
| @import google_sign_in_ios; |
| @import google_sign_in_ios.Test; |
| @import GoogleSignIn; |
| |
| // OCMock library doesn't generate a valid modulemap. |
| #import <OCMock/OCMock.h> |
| |
| @interface FLTGoogleSignInPluginTest : XCTestCase |
| |
| @property(strong, nonatomic) NSObject<FlutterBinaryMessenger> *mockBinaryMessenger; |
| @property(strong, nonatomic) NSObject<FlutterPluginRegistrar> *mockPluginRegistrar; |
| @property(strong, nonatomic) FLTGoogleSignInPlugin *plugin; |
| @property(strong, nonatomic) id mockSignIn; |
| |
| @end |
| |
| @implementation FLTGoogleSignInPluginTest |
| |
| - (void)setUp { |
| [super setUp]; |
| self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); |
| self.mockPluginRegistrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); |
| |
| id mockSignIn = OCMClassMock([GIDSignIn class]); |
| self.mockSignIn = mockSignIn; |
| |
| OCMStub(self.mockPluginRegistrar.messenger).andReturn(self.mockBinaryMessenger); |
| self.plugin = [[FLTGoogleSignInPlugin alloc] initWithSignIn:mockSignIn]; |
| [FLTGoogleSignInPlugin registerWithRegistrar:self.mockPluginRegistrar]; |
| } |
| |
| - (void)testUnimplementedMethod { |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"bogus" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(id result) { |
| XCTAssertEqualObjects(result, FlutterMethodNotImplemented); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testSignOut { |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signOut" |
| 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]; |
| OCMVerify([self.mockSignIn signOut]); |
| } |
| |
| - (void)testDisconnect { |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"disconnect" |
| arguments:nil]; |
| |
| [self.plugin handleMethodCall:methodCall |
| result:^(id result){ |
| }]; |
| OCMVerify([self.mockSignIn disconnect]); |
| } |
| |
| #pragma mark - Init |
| |
| - (void)testInitGoogleServiceInfoPlist { |
| FlutterMethodCall *methodCall = [FlutterMethodCall |
| methodCallWithMethodName:@"init" |
| arguments:@{@"scopes" : @[ @"mockScope1" ], @"hostedDomain" : @"example.com"}]; |
| |
| 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]; |
| |
| id mockSignIn = self.mockSignIn; |
| OCMVerify([mockSignIn setScopes:@[ @"mockScope1" ]]); |
| OCMVerify([mockSignIn setHostedDomain:@"example.com"]); |
| |
| // Set in example app GoogleService-Info.plist. |
| OCMVerify([mockSignIn |
| setClientID:@"479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com"]); |
| OCMVerify([mockSignIn setServerClientID:@"YOUR_SERVER_CLIENT_ID"]); |
| } |
| |
| - (void)testInitNullDomain { |
| FlutterMethodCall *methodCall = |
| [FlutterMethodCall methodCallWithMethodName:@"init" |
| arguments:@{@"hostedDomain" : [NSNull null]}]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(id r) { |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| OCMVerify([self.mockSignIn setHostedDomain:nil]); |
| } |
| |
| - (void)testInitDynamicClientId { |
| FlutterMethodCall *methodCall = |
| [FlutterMethodCall methodCallWithMethodName:@"init" |
| arguments:@{@"clientId" : @"mockClientId"}]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(id r) { |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| OCMVerify([self.mockSignIn setClientID:@"mockClientId"]); |
| } |
| |
| #pragma mark - Is signed in |
| |
| - (void)testIsNotSignedIn { |
| OCMStub([self.mockSignIn hasPreviousSignIn]).andReturn(NO); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"isSignedIn" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSNumber *result) { |
| XCTAssertFalse(result.boolValue); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testIsSignedIn { |
| OCMStub([self.mockSignIn hasPreviousSignIn]).andReturn(YES); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"isSignedIn" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSNumber *result) { |
| XCTAssertTrue(result.boolValue); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| #pragma mark - Sign in silently |
| |
| - (void)testSignInSilently { |
| OCMExpect([self.mockSignIn restorePreviousSignIn]); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently" |
| arguments:nil]; |
| |
| [self.plugin handleMethodCall:methodCall |
| result:^(id result){ |
| }]; |
| OCMVerifyAll(self.mockSignIn); |
| } |
| |
| - (void)testSignInSilentlyFailsConcurrently { |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signInSilently" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| |
| OCMExpect([self.mockSignIn restorePreviousSignIn]).andDo(^(NSInvocation *invocation) { |
| // Simulate calling the same method while the previous one is in flight. |
| [self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| XCTAssertEqualObjects(result.code, @"concurrent-requests"); |
| [expectation fulfill]; |
| }]; |
| }); |
| |
| [self.plugin handleMethodCall:methodCall |
| result:^(id result){ |
| }]; |
| |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| #pragma mark - Sign in |
| |
| - (void)testSignIn { |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn" |
| arguments:nil]; |
| |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSNumber *result){ |
| }]; |
| |
| id mockSignIn = self.mockSignIn; |
| OCMVerify([mockSignIn |
| setPresentingViewController:[OCMArg isKindOfClass:[FlutterViewController class]]]); |
| OCMVerify([mockSignIn signIn]); |
| } |
| |
| - (void)testSignInExecption { |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"signIn" |
| arguments:nil]; |
| OCMExpect([self.mockSignIn signIn]) |
| .andThrow([NSException exceptionWithName:@"MockName" reason:@"MockReason" userInfo:nil]); |
| |
| __block FlutterError *error; |
| XCTAssertThrows([self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| error = result; |
| }]); |
| |
| XCTAssertEqualObjects(error.code, @"google_sign_in"); |
| XCTAssertEqualObjects(error.message, @"MockReason"); |
| XCTAssertEqualObjects(error.details, @"MockName"); |
| } |
| |
| #pragma mark - Get tokens |
| |
| - (void)testGetTokens { |
| id mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| |
| id mockAuthentication = OCMClassMock([GIDAuthentication class]); |
| OCMStub([mockAuthentication idToken]).andReturn(@"mockIdToken"); |
| OCMStub([mockAuthentication accessToken]).andReturn(@"mockAccessToken"); |
| [[mockAuthentication stub] |
| getTokensWithHandler:[OCMArg invokeBlockWithArgs:mockAuthentication, [NSNull null], nil]]; |
| OCMStub([mockUser authentication]).andReturn(mockAuthentication); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSDictionary<NSString *, NSString *> *result) { |
| XCTAssertEqualObjects(result[@"idToken"], @"mockIdToken"); |
| XCTAssertEqualObjects(result[@"accessToken"], @"mockAccessToken"); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testGetTokensNoAuthKeychainError { |
| id mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| |
| id mockAuthentication = OCMClassMock([GIDAuthentication class]); |
| NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain |
| code:kGIDSignInErrorCodeHasNoAuthInKeychain |
| userInfo:nil]; |
| [[mockAuthentication stub] |
| getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]]; |
| OCMStub([mockUser authentication]).andReturn(mockAuthentication); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| XCTAssertEqualObjects(result.code, @"sign_in_required"); |
| XCTAssertEqualObjects(result.message, kGIDSignInErrorDomain); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testGetTokensCancelledError { |
| id mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| |
| id mockAuthentication = OCMClassMock([GIDAuthentication class]); |
| NSError *error = [NSError errorWithDomain:kGIDSignInErrorDomain |
| code:kGIDSignInErrorCodeCanceled |
| userInfo:nil]; |
| [[mockAuthentication stub] |
| getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]]; |
| OCMStub([mockUser authentication]).andReturn(mockAuthentication); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| XCTAssertEqualObjects(result.code, @"sign_in_canceled"); |
| XCTAssertEqualObjects(result.message, kGIDSignInErrorDomain); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testGetTokensURLError { |
| id mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| |
| id mockAuthentication = OCMClassMock([GIDAuthentication class]); |
| NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:nil]; |
| [[mockAuthentication stub] |
| getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]]; |
| OCMStub([mockUser authentication]).andReturn(mockAuthentication); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| XCTAssertEqualObjects(result.code, @"network_error"); |
| XCTAssertEqualObjects(result.message, NSURLErrorDomain); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testGetTokensUnknownError { |
| id mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| |
| id mockAuthentication = OCMClassMock([GIDAuthentication class]); |
| NSError *error = [NSError errorWithDomain:@"BogusDomain" code:42 userInfo:nil]; |
| [[mockAuthentication stub] |
| getTokensWithHandler:[OCMArg invokeBlockWithArgs:[NSNull null], error, nil]]; |
| OCMStub([mockUser authentication]).andReturn(mockAuthentication); |
| |
| FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"getTokens" |
| arguments:nil]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| XCTAssertEqualObjects(result.code, @"sign_in_failed"); |
| XCTAssertEqualObjects(result.message, @"BogusDomain"); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| #pragma mark - Request scopes |
| |
| - (void)testRequestScopesResultErrorIfNotSignedIn { |
| OCMStub([self.mockSignIn currentUser]).andReturn(nil); |
| |
| FlutterMethodCall *methodCall = |
| [FlutterMethodCall methodCallWithMethodName:@"requestScopes" |
| arguments:@{@"scopes" : @[ @"mockScope1" ]}]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(FlutterError *result) { |
| XCTAssertEqualObjects(result.code, @"sign_in_required"); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testRequestScopesIfNoMissingScope { |
| // Mock Google Signin internal calls |
| GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn 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"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSNumber *result) { |
| XCTAssertTrue(result.boolValue); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testRequestScopesRequestsIfNotGranted { |
| // Mock Google Signin internal calls |
| GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| NSArray *requestedScopes = @[ @"mockScope1" ]; |
| OCMStub(mockUser.grantedScopes).andReturn(@[]); |
| id mockSignIn = self.mockSignIn; |
| OCMStub([mockSignIn scopes]).andReturn(@[]); |
| |
| FlutterMethodCall *methodCall = |
| [FlutterMethodCall methodCallWithMethodName:@"requestScopes" |
| arguments:@{@"scopes" : requestedScopes}]; |
| |
| [self.plugin handleMethodCall:methodCall |
| result:^(id r){ |
| }]; |
| |
| OCMVerify([mockSignIn setScopes:@[ @"mockScope1" ]]); |
| OCMVerify([mockSignIn signIn]); |
| } |
| |
| - (void)testRequestScopesReturnsFalseIfNotGranted { |
| // Mock Google Signin internal calls |
| GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| NSArray *requestedScopes = @[ @"mockScope1" ]; |
| OCMStub(mockUser.grantedScopes).andReturn(@[]); |
| |
| OCMStub([self.mockSignIn signIn]).andDo(^(NSInvocation *invocation) { |
| [((NSObject<GIDSignInDelegate> *)self.plugin) signIn:self.mockSignIn |
| didSignInForUser:mockUser |
| withError:nil]; |
| }); |
| |
| FlutterMethodCall *methodCall = |
| [FlutterMethodCall methodCallWithMethodName:@"requestScopes" |
| arguments:@{@"scopes" : requestedScopes}]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns false"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSNumber *result) { |
| XCTAssertFalse(result.boolValue); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| - (void)testRequestScopesReturnsTrueIfGranted { |
| // Mock Google Signin internal calls |
| GIDGoogleUser *mockUser = OCMClassMock([GIDGoogleUser class]); |
| OCMStub([self.mockSignIn currentUser]).andReturn(mockUser); |
| NSArray *requestedScopes = @[ @"mockScope1" ]; |
| NSMutableArray *availableScopes = [NSMutableArray new]; |
| OCMStub(mockUser.grantedScopes).andReturn(availableScopes); |
| |
| OCMStub([self.mockSignIn signIn]).andDo(^(NSInvocation *invocation) { |
| [availableScopes addObject:@"mockScope1"]; |
| [((NSObject<GIDSignInDelegate> *)self.plugin) signIn:self.mockSignIn |
| didSignInForUser:mockUser |
| withError:nil]; |
| }); |
| |
| FlutterMethodCall *methodCall = |
| [FlutterMethodCall methodCallWithMethodName:@"requestScopes" |
| arguments:@{@"scopes" : requestedScopes}]; |
| |
| XCTestExpectation *expectation = [self expectationWithDescription:@"expect result returns true"]; |
| [self.plugin handleMethodCall:methodCall |
| result:^(NSNumber *result) { |
| XCTAssertTrue(result.boolValue); |
| [expectation fulfill]; |
| }]; |
| [self waitForExpectationsWithTimeout:5.0 handler:nil]; |
| } |
| |
| @end |