Files
firebase-ios-sdk/Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m
T

426 lines
16 KiB
Objective-C
Raw Normal View History

2017-05-15 12:27:07 -07:00
/*
* 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.
*/
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 || \
__TV_OS_VERSION_MAX_ALLOWED >= __TV_10_0 || \
__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_14
#import <UserNotifications/UserNotifications.h>
2017-05-15 12:27:07 -07:00
#endif
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
2017-05-15 12:27:07 -07:00
#import <FirebaseMessaging/FIRMessaging.h>
#import <GoogleUtilities/GULAppDelegateSwizzler.h>
#import "Firebase/Messaging/FIRMessagingRemoteNotificationsProxy.h"
#pragma mark - Invalid App Delegate or UNNotificationCenter
2017-05-15 12:27:07 -07:00
@interface RandomObject : NSObject
@property(nonatomic, weak) id delegate;
@end
@implementation RandomObject
- (void)application:(GULApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
}
2017-05-15 12:27:07 -07:00
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0), macos(10.14), tvos(10.0)){
}
2017-05-15 12:27:07 -07:00
#if TARGET_OS_IOS || TARGET_OS_OSX
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(macos(10.14), ios(10.0)){
}
#endif
2017-05-15 12:27:07 -07:00
@end
#pragma mark - Incomplete App Delegate
@interface IncompleteAppDelegate : NSObject <GULApplicationDelegate>
2017-05-15 12:27:07 -07:00
@end
@implementation IncompleteAppDelegate
@end
#pragma mark - Fake AppDelegate
@interface FakeAppDelegate : NSObject <GULApplicationDelegate>
2017-05-15 12:27:07 -07:00
@property(nonatomic) BOOL remoteNotificationMethodWasCalled;
@property(nonatomic) BOOL remoteNotificationWithFetchHandlerWasCalled;
@property(nonatomic, strong) NSData *deviceToken;
@property(nonatomic, strong) NSError *registerForRemoteNotificationsError;
2017-05-15 12:27:07 -07:00
@end
@implementation FakeAppDelegate
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (void)application:(GULApplication *)application
2017-05-15 12:27:07 -07:00
didReceiveRemoteNotification:(NSDictionary *)userInfo {
self.remoteNotificationMethodWasCalled = YES;
}
#pragma clang diagnostic pop
#if TARGET_OS_IOS || TARGET_OS_TV
2017-05-15 12:27:07 -07:00
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
self.remoteNotificationWithFetchHandlerWasCalled = YES;
}
#endif
- (void)application:(GULApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
self.deviceToken = deviceToken;
}
- (void)application:(GULApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
self.registerForRemoteNotificationsError = error;
}
2017-05-15 12:27:07 -07:00
@end
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 || \
__TV_OS_VERSION_MAX_ALLOWED >= __TV_10_0 || \
__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_14
2017-05-15 12:27:07 -07:00
#pragma mark - Incompete UNUserNotificationCenterDelegate
@interface IncompleteUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate>
@end
@implementation IncompleteUserNotificationCenterDelegate
@end
#pragma mark - Fake UNUserNotificationCenterDelegate
@interface FakeUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate>
@property(nonatomic) BOOL willPresentWasCalled;
@property(nonatomic) BOOL didReceiveResponseWasCalled;
2017-05-15 12:27:07 -07:00
@end
@implementation FakeUserNotificationCenterDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))
completionHandler API_AVAILABLE(ios(10.0), macos(10.14), tvos(10.0)){
2017-05-15 12:27:07 -07:00
self.willPresentWasCalled = YES;
}
#if TARGET_OS_IOS || TARGET_OS_OSX
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0), macos(10.14)){
self.didReceiveResponseWasCalled = YES;
}
#endif
2017-05-15 12:27:07 -07:00
@end
#endif
2017-05-15 12:27:07 -07:00
@interface GULAppDelegateSwizzler (FIRMessagingRemoteNotificationsProxyTest)
+ (void)resetProxyOriginalDelegateOnceToken;
@end
2017-05-15 12:27:07 -07:00
#pragma mark - Local, Per-Test Properties
@interface FIRMessagingRemoteNotificationsProxyTest : XCTestCase
@property(nonatomic, strong) FIRMessagingRemoteNotificationsProxy *proxy;
@property(nonatomic, strong) id mockProxyClass;
@property(nonatomic, strong) id mockMessaging;
@property(nonatomic, strong) id mockUserNotificationCenter;
2017-05-15 12:27:07 -07:00
@end
@implementation FIRMessagingRemoteNotificationsProxyTest
- (void)setUp {
[super setUp];
[GULAppDelegateSwizzler resetProxyOriginalDelegateOnceToken];
_mockMessaging = OCMClassMock([FIRMessaging class]);
OCMStub([_mockMessaging messaging]).andReturn(_mockMessaging);
2017-05-15 12:27:07 -07:00
_proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init];
_mockProxyClass = OCMClassMock([FIRMessagingRemoteNotificationsProxy class]);
// Update +sharedProxy to always return our test instance
OCMStub([_mockProxyClass sharedProxy]).andReturn(self.proxy);
if (@available(macOS 10.14, iOS 10.0, *)) {
2019-05-28 11:36:31 -07:00
_mockUserNotificationCenter = OCMPartialMock([UNUserNotificationCenter currentNotificationCenter]);
}
2017-05-15 12:27:07 -07:00
}
- (void)tearDown {
[_mockProxyClass stopMocking];
_mockProxyClass = nil;
[_mockMessaging stopMocking];
_mockMessaging = nil;
if (@available(macOS 10.14, iOS 10.0, *)) {
2019-05-28 11:36:31 -07:00
[_mockUserNotificationCenter stopMocking];
_mockUserNotificationCenter = nil;
}
2017-05-15 12:27:07 -07:00
_proxy = nil;
[super tearDown];
}
#pragma mark - Method Swizzling Tests
- (void)testSwizzlingNonAppDelegate {
RandomObject *invalidAppDelegate = [[RandomObject alloc] init];
[[GULAppDelegateSwizzler sharedApplication] setDelegate:(id<GULApplicationDelegate>)invalidAppDelegate];
[self.proxy swizzleMethodsIfPossible];
2017-05-15 12:27:07 -07:00
OCMReject([self.mockMessaging appDidReceiveMessage:[OCMArg any]]);
2019-05-28 11:36:31 -07:00
[invalidAppDelegate application:[GULAppDelegateSwizzler sharedApplication]
didReceiveRemoteNotification:@{}];
2017-05-15 12:27:07 -07:00
}
- (void)testSwizzledIncompleteAppDelegateRemoteNotificationMethod {
IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
2019-05-28 11:36:31 -07:00
[[GULAppDelegateSwizzler sharedApplication] setDelegate:incompleteAppDelegate];
[self.proxy swizzleMethodsIfPossible];
2018-12-17 10:50:20 -08:00
NSDictionary *notification = @{@"test" : @""};
OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
2019-05-28 11:36:31 -07:00
[incompleteAppDelegate application:[GULAppDelegateSwizzler sharedApplication]
didReceiveRemoteNotification:notification];
#pragma clang diagnostic pop
[self.mockMessaging verify];
2017-05-15 12:27:07 -07:00
}
- (void)testIncompleteAppDelegateRemoteNotificationWithFetchHandlerMethod {
IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
2019-05-28 11:36:31 -07:00
[[GULAppDelegateSwizzler sharedApplication] setDelegate:incompleteAppDelegate];
[self.proxy swizzleMethodsIfPossible];
#if TARGET_OS_IOS || TARGET_OS_TV
2017-05-15 12:27:07 -07:00
SEL remoteNotificationWithFetchHandler =
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
2017-05-15 12:27:07 -07:00
XCTAssertFalse([incompleteAppDelegate respondsToSelector:remoteNotificationWithFetchHandler]);
#endif
2017-05-15 12:27:07 -07:00
SEL remoteNotification = @selector(application:didReceiveRemoteNotification:);
XCTAssertTrue([incompleteAppDelegate respondsToSelector:remoteNotification]);
}
- (void)testSwizzledAppDelegateRemoteNotificationMethods {
FakeAppDelegate *appDelegate = [[FakeAppDelegate alloc] init];
2019-05-28 11:36:31 -07:00
[[GULAppDelegateSwizzler sharedApplication] setDelegate:appDelegate];
[self.proxy swizzleMethodsIfPossible];
NSDictionary *notification = @{@"test" : @""};
//Test application:didReceiveRemoteNotification:
2017-05-15 12:27:07 -07:00
// Verify our swizzled method was called
OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
2019-05-28 11:36:31 -07:00
[appDelegate application:[GULAppDelegateSwizzler sharedApplication]
didReceiveRemoteNotification:notification];
#pragma clang diagnostic pop
2017-05-15 12:27:07 -07:00
// Verify our original method was called
XCTAssertTrue(appDelegate.remoteNotificationMethodWasCalled);
[self.mockMessaging verify];
//Test application:didReceiveRemoteNotification:fetchCompletionHandler:
#if TARGET_OS_IOS || TARGET_OS_TV
2017-05-15 12:27:07 -07:00
// Verify our swizzled method was called
OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);
2019-05-28 11:36:31 -07:00
[appDelegate application:[GULAppDelegateSwizzler sharedApplication]
didReceiveRemoteNotification:notification
fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
2017-05-15 12:27:07 -07:00
// Verify our original method was called
XCTAssertTrue(appDelegate.remoteNotificationWithFetchHandlerWasCalled);
[self.mockMessaging verify];
#endif
// Verify application:didRegisterForRemoteNotificationsWithDeviceToken:
NSData *deviceToken = [NSData data];
OCMExpect([self.mockMessaging setAPNSToken:deviceToken]);
2019-05-28 11:36:31 -07:00
[appDelegate application:[GULAppDelegateSwizzler sharedApplication]
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
XCTAssertEqual(appDelegate.deviceToken, deviceToken);
[self.mockMessaging verify];
// Verify application:didFailToRegisterForRemoteNotificationsWithError:
NSError *error = [NSError errorWithDomain:@"tests" code:-1 userInfo:nil];
2019-05-28 11:36:31 -07:00
[appDelegate application:[GULAppDelegateSwizzler sharedApplication]
didFailToRegisterForRemoteNotificationsWithError:error];
XCTAssertEqual(appDelegate.registerForRemoteNotificationsError, error);
2017-05-15 12:27:07 -07:00
}
- (void)testListeningForDelegateChangesOnInvalidUserNotificationCenter {
if (@available(macOS 10.14, iOS 10.0, *)) {
2019-05-28 11:36:31 -07:00
RandomObject *invalidNotificationCenter = [[RandomObject alloc] init];
OCMStub([self.mockUserNotificationCenter currentNotificationCenter]).andReturn(invalidNotificationCenter);
[self.proxy swizzleMethodsIfPossible];
2019-05-28 11:36:31 -07:00
OCMReject([self.mockMessaging appDidReceiveMessage:[OCMArg any]]);
2019-05-28 11:36:31 -07:00
[(id<UNUserNotificationCenterDelegate>)invalidNotificationCenter.delegate
userNotificationCenter:self.mockUserNotificationCenter
willPresentNotification:OCMClassMock([UNNotification class])
withCompletionHandler:^(UNNotificationPresentationOptions options) {
}];
}
2017-05-15 12:27:07 -07:00
}
- (void)testSwizzlingInvalidUserNotificationCenterDelegate {
if (@available(macOS 10.14, iOS 10.0, *)) {
2019-05-28 11:36:31 -07:00
RandomObject *invalidDelegate = [[RandomObject alloc] init];
OCMStub([self.mockUserNotificationCenter delegate]).andReturn(invalidDelegate);
[self.proxy swizzleMethodsIfPossible];
2019-05-28 11:36:31 -07:00
OCMReject([self.mockMessaging appDidReceiveMessage:[OCMArg any]]);
2019-05-28 11:36:31 -07:00
[invalidDelegate
userNotificationCenter:self.mockUserNotificationCenter
willPresentNotification:OCMClassMock([UNNotification class])
withCompletionHandler:^(UNNotificationPresentationOptions options) {
}];
}
2017-05-15 12:27:07 -07:00
}
- (void)testSwizzlingUserNotificationsCenterDelegate {
#if TARGET_OS_IOS || TARGET_OS_OSX
if (@available(macOS 10.14, iOS 10.0, *)) {
2019-05-28 11:36:31 -07:00
FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc] init];
OCMStub([self.mockUserNotificationCenter delegate]).andReturn(delegate);
[self.proxy swizzleMethodsIfPossible];
2019-05-28 11:36:31 -07:00
NSDictionary *message = @{@"message": @""};
id notification = [self userNotificationWithMessage:message];
2019-05-28 11:36:31 -07:00
OCMExpect([self.mockMessaging appDidReceiveMessage:message]);
2019-05-28 11:36:31 -07:00
[delegate
userNotificationCenter:self.mockUserNotificationCenter
willPresentNotification:notification
withCompletionHandler:^(UNNotificationPresentationOptions options) {
}];
2019-05-28 11:36:31 -07:00
[self.mockMessaging verify];
}
#endif
2017-05-15 12:27:07 -07:00
}
// Use a fake delegate that doesn't actually implement the needed delegate method.
// Our swizzled method should not be called.
2017-05-15 12:27:07 -07:00
- (void)testIncompleteUserNotificationCenterDelegateMethod {
if (@available(macOS 10.14, iOS 10.0, *)) {
2019-05-28 11:36:31 -07:00
IncompleteUserNotificationCenterDelegate *delegate =
[[IncompleteUserNotificationCenterDelegate alloc] init];
OCMStub([self.mockUserNotificationCenter delegate]).andReturn(delegate);
[self.proxy swizzleMethodsIfPossible];
// Because the incomplete delete does not implement either of the optional delegate methods, we
// should swizzle nothing. If we had swizzled them, then respondsToSelector: would return YES
// even though the delegate does not implement the methods.
SEL willPresentSelector = @selector(userNotificationCenter:willPresentNotification:withCompletionHandler:);
XCTAssertFalse([delegate respondsToSelector:willPresentSelector]);
SEL didReceiveResponseSelector =
@selector(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:);
XCTAssertFalse([delegate respondsToSelector:didReceiveResponseSelector]);
2017-05-15 12:27:07 -07:00
}
}
// Use an object that does actually implement the optional methods. Both should be called.
2017-05-15 12:27:07 -07:00
- (void)testSwizzledUserNotificationsCenterDelegate {
#if TARGET_OS_IOS || TARGET_OS_OSX
2019-05-28 11:36:31 -07:00
FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc] init];
OCMStub([self.mockUserNotificationCenter delegate]).andReturn(delegate);
[self.proxy swizzleMethodsIfPossible];
2019-05-28 11:36:31 -07:00
NSDictionary *message = @{@"message": @""};
2019-05-28 11:36:31 -07:00
// Verify userNotificationCenter:willPresentNotification:withCompletionHandler:
OCMExpect([self.mockMessaging appDidReceiveMessage:message]);
if (@available(macOS 10.14, iOS 10.0, tvOS 10.0, *)) {
// Invoking delegate method should also invoke our swizzled method
// The swizzled method uses the +sharedProxy, which should be
// returning our proxy.
// Use non-nil, proper classes, otherwise our SDK bails out.
[delegate userNotificationCenter:self.mockUserNotificationCenter
2019-05-28 11:36:31 -07:00
willPresentNotification:[self userNotificationWithMessage:message]
withCompletionHandler:^(NSUInteger options) {}];
// Verify our original method was called
XCTAssertTrue(delegate.willPresentWasCalled);
// Verify our swizzled method was called
[self.mockMessaging verify];
}
if (@available(macOS 10.14, iOS 10.0, *)) {
// Verify userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
OCMExpect([self.mockMessaging appDidReceiveMessage:message]);
[delegate userNotificationCenter:self.mockUserNotificationCenter
didReceiveNotificationResponse:[self userNotificationResponseWithMessage:message]
withCompletionHandler:^{}];
// Verify our original method was called
XCTAssertTrue(delegate.didReceiveResponseWasCalled);
// Verify our swizzled method was called
[self.mockMessaging verify];
}
#endif
2017-05-15 12:27:07 -07:00
}
- (id)userNotificationResponseWithMessage:(NSDictionary *)message {
#if TARGET_OS_IOS || TARGET_OS_OSX
if (@available(macOS 10.14, iOS 10.0, *)) {
// Stub out: response.[mock notification above]
2019-05-28 11:36:31 -07:00
id mockNotificationResponse = OCMClassMock([UNNotificationResponse class]);
id mockNotification = [self userNotificationWithMessage:message];
OCMStub([mockNotificationResponse notification]).andReturn(mockNotification);
return mockNotificationResponse;
}
#endif
2019-05-28 11:36:31 -07:00
return nil;
}
- (UNNotification *)userNotificationWithMessage:(NSDictionary *)message API_AVAILABLE(macos(10.14), ios(10.0)){
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
#if TARGET_OS_IOS || TARGET_OS_OSX
content.userInfo = message;
#endif
id notificationRequest = OCMClassMock([UNNotificationRequest class]);
OCMStub([notificationRequest content]).andReturn(content);
id notification = OCMClassMock([UNNotification class]);
OCMStub([notification request]).andReturn(notificationRequest);
return notification;
}
2017-05-15 12:27:07 -07:00
@end