Skip to content

Commit 1e9a365

Browse files
authored
Request tests (#353)
Request Tests • Adds tests to ensure that all subclasses of OneSignalRequest are building correctly formatted requests • Moves a tests file from an incorrect folder location into the Tests folder • Adds request model body validation for our PUT and POST requests Background Location Services • Since iOS 10 Apple uses NSLocationAlwaysAndWhenInUseUsageDescription in info.plist instead of NSLocationAlwaysUsage • When requesting location permissions, the SDK only checked to see if NSLocationAlwaysUsage existed, and if it did not, the SDK would not request authorization for background location usage
1 parent a42a573 commit 1e9a365

File tree

4 files changed

+281
-2
lines changed

4 files changed

+281
-2
lines changed

iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
CA810FD1202BA97300A60FED /* OSEmailSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = CA810FD0202BA97300A60FED /* OSEmailSubscription.m */; };
145145
CA810FD2202BA97600A60FED /* OSEmailSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = CA810FD0202BA97300A60FED /* OSEmailSubscription.m */; };
146146
CA810FD3202BA97600A60FED /* OSEmailSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = CA810FD0202BA97300A60FED /* OSEmailSubscription.m */; };
147+
CA85C15320604AEA003AB529 /* RequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA85C15220604AEA003AB529 /* RequestTests.m */; };
147148
CA97E14E2051C0A5003B8CB8 /* OneSignalWebOpenDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = CA97E14C2051C0A5003B8CB8 /* OneSignalWebOpenDialog.h */; };
148149
CA97E14F2051C0A5003B8CB8 /* OneSignalWebOpenDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CA97E14D2051C0A5003B8CB8 /* OneSignalWebOpenDialog.m */; };
149150
CA97E1502051C0A5003B8CB8 /* OneSignalWebOpenDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = CA97E14D2051C0A5003B8CB8 /* OneSignalWebOpenDialog.m */; };
@@ -285,6 +286,7 @@
285286
CA70E3382023F24500019273 /* OneSignalCommonDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalCommonDefines.h; sourceTree = "<group>"; };
286287
CA810FCF202BA97300A60FED /* OSEmailSubscription.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OSEmailSubscription.h; sourceTree = "<group>"; };
287288
CA810FD0202BA97300A60FED /* OSEmailSubscription.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OSEmailSubscription.m; sourceTree = "<group>"; };
289+
CA85C15220604AEA003AB529 /* RequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RequestTests.m; sourceTree = "<group>"; };
288290
CA97E14C2051C0A5003B8CB8 /* OneSignalWebOpenDialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalWebOpenDialog.h; sourceTree = "<group>"; };
289291
CA97E14D2051C0A5003B8CB8 /* OneSignalWebOpenDialog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalWebOpenDialog.m; sourceTree = "<group>"; };
290292
CAA4ED0020646762005BD59B /* BadgeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BadgeTests.m; sourceTree = "<group>"; };
@@ -413,6 +415,7 @@
413415
children = (
414416
4529DECD1FA81DE000CEAB1D /* Shadows */,
415417
911E2CBC1E398AB3003112A4 /* UnitTests.m */,
418+
CA85C15220604AEA003AB529 /* RequestTests.m */,
416419
CAA4ED0020646762005BD59B /* BadgeTests.m */,
417420
CA63AF8320211F7400E340FB /* EmailTests.m */,
418421
CA63AF8520211FF800E340FB /* UnitTestCommonMethods.h */,
@@ -792,6 +795,7 @@
792795
91F58D8B1E7C9A240017D24D /* OneSignalNotificationSettingsIOS7.m in Sources */,
793796
91F60F7D1E80E4E400706E60 /* UncaughtExceptionHandler.m in Sources */,
794797
912412201E73342200E41FD7 /* OneSignalJailbreakDetection.m in Sources */,
798+
CA85C15320604AEA003AB529 /* RequestTests.m in Sources */,
795799
912412381E73342200E41FD7 /* OneSignalTrackIAP.m in Sources */,
796800
CA63AF8720211FF800E340FB /* UnitTestCommonMethods.m in Sources */,
797801
CA70E3372023D51300019273 /* OneSignalSetEmailParameters.m in Sources */,

