Skip to content

Commit b848121

Browse files
feat(attribute_value): Don't target NAN, INF, -INF and Doubles > 1e53… (#348)
* feat(attribute_value): Don't target NAN, INF, -INF and Doubles > 1e53 & < 1e53 * Changed Nan logic * Addressed code review comments. * Logic and Test cases updated for e^53 comparison. * Addressed code review comments. * Addressed code review comments.
1 parent 6ff2290 commit b848121

File tree

5 files changed

+182
-34
lines changed

5 files changed

+182
-34
lines changed

OptimizelySDKCore/OptimizelySDKCore.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@
229229
C77958C4219BFBC400B4CA89 /* OPTLYNSObject+Validation.h in Headers */ = {isa = PBXBuildFile; fileRef = C77958C0219BFBA000B4CA89 /* OPTLYNSObject+Validation.h */; };
230230
C77958C5219BFBC700B4CA89 /* OPTLYNSObject+Validation.m in Sources */ = {isa = PBXBuildFile; fileRef = C77958C1219BFBA000B4CA89 /* OPTLYNSObject+Validation.m */; };
231231
C77958C6219BFBC800B4CA89 /* OPTLYNSObject+Validation.m in Sources */ = {isa = PBXBuildFile; fileRef = C77958C1219BFBA000B4CA89 /* OPTLYNSObject+Validation.m */; };
232+
C7809D1921C11675005725FF /* OPTLYValidationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C7809D1821C11675005725FF /* OPTLYValidationTest.m */; };
233+
C7809D1A21C11675005725FF /* OPTLYValidationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C7809D1821C11675005725FF /* OPTLYValidationTest.m */; };
232234
EA064BC71DD3FC8800DF7537 /* OPTLYQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EA064BC51DD3FC8800DF7537 /* OPTLYQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
233235
EA064BC81DD3FC8800DF7537 /* OPTLYQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = EA064BC51DD3FC8800DF7537 /* OPTLYQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
234236
EA064BC91DD3FC8800DF7537 /* OPTLYQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = EA064BC61DD3FC8800DF7537 /* OPTLYQueue.m */; };
@@ -635,6 +637,7 @@
635637
BE0C3BD9DC6186DB98A667C2 /* Pods_OptimizelySDKCoreTVOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OptimizelySDKCoreTVOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
636638
C77958C0219BFBA000B4CA89 /* OPTLYNSObject+Validation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OPTLYNSObject+Validation.h"; sourceTree = "<group>"; };
637639
C77958C1219BFBA000B4CA89 /* OPTLYNSObject+Validation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OPTLYNSObject+Validation.m"; sourceTree = "<group>"; };
640+
C7809D1821C11675005725FF /* OPTLYValidationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OPTLYValidationTest.m; sourceTree = "<group>"; };
638641
E2E7211C032DF7A75264FDDB /* Pods-OptimizelySDKCoreTVOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OptimizelySDKCoreTVOSTests.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-OptimizelySDKCoreTVOSTests/Pods-OptimizelySDKCoreTVOSTests.debug.xcconfig"; sourceTree = "<group>"; };
639642
EA064BC51DD3FC8800DF7537 /* OPTLYQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYQueue.h; sourceTree = "<group>"; };
640643
EA064BC61DD3FC8800DF7537 /* OPTLYQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYQueue.m; sourceTree = "<group>"; };
@@ -1273,6 +1276,7 @@
12731276
EA064BCB1DD3FC9F00DF7537 /* OPTLYQueueTest.m */,
12741277
EA2FAB911DC6FDFA00B1D81B /* OPTLYTestHelper.h */,
12751278
EA2FAB921DC6FDFA00B1D81B /* OPTLYTestHelper.m */,
1279+
C7809D1821C11675005725FF /* OPTLYValidationTest.m */,
12761280
EA2FAB941DC6FDFA00B1D81B /* TestData */,
12771281
);
12781282
path = OptimizelySDKCoreTests;
@@ -1991,6 +1995,7 @@
19911995
59B9E1D120E28DBC002F732E /* OptimizelySwiftTest.swift in Sources */,
19921996
EA2FABC31DC6FDFA00B1D81B /* OPTLYTestHelper.m in Sources */,
19931997
EA2FABBD1DC6FDFA00B1D81B /* OPTLYLoggerTest.m in Sources */,
1998+
C7809D1921C11675005725FF /* OPTLYValidationTest.m in Sources */,
19941999
EA064BCE1DD3FCD700DF7537 /* OPTLYQueueTest.m in Sources */,
19952000
5E4C07FB1DFF66B00042B1F8 /* OPTLYNetworkServiceTest.m in Sources */,
19962001
EA2FABB41DC6FDFA00B1D81B /* OPTLYEventBuilderTest.m in Sources */,
@@ -2092,6 +2097,7 @@
20922097
3EA818961FFF890E00BEBD41 /* OPTLYNotificationCenterTest.m in Sources */,
20932098
EA2FABB81DC6FDFA00B1D81B /* OPTLYEventDispatcherTest.m in Sources */,
20942099
EA2FABA61DC6FDFA00B1D81B /* OPTLYAudienceTest.m in Sources */,
2100+
C7809D1A21C11675005725FF /* OPTLYValidationTest.m in Sources */,
20952101
EA2FABB21DC6FDFA00B1D81B /* OPTLYErrorHandlerTest.m in Sources */,
20962102
0BDF7200202D04EF00EB9742 /* OPTLYNotificationCenterTest2.swift in Sources */,
20972103
EA2FABC11DC6FDFA00B1D81B /* OPTLYProjectConfigTest.m in Sources */,

