Skip to content

Commit 1fbd379

Browse files
committed
Integrating feature/namedStubs
2 parents 964ace6 + 4c54ddc commit 1fbd379

File tree

7 files changed

+186
-83
lines changed

7 files changed

+186
-83
lines changed

OHHTTPStubs/OHHTTPStubs.h

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@
3434

3535
typedef BOOL(^OHHTTPStubsTestBlock)(NSURLRequest* request);
3636
typedef OHHTTPStubsResponse*(^OHHTTPStubsResponseBlock)(NSURLRequest* request);
37-
typedef id OHHTTPStubsID;
37+
38+
@protocol OHHTTPStubsDescriptor
39+
/*! Arbitrary name that you can set and get to describe your stub. Use it as your own convenience. */
40+
@property(nonatomic, strong) NSString* name;
41+
@end
3842

3943
////////////////////////////////////////////////////////////////////////////////
4044
#pragma mark - Interface
@@ -46,18 +50,23 @@ typedef id OHHTTPStubsID;
4650
#pragma mark - Class Methods
4751

4852
/*! Dedicated method to add a stub
49-
@param testBlock Block that should return `YES` if the request passed as parameter should be stubbed with the response block, `NO` if it should hit the real world (or be managed by another stub).
53+
@param testBlock Block that should return `YES` if the request passed as parameter should be stubbed with the response block,
54+
and `NO` if it should hit the real world (or be managed by another stub).
5055
@param responseBlock Block that will return the `OHHTTPStubsResponse` (response to use for stubbing) corresponding to the given request
51-
@return an opaque object that uniquely identifies the stub and can be later used to remove it with `removeStub:`
56+
@return a stub descriptor that uniquely identifies the stub and can be later used to remove it with `removeStub:`.
57+
@note The returned stub descriptor is retained (`__strong` reference) by `OHHTTPStubs` until it is removed
58+
(with one of the `removeStub:`/`removeLastStub`/`removeAllStubs` methods); it is thus recommended to
59+
keep it in a `__weak` storage (and not `__strong`) in your app code, to let the stub descriptor be destroyed
60+
and let the variable go back to `nil` automatically when the stub is removed.
5261
*/
53-
+(OHHTTPStubsID)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock
54-
withStubResponse:(OHHTTPStubsResponseBlock)responseBlock;
62+
+(id<OHHTTPStubsDescriptor>)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock
63+
withStubResponse:(OHHTTPStubsResponseBlock)responseBlock;
5564

5665
/*! Remove a stub from the list of stubs
57-
@param stubID the opaque object that has been returned when adding the stub using `stubRequestsPassingTest:withStubResponse:`
66+
@param stubDesc the stub descriptor that has been returned when adding the stub using `stubRequestsPassingTest:withStubResponse:`
5867
@return `YES` if the stub has been successfully removed, `NO` if the parameter was not a valid stub identifier
5968
*/
60-
+(BOOL)removeStub:(OHHTTPStubsID)stubID;
69+
+(BOOL)removeStub:(id<OHHTTPStubsDescriptor>)stubDesc;
6170

6271
/*! Remove the last added stub from the stubs list */
6372
+(void)removeLastStub;
@@ -70,6 +79,20 @@ typedef id OHHTTPStubsID;
7079
*/
7180
+(void)setEnabled:(BOOL)enabled;
7281

82+
#pragma mark - Debug Methods
83+
84+
/*! List all the installed stubs
85+
@return An array of id<OHHTTPStubsDescriptor> objects currently installed. Useful for debug.
86+
*/
87+
+(NSArray*)allStubs;
88+
89+
/*! Setup a block to be called each time a stub is triggered.
90+
91+
Useful if you want to log all your requests being stubbed for example and see which stub was used to respond to each request.
92+
@param block The block to call each time a request is being stubbed by OHHTTPStubs. Set it to `nil` to do nothing. Defaults is `nil`.
93+
*/
94+
+(void)onStubActivation:( void(^)(NSURLRequest* request, id<OHHTTPStubsDescriptor> stub) )block;
95+
7396
@end
7497

