Skip to content

Instantly share code, notes, and snippets.

@SamClewlow
Created February 4, 2016 13:23
Show Gist options
  • Save SamClewlow/9b1ece31bef3cfd380f3 to your computer and use it in GitHub Desktop.
Save SamClewlow/9b1ece31bef3cfd380f3 to your computer and use it in GitHub Desktop.
A basic NSURLProtocol subclass useful for capturing and mocking JSON responses
#import "SCMockURLProtocol.h"
#define HARVEST_MODE NO
#define MOCK_MODE YES
@interface SCMockURLProtocol()<NSURLConnectionDelegate>
@property (nonatomic, strong) NSURLRequest *currentRequest;
@property (nonatomic, strong) NSURLSessionTask *currentTask;
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSMutableData *responseData;
@end
@implementation SCMockURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if (!MOCK_MODE) return NO;
if (!HARVEST_MODE) {
// Check if request is one we want to handle
NSLog(@"%s, %s called %ld times, with request: %@", __FILE__, __FUNCTION__,(long)0, request.URL.absoluteString);
if ([SCMockURLProtocol haveMockJSONForURL:request.URL]) {
return YES;
} else {
return NO;
}
} else {
static NSInteger callCount = 0;
callCount++;
NSLog(@"%s, %s called %ld times, with request: %@", __FILE__, __FUNCTION__,(long)callCount, request.URL.absoluteString);
if ([NSURLProtocol propertyForKey:@"MyURLProtocolHandledKey" inRequest:request]) {
return NO;
}
return YES;
}
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
if (!HARVEST_MODE) {
// Call got response
NSHTTPURLResponse *response = [self getResponseForURL:self.request.URL];
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
// Call did load data
NSData *responseData = [self getResponseDataForURL:self.request.URL];
[self.client URLProtocol:self didLoadData:responseData];
// Finish the load
[self.client URLProtocolDidFinishLoading:self];
} else {
// Let the connection pass through and load from NSURL connection
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:@"MyURLProtocolHandledKey" inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
}
- (void)stopLoading {
[self.connection cancel];
self.connection = nil;
}
#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if (HARVEST_MODE) {
// Dump Response
NSLog(@"Response of URL %@: %@", self.request.URL, response);
}
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// We are only interested in capturing data in harvest mode
if (HARVEST_MODE) {
if (self.responseData == nil) {
self.responseData = [[NSMutableData alloc] initWithData:data];
} else {
[self.responseData appendData:data];
}
}
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (HARVEST_MODE) {
[self dumpJSONData:self.responseData];
}
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
#pragma mark - Helpers
- (NSHTTPURLResponse *)getResponseForURL:(NSURL *)URL {
NSString *fileLocation = URL.absoluteString.lastPathComponent;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[fileLocation stringByDeletingPathExtension] ofType:@"json"];
NSData* data = [NSData dataWithContentsOfFile:filePath];
__autoreleasing NSError* error = nil;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error][@"response"];
/*
{
"status code": 200,
"headers" : {
"Access-Control-Allow-Methods" : "*",
"Access-Control-Allow-Origin" : "*",
"Connection" : "keep-alive",
"Content-Encoding" : "gzip",
"Content-Length" : 13696,
"Content-Type" : "application/json; charset=utf-8",
"Date" : "Sun, 31 Jan 2016 15:11:13 GMT",
"Server" : "nginx/1.6.0",
"X-Parse-Platform" : "G1",
"X-Runtime" : "0.981976"
}
}
*/
if (error != nil) {
return nil;
} else {
return [[NSHTTPURLResponse alloc] initWithURL:self.request.URL
statusCode:[responseDict[@"status code"] integerValue]
HTTPVersion:@"HTTP/1.1"
headerFields:responseDict[@"headers"]];
}
}
- (NSData *)getResponseDataForURL:(NSURL *)URL {
NSString *fileLocation = URL.absoluteString.lastPathComponent;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[fileLocation stringByDeletingPathExtension] ofType:@"json"];
NSData* data = [NSData dataWithContentsOfFile:filePath];
__autoreleasing NSError* error = nil;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error][@"response_data"];
return [NSJSONSerialization dataWithJSONObject:responseDict options:NSJSONWritingPrettyPrinted error:nil];
}
+ (BOOL)haveMockJSONForURL:(NSURL *)URL {
NSString *fileLocation = URL.absoluteString.lastPathComponent;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[fileLocation stringByDeletingPathExtension] ofType:@"json"];
if (filePath != nil) {
return YES;
} else {
return NO;
}
}
- (void)dumpJSONData:(NSData *)responseData {
NSString *JSONString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(@"/n/n/n ****** /n Response for URL: %@ /n/n %@, /n/n *******", self.request.URL.absoluteString, JSONString);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment