blob: 3bc08d18604a144cae50389a15bca4a0e01eb2f0 [file] [log] [blame]
// 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