7598

@@ -80,7 +103,9 @@ typedef id OHHTTPStubsID;
80103

81104
@interface OHHTTPStubs (Deprecated)
82105

83-
typedef id OHHTTPStubsRequestHandlerID __attribute__((deprecated("Use OHHTTPStubsID instead")));
106+
typedef id OHHTTPStubsRequestHandlerID __deprecated_msg("Use OHHTTPStubsDescriptor* instead");
107+
typedef id<OHHTTPStubsDescriptor> OHHTTPStubsID __deprecated_msg("Use id<OHHTTPStubsDescriptor> instead");
108+
84109

85110
/*! @warning This method is deprecated
86111
@@ -92,22 +117,22 @@ typedef id OHHTTPStubsRequestHandlerID __attribute__((deprecated("Use OHHTTPStub
92117
@return an opaque object that uniquely identifies the handler and can be later used to remove it with `removeRequestHandler:`
93118
*/
94119
+(OHHTTPStubsRequestHandlerID)addRequestHandler:(OHHTTPStubsResponse*(^)(NSURLRequest* request, BOOL onlyCheck))handler
95-
__attribute__((deprecated("Use stubRequestsPassingTest:withStubResponse: instead")));
120+
__deprecated_msg("Use stubRequestsPassingTest:withStubResponse: instead");
96121

97122
/*! Remove a request handler from the list of stubs
98123
@param handlerID the opaque object that has been returned when adding the handler using `stubRequestsPassingTest:withStubResponse:`
99124
or using `addRequestHandler:`
100125
@return `YES` if the request handler has been successfully removed, `NO` if the parameter was not a valid handler identifier
101126
*/
102127
+(BOOL)removeRequestHandler:(OHHTTPStubsRequestHandlerID)handlerID
103-
__attribute__((deprecated("Use removeStub: instead")));
128+
__deprecated_msg("Use removeStub: instead");
104129

105130
/*! Remove the last added request handler from the stubs list */
106131
+(void)removeLastRequestHandler
107-
__attribute__((deprecated("Use removeLastStub instead")));
132+
__deprecated_msg("Use removeLastStub instead");
108133

109134
/*! Remove all the requests handlers from the stubs list. */
110135
+(void)removeAllRequestHandlers
111-
__attribute__((deprecated("Use removeAllStubs instead")));
136+
__deprecated_msg("Use removeAllStubs instead");
112137

113138
@end

OHHTTPStubs/OHHTTPStubs.m

Lines changed: 101 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,51 @@
3636
#pragma mark - Types & Constants
3737

3838
@interface OHHTTPStubsProtocol : NSURLProtocol @end
39-
typedef OHHTTPStubsResponse*(^OHHTTPStubsRequestHandler)(NSURLRequest* request, BOOL onlyCheck);
4039

4140
static NSTimeInterval const kSlotTime = 0.25; // Must be >0. We will send a chunk of the data from the stream each 'slotTime' seconds
4241

4342
////////////////////////////////////////////////////////////////////////////////
44-
#pragma mark - Private Interface
43+
#pragma mark - Private Interfaces
4544

4645
@interface OHHTTPStubs()
4746
+ (instancetype)sharedInstance;
48-
@property(atomic, strong) NSMutableArray* requestHandlers;
47+
@property(atomic, copy) NSMutableArray* stubDescriptors;
48+
@property(atomic, copy) void (^onStubActivationBlock)(NSURLRequest*, id<OHHTTPStubsDescriptor>);
4949
@end
5050

