mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-11 22:55:59 +05:45
756 lines
31 KiB
Objective-C
756 lines
31 KiB
Objective-C
/*
|
|
* Copyright 2017 Google
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#import <XCTest/XCTest.h>
|
|
#import <UIKit/UIKit.h>
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
#import "FIRAuthAppDelegateProxy.h"
|
|
#import <OCMock/OCMock.h>
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
/** @class FIRAuthEmptyAppDelegate
|
|
@brief A @c UIApplicationDelegate implementation that does nothing.
|
|
*/
|
|
@interface FIRAuthEmptyAppDelegate : NSObject <UIApplicationDelegate>
|
|
@end
|
|
@implementation FIRAuthEmptyAppDelegate
|
|
@end
|
|
|
|
/** @class FIRAuthLegacyAppDelegate
|
|
@brief A @c UIApplicationDelegate implementation that implements
|
|
`application:didReceiveRemoteNotification:` and
|
|
`application:openURL:sourceApplication:annotation:`.
|
|
*/
|
|
@interface FIRAuthLegacyAppDelegate : NSObject <UIApplicationDelegate>
|
|
|
|
/** @var notificationReceived
|
|
@brief The last notification received, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSDictionary *notificationReceived;
|
|
|
|
/** @var urlOpened
|
|
@brief The last URL opened, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSURL *urlOpened;
|
|
|
|
@end
|
|
|
|
@implementation FIRAuthLegacyAppDelegate
|
|
|
|
- (void)application:(UIApplication *)application
|
|
didReceiveRemoteNotification:(NSDictionary *)userInfo {
|
|
self.notificationReceived = userInfo;
|
|
}
|
|
|
|
- (BOOL)application:(UIApplication *)application
|
|
openURL:(NSURL *)url
|
|
sourceApplication:(nullable NSString *)sourceApplication
|
|
annotation:(id)annotation {
|
|
self.urlOpened = url;
|
|
return NO;
|
|
}
|
|
|
|
@end
|
|
|
|
/** @class FIRAuthModernAppDelegate
|
|
@brief A @c UIApplicationDelegate implementation that implements both
|
|
`application:didRegisterForRemoteNotificationsWithDeviceToken:`,
|
|
`application:didReceiveRemoteNotification:fetchCompletionHandler:`, and
|
|
`application:openURL:options:`.
|
|
*/
|
|
@interface FIRAuthModernAppDelegate : NSObject <UIApplicationDelegate>
|
|
|
|
/** @var deviceTokenReceived
|
|
@brief The last device token received, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSData *deviceTokenReceived;
|
|
|
|
/** @var tokenErrorReceived
|
|
@brief The last token error received, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSError *tokenErrorReceived;
|
|
|
|
/** @var notificationReceived
|
|
@brief The last notification received, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSDictionary *notificationReceived;
|
|
|
|
/** @var urlOpened
|
|
@brief The last URL opened, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSURL *urlOpened;
|
|
|
|
@end
|
|
|
|
@implementation FIRAuthModernAppDelegate
|
|
|
|
- (void)application:(UIApplication *)application
|
|
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
|
self.deviceTokenReceived = deviceToken;
|
|
}
|
|
|
|
- (void)application:(UIApplication *)application
|
|
didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error {
|
|
self.tokenErrorReceived = error;
|
|
}
|
|
|
|
- (void)application:(UIApplication *)application
|
|
didReceiveRemoteNotification:(NSDictionary *)userInfo
|
|
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
|
self.notificationReceived = userInfo;
|
|
completionHandler(UIBackgroundFetchResultNewData);
|
|
}
|
|
|
|
- (BOOL)application:(UIApplication *)app
|
|
openURL:(NSURL *)url
|
|
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
|
|
self.urlOpened = url;
|
|
return NO;
|
|
}
|
|
|
|
@end
|
|
|
|
/** @class FIRAuthOtherLegacyAppDelegate
|
|
@brief A @c UIApplicationDelegate implementation that implements `application:handleOpenURL:`.
|
|
*/
|
|
@interface FIRAuthOtherLegacyAppDelegate : NSObject <UIApplicationDelegate>
|
|
|
|
/** @var urlOpened
|
|
@brief The last URL opened, if any.
|
|
*/
|
|
@property(nonatomic, copy, nullable) NSURL *urlOpened;
|
|
|
|
@end
|
|
|
|
@implementation FIRAuthOtherLegacyAppDelegate
|
|
|
|
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
|
|
self.urlOpened = url;
|
|
return NO;
|
|
}
|
|
|
|
@end
|
|
|
|
/** @class FIRAuthAppDelegateProxyTests
|
|
@brief Unit tests for @c FIRAuthAppDelegateProxy .
|
|
*/
|
|
@interface FIRAuthAppDelegateProxyTests : XCTestCase
|
|
@end
|
|
@implementation FIRAuthAppDelegateProxyTests {
|
|
/** @var _mockApplication
|
|
@brief The mock UIApplication used for testing.
|
|
*/
|
|
id _mockApplication;
|
|
|
|
/** @var _deviceToken
|
|
@brief The fake APNs device token for testing.
|
|
*/
|
|
NSData *_deviceToken;
|
|
|
|
/** @var _error
|
|
@brief The fake error for testing.
|
|
*/
|
|
NSError *_error;
|
|
|
|
/** @var _notification
|
|
@brief The fake notification for testing.
|
|
*/
|
|
NSDictionary* _notification;
|
|
|
|
/** @var _url
|
|
@brief The fake URL for testing.
|
|
*/
|
|
NSURL *_url;
|
|
|
|
/** @var _isIOS9orLater
|
|
@brief Whether the OS version is iOS 9 or later.
|
|
*/
|
|
BOOL _isIOS9orLater;
|
|
}
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
_mockApplication = OCMClassMock([UIApplication class]);
|
|
_deviceToken = [@"asdf" dataUsingEncoding:NSUTF8StringEncoding];
|
|
_error = [NSError errorWithDomain:@"FakeError" code:12345 userInfo:nil];
|
|
_notification = @{ @"zxcv" : @1234 };
|
|
_url = [NSURL URLWithString:@"https://abc.def/ghi"];
|
|
_isIOS9orLater = [[[UIDevice currentDevice] systemVersion] doubleValue] >= 9.0;
|
|
}
|
|
|
|
- (void)tearDown {
|
|
OCMVerifyAll(_mockApplication);
|
|
[super tearDown];
|
|
}
|
|
|
|
/** @fn testSharedInstance
|
|
@brief Tests that the shared instance is the same one.
|
|
*/
|
|
- (void)testSharedInstance {
|
|
FIRAuthAppDelegateProxy *proxy1 = [FIRAuthAppDelegateProxy sharedInstance];
|
|
FIRAuthAppDelegateProxy *proxy2 = [FIRAuthAppDelegateProxy sharedInstance];
|
|
XCTAssertEqual(proxy1, proxy2);
|
|
}
|
|
|
|
/** @fn testNilApplication
|
|
@brief Tests that initialization fails if the application is nil.
|
|
*/
|
|
- (void)testNilApplication {
|
|
XCTAssertNil([[FIRAuthAppDelegateProxy alloc] initWithApplication:nil]);
|
|
}
|
|
|
|
/** @fn testNilDelegate
|
|
@brief Tests that initialization fails if the application's delegate is nil.
|
|
*/
|
|
- (void)testNilDelegate {
|
|
OCMExpect([_mockApplication delegate]).andReturn(nil);
|
|
XCTAssertNil([[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication]);
|
|
}
|
|
|
|
/** @fn testNonconformingDelegate
|
|
@brief Tests that initialization fails if the application's delegate does not conform to
|
|
@c UIApplicationDelegate protocol.
|
|
*/
|
|
- (void)testNonconformingDelegate {
|
|
OCMExpect([_mockApplication delegate]).andReturn(@"abc");
|
|
XCTAssertNil([[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication]);
|
|
}
|
|
|
|
/** @fn testDisabledByBundleEntry
|
|
@brief Tests that initialization fails if the proxy is disabled by a bundle entry.
|
|
*/
|
|
- (void)testDisabledByBundleEntry {
|
|
// Swizzle NSBundle's objectForInfoDictionaryKey to return @NO for the specific key.
|
|
Method method = class_getInstanceMethod([NSBundle class], @selector(objectForInfoDictionaryKey:));
|
|
__block IMP originalImplementation;
|
|
IMP newImplmentation = imp_implementationWithBlock(^id(id object, NSString *key) {
|
|
if ([key isEqualToString:@"FirebaseAppDelegateProxyEnabled"]) {
|
|
return @NO;
|
|
}
|
|
typedef id (*Implementation)(id object, SEL cmd, NSString *key);
|
|
return ((Implementation)originalImplementation)(object, @selector(objectForInfoDictionaryKey:),
|
|
key);
|
|
});
|
|
originalImplementation = method_setImplementation(method, newImplmentation);
|
|
|
|
// Verify that initialization fails.
|
|
FIRAuthEmptyAppDelegate *delegate = [[FIRAuthEmptyAppDelegate alloc] init];
|
|
OCMStub([_mockApplication delegate]).andReturn(delegate);
|
|
XCTAssertNil([[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication]);
|
|
|
|
// Unswizzle.
|
|
imp_removeBlock(method_setImplementation(method, originalImplementation));
|
|
}
|
|
|
|
// Deprecated methods are call intentionally in tests to verify behaviors on older iOS systems.
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
/** @fn testEmptyDelegateOneHandler
|
|
@brief Tests that the proxy works against an empty @c UIApplicationDelegate for one handler.
|
|
*/
|
|
- (void)testEmptyDelegateOneHandler {
|
|
FIRAuthEmptyAppDelegate *delegate = [[FIRAuthEmptyAppDelegate alloc] init];
|
|
OCMExpect([_mockApplication delegate]).andReturn(delegate);
|
|
__weak id weakProxy;
|
|
@autoreleasepool {
|
|
FIRAuthAppDelegateProxy *proxy =
|
|
[[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication];
|
|
XCTAssertNotNil(proxy);
|
|
|
|
// Verify certain methods are swizzled while others are not.
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didFailToRegisterForRemoteNotificationsWithError:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:
|
|
@selector(application:didReceiveRemoteNotification:)]);
|
|
if (_isIOS9orLater) {
|
|
XCTAssertTrue([delegate respondsToSelector:@selector(application:openURL:options:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:
|
|
@selector(application:openURL:sourceApplication:annotation:)]);
|
|
} else {
|
|
XCTAssertFalse([delegate respondsToSelector:@selector(application:openURL:options:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:openURL:sourceApplication:annotation:)]);
|
|
}
|
|
XCTAssertFalse([delegate respondsToSelector:@selector(application:handleOpenURL:)]);
|
|
|
|
// Verify the handler is called after being added.
|
|
__weak id weakHandler;
|
|
@autoreleasepool {
|
|
id mockHandler = OCMProtocolMock(@protocol(FIRAuthAppDelegateHandler));
|
|
[proxy addHandler:mockHandler];
|
|
|
|
// Verify `application:didRegisterForRemoteNotificationsWithDeviceToken:` is handled.
|
|
OCMExpect([mockHandler setAPNSToken:_deviceToken]);
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
OCMVerifyAll(mockHandler);
|
|
|
|
// Verify `application:didFailToRegisterForRemoteNotificationsWithError:` is handled.
|
|
OCMExpect([mockHandler handleAPNSTokenError:_error]);
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
OCMVerifyAll(mockHandler);
|
|
|
|
// Verify `application:didReceiveRemoteNotification:fetchCompletionHandler:` is handled.
|
|
OCMExpect([mockHandler canHandleNotification:_notification]).andReturn(YES);
|
|
__block BOOL fetchCompletionHandlerCalled = NO;
|
|
[delegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTAssertEqual(result, UIBackgroundFetchResultNoData);
|
|
fetchCompletionHandlerCalled = YES;
|
|
}];
|
|
OCMVerifyAll(mockHandler);
|
|
XCTAssertTrue(fetchCompletionHandlerCalled);
|
|
|
|
// Verify one of the `application:openURL:...` methods is handled.
|
|
OCMExpect([mockHandler canHandleURL:_url]).andReturn(YES);
|
|
if (_isIOS9orLater) {
|
|
// Verify `application:openURL:options:` is handled.
|
|
XCTAssertTrue([delegate application:_mockApplication openURL:_url options:@{}]);
|
|
} else {
|
|
// Verify `application:openURL:sourceApplication:annotation:` is handled.
|
|
XCTAssertTrue([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotaton"]);
|
|
}
|
|
OCMVerifyAll(mockHandler);
|
|
|
|
weakHandler = mockHandler;
|
|
XCTAssertNotNil(weakHandler);
|
|
}
|
|
// Verify the handler is not retained by the proxy.
|
|
XCTAssertNil(weakHandler);
|
|
|
|
// Verify nothing bad happens after the handler is released.
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
[delegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTFail(@"Should not call completion handler.");
|
|
}];
|
|
if (_isIOS9orLater) {
|
|
XCTAssertFalse([delegate application:_mockApplication openURL:_url options:@{}]);
|
|
} else {
|
|
XCTAssertFalse([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotaton"]);
|
|
}
|
|
weakProxy = proxy;
|
|
XCTAssertNotNil(weakProxy);
|
|
}
|
|
// Verify the proxy does not retain itself.
|
|
XCTAssertNil(weakProxy);
|
|
// Verify nothing bad happens after the proxy is released.
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
[delegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTFail(@"Should not call completion handler.");
|
|
}];
|
|
if (_isIOS9orLater) {
|
|
XCTAssertFalse([delegate application:_mockApplication openURL:_url options:@{}]);
|
|
} else {
|
|
XCTAssertFalse([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotaton"]);
|
|
}
|
|
}
|
|
|
|
/** @fn testLegacyDelegateTwoHandlers
|
|
@brief Tests that the proxy works against a legacy @c UIApplicationDelegate for two handlers.
|
|
*/
|
|
- (void)testLegacyDelegateTwoHandlers {
|
|
FIRAuthLegacyAppDelegate *delegate = [[FIRAuthLegacyAppDelegate alloc] init];
|
|
OCMExpect([_mockApplication delegate]).andReturn(delegate);
|
|
__weak id weakProxy;
|
|
@autoreleasepool {
|
|
FIRAuthAppDelegateProxy *proxy =
|
|
[[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication];
|
|
XCTAssertNotNil(proxy);
|
|
|
|
// Verify certain methods are swizzled while others are not.
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didFailToRegisterForRemoteNotificationsWithError:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:
|
|
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didReceiveRemoteNotification:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:@selector(application:openURL:options:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:openURL:sourceApplication:annotation:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:@selector(application:handleOpenURL:)]);
|
|
|
|
// Verify the handler is called after being added.
|
|
__weak id weakHandler1;
|
|
@autoreleasepool {
|
|
id mockHandler1 = OCMProtocolMock(@protocol(FIRAuthAppDelegateHandler));
|
|
[proxy addHandler:mockHandler1];
|
|
__weak id weakHandler2;
|
|
@autoreleasepool {
|
|
id mockHandler2 = OCMProtocolMock(@protocol(FIRAuthAppDelegateHandler));
|
|
[proxy addHandler:mockHandler2];
|
|
|
|
// Verify `application:didRegisterForRemoteNotificationsWithDeviceToken:` is handled.
|
|
OCMExpect([mockHandler1 setAPNSToken:_deviceToken]);
|
|
OCMExpect([mockHandler2 setAPNSToken:_deviceToken]);
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
OCMVerifyAll(mockHandler1);
|
|
OCMVerifyAll(mockHandler2);
|
|
|
|
// Verify `application:didFailToRegisterForRemoteNotificationsWithError:` is handled.
|
|
OCMExpect([mockHandler1 handleAPNSTokenError:_error]);
|
|
OCMExpect([mockHandler2 handleAPNSTokenError:_error]);
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
OCMVerifyAll(mockHandler1);
|
|
OCMVerifyAll(mockHandler2);
|
|
|
|
// Verify `application:didReceiveRemoteNotification:fetchCompletionHandler:` is handled.
|
|
OCMExpect([mockHandler1 canHandleNotification:_notification]).andReturn(YES);
|
|
// handler2 shouldn't been invoked because it is already handled by handler1.
|
|
[delegate application:_mockApplication didReceiveRemoteNotification:_notification];
|
|
OCMVerifyAll(mockHandler1);
|
|
OCMVerifyAll(mockHandler2);
|
|
XCTAssertNil(delegate.notificationReceived);
|
|
|
|
// Verify `application:openURL:sourceApplication:annotation:` is handled.
|
|
OCMExpect([mockHandler1 canHandleURL:_url]).andReturn(YES);
|
|
XCTAssertTrue([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotaton"]);
|
|
OCMVerifyAll(mockHandler1);
|
|
OCMVerifyAll(mockHandler2);
|
|
XCTAssertNil(delegate.urlOpened);
|
|
|
|
weakHandler2 = mockHandler2;
|
|
XCTAssertNotNil(weakHandler2);
|
|
}
|
|
// Verify the handler2 is not retained by the proxy.
|
|
XCTAssertNil(weakHandler2);
|
|
|
|
// Verify `application:didRegisterForRemoteNotificationsWithDeviceToken:` is handled.
|
|
OCMExpect([mockHandler1 setAPNSToken:_deviceToken]);
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
OCMVerifyAll(mockHandler1);
|
|
|
|
// Verify `application:didFailToRegisterForRemoteNotificationsWithError:` is handled.
|
|
OCMExpect([mockHandler1 handleAPNSTokenError:_error]);
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
OCMVerifyAll(mockHandler1);
|
|
|
|
// Verify `application:didReceiveRemoteNotification:fetchCompletionHandler:` is NOT handled.
|
|
OCMExpect([mockHandler1 canHandleNotification:_notification]).andReturn(NO);
|
|
[delegate application:_mockApplication didReceiveRemoteNotification:_notification];
|
|
OCMVerifyAll(mockHandler1);
|
|
XCTAssertEqualObjects(delegate.notificationReceived, _notification);
|
|
delegate.notificationReceived = nil;
|
|
|
|
// Verify `application:openURL:sourceApplication:annotation:` is NOT handled.
|
|
OCMExpect([mockHandler1 canHandleURL:_url]).andReturn(NO);
|
|
XCTAssertFalse([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotation"]);
|
|
OCMVerifyAll(mockHandler1);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
|
|
weakHandler1 = mockHandler1;
|
|
XCTAssertNotNil(weakHandler1);
|
|
}
|
|
// Verify the handler1 is not retained by the proxy.
|
|
XCTAssertNil(weakHandler1);
|
|
|
|
// Verify the delegate still works after all handlers are released.
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
[delegate application:_mockApplication didReceiveRemoteNotification:_notification];
|
|
XCTAssertEqualObjects(delegate.notificationReceived, _notification);
|
|
delegate.notificationReceived = nil;
|
|
XCTAssertFalse([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotation"]);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
|
|
weakProxy = proxy;
|
|
XCTAssertNotNil(weakProxy);
|
|
}
|
|
// Verify the proxy does not retain itself.
|
|
XCTAssertNil(weakProxy);
|
|
|
|
// Verify the delegate still works after the proxy is released.
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
[delegate application:_mockApplication didReceiveRemoteNotification:_notification];
|
|
XCTAssertEqualObjects(delegate.notificationReceived, _notification);
|
|
delegate.notificationReceived = nil;
|
|
XCTAssertFalse([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotation"]);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
}
|
|
|
|
/** @fn testModernDelegateWithOtherInstance
|
|
@brief Tests that the proxy works against a modern @c UIApplicationDelegate along with
|
|
another unaffected instance.
|
|
*/
|
|
- (void)testModernDelegateWithUnaffectedInstance {
|
|
FIRAuthModernAppDelegate *delegate = [[FIRAuthModernAppDelegate alloc] init];
|
|
OCMExpect([_mockApplication delegate]).andReturn(delegate);
|
|
FIRAuthModernAppDelegate *unaffectedDelegate = [[FIRAuthModernAppDelegate alloc] init];
|
|
__weak id weakProxy;
|
|
@autoreleasepool {
|
|
FIRAuthAppDelegateProxy *proxy =
|
|
[[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication];
|
|
XCTAssertNotNil(proxy);
|
|
|
|
// Verify certain methods are swizzled while others are not.
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didFailToRegisterForRemoteNotificationsWithError:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:
|
|
@selector(application:didReceiveRemoteNotification:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:@selector(application:openURL:options:)]);
|
|
if (_isIOS9orLater) {
|
|
XCTAssertFalse([delegate respondsToSelector:
|
|
@selector(application:openURL:sourceApplication:annotation:)]);
|
|
} else {
|
|
XCTAssertTrue([delegate respondsToSelector:
|
|
@selector(application:openURL:sourceApplication:annotation:)]);
|
|
}
|
|
XCTAssertFalse([delegate respondsToSelector:@selector(application:handleOpenURL:)]);
|
|
|
|
// Verify the handler is called after being added.
|
|
__weak id weakHandler;
|
|
@autoreleasepool {
|
|
id mockHandler = OCMProtocolMock(@protocol(FIRAuthAppDelegateHandler));
|
|
[proxy addHandler:mockHandler];
|
|
|
|
// Verify `application:didRegisterForRemoteNotificationsWithDeviceToken:` is handled.
|
|
OCMExpect([mockHandler setAPNSToken:_deviceToken]);
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
OCMVerifyAll(mockHandler);
|
|
XCTAssertEqualObjects(delegate.deviceTokenReceived, _deviceToken);
|
|
delegate.deviceTokenReceived = nil;
|
|
|
|
// Verify `application:didFailToRegisterForRemoteNotificationsWithError:` is handled.
|
|
OCMExpect([mockHandler handleAPNSTokenError:_error]);
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
OCMVerifyAll(mockHandler);
|
|
XCTAssertEqualObjects(delegate.tokenErrorReceived, _error);
|
|
delegate.tokenErrorReceived = nil;
|
|
|
|
// Verify `application:didReceiveRemoteNotification:fetchCompletionHandler:` is handled.
|
|
OCMExpect([mockHandler canHandleNotification:_notification]).andReturn(YES);
|
|
__block BOOL fetchCompletionHandlerCalled = NO;
|
|
[delegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTAssertEqual(result, UIBackgroundFetchResultNoData);
|
|
fetchCompletionHandlerCalled = YES;
|
|
}];
|
|
OCMVerifyAll(mockHandler);
|
|
XCTAssertTrue(fetchCompletionHandlerCalled);
|
|
XCTAssertNil(delegate.notificationReceived);
|
|
|
|
// Verify one of the `application:openURL:...` methods is handled.
|
|
OCMExpect([mockHandler canHandleURL:_url]).andReturn(YES);
|
|
if (_isIOS9orLater) {
|
|
// Verify `application:openURL:options:` is handled.
|
|
XCTAssertTrue([delegate application:_mockApplication openURL:_url options:@{}]);
|
|
} else {
|
|
// Verify `application:openURL:sourceApplication:annotation:` is handled.
|
|
XCTAssertTrue([delegate application:_mockApplication
|
|
openURL:_url
|
|
sourceApplication:@"sourceApplication"
|
|
annotation:@"annotaton"]);
|
|
}
|
|
OCMVerifyAll(mockHandler);
|
|
XCTAssertNil(delegate.urlOpened);
|
|
|
|
// Verify unaffected delegate instance.
|
|
[unaffectedDelegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
XCTAssertEqualObjects(unaffectedDelegate.deviceTokenReceived, _deviceToken);
|
|
unaffectedDelegate.deviceTokenReceived = nil;
|
|
[unaffectedDelegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
XCTAssertEqualObjects(unaffectedDelegate.tokenErrorReceived, _error);
|
|
unaffectedDelegate.tokenErrorReceived = nil;
|
|
fetchCompletionHandlerCalled = NO;
|
|
[unaffectedDelegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTAssertEqual(result, UIBackgroundFetchResultNewData);
|
|
fetchCompletionHandlerCalled = YES;
|
|
}];
|
|
XCTAssertTrue(fetchCompletionHandlerCalled);
|
|
XCTAssertEqualObjects(unaffectedDelegate.notificationReceived, _notification);
|
|
unaffectedDelegate.notificationReceived = nil;
|
|
XCTAssertFalse([unaffectedDelegate application:_mockApplication openURL:_url options:@{}]);
|
|
XCTAssertEqualObjects(unaffectedDelegate.urlOpened, _url);
|
|
unaffectedDelegate.urlOpened = nil;
|
|
|
|
weakHandler = mockHandler;
|
|
XCTAssertNotNil(weakHandler);
|
|
}
|
|
// Verify the handler is not retained by the proxy.
|
|
XCTAssertNil(weakHandler);
|
|
|
|
// Verify the delegate still works after the handler is released.
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
XCTAssertEqualObjects(delegate.deviceTokenReceived, _deviceToken);
|
|
delegate.deviceTokenReceived = nil;
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
XCTAssertEqualObjects(delegate.tokenErrorReceived, _error);
|
|
delegate.tokenErrorReceived = nil;
|
|
__block BOOL fetchCompletionHandlerCalled = NO;
|
|
[delegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTAssertEqual(result, UIBackgroundFetchResultNewData);
|
|
fetchCompletionHandlerCalled = YES;
|
|
}];
|
|
XCTAssertEqualObjects(delegate.notificationReceived, _notification);
|
|
delegate.notificationReceived = nil;
|
|
XCTAssertTrue(fetchCompletionHandlerCalled);
|
|
XCTAssertFalse([delegate application:_mockApplication openURL:_url options:@{}]);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
|
|
weakProxy = proxy;
|
|
XCTAssertNotNil(weakProxy);
|
|
}
|
|
// Verify the proxy does not retain itself.
|
|
XCTAssertNil(weakProxy);
|
|
|
|
// Verify the delegate still works after the proxy is released.
|
|
[delegate application:_mockApplication
|
|
didRegisterForRemoteNotificationsWithDeviceToken:_deviceToken];
|
|
XCTAssertEqualObjects(delegate.deviceTokenReceived, _deviceToken);
|
|
delegate.deviceTokenReceived = nil;
|
|
[delegate application:_mockApplication
|
|
didFailToRegisterForRemoteNotificationsWithError:_error];
|
|
XCTAssertEqualObjects(delegate.tokenErrorReceived, _error);
|
|
delegate.tokenErrorReceived = nil;
|
|
__block BOOL fetchCompletionHandlerCalled = NO;
|
|
[delegate application:_mockApplication
|
|
didReceiveRemoteNotification:_notification
|
|
fetchCompletionHandler:^(UIBackgroundFetchResult result) {
|
|
XCTAssertEqual(result, UIBackgroundFetchResultNewData);
|
|
fetchCompletionHandlerCalled = YES;
|
|
}];
|
|
XCTAssertEqualObjects(delegate.notificationReceived, _notification);
|
|
delegate.notificationReceived = nil;
|
|
XCTAssertTrue(fetchCompletionHandlerCalled);
|
|
XCTAssertFalse([delegate application:_mockApplication openURL:_url options:@{}]);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
}
|
|
|
|
/** @fn testOtherLegacyDelegateHandleOpenURL
|
|
@brief Tests that the proxy works against another legacy @c UIApplicationDelegate for
|
|
`application:handleOpenURL:`.
|
|
*/
|
|
- (void)testOtherLegacyDelegateHandleOpenURL {
|
|
FIRAuthOtherLegacyAppDelegate *delegate = [[FIRAuthOtherLegacyAppDelegate alloc] init];
|
|
OCMExpect([_mockApplication delegate]).andReturn(delegate);
|
|
__weak id weakProxy;
|
|
@autoreleasepool {
|
|
FIRAuthAppDelegateProxy *proxy =
|
|
[[FIRAuthAppDelegateProxy alloc] initWithApplication:_mockApplication];
|
|
XCTAssertNotNil(proxy);
|
|
|
|
// Verify certain methods are swizzled while others are not.
|
|
XCTAssertFalse([delegate respondsToSelector:@selector(application:openURL:options:)]);
|
|
XCTAssertFalse([delegate respondsToSelector:
|
|
@selector(application:openURL:sourceApplication:annotation:)]);
|
|
XCTAssertTrue([delegate respondsToSelector:@selector(application:handleOpenURL:)]);
|
|
|
|
// Verify the handler is called after being added.
|
|
__weak id weakHandler;
|
|
@autoreleasepool {
|
|
id mockHandler = OCMProtocolMock(@protocol(FIRAuthAppDelegateHandler));
|
|
[proxy addHandler:mockHandler];
|
|
|
|
// Verify `application:handleOpenURL:` is handled.
|
|
OCMExpect([mockHandler canHandleURL:_url]).andReturn(YES);
|
|
XCTAssertTrue([delegate application:_mockApplication handleOpenURL:_url]);
|
|
OCMVerifyAll(mockHandler);
|
|
|
|
weakHandler = mockHandler;
|
|
XCTAssertNotNil(weakHandler);
|
|
}
|
|
// Verify the handler is not retained by the proxy.
|
|
XCTAssertNil(weakHandler);
|
|
|
|
// Verify nothing bad happens after the handler is released.
|
|
XCTAssertFalse([delegate application:_mockApplication handleOpenURL:_url]);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
|
|
weakProxy = proxy;
|
|
XCTAssertNotNil(weakProxy);
|
|
}
|
|
// Verify the proxy does not retain itself.
|
|
XCTAssertNil(weakProxy);
|
|
// Verify nothing bad happens after the proxy is released.
|
|
XCTAssertFalse([delegate application:_mockApplication handleOpenURL:_url]);
|
|
XCTAssertEqualObjects(delegate.urlOpened, _url);
|
|
delegate.urlOpened = nil;
|
|
}
|
|
|
|
#pragma clang diagnostic pop // ignored "-Wdeprecated-declarations"
|
|
|
|
@end
|
|
|
|
NS_ASSUME_NONNULL_END
|