FIRMessagingRemoteNotificationsProxyTest.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  17. #import <UserNotifications/UserNotifications.h>
  18. #endif
  19. #import <XCTest/XCTest.h>
  20. #import <OCMock/OCMock.h>
  21. #import "FIRMessaging.h"
  22. #import "FIRMessagingRemoteNotificationsProxy.h"
  23. #import <GoogleUtilities/GULAppDelegateSwizzler.h>
  24. #pragma mark - Invalid App Delegate or UNNotificationCenter
  25. @interface RandomObject : NSObject
  26. @property(nonatomic, weak) id delegate;
  27. @end
  28. @implementation RandomObject
  29. - (void)application:(UIApplication *)application
  30. didReceiveRemoteNotification:(NSDictionary *)userInfo
  31. fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  32. }
  33. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  34. - (void)userNotificationCenter:(UNUserNotificationCenter *)center
  35. willPresentNotification:(UNNotification *)notification
  36. withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))
  37. completionHandler API_AVAILABLE(ios(10.0)){
  38. }
  39. #if TARGET_OS_IOS
  40. - (void)userNotificationCenter:(UNUserNotificationCenter *)center
  41. didReceiveNotificationResponse:(UNNotificationResponse *)response
  42. withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(ios(10.0)){
  43. }
  44. #endif // TARGET_OS_IOS
  45. #endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  46. @end
  47. #pragma mark - Incomplete App Delegate
  48. @interface IncompleteAppDelegate : NSObject <UIApplicationDelegate>
  49. @end
  50. @implementation IncompleteAppDelegate
  51. @end
  52. #pragma mark - Fake AppDelegate
  53. @interface FakeAppDelegate : NSObject <UIApplicationDelegate>
  54. @property(nonatomic) BOOL remoteNotificationMethodWasCalled;
  55. @property(nonatomic) BOOL remoteNotificationWithFetchHandlerWasCalled;
  56. @property(nonatomic, strong) NSData *deviceToken;
  57. @property(nonatomic, strong) NSError *registerForRemoteNotificationsError;
  58. @end
  59. @implementation FakeAppDelegate
  60. #if TARGET_OS_IOS
  61. - (void)application:(UIApplication *)application
  62. didReceiveRemoteNotification:(NSDictionary *)userInfo {
  63. self.remoteNotificationMethodWasCalled = YES;
  64. }
  65. #endif
  66. - (void)application:(UIApplication *)application
  67. didReceiveRemoteNotification:(NSDictionary *)userInfo
  68. fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  69. self.remoteNotificationWithFetchHandlerWasCalled = YES;
  70. }
  71. - (void)application:(UIApplication *)application
  72. didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  73. self.deviceToken = deviceToken;
  74. }
  75. - (void)application:(UIApplication *)application
  76. didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  77. self.registerForRemoteNotificationsError = error;
  78. }
  79. @end
  80. #pragma mark - Incompete UNUserNotificationCenterDelegate
  81. @interface IncompleteUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate>
  82. @end
  83. @implementation IncompleteUserNotificationCenterDelegate
  84. @end
  85. #pragma mark - Fake UNUserNotificationCenterDelegate
  86. #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  87. @interface FakeUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate>
  88. @property(nonatomic) BOOL willPresentWasCalled;
  89. @property(nonatomic) BOOL didReceiveResponseWasCalled;
  90. @end
  91. @implementation FakeUserNotificationCenterDelegate
  92. - (void)userNotificationCenter:(UNUserNotificationCenter *)center
  93. willPresentNotification:(UNNotification *)notification
  94. withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))
  95. completionHandler API_AVAILABLE(ios(10.0)){
  96. self.willPresentWasCalled = YES;
  97. }
  98. #if TARGET_OS_IOS
  99. - (void)userNotificationCenter:(UNUserNotificationCenter *)center
  100. didReceiveNotificationResponse:(UNNotificationResponse *)response
  101. withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0)){
  102. self.didReceiveResponseWasCalled = YES;
  103. }
  104. #endif // TARGET_OS_IOS
  105. @end
  106. #endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
  107. @interface GULAppDelegateSwizzler (FIRMessagingRemoteNotificationsProxyTest)
  108. + (void)resetProxyOriginalDelegateOnceToken;
  109. @end
  110. #pragma mark - Local, Per-Test Properties
  111. @interface FIRMessagingRemoteNotificationsProxyTest : XCTestCase
  112. @property(nonatomic, strong) FIRMessagingRemoteNotificationsProxy *proxy;
  113. @property(nonatomic, strong) id mockProxyClass;
  114. @property(nonatomic, strong) id mockMessaging;
  115. @property(nonatomic, strong) id mockUserNotificationCenter;
  116. @end
  117. @implementation FIRMessagingRemoteNotificationsProxyTest
  118. - (void)setUp {
  119. [super setUp];
  120. [GULAppDelegateSwizzler resetProxyOriginalDelegateOnceToken];
  121. _mockMessaging = OCMClassMock([FIRMessaging class]);
  122. OCMStub([_mockMessaging messaging]).andReturn(_mockMessaging);
  123. _proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init];
  124. _mockProxyClass = OCMClassMock([FIRMessagingRemoteNotificationsProxy class]);
  125. // Update +sharedProxy to always return our test instance
  126. OCMStub([_mockProxyClass sharedProxy]).andReturn(self.proxy);
  127. if (@available(iOS 10.0, *)) {
  128. _mockUserNotificationCenter = OCMPartialMock([UNUserNotificationCenter currentNotificationCenter]);
  129. }
  130. }
  131. - (void)tearDown {
  132. [_mockProxyClass stopMocking];
  133. _mockProxyClass = nil;
  134. [_mockMessaging stopMocking];
  135. _mockMessaging = nil;
  136. if (@available(iOS 10.0, *)) {
  137. [_mockUserNotificationCenter stopMocking];
  138. _mockUserNotificationCenter = nil;
  139. }
  140. _proxy = nil;
  141. [super tearDown];
  142. }
  143. #pragma mark - Method Swizzling Tests
  144. - (void)testSwizzlingNonAppDelegate {
  145. RandomObject *invalidAppDelegate = [[RandomObject alloc] init];
  146. [[GULAppDelegateSwizzler sharedApplication] setDelegate:(id<UIApplicationDelegate>)invalidAppDelegate];
  147. [self.proxy swizzleMethodsIfPossible];
  148. OCMReject([self.mockMessaging appDidReceiveMessage:[OCMArg any]]);
  149. [invalidAppDelegate application:[GULAppDelegateSwizzler sharedApplication]
  150. didReceiveRemoteNotification:@{}
  151. fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
  152. }
  153. - (void)testSwizzledIncompleteAppDelegateRemoteNotificationMethod {
  154. #if TARGET_OS_IOS
  155. IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
  156. [[GULAppDelegateSwizzler sharedApplication] setDelegate:incompleteAppDelegate];
  157. [self.proxy swizzleMethodsIfPossible];
  158. NSDictionary *notification = @{@"test" : @""};
  159. OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);
  160. [incompleteAppDelegate application:[GULAppDelegateSwizzler sharedApplication]
  161. didReceiveRemoteNotification:notification];
  162. [self.mockMessaging verify];
  163. #endif // TARGET_OS_IOS
  164. }
  165. - (void)testIncompleteAppDelegateRemoteNotificationWithFetchHandlerMethod {
  166. IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc] init];
  167. [[GULAppDelegateSwizzler sharedApplication] setDelegate:incompleteAppDelegate];
  168. [self.proxy swizzleMethodsIfPossible];
  169. SEL remoteNotificationWithFetchHandler =
  170. @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
  171. XCTAssertFalse([incompleteAppDelegate respondsToSelector:remoteNotificationWithFetchHandler]);
  172. #if TARGET_OS_IOS
  173. SEL remoteNotification = @selector(application:didReceiveRemoteNotification:);
  174. XCTAssertTrue([incompleteAppDelegate respondsToSelector:remoteNotification]);
  175. #endif // TARGET_OS_IOS
  176. }
  177. - (void)testSwizzledAppDelegateRemoteNotificationMethods {
  178. #if TARGET_OS_IOS
  179. FakeAppDelegate *appDelegate = [[FakeAppDelegate alloc] init];
  180. [[GULAppDelegateSwizzler sharedApplication] setDelegate:appDelegate];
  181. [self.proxy swizzleMethodsIfPossible];
  182. NSDictionary *notification = @{@"test" : @""};
  183. //Test application:didReceiveRemoteNotification:
  184. // Verify our swizzled method was called
  185. OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);
  186. // Call the method
  187. [appDelegate application:[GULAppDelegateSwizzler sharedApplication]
  188. didReceiveRemoteNotification:notification];
  189. // Verify our original method was called
  190. XCTAssertTrue(appDelegate.remoteNotificationMethodWasCalled);
  191. [self.mockMessaging verify];
  192. //Test application:didReceiveRemoteNotification:fetchCompletionHandler:
  193. // Verify our swizzled method was called
  194. OCMExpect([self.mockMessaging appDidReceiveMessage:notification]);
  195. [appDelegate application:[GULAppDelegateSwizzler sharedApplication]
  196. didReceiveRemoteNotification:notification
  197. fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
  198. // Verify our original method was called
  199. XCTAssertTrue(appDelegate.remoteNotificationWithFetchHandlerWasCalled);
  200. [self.mockMessaging verify];
  201. // Verify application:didRegisterForRemoteNotificationsWithDeviceToken:
  202. NSData *deviceToken = [NSData data];
  203. OCMExpect([self.mockMessaging setAPNSToken:deviceToken]);
  204. [appDelegate application:[GULAppDelegateSwizzler sharedApplication]
  205. didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
  206. XCTAssertEqual(appDelegate.deviceToken, deviceToken);
  207. [self.mockMessaging verify];
  208. // Verify application:didFailToRegisterForRemoteNotificationsWithError:
  209. NSError *error = [NSError errorWithDomain:@"tests" code:-1 userInfo:nil];
  210. [appDelegate application:[GULAppDelegateSwizzler sharedApplication]
  211. didFailToRegisterForRemoteNotificationsWithError:error];
  212. XCTAssertEqual(appDelegate.registerForRemoteNotificationsError, error);
  213. #endif
  214. }
  215. - (void)testListeningForDelegateChangesOnInvalidUserNotificationCenter {
  216. if (@available(iOS 10.0, *)) {
  217. RandomObject *invalidNotificationCenter = [[RandomObject alloc] init];
  218. OCMStub([self.mockUserNotificationCenter currentNotificationCenter]).andReturn(invalidNotificationCenter);
  219. [self.proxy swizzleMethodsIfPossible];
  220. OCMReject([self.mockMessaging appDidReceiveMessage:[OCMArg any]]);
  221. [(id<UNUserNotificationCenterDelegate>)invalidNotificationCenter.delegate
  222. userNotificationCenter:self.mockUserNotificationCenter
  223. willPresentNotification:OCMClassMock([UNNotification class])
  224. withCompletionHandler:^(UNNotificationPresentationOptions options) {
  225. }];
  226. }
  227. }
  228. - (void)testSwizzlingInvalidUserNotificationCenterDelegate {
  229. if (@available(iOS 10.0, *)) {
  230. RandomObject *invalidDelegate = [[RandomObject alloc] init];
  231. OCMStub([self.mockUserNotificationCenter delegate]).andReturn(invalidDelegate);
  232. [self.proxy swizzleMethodsIfPossible];
  233. OCMReject([self.mockMessaging appDidReceiveMessage:[OCMArg any]]);
  234. [invalidDelegate
  235. userNotificationCenter:self.mockUserNotificationCenter
  236. willPresentNotification:OCMClassMock([UNNotification class])
  237. withCompletionHandler:^(UNNotificationPresentationOptions options) {
  238. }];
  239. }
  240. }
  241. - (void)testSwizzlingUserNotificationsCenterDelegate {
  242. if (@available(iOS 10.0, *)) {
  243. FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc] init];
  244. OCMStub([self.mockUserNotificationCenter delegate]).andReturn(delegate);
  245. [self.proxy swizzleMethodsIfPossible];
  246. NSDictionary *message = @{@"message": @""};
  247. id notification = [self userNotificationWithMessage:message];
  248. OCMExpect([self.mockMessaging appDidReceiveMessage:message]);
  249. [delegate
  250. userNotificationCenter:self.mockUserNotificationCenter
  251. willPresentNotification:notification
  252. withCompletionHandler:^(UNNotificationPresentationOptions options) {
  253. }];
  254. [self.mockMessaging verify];
  255. }
  256. }
  257. // Use a fake delegate that doesn't actually implement the needed delegate method.
  258. // Our swizzled method should not be called.
  259. - (void)testIncompleteUserNotificationCenterDelegateMethod {
  260. if (@available(iOS 10.0, *)) {
  261. IncompleteUserNotificationCenterDelegate *delegate =
  262. [[IncompleteUserNotificationCenterDelegate alloc] init];
  263. OCMStub([self.mockUserNotificationCenter delegate]).andReturn(delegate);
  264. [self.proxy swizzleMethodsIfPossible];
  265. // Because the incomplete delete does not implement either of the optional delegate methods, we
  266. // should swizzle nothing. If we had swizzled them, then respondsToSelector: would return YES
  267. // even though the delegate does not implement the methods.
  268. SEL willPresentSelector = @selector(userNotificationCenter:willPresentNotification:withCompletionHandler:);
  269. XCTAssertFalse([delegate respondsToSelector:willPresentSelector]);
  270. SEL didReceiveResponseSelector =
  271. @selector(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:);
  272. XCTAssertFalse([delegate respondsToSelector:didReceiveResponseSelector]);
  273. }
  274. }
  275. // Use an object that does actually implement the optional methods. Both should be called.
  276. - (void)testSwizzledUserNotificationsCenterDelegate {
  277. if (@available(iOS 10.0, *)) {
  278. FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc] init];
  279. OCMStub([self.mockUserNotificationCenter delegate]).andReturn(delegate);
  280. [self.proxy swizzleMethodsIfPossible];
  281. NSDictionary *message = @{@"message": @""};
  282. // Verify userNotificationCenter:willPresentNotification:withCompletionHandler:
  283. OCMExpect([self.mockMessaging appDidReceiveMessage:message]);
  284. // Invoking delegate method should also invoke our swizzled method
  285. // The swizzled method uses the +sharedProxy, which should be
  286. // returning our proxy.
  287. // Use non-nil, proper classes, otherwise our SDK bails out.
  288. [delegate userNotificationCenter:self.mockUserNotificationCenter
  289. willPresentNotification:[self userNotificationWithMessage:message]
  290. withCompletionHandler:^(NSUInteger options) {}];
  291. // Verify our original method was called
  292. XCTAssertTrue(delegate.willPresentWasCalled);
  293. // Verify our swizzled method was called
  294. [self.mockMessaging verify];
  295. #if TARGET_OS_IOS
  296. // Verify userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
  297. OCMExpect([self.mockMessaging appDidReceiveMessage:message]);
  298. [delegate userNotificationCenter:self.mockUserNotificationCenter
  299. didReceiveNotificationResponse:[self userNotificationResponseWithMessage:message]
  300. withCompletionHandler:^{}];
  301. // Verify our original method was called
  302. XCTAssertTrue(delegate.didReceiveResponseWasCalled);
  303. // Verify our swizzled method was called
  304. [self.mockMessaging verify];
  305. #endif // TARGET_OS_IOS
  306. }
  307. }
  308. - (id)userNotificationResponseWithMessage:(NSDictionary *)message {
  309. if (@available(iOS 10.0, *)) {
  310. // Stub out: response.[mock notification above]
  311. #if TARGET_OS_IOS
  312. id mockNotificationResponse = OCMClassMock([UNNotificationResponse class]);
  313. id mockNotification = [self userNotificationWithMessage:message];
  314. OCMStub([mockNotificationResponse notification]).andReturn(mockNotification);
  315. return mockNotificationResponse;
  316. #endif // TARGET_OS_IOS
  317. }
  318. return nil;
  319. }
  320. - (UNNotification *)userNotificationWithMessage:(NSDictionary *)message API_AVAILABLE(ios(10.0)){
  321. UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
  322. content.userInfo = message;
  323. id notificationRequest = OCMClassMock([UNNotificationRequest class]);
  324. OCMStub([notificationRequest content]).andReturn(content);
  325. id notification = OCMClassMock([UNNotification class]);
  326. OCMStub([notification request]).andReturn(notificationRequest);
  327. return notification;
  328. }
  329. @end