51+
@interface OHHTTPStubsDescriptor : NSObject <OHHTTPStubsDescriptor>
52+
@property(atomic, copy) OHHTTPStubsTestBlock testBlock;
53+
@property(atomic, copy) OHHTTPStubsResponseBlock responseBlock;
54+
@end
55+
56+
////////////////////////////////////////////////////////////////////////////////
57+
#pragma mark - OHHTTPStubsDescriptor Implementation
58+
59+
@implementation OHHTTPStubsDescriptor
60+
61+
@synthesize name = _name;
62+
63+
+(instancetype)stubDescriptorWithTestBlock:(OHHTTPStubsTestBlock)testBlock
64+
responseBlock:(OHHTTPStubsResponseBlock)responseBlock
65+
{
66+
OHHTTPStubsDescriptor* stub = [OHHTTPStubsDescriptor new];
67+
stub.testBlock = testBlock;
68+
stub.responseBlock = responseBlock;
69+
return stub;
70+
}
71+
72+
-(NSString*)description
73+
{
74+
return [NSString stringWithFormat:@"<%@ %p : %@>", self.class, self, self.name];
75+
}
76+
77+
@end
78+
79+
80+
81+
5182
////////////////////////////////////////////////////////////////////////////////
52-
#pragma mark - Implementation
83+
#pragma mark - OHHTTPStubs Implementation
5384

5485
@implementation OHHTTPStubs
5586

@@ -76,7 +107,7 @@ - (id)init
76107
self = [super init];
77108
if (self)
78109
{
79-
_requestHandlers = [NSMutableArray array];
110+
_stubDescriptors = [NSMutableArray array];
80111
[self.class setEnabled:YES];
81112
}
82113
return self;
@@ -90,34 +121,26 @@ - (void)dealloc
90121
////////////////////////////////////////////////////////////////////////////////
91122
#pragma mark - Public class methods
92123

93-
+(OHHTTPStubsID)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock
94-
withStubResponse:(OHHTTPStubsResponseBlock)responseBlock
124+
+(id<OHHTTPStubsDescriptor>)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock
125+
withStubResponse:(OHHTTPStubsResponseBlock)responseBlock
95126
{
96-
return [self.sharedInstance addRequestHandler:^OHHTTPStubsResponse *(NSURLRequest *request, BOOL onlyCheck)
97-
{
98-
BOOL shouldStub = testBlock ? testBlock(request) : YES;
99-
if (onlyCheck)
100-
{
101-
return shouldStub ? (OHHTTPStubsResponse*)@"DummyStub" : (OHHTTPStubsResponse*)nil;
102-
}
103-
else
104-
{
105-
return (responseBlock && shouldStub) ? responseBlock(request) : nil;
106-
}
107-
}];
127+
OHHTTPStubsDescriptor* stub = [OHHTTPStubsDescriptor stubDescriptorWithTestBlock:testBlock
128+
responseBlock:responseBlock];
129+
[OHHTTPStubs.sharedInstance addStub:stub];
130+
return stub;
108131
}
109132

110-
+(BOOL)removeStub:(OHHTTPStubsID)stubID
133+
+(BOOL)removeStub:(id<OHHTTPStubsDescriptor>)stubDesc
111134
{
112-
return [self.sharedInstance removeRequestHandler:stubID];
135+
return [OHHTTPStubs.sharedInstance removeStub:stubDesc];
113136
}
114137
+(void)removeLastStub
115138
{
116-
[self.sharedInstance removeLastRequestHandler];
139+
[OHHTTPStubs.sharedInstance removeLastStub];
117140
}
118141
+(void)removeAllStubs
119142
{
120-
[self.sharedInstance removeAllRequestHandlers];
143+
[OHHTTPStubs.sharedInstance removeAllStubs];
121144
}
122145

123146
+(void)setEnabled:(BOOL)enabled
@@ -130,66 +153,77 @@ +(void)setEnabled:(BOOL)enabled
130153
else if (!enabled && currentEnabledState)
131154
{
132155
// Force instanciate sharedInstance to avoid it being created later and this turning setEnabled to YES again
133-
(void)self.sharedInstance; // This way if we call [setEnabled:NO] before any call to sharedInstance it will be kept disabled
156+
(void)OHHTTPStubs.sharedInstance; // This way if we call [setEnabled:NO] before any call to sharedInstance it will be kept disabled
134157
[NSURLProtocol unregisterClass:OHHTTPStubsProtocol.class];
135158
}
136159
currentEnabledState = enabled;
137160
}
138161

