aboutsummaryrefslogtreecommitdiffhomepage
path: root/Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
committerGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
commit98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch)
tree131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m
parent32461366c9e204a527ca05e6e9b9404a2454ac51 (diff)
Initial
Diffstat (limited to 'Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m')
-rw-r--r--Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m279
1 files changed, 279 insertions, 0 deletions
diff --git a/Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m b/Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m
new file mode 100644
index 0000000..9138c50
--- /dev/null
+++ b/Example/Messaging/Tests/FIRMessagingRemoteNotificationsProxyTest.m
@@ -0,0 +1,279 @@
+/*
+ * 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