Skip to content

Commit 2c9ff1a

Browse files
committed
Addressed the PR comments & implemented unit tests
1 parent f56db59 commit 2c9ff1a

File tree

2 files changed

+188
-13
lines changed

2 files changed

+188
-13
lines changed

GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -884,20 +884,19 @@ - (void)application:(GULApplication *)application
884884
[didReceiveRemoteNotificationWithCompletionIMPPointer pointerValue];
885885

886886
dispatch_group_t __block callbackGroup = dispatch_group_create();
887-
UIBackgroundFetchResult __block latestFetchResult = UIBackgroundFetchResultNoData;
888-
dispatch_group_notify(callbackGroup, dispatch_get_main_queue(), ^() {
889-
completionHandler(latestFetchResult);
890-
});
887+
NSMutableArray<NSNumber *> *__block fetchResults = [NSMutableArray array];
888+
889+
void (^localCompletionHandler)(UIBackgroundFetchResult) =
890+
^void(UIBackgroundFetchResult fetchResult) {
891+
[fetchResults addObject:[NSNumber numberWithInt:(int)fetchResult]];
892+
dispatch_group_leave(callbackGroup);
893+
};
894+
891895
// Notify interceptors.
892896
[GULAppDelegateSwizzler
893897
notifyInterceptorsWithMethodSelector:methodSelector
894898
callback:^(id<GULApplicationDelegate> interceptor) {
895899
dispatch_group_enter(callbackGroup);
896-
void (^localCompletionHandler)(UIBackgroundFetchResult) =
897-
^void(UIBackgroundFetchResult fetchResult) {
898-
latestFetchResult = fetchResult;
899-
dispatch_group_leave(callbackGroup);
900-
};
901900

902901
NSInvocation *invocation = [GULAppDelegateSwizzler
903902
appDelegateInvocationForSelector:methodSelector];
@@ -911,9 +910,45 @@ - (void)application:(GULApplication *)application
911910
}];
912911
// Call the real implementation if the real App Delegate has any.
913912
if (didReceiveRemoteNotificationWithCompletionIMP) {
913+
dispatch_group_enter(callbackGroup);
914+
914915
didReceiveRemoteNotificationWithCompletionIMP(self, methodSelector, application, userInfo,
915-
completionHandler);
916+
localCompletionHandler);
916917
}
918+
919+
dispatch_group_notify(callbackGroup, dispatch_get_main_queue(), ^() {
920+
BOOL allFetchesFailed = YES;
921+
BOOL anyFetchHasNewData = NO;
922+
923+
for (NSNumber *oneResult in fetchResults) {
924+
UIBackgroundFetchResult result = oneResult.intValue;
925+
926+
switch (result) {
927+
case UIBackgroundFetchResultNoData:
928+
allFetchesFailed = NO;
929+
break;
930+
case UIBackgroundFetchResultNewData:
931+
allFetchesFailed = NO;
932+
anyFetchHasNewData = YES;
933+
break;
934+
case UIBackgroundFetchResultFailed:
935+
936+
break;
937+
}
938+
}
939+
940+
UIBackgroundFetchResult finalFetchResult = UIBackgroundFetchResultNoData;
941+
942+
if (allFetchesFailed) {
943+
finalFetchResult = UIBackgroundFetchResultFailed;
944+
} else if (anyFetchHasNewData) {
945+
finalFetchResult = UIBackgroundFetchResultNewData;
946+
} else {
947+
finalFetchResult = UIBackgroundFetchResultNoData;
948+
}
949+
950+
completionHandler(finalFetchResult);
951+
});
917952
}
918953
#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX
919954

GoogleUtilities/Tests/Unit/Swizzler/GULAppDelegateSwizzlerTest.m

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,12 +1065,12 @@ - (void)testApplicationDidReceiveRemoteNotificationWithCompletionIsInvokedOnInte
10651065
id interceptor = OCMProtocolMock(@protocol(GULApplicationDelegate));
10661066
OCMExpect([interceptor application:application
10671067
didReceiveRemoteNotification:notification
1068-
fetchCompletionHandler:completion]);
1068+
fetchCompletionHandler:[OCMArg isNotNil]]);
10691069