162+
+(NSArray*)allStubs
163+
{
164+
return [OHHTTPStubs.sharedInstance stubDescriptors];
165+
}
166+
167+
+(void)onStubActivation:( void(^)(NSURLRequest* request, id<OHHTTPStubsDescriptor> stub) )block
168+
{
169+
[OHHTTPStubs.sharedInstance setOnStubActivationBlock:block];
170+
}
171+
172+
173+
139174
////////////////////////////////////////////////////////////////////////////////
140175
#pragma mark - Private instance methods
141176

142-
-(OHHTTPStubsID)addRequestHandler:(OHHTTPStubsRequestHandler)handler
177+
-(void)addStub:(OHHTTPStubsDescriptor*)stubDesc
143178
{
144-
OHHTTPStubsRequestHandler handlerCopy = [handler copy];
145-
@synchronized(_requestHandlers)
179+
@synchronized(_stubDescriptors)
146180
{
147-
[_requestHandlers addObject:handlerCopy];
181+
[_stubDescriptors addObject:stubDesc];
148182
}
149-
return handlerCopy;
150183
}
151184

152-
-(BOOL)removeRequestHandler:(OHHTTPStubsID)stubID
185+
-(BOOL)removeStub:(id<OHHTTPStubsDescriptor>)stubDesc
153186
{
154187
BOOL handlerFound = NO;
155-
@synchronized(_requestHandlers)
188+
@synchronized(_stubDescriptors)
156189
{
157-
handlerFound = [self.requestHandlers containsObject:stubID];
158-
[_requestHandlers removeObject:stubID];
190+
handlerFound = [_stubDescriptors containsObject:stubDesc];
191+
[_stubDescriptors removeObject:stubDesc];
159192
}
160193
return handlerFound;
161194
}
162-
-(void)removeLastRequestHandler
195+
196+
-(void)removeLastStub
163197
{
164-
@synchronized(_requestHandlers)
198+
@synchronized(_stubDescriptors)
165199
{
166-
[_requestHandlers removeLastObject];
200+
[_stubDescriptors removeLastObject];
167201
}
168202
}
169203

170-
-(void)removeAllRequestHandlers
204+
-(void)removeAllStubs
171205
{
172-
@synchronized(_requestHandlers)
206+
@synchronized(_stubDescriptors)
173207
{
174-
[_requestHandlers removeAllObjects];
208+
[_stubDescriptors removeAllObjects];
175209
}
176210
}
177211

178-
////////////////////////////////////////////////////////////////////////////////
179-
#pragma mark - Private methods
180-
181-
- (OHHTTPStubsResponse*)responseForRequest:(NSURLRequest*)request onlyCheck:(BOOL)onlyCheck
212+
- (OHHTTPStubsDescriptor*)firstStubPassingTestForRequest:(NSURLRequest*)request
182213
{
183-
OHHTTPStubsResponse* response = nil;
184-
@synchronized(_requestHandlers)
214+
OHHTTPStubsDescriptor* foundStub = nil;
215+
@synchronized(_stubDescriptors)
185216
{
186-
for(OHHTTPStubsRequestHandler handler in _requestHandlers.reverseObjectEnumerator)
217+
for(OHHTTPStubsDescriptor* stub in _stubDescriptors.reverseObjectEnumerator)
187218
{
188-
response = handler(request, onlyCheck);
189-
if (response) break;
219+
if (stub.testBlock(request))
220+
{
221+
foundStub = stub;
222+
break;
223+
}
190224
}
191225
}
192-
return response;
226+
return foundStub;
193227
}
194228

