24
24
#import " FIRMessaging.h"
25
25
#import " FIRMessagingRemoteNotificationsProxy.h"
26
26
27
- #pragma mark - Expose Internal Methods for Testing
28
- // Expose some internal properties and methods here, in order to test
29
- @interface FIRMessagingRemoteNotificationsProxy ()
30
-
31
- @property (readonly , nonatomic ) BOOL didSwizzleMethods;
32
- @property (readonly , nonatomic ) BOOL didSwizzleAppDelegateMethods;
33
-
34
- @property (readonly , nonatomic ) BOOL hasSwizzledUserNotificationDelegate;
35
- @property (readonly , nonatomic ) BOOL isObservingUserNotificationDelegateChanges;
36
-
37
- @property (strong , readonly , nonatomic ) id userNotificationCenter;
38
- @property (strong , readonly , nonatomic ) id currentUserNotificationCenterDelegate;
39
-
40
- + (instancetype )sharedProxy ;
41
-
42
- - (BOOL )swizzleAppDelegateMethods : (id <UIApplicationDelegate>)appDelegate ;
43
- - (void )listenForDelegateChangesInUserNotificationCenter : (id )notificationCenter ;
44
- - (void )swizzleUserNotificationCenterDelegate : (id )delegate ;
45
- - (void )unswizzleUserNotificationCenterDelegate : (id )delegate ;
46
-
47
- void FCM_swizzle_appDidReceiveRemoteNotification (id self,
48
- SEL _cmd,
49
- UIApplication *app,
50
- NSDictionary *userInfo);
51
- void FCM_swizzle_appDidReceiveRemoteNotificationWithHandler (
52
- id self, SEL _cmd, UIApplication *app, NSDictionary *userInfo,
53
- void (^handler)(UIBackgroundFetchResult));
54
- void FCM_swizzle_willPresentNotificationWithHandler (
55
- id self, SEL _cmd, id center, id notification, void (^handler)(NSUInteger ));
56
- void FCM_swizzle_didReceiveNotificationResponseWithHandler (
57
- id self, SEL _cmd, id center, id response, void (^handler)());
27
+ #pragma mark - Invalid App Delegate or UNNotificationCenter
58
28
29
+ @interface RandomObject : NSObject
30
+ @property (nonatomic , weak ) id delegate;
31
+ @end
32
+ @implementation RandomObject
33
+ - (void )application : (UIApplication *)application
34
+ didReceiveRemoteNotification : (NSDictionary *)userInfo
35
+ fetchCompletionHandler : (void (^)(UIBackgroundFetchResult))completionHandler {
36
+ }
37
+
38
+ #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
39
+ - (void )userNotificationCenter : (UNUserNotificationCenter *)center
40
+ willPresentNotification : (UNNotification *)notification
41
+ withCompletionHandler : (void (^)(UNNotificationPresentationOptions options))
42
+ completionHandler {
43
+ }
44
+
45
+ #if TARGET_OS_IOS
46
+ - (void )userNotificationCenter:(UNUserNotificationCenter *)center
47
+ didReceiveNotificationResponse:(UNNotificationResponse *)response
48
+ withCompletionHandler:(void (^)(void ))completionHandler {
49
+ }
50
+ #endif // TARGET_OS_IOS
51
+
52
+ #endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
59
53
@end
60
54
61
55
#pragma mark - Incomplete App Delegate
@@ -104,7 +98,9 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
104
98
self.willPresentWasCalled = YES ;
105
99
}
106
100
#if TARGET_OS_IOS
107
- - (void )userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void ))completionHandler {
101
+ - (void )userNotificationCenter:(UNUserNotificationCenter *)center
102
+ didReceiveNotificationResponse:(UNNotificationResponse *)response
103
+ withCompletionHandler:(void (^)(void ))completionHandler {
108
104
self.didReceiveResponseWasCalled = YES ;
109
105
}
110
106
#endif // TARGET_OS_IOS
@@ -116,36 +112,42 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNoti
116
112
@interface FIRMessagingRemoteNotificationsProxyTest : XCTestCase
117
113
118
114
@property (nonatomic , strong ) FIRMessagingRemoteNotificationsProxy *proxy;
119
- @property (nonatomic , strong ) id mockProxy;
120
115
@property (nonatomic , strong ) id mockProxyClass;
121
- @property (nonatomic , strong ) id mockMessagingClass;
116
+ @property (nonatomic , strong ) id mockSharedApplication;
117
+ @property (nonatomic , strong ) id mockMessaging;
118
+ @property (nonatomic , strong ) id mockUserNotificationCenter;
122
119
123
120
@end
124
121
125
122
@implementation FIRMessagingRemoteNotificationsProxyTest
126
123
127
124
- (void )setUp {
128
125
[super setUp ];
126
+ _mockSharedApplication = OCMPartialMock ([UIApplication sharedApplication ]);
127
+
128
+ _mockMessaging = OCMClassMock ([FIRMessaging class ]);
129
+ OCMStub ([_mockMessaging messaging ]).andReturn (_mockMessaging);
130
+
129
131
_proxy = [[FIRMessagingRemoteNotificationsProxy alloc ] init ];
130
- _mockProxy = OCMPartialMock (_proxy);
131
132
_mockProxyClass = OCMClassMock ([FIRMessagingRemoteNotificationsProxy class ]);
132
- // Update +sharedProxy to always return our partial mock of FIRMessagingRemoteNotificationsProxy
133
- OCMStub ([_mockProxyClass sharedProxy ]).andReturn (_mockProxy);
134
- // Many of our swizzled methods call [FIRMessaging messaging], but we don't need it,
135
- // so just stub it to return nil
136
- _mockMessagingClass = OCMClassMock ([FIRMessaging class ]);
137
- OCMStub ([_mockMessagingClass messaging ]).andReturn (nil );
133
+ // Update +sharedProxy to always return our test instance
134
+ OCMStub ([_mockProxyClass sharedProxy ]).andReturn (self.proxy );
135
+
136
+ #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
137
+ _mockUserNotificationCenter = OCMClassMock ([UNUserNotificationCenter class ]);
138
+ OCMStub ([_mockUserNotificationCenter currentNotificationCenter ]).andReturn (_mockUserNotificationCenter);
139
+ #endif
138
140
}
139
141
140
142
- (void )tearDown {
141
- [_mockMessagingClass stopMocking ];
142
- _mockMessagingClass = nil ;
143
-
144
143
[_mockProxyClass stopMocking ];
145
144
_mockProxyClass = nil ;
146
145
147
- [_mockProxy stopMocking ];
148
- _mockProxy = nil ;
146
+ [_mockMessaging stopMocking ];
147
+ _mockMessaging = nil ;
148
+
149
+ [_mockSharedApplication stopMocking ];
150
+ _mockSharedApplication = nil ;
149
151
150
152
_proxy = nil ;
151
153
[super tearDown ];
@@ -154,30 +156,36 @@ - (void)tearDown {
154
156
#pragma mark - Method Swizzling Tests
155
157
156
158
- (void )testSwizzlingNonAppDelegate {
157
- id randomObject = @" Random Object that is not an App Delegate" ;
158
- [self .proxy swizzleAppDelegateMethods: randomObject];
159
- XCTAssertFalse (self.proxy .didSwizzleAppDelegateMethods );
160
- }
159
+ RandomObject *invalidAppDelegate = [[RandomObject alloc ] init ];
160
+ [OCMStub ([self .mockSharedApplication delegate ]) andReturn: invalidAppDelegate];
161
+ [self .proxy swizzleMethodsIfPossible ];
161
162
162
- - (void )testSwizzlingAppDelegate {
163
- IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc ] init ];
164
- [self .proxy swizzleAppDelegateMethods: incompleteAppDelegate];
165
- XCTAssertTrue (self.proxy .didSwizzleAppDelegateMethods );
163
+ OCMReject ([self .mockMessaging appDidReceiveMessage: [OCMArg any ]]);
164
+
165
+ [invalidAppDelegate application: self .mockSharedApplication
166
+ didReceiveRemoteNotification: @{}
167
+ fetchCompletionHandler: ^(UIBackgroundFetchResult result) {}];
166
168
}
167
169
168
170
- (void )testSwizzledIncompleteAppDelegateRemoteNotificationMethod {
169
- IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc ] init ];
170
- [self .mockProxy swizzleAppDelegateMethods: incompleteAppDelegate];
171
+ IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc ] init ];
172
+ [OCMStub ([self .mockSharedApplication delegate ]) andReturn: incompleteAppDelegate];
173
+ [self .proxy swizzleMethodsIfPossible ];
174
+
175
+ NSDictionary *notification = @{@" test" : @" " };
176
+ OCMExpect ([self .mockMessaging appDidReceiveMessage: notification]);
171
177
172
- [incompleteAppDelegate application: OCMClassMock ([UIApplication class ])
173
- didReceiveRemoteNotification: @{} ];
174
- // Verify our swizzled method was called
175
- OCMVerify (FCM_swizzle_appDidReceiveRemoteNotification) ;
178
+ [incompleteAppDelegate application: self .mockSharedApplication
179
+ didReceiveRemoteNotification: notification ];
180
+
181
+ [ self .mockMessaging verify ] ;
176
182
}
177
183
178
184
- (void )testIncompleteAppDelegateRemoteNotificationWithFetchHandlerMethod {
179
185
IncompleteAppDelegate *incompleteAppDelegate = [[IncompleteAppDelegate alloc ] init ];
180
- [self .mockProxy swizzleAppDelegateMethods: incompleteAppDelegate];
186
+ [OCMStub ([self .mockSharedApplication delegate ]) andReturn: incompleteAppDelegate];
187
+ [self .proxy swizzleMethodsIfPossible ];
188
+
181
189
SEL remoteNotificationWithFetchHandler =
182
190
@selector (application:didReceiveRemoteNotification:fetchCompletionHandler: );
183
191
XCTAssertFalse ([incompleteAppDelegate respondsToSelector: remoteNotificationWithFetchHandler]);
@@ -188,43 +196,87 @@ - (void)testIncompleteAppDelegateRemoteNotificationWithFetchHandlerMethod {
188
196
- (void )testSwizzledAppDelegateRemoteNotificationMethods {
189
197
#if TARGET_OS_IOS
190
198
FakeAppDelegate *appDelegate = [[FakeAppDelegate alloc ] init ];
191
- [self .mockProxy swizzleAppDelegateMethods: appDelegate];
192
- [appDelegate application: OCMClassMock ([UIApplication class ]) didReceiveRemoteNotification: @{}];
199
+ [OCMStub ([self .mockSharedApplication delegate ]) andReturn: appDelegate];
200
+ [self .proxy swizzleMethodsIfPossible ];
201
+
202
+ NSDictionary *notification = @{@" test" : @" " };
203
+
204
+ // Test application:didReceiveRemoteNotification:
205
+
193
206
// Verify our swizzled method was called
194
- OCMVerify (FCM_swizzle_appDidReceiveRemoteNotification);
207
+ OCMExpect ([self .mockMessaging appDidReceiveMessage: notification]);
208
+
209
+ // Call the method
210
+ [appDelegate application: self .mockSharedApplication
211
+ didReceiveRemoteNotification: notification];
212
+
195
213
// Verify our original method was called
196
214
XCTAssertTrue (appDelegate.remoteNotificationMethodWasCalled );
215
+ [self .mockMessaging verify ];
216
+
217
+ // Test application:didReceiveRemoteNotification:fetchCompletionHandler:
218
+
219
+ // Verify our swizzled method was called
220
+ OCMExpect ([self .mockMessaging appDidReceiveMessage: notification]);
197
221
198
- // Now call the remote notification with handler method
199
222
[appDelegate application: OCMClassMock ([UIApplication class ])
200
- didReceiveRemoteNotification: @{}
223
+ didReceiveRemoteNotification: notification
201
224
fetchCompletionHandler: ^(UIBackgroundFetchResult result) {}];
202
- // Verify our swizzled method was called
203
- OCMVerify (FCM_swizzle_appDidReceiveRemoteNotificationWithHandler);
225
+
204
226
// Verify our original method was called
205
227
XCTAssertTrue (appDelegate.remoteNotificationWithFetchHandlerWasCalled );
206
- #endif
207
228
229
+ [self .mockMessaging verify ];
230
+ #endif
208
231
}
209
232
210
233
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
211
234
212
235
- (void )testListeningForDelegateChangesOnInvalidUserNotificationCenter {
213
- id randomObject = @" Random Object that is not a User Notification Center" ;
214
- [self .proxy listenForDelegateChangesInUserNotificationCenter: randomObject];
215
- XCTAssertFalse (self.proxy .isObservingUserNotificationDelegateChanges );
236
+ RandomObject *invalidNotificationCenter = [[RandomObject alloc ] init ];
237
+ OCMStub ([self .mockUserNotificationCenter currentNotificationCenter ]).andReturn (invalidNotificationCenter);
238
+ [self .proxy swizzleMethodsIfPossible ];
239
+
240
+ OCMReject ([self .mockMessaging appDidReceiveMessage: [OCMArg any ]]);
241
+
242
+ [(id <UNUserNotificationCenterDelegate >)invalidNotificationCenter.delegate
243
+ userNotificationCenter: self .mockUserNotificationCenter
244
+ willPresentNotification: OCMClassMock ([UNNotification class ])
245
+ withCompletionHandler: ^(UNNotificationPresentationOptions options) {
246
+ }];
216
247
}
217
248
218
249
- (void )testSwizzlingInvalidUserNotificationCenterDelegate {
219
- id randomObject = @" Random Object that is not a User Notification Center Delegate" ;
220
- [self .proxy swizzleUserNotificationCenterDelegate: randomObject];
221
- XCTAssertFalse (self.proxy .hasSwizzledUserNotificationDelegate );
250
+ RandomObject *invalidDelegate = [[RandomObject alloc ] init ];
251
+ OCMStub ([self .mockUserNotificationCenter delegate ]).andReturn (invalidDelegate);
252
+ [self .proxy swizzleMethodsIfPossible ];
253
+
254
+ OCMReject ([self .mockMessaging appDidReceiveMessage: [OCMArg any ]]);
255
+
256
+ [invalidDelegate
257
+ userNotificationCenter: self .mockUserNotificationCenter
258
+ willPresentNotification: OCMClassMock ([UNNotification class ])
259
+ withCompletionHandler: ^(UNNotificationPresentationOptions options) {
260
+ }];
222
261
}
223
262
224
263
- (void )testSwizzlingUserNotificationsCenterDelegate {
225
264
FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc ] init ];
226
- [self .proxy swizzleUserNotificationCenterDelegate: delegate];
227
- XCTAssertTrue (self.proxy .hasSwizzledUserNotificationDelegate );
265
+ OCMStub ([self .mockUserNotificationCenter delegate ]).andReturn (delegate);
266
+ [self .proxy swizzleMethodsIfPossible ];
267
+
268
+ NSDictionary *message = @{@" message" : @" " };
269
+ id notification = [self userNotificationWithMessage: message];
270
+
271
+ OCMExpect ([self .mockMessaging appDidReceiveMessage: message]);
272
+
273
+ [delegate
274
+ userNotificationCenter: self .mockUserNotificationCenter
275
+ willPresentNotification: notification
276
+ withCompletionHandler: ^(UNNotificationPresentationOptions options) {
277
+ }];
278
+
279
+ [self .mockMessaging verify ];
228
280
}
229
281
230
282
// Use a fake delegate that doesn't actually implement the needed delegate method.
@@ -237,7 +289,8 @@ - (void)testIncompleteUserNotificationCenterDelegateMethod {
237
289
}
238
290
IncompleteUserNotificationCenterDelegate *delegate =
239
291
[[IncompleteUserNotificationCenterDelegate alloc ] init ];
240
- [self .mockProxy swizzleUserNotificationCenterDelegate: delegate];
292
+ OCMStub ([self .mockUserNotificationCenter delegate ]).andReturn (delegate);
293
+ [self .proxy swizzleMethodsIfPossible ];
241
294
// Because the incomplete delete does not implement either of the optional delegate methods, we
242
295
// should swizzle nothing. If we had swizzled them, then respondsToSelector: would return YES
243
296
// even though the delegate does not implement the methods.
@@ -250,55 +303,67 @@ - (void)testIncompleteUserNotificationCenterDelegateMethod {
250
303
251
304
// Use an object that does actually implement the optional methods. Both should be called.
252
305
- (void )testSwizzledUserNotificationsCenterDelegate {
253
- // Early exit if running on pre iOS 10
254
- if (![UNNotification class ]) {
255
- return ;
256
- }
257
306
FakeUserNotificationCenterDelegate *delegate = [[FakeUserNotificationCenterDelegate alloc ] init ];
258
- [self .mockProxy swizzleUserNotificationCenterDelegate: delegate];
307
+ OCMStub ([self .mockUserNotificationCenter delegate ]).andReturn (delegate);
308
+ [self .proxy swizzleMethodsIfPossible ];
309
+
310
+ NSDictionary *message = @{@" message" : @" " };
311
+
312
+ // Verify userNotificationCenter:willPresentNotification:withCompletionHandler:
313
+ OCMExpect ([self .mockMessaging appDidReceiveMessage: message]);
314
+
259
315
// Invoking delegate method should also invoke our swizzled method
260
316
// The swizzled method uses the +sharedProxy, which should be
261
- // returning our mocked proxy.
317
+ // returning our proxy.
262
318
// Use non-nil, proper classes, otherwise our SDK bails out.
263
- [delegate userNotificationCenter: OCMClassMock ([ UNUserNotificationCenter class ])
264
- willPresentNotification: [self generateMockNotification ]
319
+ [delegate userNotificationCenter: self .mockUserNotificationCenter
320
+ willPresentNotification: [self userNotificationWithMessage: message ]
265
321
withCompletionHandler: ^(NSUInteger options) {}];
266
- // Verify our swizzled method was called
267
- OCMVerify (FCM_swizzle_willPresentNotificationWithHandler);
322
+
268
323
// Verify our original method was called
269
324
XCTAssertTrue (delegate.willPresentWasCalled );
325
+
326
+ // Verify our swizzled method was called
327
+ [self .mockMessaging verify ];
328
+
270
329
#if TARGET_OS_IOS
271
- [delegate userNotificationCenter: OCMClassMock ([UNUserNotificationCenter class ])
272
- didReceiveNotificationResponse: [self generateMockNotificationResponse ]
330
+ // Verify userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
331
+
332
+ OCMExpect ([self .mockMessaging appDidReceiveMessage: message]);
333
+
334
+ [delegate userNotificationCenter: self .mockUserNotificationCenter
335
+ didReceiveNotificationResponse: [self userNotificationResponseWithMessage: message]
273
336
withCompletionHandler: ^{}];
274
- // Verify our swizzled method was called
275
- OCMVerify (FCM_swizzle_appDidReceiveRemoteNotificationWithHandler);
337
+
276
338
// Verify our original method was called
277
339
XCTAssertTrue (delegate.didReceiveResponseWasCalled );
278
- #endif
279
- }
280
340
281
- - (id )generateMockNotification {
282
- // Stub out: notification.request.content.userInfo
283
- id mockNotification = OCMClassMock ([UNNotification class ]);
284
- id mockRequest = OCMClassMock ([UNNotificationRequest class ]);
285
- id mockContent = OCMClassMock ([UNNotificationContent class ]);
286
- OCMStub ([mockContent userInfo ]).andReturn (@{});
287
- OCMStub ([mockRequest content ]).andReturn (mockContent);
288
- OCMStub ([mockNotification request ]).andReturn (mockRequest);
289
- return mockNotification;
341
+ // Verify our swizzled method was called
342
+ [self .mockMessaging verify ];
343
+ #endif // TARGET_OS_IOS
290
344
}
291
345
292
- - (id )generateMockNotificationResponse {
346
+ - (id )userNotificationResponseWithMessage : ( NSDictionary *) message {
293
347
// Stub out: response.[mock notification above]
294
348
#if TARGET_OS_IOS
295
349
id mockNotificationResponse = OCMClassMock ([UNNotificationResponse class ]);
296
- id mockNotification = [self generateMockNotification ];
350
+ id mockNotification = [self userNotificationWithMessage: message ];
297
351
OCMStub ([mockNotificationResponse notification ]).andReturn (mockNotification);
298
352
return mockNotificationResponse;
299
- #else
353
+ #else // TARGET_OS_IOS
300
354
return nil ;
301
- #endif
355
+ #endif // TARGET_OS_IOS
356
+ }
357
+
358
+ - (UNNotification *)userNotificationWithMessage : (NSDictionary *)message {
359
+ UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc ] init ];
360
+ content.userInfo = message;
361
+ id notificationRequest = OCMClassMock ([UNNotificationRequest class ]);
362
+ OCMStub ([notificationRequest content ]).andReturn (content);
363
+ id notification = OCMClassMock ([UNNotification class ]);
364
+ OCMStub ([notification request ]).andReturn (notificationRequest);
365
+
366
+ return notification;
302
367
}
303
368
304
369
#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
0 commit comments