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

279 lines
11 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
@import UserNotifications;
#endif
@import XCTest;
#import <OCMock/OCMock.h>
#import "FIRMessaging.h"
#import "FIRMessagingRemoteNotificationsProxy.h"
#pragma mark - Expose Internal Methods for Testing
// Expose some internal properties and methods here, in order to test
@interface FIRMessagingRemoteNotificationsProxy ()
@property(readonly, nonatomic) BOOL didSwizzleMethods;
@property(readonly, nonatomic) BOOL didSwizzleAppDelegateMethods;
@property(readonly, nonatomic) BOOL hasSwizzledUserNotificationDelegate;
@property(readonly, nonatomic) BOOL isObservingUserNotificationDelegateChanges;
@property(strong, readonly, nonatomic) id userNotificationCenter;
@property(strong, readonly, nonatomic) id currentUserNotificationCenterDelegate;
+ (instancetype)sharedProxy;
- (BOOL)swizzleAppDelegateMethods:(id<UIApplicationDelegate>)appDelegate;
- (void)listenForDelegateChangesInUserNotificationCenter:(id)notificationCenter;
- (void)swizzleUserNotificationCenterDelegate:(id)delegate;
- (void)unswizzleUserNotificationCenterDelegate:(id)delegate;
void FCM_swizzle_appDidReceiveRemoteNotification(id self,
SEL _cmd,
UIApplication *app,
NSDictionary *userInfo);
void FCM_swizzle_appDidReceiveRemoteNotificationWithHandler(
id self, SEL _cmd, UIApplication *app, NSDictionary *userInfo,
void (^handler)(UIBackgroundFetchResult));
void FCM_swizzle_willPresentNotificationWithHandler(
id self, SEL _cmd, id center, id notification, void (^handler)(NSUInteger));
@end
#pragma mark - Incomplete App Delegate
@interface IncompleteAppDelegate : NSObject <UIApplicationDelegate>
@end
@implementation IncompleteAppDelegate
@end
#pragma mark - Fake AppDelegate
@interface FakeAppDelegate : NSObject <UIApplicationDelegate>
@property(nonatomic) BOOL remoteNotificationMethodWasCalled;
@property(nonatomic) BOOL remoteNotificationWithFetchHandlerWasCalled;
@end
@implementation FakeAppDelegate
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
self.remoteNotificationMethodWasCalled = YES;
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
self.remoteNotificationWithFetchHandlerWasCalled = YES;
}
@end
#pragma mark - Incompete UNUserNotificationCenterDelegate
@interface IncompleteUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate>
@end
@implementation IncompleteUserNotificationCenterDelegate
@end
#pragma mark - Fake UNUserNotificationCenterDelegate
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
@interface FakeUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate>
@property(nonatomic) BOOL willPresentWasCalled;
@end
@implementation FakeUserNotificationCenterDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))
completionHandler {
self.willPresentWasCalled = YES;
}
@end
#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#pragma mark - Local, Per-Test Properties
@interface FIRMessagingRemoteNotificationsProxyTest : XCTestCase
@property(nonatomic, strong) FIRMessagingRemoteNotificationsProxy *proxy;
@property(nonatomic, strong) id mockProxy;
@property(nonatomic, strong) id mockProxyClass;
@property(nonatomic, strong) id mockMessagingClass;
@end
@implementation FIRMessagingRemoteNotificationsProxyTest
- (void)setUp {
[super setUp];
_proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init];
_mockProxy = OCMPartialMock(_proxy);
_mockProxyClass = OCMClassMock([FIRMessagingRemoteNotificationsProxy class]);
// Update +sharedProxy to always return our partial mock of FIRMessagingRemoteNotificationsProxy
OCMStub([_mockProxyClass sharedProxy]).andReturn(_mockProxy);
// Many of our swizzled methods call [FIRMessaging messaging], but we don't need it,
// so just stub it to return nil
_mockMessagingClass = OCMClassMock([FIRMessaging class]);
OCMStub([_mockMessagingClass messaging]).andReturn(nil);
}
- (void)tearDown {
[_mockMessagingClass stopMocking];
_mockMessagingClass = nil;
[_mockProxyClass stopMocking];
_mockProxyClass = nil;
[_mockProxy stopMocking];
_mockProxy = nil;
_proxy = nil;
[super tearDown];
}
#pragma mark - Method Swizzling Tests
- (void)testSwizzlingNonAppDelegate {
id randomObject = @"Random Object that is not an App Delegate";
[self.proxy swizzleAppDelegateMethods:randomObject];
XCTAssertFalse(self.proxy.didSwizzleAppDelegateMethods);
}
- (void)testSwizzlingAppDelegate {
IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
[self.proxy swizzleAppDelegateMethods:incompleteAppDelegate];
XCTAssertTrue(self.proxy.didSwizzleAppDelegateMethods);
}
- (void)testSwizzledIncompleteAppDelegateRemoteNotificationMethod {
IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
[self.mockProxy swizzleAppDelegateMethods:incompleteAppDelegate];
SEL selector = @selector(application:didReceiveRemoteNotification:);
XCTAssertTrue([incompleteAppDelegate respondsToSelector:selector]);
[incompleteAppDelegate application:OCMClassMock([UIApplication class])
didReceiveRemoteNotification:@{}];
// Verify our swizzled method was called
OCMVerify(FCM_swizzle_appDidReceiveRemoteNotification);
}
// If the remote notification with fetch handler is NOT implemented, we will force-implement
// the backup -application:didReceiveRemoteNotification: method
- (void)testIncompleteAppDelegateRemoteNotificationWithFetchHandlerMethod {
IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
[self.mockProxy swizzleAppDelegateMethods:incompleteAppDelegate];
SEL remoteNotificationWithFetchHandler =
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
XCTAssertFalse([incompleteAppDelegate respondsToSelector:remoteNotificationWithFetchHandler]);
SEL remoteNotification = @selector(application:didReceiveRemoteNotification:);
XCTAssertTrue([incompleteAppDelegate respondsToSelector:remoteNotification]);
}
- (void)testSwizzledAppDelegateRemoteNotificationMethods {
FakeAppDelegate *appDelegate = [[FakeAppDelegate alloc] init];
[self.mockProxy swizzleAppDelegateMethods:appDelegate];
[appDelegate application:OCMClassMock([UIApplication class]) didReceiveRemoteNotification:@{}];
// Verify our swizzled method was called
OCMVerify(FCM_swizzle_appDidReceiveRemoteNotification);
// Verify our original method was called
XCTAssertTrue(appDelegate.remoteNotificationMethodWasCalled);
// Now call the remote notification with handler method
[appDelegate application:OCMClassMock([UIApplication class])
didReceiveRemoteNotification:@{}
fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
// Verify our swizzled method was called
OCMVerify(FCM_swizzle_appDidReceiveRemoteNotificationWithHandler);
// Verify our original method was called
XCTAssertTrue(appDelegate.remoteNotificationWithFetchHandlerWasCalled);
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
- (void)testListeningForDelegateChangesOnInvalidUserNotificationCenter {
id randomObject = @"Random Object that is not a User Notification Center";
[self.proxy listenForDelegateChangesInUserNotificationCenter:randomObject];
XCTAssertFalse(self.proxy.isObservingUserNotificationDelegateChanges);
}
- (void)testSwizzlingInvalidUserNotificationCenterDelegate {
id randomObject = @"Random Object that is not a User Notification Center Delegate";
[self.proxy swizzleUserNotificationCenterDelegate:randomObject];
XCTAssertFalse(self.proxy.hasSwizzledUserNotificationDelegate);
}
- (void)testSwizzlingUserNotificationsCenterDelegate {
FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc] init];
[self.proxy swizzleUserNotificationCenterDelegate:delegate];
XCTAssertTrue(self.proxy.hasSwizzledUserNotificationDelegate);
}
// Use a fake delegate that doesn't actually implement the needed delegate method.
// Our swizzled method should still be called.
- (void)testIncompleteUserNotificationCenterDelegateMethod {
// Early exit if running on pre iOS 10
if (![UNNotification class]) {
return;
}
IncompleteUserNotificationCenterDelegate *delegate =
[[IncompleteUserNotificationCenterDelegate alloc] init];
[self.mockProxy swizzleUserNotificationCenterDelegate:delegate];
SEL selector = @selector(userNotificationCenter:willPresentNotification:withCompletionHandler:);
XCTAssertTrue([delegate respondsToSelector:selector]);
// Invoking delegate method should also invoke our swizzled method
// The swizzled method uses the +sharedProxy, which should be
// returning our mocked proxy.
// Use non-nil, proper classes, otherwise our SDK bails out.
[delegate userNotificationCenter:OCMClassMock([UNUserNotificationCenter class])
willPresentNotification:[self generateMockNotification]
withCompletionHandler:^(NSUInteger options) {}];
// Verify our swizzled method was called
OCMVerify(FCM_swizzle_willPresentNotificationWithHandler);
}
// Use an object that does actually implement the needed method. Both should be called.
- (void)testSwizzledUserNotificationsCenterDelegate {
// Early exit if running on pre iOS 10
if (![UNNotification class]) {
return;
}
FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc] init];
[self.mockProxy swizzleUserNotificationCenterDelegate:delegate];
// Invoking delegate method should also invoke our swizzled method
// The swizzled method uses the +sharedProxy, which should be
// returning our mocked proxy.
// Use non-nil, proper classes, otherwise our SDK bails out.
[delegate userNotificationCenter:OCMClassMock([UNUserNotificationCenter class])
willPresentNotification:[self generateMockNotification]
withCompletionHandler:^(NSUInteger options) {}];
// Verify our swizzled method was called
OCMVerify(FCM_swizzle_willPresentNotificationWithHandler);
// Verify our original method was called
XCTAssertTrue(delegate.willPresentWasCalled);
}
- (id)generateMockNotification {
// Stub out: notification.request.content.userInfo
id mockNotification = OCMClassMock([UNNotification class]);
id mockRequest = OCMClassMock([UNNotificationRequest class]);
id mockContent = OCMClassMock([UNNotificationContent class]);
OCMStub([mockContent userInfo]).andReturn(@{});
OCMStub([mockRequest content]).andReturn(mockContent);
OCMStub([mockNotification request]).andReturn(mockRequest);
return mockNotification;
}
#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
@end