@@ -72,19 +72,51 @@ BOOL injectStaticSelector(Class newClass, SEL newSel, Class addToClass, SEL make
7272
7373// START - Selector Shadowing
7474
75+
76+ @interface SelectorToRun : NSObject
77+ @property NSObject * runOn;
78+ @property SEL selector;
79+ @property NSObject * withObject;
80+ @end
81+
82+
83+ @implementation SelectorToRun
84+ @end
85+
7586@interface NSObjectOverrider : NSObject
7687@end
88+
7789@implementation NSObjectOverrider
7890
79- static BOOL enabledPerformSelectorAfterDelay = true ;
91+ static NSMutableArray * selectorsToRun;
92+ static BOOL instantRunPerformSelectorAfterDelay;
8093
8194+ (void )load {
8295 injectToProperClass (@selector (overridePerformSelector:withObject:afterDelay: ), @selector (performSelector:withObject:afterDelay: ), @[], [NSObjectOverrider class ], [NSObject class ]);
96+ injectToProperClass (@selector (overridePerformSelector:withObject: ), @selector (performSelector:withObject: ), @[], [NSObjectOverrider class ], [NSObject class ]);
8397}
8498
8599- (void )overridePerformSelector : (SEL )aSelector withObject : (nullable id )anArgument afterDelay : (NSTimeInterval )delay {
86- if (enabledPerformSelectorAfterDelay)
87- [self overridePerformSelector: aSelector withObject: nil afterDelay: delay];
100+ if (instantRunPerformSelectorAfterDelay)
101+ [self performSelector: aSelector withObject: anArgument];
102+ else {
103+ SelectorToRun* selectorToRun = [SelectorToRun alloc ];
104+ selectorToRun.runOn = self;
105+ selectorToRun.selector = aSelector;
106+ selectorToRun.withObject = anArgument;
107+ [selectorsToRun addObject: selectorToRun];
108+ }
109+ }
110+
111+ - (void )overridePerformSelector : (SEL )aSelector withObject : (nullable id )anArgument {
112+ [self overridePerformSelector: aSelector withObject: anArgument];
113+ }
114+
115+ + (void )runPendingSelectors {
116+ for (SelectorToRun* selectorToRun in selectorsToRun)
117+ [selectorToRun.runOn performSelector: selectorToRun.selector withObject: selectorToRun.withObject];
118+
119+ [selectorsToRun removeAllObjects ];
88120}
89121
90122@end
@@ -363,6 +395,9 @@ - (void)setUp {
363395 didFailRegistarationErrorCode = 0 ;
364396 nsbundleDictionary = @{@" UIBackgroundModes" : @[@" remote-notification" ]};
365397
398+ instantRunPerformSelectorAfterDelay = false ;
399+ selectorsToRun = [[NSMutableArray alloc ] init ];
400+
366401 // TODO: Keep commented out for now, might need this later.
367402 // [OneSignal performSelector:NSSelectorFromString(@"clearStatics")];
368403
@@ -799,16 +834,62 @@ - (void)testRecievedCallbackWithButtons {
799834- (void )testSendTags {
800835 [self initOneSignal ];
801836 [self runBackgroundThreads ];
837+ XCTAssertEqual (networkRequestCount, 1 );
802838
839+ // Simple test with a sendTag and sendTags call.
803840 [OneSignal sendTag: @" key" value: @" value" ];
804- XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key" ], @" value" );
805-
806841 [OneSignal sendTags: @{@" key1" : @" value1" , @" key2" : @" value2" }];
842+
843+ // Make sure all 3 sets of tags where send in 1 network call.
844+ [NSObjectOverrider runPendingSelectors ];
845+ XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key" ], @" value" );
807846 XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key1" ], @" value1" );
808847 XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key2" ], @" value2" );
848+ XCTAssertEqual (networkRequestCount, 2 );
849+
850+
851+ // More advanced test with callbacks.
852+ __block BOOL didRunSuccess1, didRunSuccess2, didRunSuccess3;
853+ [OneSignal sendTag: @" key10" value: @" value10" onSuccess: ^(NSDictionary *result) {
854+ didRunSuccess1 = true ;
855+ } onFailure: ^(NSError *error) {}];
856+ [OneSignal sendTags: @{@" key11" : @" value11" , @" key12" : @" value12" } onSuccess: ^(NSDictionary *result) {
857+ didRunSuccess2 = true ;
858+ } onFailure: ^(NSError *error) {}];
809859
810- // TODO: Optimization: This could be 1 network call if we delay the request in init and sendTags
860+ instantRunPerformSelectorAfterDelay = true ;
861+ [OneSignal sendTag: @" key13" value: @" value13" onSuccess: ^(NSDictionary *result) {
862+ didRunSuccess3 = true ;
863+ } onFailure: ^(NSError *error) {}];
864+
865+ [NSObjectOverrider runPendingSelectors ];
866+
867+ XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key10" ], @" value10" );
868+ XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key11" ], @" value11" );
869+ XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key12" ], @" value12" );
870+ XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key13" ], @" value13" );
811871 XCTAssertEqual (networkRequestCount, 3 );
872+
873+ XCTAssertEqual (didRunSuccess1, true );
874+ XCTAssertEqual (didRunSuccess2, true );
875+ XCTAssertEqual (didRunSuccess3, true );
876+ }
877+
878+ - (void )testDeleteTags {
879+ [self initOneSignal ];
880+ [self runBackgroundThreads ];
881+ XCTAssertEqual (networkRequestCount, 1 );
882+
883+ // send 2 tags and delete 1 before they get sent off.
884+ [OneSignal sendTag: @" key" value: @" value" ];
885+ [OneSignal sendTag: @" key2" value: @" value2" ];
886+ [OneSignal deleteTag: @" key" ];
887+
888+ // Make sure only 1 network call is made and only key2 gets sent.
889+ [NSObjectOverrider runPendingSelectors ];
890+ XCTAssertNil (lastHTTPRequset[@" tags" ][@" key" ]);
891+ XCTAssertEqualObjects (lastHTTPRequset[@" tags" ][@" key2" ], @" value2" );
892+ XCTAssertEqual (networkRequestCount, 2 );
812893}
813894
814895- (void )testFirstInitWithNotificationsAlreadyDeclined {
0 commit comments