195229
@end
@@ -201,11 +235,18 @@ - (OHHTTPStubsResponse*)responseForRequest:(NSURLRequest*)request onlyCheck:(BOO
201235
#pragma mark - Deprecated Methods (will be removed in 3.0)
202236
/*! @name Deprecated Methods */
203237

238+
typedef OHHTTPStubsResponse*(^OHHTTPStubsRequestHandler)(NSURLRequest* request, BOOL onlyCheck) __deprecated;
239+
204240
@implementation OHHTTPStubs (Deprecated)
205241

206242
+(OHHTTPStubsRequestHandlerID)addRequestHandler:(OHHTTPStubsRequestHandler)handler
207243
{
208-
return [self.sharedInstance addRequestHandler:handler];
244+
return [OHHTTPStubsDescriptor stubDescriptorWithTestBlock:^BOOL(NSURLRequest *request)
245+
{
246+
return (handler(request, YES) != nil);
247+
} responseBlock:^OHHTTPStubsResponse *(NSURLRequest *request) {
248+
return handler(request, NO);
249+
}];
209250
}
210251

211252
+(BOOL)removeRequestHandler:(OHHTTPStubsRequestHandlerID)handler
@@ -242,7 +283,7 @@ @implementation OHHTTPStubsProtocol
242283

243284
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
244285
{
245-
return ([OHHTTPStubs.sharedInstance responseForRequest:request onlyCheck:YES] != nil);
286+
return ([OHHTTPStubs.sharedInstance firstStubPassingTestForRequest:request] != nil);
246287
}
247288

248289
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)response client:(id<NSURLProtocolClient>)client
@@ -266,7 +307,14 @@ - (void)startLoading
266307
NSURLRequest* request = self.request;
267308
id<NSURLProtocolClient> client = self.client;
268309

269-
OHHTTPStubsResponse* responseStub = [OHHTTPStubs.sharedInstance responseForRequest:request onlyCheck:NO];
310+
OHHTTPStubsDescriptor* stub = [OHHTTPStubs.sharedInstance firstStubPassingTestForRequest:request];
311+
NSAssert(stub, @"At the time startLoading is called, canInitRequest should have assured that stub is != nil beforehand");
312+
OHHTTPStubsResponse* responseStub = stub.responseBlock(request);
313+
314+
if (OHHTTPStubs.sharedInstance.onStubActivationBlock)
315+
{
316+
OHHTTPStubs.sharedInstance.onStubActivationBlock(request, stub);
317+
}
270318

271319
if (responseStub.error == nil)
272320
{
@@ -456,7 +504,7 @@ - (void) streamDataForClient:(id<NSURLProtocolClient>)client
456504
// Delayed execution utility methods
457505
/////////////////////////////////////////////
458506

459-
void execute_after(NSTimeInterval delayInSeconds, dispatch_block_t block)
507+
static void execute_after(NSTimeInterval delayInSeconds, dispatch_block_t block)
460508
{
461509
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
462510
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);

OHHTTPStubs/OHHTTPStubsResponse+HTTPMessage.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
*/
5757
+(instancetype)responseWithHTTPMessageData:(NSData*)responseData
5858
responseTime:(NSTimeInterval)responseTime
59-
__attribute__((deprecated("Use responseWithHTTPMessageData: and requestTime:responseTime: instead")));
59+
__deprecated_msg("Use responseWithHTTPMessageData: and requestTime:responseTime: instead");
6060

6161
/*! @warning This method is deprecated
6262
@@ -74,7 +74,7 @@ __attribute__((deprecated("Use responseWithHTTPMessageData: and requestTime:resp
7474
+(instancetype)responseNamed:(NSString*)responseName
7575
fromBundle:(NSBundle*)bundle
7676
responseTime:(NSTimeInterval)responseTime
77-
__attribute__((deprecated("Use responseNamed:inBundle: and requestTime:responseTime: instead")));
77+
__deprecated_msg("Use responseNamed:inBundle: and requestTime:responseTime: instead");
7878

7979

8080
@end

OHHTTPStubs/OHHTTPStubsResponse+JSON.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@
5454
statusCode:(int)statusCode
5555
responseTime:(NSTimeInterval)responseTime
5656
headers:(NSDictionary*)httpHeaders
57-
__attribute__((deprecated("Use responseWithJSONObject:statusCode:headers: and requestTime:responseTime: instead")));
57+
__deprecated_msg("Use responseWithJSONObject:statusCode:headers: and requestTime:responseTime: instead");
5858

5959
@end

0 commit comments

Comments
 (0)