iOS_SDK/OneSignalSDK/Source/OneSignalLocation.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ + (void) internalGetLocation:(bool)prompt {
181181
//LocationAlways > LocationWhenInUse > No entry (Log error)
182182
//Location Always requires: Location Background Mode + NSLocationAlwaysUsageDescription
183183
NSArray* backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
184-
NSString* alwaysDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"];
184+
NSString* alwaysDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"];
185185
if(backgroundModes && [backgroundModes containsObject:@"location"] && alwaysDescription) {
186186
[locationManager performSelector:@selector(requestAlwaysAuthorization)];
187187
if (deviceOSVersion >= 9.0) {

iOS_SDK/OneSignalSDK/Source/Requests.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ + (instancetype _Nonnull)withUserId:(NSString * _Nonnull)userId appId:(NSString
109109

110110
let params = [NSMutableDictionary new];
111111
params[@"app_id"] = appId;
112-
params[@"email"] = email;
112+
113+
if (email)
114+
params[@"email"] = email;
113115

114116
if (notificationTypes)
115117
params[@"notification_types"] = notificationTypes;
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/**
2+
* Modified MIT License
3+
*
4+
* Copyright 2017 OneSignal
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#import <XCTest/XCTest.h>
29+
#import "Requests.h"
30+
#import "OneSignalHelper.h"
31+
#import "Requests.h"
32+
#import "OneSignalCommonDefines.h"
33+
34+
@interface RequestTests : XCTestCase
35+
36+
@end
37+
38+
@implementation RequestTests {
39+
NSString *testAppId;
40+
NSString *testUserId;
41+
NSString *testEmailUserId;
42+
NSString *testMessageId;
43+
NSString *testEmailAddress;
44+
}
45+
46+
- (void)setUp {
47+
[super setUp];
48+
// Put setup code here. This method is called before the invocation of each test method in the class.
49+
50+
testAppId = @"test_app_id";
51+
testUserId = @"test_user_id";
52+
testEmailUserId = @"test_email_user_id";
53+
testEmailAddress = @"[email protected]";
54+
testMessageId = @"test_message_id";
55+
}
56+
57+
NSString *urlStringForRequest(OneSignalRequest *request) {
58+
return correctUrlWithPath(request.path);
59+
}
60+
61+
NSString *correctUrlWithPath(NSString *path) {
62+
return [[SERVER_URL stringByAppendingString:API_VERSION] stringByAppendingString:path];
63+
}
64+
65+
// only works for dictionaries with values that are strings, numbers, or sub-dictionaries/arrays of strings and numbers
66+
// since this is all our SDK uses, it should suffice.
67+
BOOL dictionariesAreEquivalent(NSDictionary *first, NSDictionary *second) {
68+
let firstKeys = first.allKeys;
69+
let secondKeys = second.allKeys;
70+
71+
if (firstKeys.count != secondKeys.count)
72+
return false;
73+
74+
for (id key in firstKeys) {
75+
if (![secondKeys containsObject:key]) {
76+
return false;
77+
} else if ([first[key] isKindOfClass:[NSString class]] && ![(NSString *)first[key] isEqualToString:(NSString *)second[key]]) {
78+
return false;
79+
} else if ([first[key] isKindOfClass:[NSNumber class]] && ![(NSNumber *)first[key] isEqualToNumber:(NSNumber *)second[key]]) {
80+
return false;
81+
} else if ([first[key] isKindOfClass:[NSDictionary class]]) {
82+
if (![second[key] isKindOfClass:[NSDictionary class]] && !dictionariesAreEquivalent((NSDictionary *)first[key], (NSDictionary *)second[key]))
83+
return false;
84+
} else if ([first[key] isKindOfClass:[NSArray class]]) {
85+
if (![second[key] isKindOfClass:[NSArray class]])
86+
return false;
87+
88+
let firstArray = (NSArray *)first[key];
89+
let secondArray = (NSArray *)second[key];
90+
91+
for (id element in firstArray)
92+
if (![secondArray containsObject:element])
93+
return false;
94+
}
95+
}
96+
97+
return true;
98+
}
99+
100+
BOOL checkHttpBody(NSData *bodyData, NSDictionary *correct) {
101+
NSError *error;
102+
NSDictionary *serialized = [NSJSONSerialization JSONObjectWithData:bodyData options:NSJSONReadingAllowFragments error:&error];
103+
104+
if (error)
105+
return false;
106+
107+
return dictionariesAreEquivalent(serialized, correct);
108+
}
109+
110+
- (void)testBuildGetTags {
111+
let request = [OSRequestGetTags withUserId:testUserId appId:testAppId];
112+
113+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@?app_id=%@", testUserId, testAppId]);
114+
115+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
116+
}
117+
118+
- (void)testBuildGetIosParams {
119+
let request = [OSRequestGetIosParams withUserId:testUserId appId:testAppId];
120+
121+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"apps/%@/ios_params.js?player_id=%@", testAppId, testUserId]);
122+
123+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
124+
}
125+
126+
- (void)testBuildPostNotification {
127+
let request = [OSRequestPostNotification withAppId:testAppId withJson:[@{} mutableCopy]];
128+
129+
let correctUrl = correctUrlWithPath(@"notifications");
130+
131+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
132+
133+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId}));
134+
}
135+
136+
- (void)testSendTags {
137+
let request = [OSRequestSendTagsToServer withUserId:testUserId appId:testAppId tags:@{} networkType:@0 withEmailAuthHashToken:nil];
138+
139+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
140+
141+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
142+
143+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId, @"tags" : @{}, @"net_type" : @0}));
144+
}
145+
146+
- (void)testUpdateDeviceToken {
147+
let request = [OSRequestUpdateDeviceToken withUserId:testUserId appId:testAppId deviceToken:@"test_device_token" notificationTypes:@0 withParentId:@"test_parent_id" emailAuthToken:nil email:testEmailAddress];
148+
149+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
150+
151+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
152+
153+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId, @"email" : testEmailAddress, @"notification_types" : @0, @"identifier" : @"test_device_token", @"parent_player_id" : @"test_parent_id"}));
154+
}
155+
156+
- (void)testCreateDevice {
157+
let request = [OSRequestCreateDevice withAppId:testAppId withDeviceType:@0 withEmail:testEmailAddress withPlayerId:testUserId withEmailAuthHash:nil];
158+
159+
let correctUrl = correctUrlWithPath(@"players");
160+
161+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
162+
163+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId, @"device_type" : @0, @"identifier" : testEmailAddress, @"email_auth_hash" : [NSNull null], @"device_player_id" : testUserId}));
164+
}
165+
166+
- (void)testLogoutEmail {
167+
let request = [OSRequestLogoutEmail withAppId:testAppId emailPlayerId:testEmailUserId devicePlayerId:testUserId emailAuthHash:nil];
168+
169+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@/email_logout", testUserId]);
170+
171+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
172+
173+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"parent_player_id" : testEmailUserId, @"email_auth_hash" : [NSNull null], @"app_id" : testAppId}));
174+
}
175+
176+
- (void)testUpdateNotificationTypes {
177+
let request = [OSRequestUpdateNotificationTypes withUserId:testUserId appId:testAppId notificationTypes:@0];
178+
179+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
180+
181+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
182+
183+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId, @"notification_types" : @0}));
184+
}
185+
186+
- (void)testSendPurchases {
187+
let standardRequest = [OSRequestSendPurchases withUserId:testUserId appId:testAppId withPurchases:@[]];
188+
189+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@/on_purchase", testUserId]);
190+
191+
XCTAssertTrue([correctUrl isEqualToString:standardRequest.request.URL.absoluteString]);
192+
193+
let emailRequest = [OSRequestSendPurchases withUserId:testUserId emailAuthToken:@"email_auth_token" appId:testAppId withPurchases:@[]];
194+
195+
XCTAssertTrue([correctUrl isEqualToString:emailRequest.request.URL.absoluteString]);
196+
197+
XCTAssertTrue(checkHttpBody(standardRequest.request.HTTPBody, @{@"app_id" : testAppId, @"purchases" : @[]}));
198+
199+
XCTAssertTrue(checkHttpBody(emailRequest.request.HTTPBody, @{@"app_id" : testAppId, @"purchases" : @[], @"email_auth_hash" : @"email_auth_token"}));
200+
}
201+
202+
- (void)testSubmitNotificationOpened {
203+
let request = [OSRequestSubmitNotificationOpened withUserId:testUserId appId:testAppId wasOpened:true messageId:testMessageId];
204+
205+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"notifications/%@", testMessageId]);
206+
207+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
208+
209+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"player_id" : testUserId, @"app_id" : testAppId, @"opened" : @1}));
210+
}
211+
212+
- (void)testRegisterUser {
213+
let request = [OSRequestRegisterUser withData:@{@"test_key" : @"test_value"} userId:testUserId];
214+
215+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@/on_session", testUserId]);
216+
217+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
218+
219+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"test_key" : @"test_value"}));
220+
}
221+
222+
- (void)testSyncHashedEmail {
223+
let request = [OSRequestSyncHashedEmail withUserId:testUserId appId:testAppId email:testEmailAddress networkType:@1];
224+
225+
let lowerCase = [testEmailAddress lowercaseString];
226+
let md5Hash = [OneSignalHelper hashUsingMD5:lowerCase];
227+
let sha1Hash = [OneSignalHelper hashUsingSha1:lowerCase];
228+
229+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
230+
231+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
232+
233+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId, @"em_m" : md5Hash, @"em_s" : sha1Hash, @"net_type" : @1}));
234+
}
235+
236+
- (void)testSendLocation {
237+
os_last_location *location = (os_last_location*)malloc(sizeof(os_last_location));
238+
239+
location->verticalAccuracy = 1.0;
240+
location->horizontalAccuracy = 2.0;
241+
location->cords.latitude = 3.0;
242+
location->cords.longitude = 4.0;
243+
244+
let request = [OSRequestSendLocation withUserId:testUserId appId:testAppId location:location networkType:@0 backgroundState:true emailAuthHashToken:nil];
245+
246+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
247+
248+
XCTAssertTrue([correctUrl isEqualToString:request.request.URL.absoluteString]);
249+
250+
XCTAssertTrue(checkHttpBody(request.request.HTTPBody, @{@"app_id" : testAppId, @"lat" : @3.0, @"long" : @4.0, @"loc_acc_vert" : @1.0, @"loc_acc" : @2.0, @"net_type" : @0, @"loc_bg" : @1}));
251+
}
252+
253+
- (void)testOnFocus {
254+
let firstRequest = [OSRequestOnFocus withUserId:testUserId appId:testAppId badgeCount:@0 emailAuthToken:nil];
255+
256+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
257+
258+
XCTAssertTrue([correctUrl isEqualToString:firstRequest.request.URL.absoluteString]);
259+
260+
let secondRequest = [OSRequestOnFocus withUserId:testUserId appId:testAppId state:@"test_state" type:@1 activeTime:@2 netType:@3 emailAuthToken:nil];
261+
262+
let secondCorrectUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@/on_focus", testUserId]);
263+
264+
XCTAssertTrue([secondCorrectUrl isEqualToString:secondRequest.request.URL.absoluteString]);
265+
266+
XCTAssertTrue(checkHttpBody(firstRequest.request.HTTPBody, @{@"app_id" : testAppId, @"badgeCount" : @0}));
267+
268+
XCTAssertTrue(checkHttpBody(secondRequest.request.HTTPBody, @{@"app_id" : testAppId, @"state" : @"test_state", @"type" : @1, @"active_time" : @2, @"net_type" : @3}));
269+
}
270+
271+
272+
273+
@end

0 commit comments

Comments
 (0)