Skip to content

Commit 11b6552

Browse files
committed
put the protocol of OPTLYDatafileManager in Shared SDK and check that whatever is passed to the builder conforms to the manager
1 parent 80a790f commit 11b6552

File tree

10 files changed

+168
-15
lines changed

10 files changed

+168
-15
lines changed

OptimizelySDKDatafileManager/OptimizelySDKDatafileManager/OPTLYDatafileManager.h

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,12 @@
1818
#import "OPTLYDatafileManagerBuilder.h"
1919
#import <OptimizelySDKCore/OPTLYErrorHandler.h>
2020
#import <OptimizelySDKCore/OPTLYLogger.h>
21+
#import <OptimizelySDKShared/OPTLYDatafileManager.h>
2122
#import <OptimizelySDKShared/OPTLYHTTPRequestManager.h>
2223

2324

2425
@protocol OPTLYErrorHandler, OPTLYLogger;
2526

26-
@protocol OPTLYDatafileManager <NSObject>
27-
28-
/**
29-
* Download the datafile for the project ID
30-
* @param projectId The project ID of the datafile to request.
31-
* @param completion Completion handler.
32-
*/
33-
- (void)downloadDatafile:(nonnull NSString *)projectId
34-
completionHandler:(nullable OPTLYHTTPRequestManagerResponse)completion;
35-
36-
@end
37-
3827
@interface OPTLYDatafileManager : NSObject<OPTLYDatafileManager>
3928

4029
/// The time interval to regularly fetch the datafile.