OptimizelySDKCore/OptimizelySDKCore/OPTLYEventBuilder.m

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ - (NSArray *)createUserFeatures:(OPTLYProjectConfig *)config
208208

209209
for (NSString *attributeKey in attributeKeys) {
210210
NSObject *attributeValue = attributes[attributeKey];
211-
if (![OPTLYEventBuilderDefault isValidAttributeValue:attributeValue]) {
211+
if (![attributeValue isValidAttributeValue]) {
212212
NSString *logMessage = [NSString stringWithFormat:OPTLYLoggerMessagesAttributeValueInvalidFormat, attributeKey];
213213
[config.logger logMessage:logMessage withLevel:OptimizelyLogLevelDebug];
214214
continue;
@@ -248,37 +248,4 @@ - (NSNumber *)time
248248
return timestamp;
249249
}
250250

251-
+ (BOOL)isValidAttributeValue:(NSObject *)value {
252-
// check value is NSObject
253-
if (!value || [value isEqual:[NSNull null]]) {
254-
return false;
255-
}
256-
// check value is NSString
257-
if ([value isKindOfClass:[NSString class]]) {
258-
return true;
259-
}
260-
NSNumber *number = (NSNumber *)value;
261-
// check value is NSNumber
262-
if (number && [number isKindOfClass:[NSNumber class]]) {
263-
const char *objCType = [number objCType];
264-
// check NSNumber is of type int, double, bool
265-
return (strcmp(objCType, @encode(short)) == 0)
266-
|| (strcmp(objCType, @encode(unsigned short)) == 0)
267-
|| (strcmp(objCType, @encode(int)) == 0)
268-
|| (strcmp(objCType, @encode(unsigned int)) == 0)
269-
|| (strcmp(objCType, @encode(long)) == 0)
270-
|| (strcmp(objCType, @encode(unsigned long)) == 0)
271-
|| (strcmp(objCType, @encode(long long)) == 0)
272-
|| (strcmp(objCType, @encode(unsigned long long)) == 0)
273-
|| (strcmp(objCType, @encode(float)) == 0)
274-
|| (strcmp(objCType, @encode(double)) == 0)
275-
|| (strcmp(objCType, @encode(char)) == 0)
276-
|| (strcmp(objCType, @encode(unsigned char)) == 0)
277-
|| (strcmp(objCType, @encode(bool)) == 0)
278-
|| [number isEqual:@YES]
279-
|| [number isEqual:@NO];
280-
}
281-
return false;
282-
}
283-
284251
@end

OptimizelySDKCore/OptimizelySDKCore/OPTLYNSObject+Validation.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,27 @@ NS_ASSUME_NONNULL_BEGIN
4848
**/
4949
- (NSString *)getStringOrEmpty;
5050

51+
/**
52+
* Returns if object is a valid attribute
53+
*
54+
* @returns A Bool whether object is a valid attribute.
55+
**/
56+
- (BOOL)isValidAttributeValue;
57+
58+
/**
59+
* Returns if object is a valid boolean attribute
60+
*
61+
* @returns A Bool whether object is a valid boolean attribute.
62+
**/
63+
- (BOOL)isValidBooleanAttributeValue;
64+
65+
/**
66+
* Returns if object is a valid numeric attribute
67+
*
68+
* @returns A Bool whether object is a valid numeric attribute.
69+
**/
70+
- (BOOL)isValidNumericAttributeValue;
71+
5172
@end
5273

5374
NS_ASSUME_NONNULL_END

OptimizelySDKCore/OptimizelySDKCore/OPTLYNSObject+Validation.m

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,88 @@ - (NSString *)getStringOrEmpty {
5454
}
5555
return string;
5656
}
57+
58+
- (BOOL)isValidAttributeValue {
59+
if (self) {
60+
if ([self isEqual:[NSNull null]]) {
61+
return false;
62+
}
63+
// check value is NSString
64+
if ([self isKindOfClass:[NSString class]]) {
65+
return true;
66+
}
67+
// check value is Boolean
68+
if ([self isValidBooleanAttributeValue]) {
69+
return true;
70+
}
71+
//check value is valid numeric attribute
72+
if ([self isValidNumericAttributeValue]) {
73+
return true;
74+
}
75+
}
76+
return false;
77+
}
78+
79+
-(BOOL)isValidBooleanAttributeValue {
80+
if (self) {
81+
NSNumber *number = (NSNumber *)self;
82+
// check value is NSNumber
83+
if (number && [number isKindOfClass:[NSNumber class]]) {
84+
const char *objCType = [number objCType];
85+
86+
// check NSNumber is bool
87+
if ((strcmp(objCType, @encode(bool)) == 0)
88+
|| [number isEqual:@YES]
89+
|| [number isEqual:@NO]) {
90+
return true;
91+
}
92+
}
93+
}
94+
return false;
95+
}
96+
97+
-(BOOL)isValidNumericAttributeValue {
98+
if (self) {
99+
NSNumber *number = (NSNumber *)self;
100+
// check value is NSNumber
101+
if (number && [number isKindOfClass:[NSNumber class]]) {
102+
const char *objCType = [number objCType];
103+
104+
// check for Nan
105+
if (isnan([number doubleValue])) {
106+
return false;
107+
}
108+
// check NSNumber is bool
109+
if ((strcmp(objCType, @encode(bool)) == 0)
110+
|| [number isEqual:@YES]
111+
|| [number isEqual:@NO]) {
112+
return false;
113+
}
114+
// check for infinity
115+
if (isinf([number doubleValue])) {
116+
return false;
117+
}
118+
// check NSNumber is of type int, double
119+
Boolean isNumeric = (strcmp(objCType, @encode(short)) == 0)
120+
|| (strcmp(objCType, @encode(unsigned short)) == 0)
121+
|| (strcmp(objCType, @encode(int)) == 0)
122+
|| (strcmp(objCType, @encode(unsigned int)) == 0)
123+
|| (strcmp(objCType, @encode(long)) == 0)
124+
|| (strcmp(objCType, @encode(unsigned long)) == 0)
125+
|| (strcmp(objCType, @encode(long long)) == 0)
126+
|| (strcmp(objCType, @encode(unsigned long long)) == 0)
127+
|| (strcmp(objCType, @encode(float)) == 0)
128+
|| (strcmp(objCType, @encode(double)) == 0)
129+
|| (strcmp(objCType, @encode(char)) == 0)
130+
|| (strcmp(objCType, @encode(unsigned char)) == 0);
131+
132+
if (isNumeric) {
133+
NSNumber *maxValue = [NSNumber numberWithDouble:pow(2,53)];
134+
return (fabs([number doubleValue]) <= [maxValue doubleValue]);
135+
}
136+
}
137+
}
138+
return false;
139+
}
140+
57141
@end
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/****************************************************************************
2+
* Copyright 2018, Optimizely, Inc. and contributors *
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+
17+
#import <XCTest/XCTest.h>
18+
#import "OPTLYNSObject+Validation.h"
19+
20+
@interface OPTLYValidationTest : XCTestCase
21+
22+
@end
23+
24+
@implementation OPTLYValidationTest
25+
26+
- (void)setUp {
27+
[super setUp];
28+
// Put setup code here. This method is called before the invocation of each test method in the class.
29+
}
30+
31+
- (void)tearDown {
32+
// Put teardown code here. This method is called after the invocation of each test method in the class.
33+
[super tearDown];
34+
}
35+
36+
#pragma mark - Test Method isValidAttributeValue
37+
38+
- (void)testMethodIsValidAttributeValueReturnsTrueForValidData
39+
{
40+
XCTAssertTrue([(NSObject *)@false isValidAttributeValue]);
41+
XCTAssertTrue([(NSObject *)@true isValidAttributeValue]);
42+
XCTAssertTrue([(NSObject *)@YES isValidAttributeValue]);
43+
XCTAssertTrue([(NSObject *)@NO isValidAttributeValue]);
44+
XCTAssertTrue([(NSObject *)@0 isValidAttributeValue]);
45+
XCTAssertTrue([(NSObject *)@0.0 isValidAttributeValue]);
46+
XCTAssertTrue([(NSObject *)@"" isValidAttributeValue]);
47+
XCTAssertTrue([(NSObject *)@"test_value" isValidAttributeValue]);
48+
XCTAssertTrue([(NSObject *)[NSNumber numberWithDouble:(pow(2, 53))] isValidAttributeValue]);
49+
XCTAssertTrue([(NSObject *)[NSNumber numberWithDouble:(-pow(2, 53))] isValidAttributeValue]);
50+
XCTAssertTrue([(NSObject *)[NSNumber numberWithLongLong:(pow(2, 53))] isValidAttributeValue]);
51+
XCTAssertTrue([(NSObject *)[NSNumber numberWithLongLong:(-pow(2, 53))] isValidAttributeValue]);
52+
XCTAssertTrue([(NSObject *)[NSNumber numberWithUnsignedLongLong:(pow(2, 53))] isValidAttributeValue]);
53+
}
54+
55+
- (void)testMethodIsValidAttributeValueReturnsFalseForInvalidData
56+
{
57+
XCTAssertFalse([(NSObject *)nil isValidAttributeValue]);
58+
XCTAssertFalse([(NSObject *)@{} isValidAttributeValue]);
59+
XCTAssertFalse([(NSObject *)@[] isValidAttributeValue]);
60+
XCTAssertFalse([(NSObject *)[NSNumber numberWithFloat:INFINITY] isValidAttributeValue]);
61+
XCTAssertFalse([(NSObject *)[NSNumber numberWithFloat:-INFINITY] isValidAttributeValue]);
62+
XCTAssertFalse([(NSObject *)[NSNumber numberWithDouble:NAN] isValidAttributeValue]);
63+
XCTAssertFalse([(NSObject *)[NSNumber numberWithDouble:(pow(2, 53) + 2)] isValidAttributeValue]);
64+
XCTAssertFalse([(NSObject *)[NSNumber numberWithDouble:(-pow(2, 53) - 2)] isValidAttributeValue]);
65+
XCTAssertFalse([(NSObject *)[NSNumber numberWithLongLong:(pow(2, 53) + 2)] isValidAttributeValue]);
66+
XCTAssertFalse([(NSObject *)[NSNumber numberWithLongLong:(-pow(2, 53) - 2)] isValidAttributeValue]);
67+
XCTAssertFalse([(NSObject *)[NSNumber numberWithUnsignedLongLong:(pow(2, 53) + 2)] isValidAttributeValue]);
68+
}
69+
70+
@end

0 commit comments

Comments
 (0)