10701070
id interceptor2 = OCMProtocolMock(@protocol(GULApplicationDelegate));
10711071
OCMExpect([interceptor2 application:application
10721072
didReceiveRemoteNotification:notification
1073-
fetchCompletionHandler:completion]);
1073+
fetchCompletionHandler:[OCMArg isNotNil]]);
10741074

10751075
GULTestAppDelegate *testAppDelegate = [[GULTestAppDelegate alloc] init];
10761076
OCMStub([self.mockSharedApplication delegate]).andReturn(testAppDelegate);
@@ -1087,7 +1087,147 @@ - (void)testApplicationDidReceiveRemoteNotificationWithCompletionIsInvokedOnInte
10871087

10881088
XCTAssertEqual(testAppDelegate.application, application);
10891089
XCTAssertEqual(testAppDelegate.remoteNotification, notification);
1090-
XCTAssertEqual(testAppDelegate.remoteNotificationCompletionHandler, completion);
1090+
}
1091+
1092+
- (void)extracted:(UIApplication *)application
1093+
completion:(void (^)(UIBackgroundFetchResult))completion
1094+
notification:(NSDictionary *)notification
1095+
testAppDelegate:(GULTestAppDelegate *)testAppDelegate {
1096+
[testAppDelegate application:application
1097+
didReceiveRemoteNotification:notification
1098+
fetchCompletionHandler:completion];
1099+
}
1100+
1101+
- (void)testApplicationDidReceiveRemoteNotificationWithCompletionCompletionIsCalledOnce {
1102+
NSDictionary *notification = @{};
1103+
GULApplication *application = [GULApplication sharedApplication];
1104+
1105+
XCTestExpectation *completionExpectation =
1106+
[[XCTestExpectation alloc] initWithDescription:@"Completion called once"];
1107+
completionExpectation.assertForOverFulfill = YES;
1108+
1109+
void (^completion)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result) {
1110+
[completionExpectation fulfill];
1111+
};
1112+
1113+
void (^onDidReceiveRemoteNotification)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
1114+
void __unsafe_unretained (^localCompletionHandler)(UIBackgroundFetchResult) = nil;
1115+
[invocation getArgument:(void *)(&localCompletionHandler) atIndex:4];
1116+
XCTAssertNotNil(localCompletionHandler);
1117+
localCompletionHandler(UIBackgroundFetchResultNoData);
1118+
};
1119+
1120+
id interceptor = OCMProtocolMock(@protocol(GULApplicationDelegate));
1121+
OCMExpect([interceptor application:application
1122+
didReceiveRemoteNotification:notification
1123+
fetchCompletionHandler:[OCMArg isNotNil]])
1124+
.andDo(onDidReceiveRemoteNotification);
1125+
1126+
id interceptor2 = OCMProtocolMock(@protocol(GULApplicationDelegate));
1127+
OCMExpect([interceptor2 application:application
1128+
didReceiveRemoteNotification:notification
1129+
fetchCompletionHandler:[OCMArg isNotNil]])
1130+
.andDo(onDidReceiveRemoteNotification);
1131+
1132+
GULTestAppDelegate *testAppDelegate = [[GULTestAppDelegate alloc] init];
1133+
OCMStub([self.mockSharedApplication delegate]).andReturn(testAppDelegate);
1134+
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
1135+
1136+
[GULAppDelegateSwizzler registerAppDelegateInterceptor:interceptor];
1137+
[GULAppDelegateSwizzler registerAppDelegateInterceptor:interceptor2];
1138+
1139+
[self extracted:application
1140+
completion:completion
1141+
notification:notification
1142+
testAppDelegate:testAppDelegate];
1143+
testAppDelegate.remoteNotificationCompletionHandler(UIBackgroundFetchResultNoData);
1144+
OCMVerifyAll(interceptor);
1145+
OCMVerifyAll(interceptor2);
1146+
[self waitForExpectations:@[ completionExpectation ] timeout:0.1];
1147+
}
1148+
1149+
- (void)
1150+
testApplicationDidReceiveRemoteNotificationWithCompletionCompletionIsCalledOnce_HandleFailedState {
1151+
NSDictionary *notification = @{};
1152+
GULApplication *application = [GULApplication sharedApplication];
1153+
1154+
XCTestExpectation *completionExpectation =
1155+
[[XCTestExpectation alloc] initWithDescription:@"Completion called once"];
1156+
completionExpectation.assertForOverFulfill = YES;
1157+
1158+
void (^completion)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result) {
1159+
XCTAssertEqual(result, UIBackgroundFetchResultFailed);
1160+
[completionExpectation fulfill];
1161+
};
1162+
1163+
void (^onDidReceiveRemoteNotification)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
1164+
void __unsafe_unretained (^localCompletionHandler)(UIBackgroundFetchResult) = nil;
1165+
[invocation getArgument:(void *)(&localCompletionHandler) atIndex:4];
1166+
XCTAssertNotNil(localCompletionHandler);
1167+
localCompletionHandler(UIBackgroundFetchResultFailed);
1168+
};
1169+
1170+
id interceptor = OCMProtocolMock(@protocol(GULApplicationDelegate));
1171+
OCMExpect([interceptor application:application
1172+
didReceiveRemoteNotification:notification
1173+
fetchCompletionHandler:[OCMArg isNotNil]])
1174+
.andDo(onDidReceiveRemoteNotification);
1175+
1176+
GULTestAppDelegate *testAppDelegate = [[GULTestAppDelegate alloc] init];
1177+
OCMStub([self.mockSharedApplication delegate]).andReturn(testAppDelegate);
1178+
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
1179+
1180+
[GULAppDelegateSwizzler registerAppDelegateInterceptor:interceptor];
1181+
1182+
[self extracted:application
1183+
completion:completion
1184+
notification:notification
1185+
testAppDelegate:testAppDelegate];
1186+
testAppDelegate.remoteNotificationCompletionHandler(UIBackgroundFetchResultFailed);
1187+
OCMVerifyAll(interceptor);
1188+
[self waitForExpectations:@[ completionExpectation ] timeout:0.1];
1189+
}
1190+
1191+
- (void)
1192+
testApplicationDidReceiveRemoteNotificationWithCompletionCompletionIsCalledOnce_HandleNewDataState {
1193+
NSDictionary *notification = @{};
1194+
GULApplication *application = [GULApplication sharedApplication];
1195+
1196+
XCTestExpectation *completionExpectation =
1197+
[[XCTestExpectation alloc] initWithDescription:@"Completion called once"];
1198+
completionExpectation.assertForOverFulfill = YES;
1199+
1200+
void (^completion)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result) {
1201+
XCTAssertEqual(result, UIBackgroundFetchResultNewData);
1202+
[completionExpectation fulfill];
1203+
};
1204+
1205+
void (^onDidReceiveRemoteNotification)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
1206+
void __unsafe_unretained (^localCompletionHandler)(UIBackgroundFetchResult) = nil;
1207+
[invocation getArgument:(void *)(&localCompletionHandler) atIndex:4];
1208+
XCTAssertNotNil(localCompletionHandler);
1209+
localCompletionHandler(UIBackgroundFetchResultFailed);
1210+
};
1211+
1212+
id interceptor = OCMProtocolMock(@protocol(GULApplicationDelegate));
1213+
OCMExpect([interceptor application:application
1214+
didReceiveRemoteNotification:notification
1215+
fetchCompletionHandler:[OCMArg isNotNil]])
1216+
.andDo(onDidReceiveRemoteNotification);
1217+
1218+
GULTestAppDelegate *testAppDelegate = [[GULTestAppDelegate alloc] init];
1219+
OCMStub([self.mockSharedApplication delegate]).andReturn(testAppDelegate);
1220+
[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods];
1221+
1222+
[GULAppDelegateSwizzler registerAppDelegateInterceptor:interceptor];
1223+
1224+
[self extracted:application
1225+
completion:completion
1226+
notification:notification
1227+
testAppDelegate:testAppDelegate];
1228+
testAppDelegate.remoteNotificationCompletionHandler(UIBackgroundFetchResultNewData);
1229+
OCMVerifyAll(interceptor);
1230+
[self waitForExpectations:@[ completionExpectation ] timeout:0.1];
10911231
}
10921232

10931233
- (void)testApplicationDidReceiveRemoteNotificationWithCompletionImplementationIsNotAdded {

0 commit comments

Comments
 (0)