OptimizelySDKShared/OptimizelySDKShared.xcodeproj/project.pbxproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
2DB3D1811DC8181400ECF72E /* OPTLYManagerBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DB3D17B1DC816D600ECF72E /* OPTLYManagerBuilder.m */; };
4040
2DCC50B31DD3CDAB006C9815 /* OPTLYManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DCC50B21DD3CDAB006C9815 /* OPTLYManagerTest.m */; };
4141
2DCC50B41DD3CDAB006C9815 /* OPTLYManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DCC50B21DD3CDAB006C9815 /* OPTLYManagerTest.m */; };
42+
2DCC51231DDE3C90006C9815 /* OPTLYDatafileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DCC51221DDE3C90006C9815 /* OPTLYDatafileManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
43+
2DCC51241DDE3C90006C9815 /* OPTLYDatafileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DCC51221DDE3C90006C9815 /* OPTLYDatafileManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
44+
2DCC51261DDE3CA4006C9815 /* OPTLYDatafileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DCC51251DDE3CA4006C9815 /* OPTLYDatafileManager.m */; };
45+
2DCC51271DDE3CA4006C9815 /* OPTLYDatafileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DCC51251DDE3CA4006C9815 /* OPTLYDatafileManager.m */; };
4246
5318433267A9188A3D16D3A2 /* Pods_OptimizelySDKSharediOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B9FE2FE02E36C64D6F1F442 /* Pods_OptimizelySDKSharediOSTests.framework */; };
4347
5A8753FCE65715A7A353C14C /* Pods_OptimizelySDKSharediOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09704701D3CB97F3D3F408E3 /* Pods_OptimizelySDKSharediOS.framework */; };
4448
6433BEBF70E8BE35397D1778 /* Pods_OptimizelySDKSharedTVOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EDD2F1182FB354ABC0E04A1 /* Pods_OptimizelySDKSharedTVOS.framework */; };
@@ -161,6 +165,8 @@
161165
2DB3D17A1DC816D600ECF72E /* OPTLYManagerBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYManagerBuilder.h; sourceTree = "<group>"; };
162166
2DB3D17B1DC816D600ECF72E /* OPTLYManagerBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYManagerBuilder.m; sourceTree = "<group>"; };
163167
2DCC50B21DD3CDAB006C9815 /* OPTLYManagerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYManagerTest.m; sourceTree = "<group>"; };
168+
2DCC51221DDE3C90006C9815 /* OPTLYDatafileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYDatafileManager.h; sourceTree = "<group>"; };
169+
2DCC51251DDE3CA4006C9815 /* OPTLYDatafileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYDatafileManager.m; sourceTree = "<group>"; };
164170
5CF4F1B8D6539A2AE661E1E1 /* Pods-OptimizelySDKSharedTVOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OptimizelySDKSharedTVOS.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-OptimizelySDKSharedTVOS/Pods-OptimizelySDKSharedTVOS.debug.xcconfig"; sourceTree = "<group>"; };
165171
5EDD2F1182FB354ABC0E04A1 /* Pods_OptimizelySDKSharedTVOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OptimizelySDKSharedTVOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
166172
6042179012EFD11109128C34 /* Pods-OptimizelySDKSharedTVOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OptimizelySDKSharedTVOS.release.xcconfig"; path = "../Pods/Target Support Files/Pods-OptimizelySDKSharedTVOS/Pods-OptimizelySDKSharedTVOS.release.xcconfig"; sourceTree = "<group>"; };
@@ -273,6 +279,15 @@
273279
name = TestData;
274280
sourceTree = "<group>";
275281
};
282+
2DCC51211DDE3C74006C9815 /* DatafileManager */ = {
283+
isa = PBXGroup;
284+
children = (
285+
2DCC51221DDE3C90006C9815 /* OPTLYDatafileManager.h */,
286+
2DCC51251DDE3CA4006C9815 /* OPTLYDatafileManager.m */,
287+
);
288+
name = DatafileManager;
289+
sourceTree = "<group>";
290+
};
276291
B770041BA173BC0CC7E9DB5F /* Pods */ = {
277292
isa = PBXGroup;
278293
children = (
@@ -326,6 +341,7 @@
326341
EA3C682C1DC1E68E00C578CA /* OptimizelySDKShared.h */,
327342
EA52478F1DC7246C00AF6685 /* Manager */,
328343
2D08FB671DCA5A78006CA063 /* Client */,
344+
2DCC51211DDE3C74006C9815 /* DatafileManager */,
329345
EA5247911DC7248200AF6685 /* DataStore */,
330346
EA5247901DC7247500AF6685 /* Network */,
331347
);
@@ -420,6 +436,7 @@
420436
buildActionMask = 2147483647;
421437
files = (
422438
2D08FB9F1DCA5FA8006CA063 /* OPTLYClientBuilder.h in Headers */,
439+
2DCC51231DDE3C90006C9815 /* OPTLYDatafileManager.h in Headers */,
423440
EA5249971DC7D8AD00AF6685 /* OptimizelySDKShared.h in Headers */,
424441
2D08FB6B1DCA5A99006CA063 /* OPTLYClient.h in Headers */,
425442
EA5247851DC7226400AF6685 /* OPTLYManager.h in Headers */,
@@ -440,6 +457,7 @@
440457
2D08FBA01DCA5FA8006CA063 /* OPTLYClientBuilder.h in Headers */,
441458
EA52499A1DC7D8B800AF6685 /* OptimizelySDKShared.h in Headers */,
442459
2DB3D1801DC8181100ECF72E /* OPTLYManagerBuilder.h in Headers */,
460+
2DCC51241DDE3C90006C9815 /* OPTLYDatafileManager.h in Headers */,
443461
2D08FB6C1DCA5A99006CA063 /* OPTLYClient.h in Headers */,
444462
EA5247861DC7226400AF6685 /* OPTLYManager.h in Headers */,
445463
EA5247971DC724AF00AF6685 /* OPTLYHTTPRequestManager.h in Headers */,
@@ -825,6 +843,7 @@
825843
EA29D8FF1DCBBE250034A4FE /* OPTLYFileManager.m in Sources */,
826844
EA5247981DC724AF00AF6685 /* OPTLYHTTPRequestManager.m in Sources */,
827845
EA5247871DC7226400AF6685 /* OPTLYManager.m in Sources */,
846+
2DCC51261DDE3CA4006C9815 /* OPTLYDatafileManager.m in Sources */,
828847
2D08FB6E1DCA5B3D006CA063 /* OPTLYClient.m in Sources */,
829848
2D08FBA21DCA5FB3006CA063 /* OPTLYClientBuilder.m in Sources */,
830849
EA52479C1DC724AF00AF6685 /* OPTLYNetworkService.m in Sources */,
@@ -860,6 +879,7 @@
860879
2D08FBA31DCA5FB3006CA063 /* OPTLYClientBuilder.m in Sources */,
861880
EA52479D1DC724AF00AF6685 /* OPTLYNetworkService.m in Sources */,
862881
2DB3D1811DC8181400ECF72E /* OPTLYManagerBuilder.m in Sources */,
882+
2DCC51271DDE3CA4006C9815 /* OPTLYDatafileManager.m in Sources */,
863883
);
864884
runOnlyForDeploymentPostprocessing = 0;
865885
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/****************************************************************************
2+
* Copyright 2016, 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 <Foundation/Foundation.h>
18+
#import <OptimizelySDKCore/OPTLYErrorHandler.h>
19+
#import <OptimizelySDKCore/OPTLYLogger.h>
20+
#import <OptimizelySDKShared/OPTLYHTTPRequestManager.h>
21+
22+
23+
@protocol OPTLYErrorHandler, OPTLYLogger;
24+
25+
@protocol OPTLYDatafileManager <NSObject>
26+
27+
/**
28+
* Download the datafile for the project ID
29+
* @param projectId The project ID of the datafile to request.
30+
* @param completion Completion handler.
31+
*/
32+
- (void)downloadDatafile:(nonnull NSString *)projectId
33+
completionHandler:(nullable OPTLYHTTPRequestManagerResponse)completion;
34+
35+
@end
36+
37+
@interface OPTLYDatafileManagerUtility : NSObject
38+
39+
/**
40+
* Utility method to check if a class conforms to the OPTLYDatafileManager protocol
41+
* This method uses compile and run time checks
42+
*/
43+
+ (BOOL)conformsToOPTLYDatafileManagerProtocol:(nonnull Class)instanceClass;
44+
45+
@end
46+
47+
@interface OPTLYDatafileManagerNoOp : NSObject<OPTLYDatafileManager>
48+
49+
@end
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/****************************************************************************
2+
* Copyright 2016, 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 "OPTLYDatafileManager.h"
18+
19+
@implementation OPTLYDatafileManagerUtility
20+
21+
+ (BOOL)conformsToOPTLYDatafileManagerProtocol:(Class)instanceClass {
22+
// compile time check
23+
BOOL validProtocolDeclaration = [instanceClass conformsToProtocol:@protocol(OPTLYDatafileManager)];
24+
25+
// runtime check
26+
BOOL implementsDownloadDatafileMethod = [instanceClass instancesRespondToSelector:@selector(downloadDatafile:completionHandler:)];
27+
28+
return validProtocolDeclaration && implementsDownloadDatafileMethod;
29+
}
30+
31+
@end
32+
33+
@implementation OPTLYDatafileManagerNoOp
34+
35+
- (void)downloadDatafile:(NSString *)projectId completionHandler:(OPTLYHTTPRequestManagerResponse)completion {
36+
completion(nil, nil, nil);
37+
return;
38+
}
39+
40+
@end

OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
@property (nonatomic, readonly, strong, nonnull) NSString *projectId;
2626
/// The default datafile to initialize an Optimizely Client with
2727
@property (nonatomic, readwrite, strong, nullable) NSData *datafile;
28+
/// The datafile manager that will download the datafile for the manager
29+
@property (nonatomic, readwrite, strong, nullable) id<OPTLYDatafileManager> datafileManager;
2830
/// The error handler to be used for the manager, client, and all subcomponents
2931
@property (nonatomic, readwrite, strong, nullable) id<OPTLYErrorHandler> errorHandler;
3032
/// The event dispatcher to initialize an Optimizely Client with

OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ - (instancetype)initWithBuilder:(OPTLYManagerBuilder *)builder {
5252
_errorHandler = builder.errorHandler;
5353
_eventDispatcher = builder.eventDispatcher;
5454
_logger = builder.logger;
55-
// TODO: Josh W. initialize datafile manager
55+
// initialize datafile manager
56+
_datafileManager = builder.datafileManager;
5657
// TODO: Josh W. initialize event dispatcher
5758
// TODO: Josh W. initialize user experiment record
5859
}

OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#import <Foundation/Foundation.h>
1818

19-
@protocol OPTLYErrorHandler, OPTLYEventDispatcher, OPTLYLogger;
19+
@protocol OPTLYDatafileManager, OPTLYErrorHandler, OPTLYEventDispatcher, OPTLYLogger;
2020

2121
@class OPTLYManagerBuilder;
2222

@@ -30,6 +30,8 @@ typedef void (^OPTLYManagerBuilderBlock)(OPTLYManagerBuilder * _Nullable builder
3030
@property (nonatomic, readwrite) NSTimeInterval eventDispatchInterval;
3131
/// The ID of the Optimizely Project the manager will oversee
3232
@property (nonatomic, readwrite, strong, nonnull) NSString *projectId;
33+
/// The datafile manager to be used for the manager
34+
@property (nonatomic, readwrite, strong, nonnull) id<OPTLYDatafileManager> datafileManager;
3335
/// The error handler to be used for the manager, client, and all subcomponents
3436
@property (nonatomic, readwrite, strong, nullable) id<OPTLYErrorHandler> errorHandler;
3537
/// The event dispatcher to initialize an Optimizely Client with

OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
***************************************************************************/
1616

1717
#import "OPTLYManagerBuilder.h"
18+
#import "OPTLYDatafileManager.h"
1819
#import <OptimizelySDKCore/OPTLYErrorHandler.h>
1920
#import <OptimizelySDKCore/OPTLYEventDispatcher.h>
2021
#import <OptimizelySDKCore/OPTLYLogger.h>
22+
#import <OptimizelySDKShared/OPTLYDatafileManager.h>
2123

2224
@implementation OPTLYManagerBuilder
2325

@@ -34,10 +36,20 @@ - (id)initWithBlock:(OPTLYManagerBuilderBlock)block {
3436
self = [super init];
3537
if (self != nil) {
3638
block(self);
39+
if (![OPTLYDatafileManagerUtility conformsToOPTLYDatafileManagerProtocol:[self.datafileManager class]]) {
40+
return nil;
41+
}
3742
}
3843
return self;
3944
}
4045

46+
- (id<OPTLYDatafileManager>)datafileManager {
47+
if (!_datafileManager) {
48+
_datafileManager = [[OPTLYDatafileManagerNoOp alloc] init];
49+
}
50+
return _datafileManager;
51+
}
52+
4153
- (id<OPTLYErrorHandler>)errorHandler {
4254
if (!_errorHandler) {
4355
_errorHandler = [[OPTLYErrorHandlerNoOp alloc] init];

OptimizelySDKShared/OptimizelySDKShared/OptimizelySDKShared.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#import "OPTLYManager.h"
1919
#import "OPTLYHTTPRequestManager.h"
2020
#import "OPTLYNetworkService.h"
21+
#import "OPTLYDatafileManager.h"
2122
#import "OPTLYDataStore.h"
2223
#import "OPTLYClient.h"
2324
#import "OPTLYFileManager.h"

OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerBuilderTest.m

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,17 @@
2121
#import <OptimizelySDKCore/OPTLYLogger.h>
2222
#import "OPTLYManager.h"
2323
#import "OPTLYManagerBuilder.h"
24+
#import "OPTLYDatafileManager.h"
2425

2526
static NSString *const kProjectId = @"6372300739";
2627

28+
@interface OPTLYFakeDatafileManagerClass : NSObject <OPTLYDatafileManager>
29+
30+
@end
31+
32+
@implementation OPTLYFakeDatafileManagerClass
33+
@end
34+
2735
@interface OPTLYManagerBuilderTest : XCTestCase
2836

2937
@end
@@ -52,6 +60,7 @@ - (void)testManagerBuilderBuildsSuccessfulWithProjectId {
5260
XCTAssertNotNil(manager.errorHandler);
5361
XCTAssertNotNil(manager.eventDispatcher);
5462
XCTAssertNotNil(manager.logger);
63+
XCTAssertNotNil(manager.datafileManager);
5564
}
5665

5766
- (void)testBuilderCanAssignErrorHandler {
@@ -73,7 +82,7 @@ - (void)testBuilderCanAssignErrorHandler {
7382
}
7483

7584
- (void)testBuilderCanAssignEventDispatcher {
76-
id<OPTLYEventDispatcher> eventDispatcher = [[NSObject alloc] init];
85+
OPTLYEventDispatcherNoOp *eventDispatcher = [[OPTLYEventDispatcherNoOp alloc] init];
7786

7887
OPTLYManager *defaultManager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) {
7988
builder.projectId = kProjectId;
@@ -108,5 +117,33 @@ - (void)testBuilderCanAssignLogger {
108117
XCTAssertEqual(logger, customManager.logger, @"Should be the same object with custom builder");
109118
}
110119

120+
- (void)testBuilderCanAssignDatafileManager {
121+
OPTLYDatafileManagerNoOp *datafileManager = [[OPTLYDatafileManagerNoOp alloc] init];
122+
123+
OPTLYManager *defaultManager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) {
124+
builder.projectId = kProjectId;
125+
}];
126+
127+
OPTLYManager *customManager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) {
128+
builder.projectId = kProjectId;
129+
builder.datafileManager = datafileManager;
130+
}];
131+
132+
XCTAssertNotNil(customManager);
133+
XCTAssertNotNil(customManager.datafileManager);
134+
XCTAssertNotEqual(customManager.datafileManager, defaultManager.datafileManager);
135+
XCTAssertEqual(datafileManager, customManager.datafileManager);
136+
}
137+
138+
- (void)testBuilderCannotAssignDatafileManagerThatDoesNotConformToProtocol {
139+
OPTLYFakeDatafileManagerClass *object = [[OPTLYFakeDatafileManagerClass alloc] init];
140+
141+
OPTLYManager *managerWithObject = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) {
142+
builder.projectId = kProjectId;
143+
builder.datafileManager = object;
144+
}];
145+
146+
XCTAssertNil(managerWithObject);
147+
}
111148

112149
@end

0 commit comments

Comments
 (0)