Skip to content

Instantly share code, notes, and snippets.

@SamClewlow
Created September 6, 2016 10:13
Show Gist options
  • Save SamClewlow/c00157b710fda79a1da6d6cdb0dc2186 to your computer and use it in GitHub Desktop.
Save SamClewlow/c00157b710fda79a1da6d6cdb0dc2186 to your computer and use it in GitHub Desktop.
import UIKit
class MockURLProtocol: NSURLProtocol, NSURLConnectionDelegate {
// MARK:- Constants
static let harvestMode = false
static let mockMode = true
// MARK:- Properties
var currentRequest: NSURLRequest?
var currentTask: NSURLSessionTask?
var connection: NSURLConnection?
var responseData: NSMutableData?
static var callCount: Int = 0
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
if !mockMode { return false }
if !harvestMode {
// Check if request is one we want to handle
print("\(#file), \(#function) called \(Int(0)) times, with request: \(request.URL!.absoluteString)")
if MockURLProtocol.haveMockJSONForURL(request.URL!) {
return true
} else {
return false
}
} else {
callCount = callCount + 1
print("\(#file), \(#function) called \(Int(callCount)) times, with request: \(request.URL!.absoluteString)")
if (NSURLProtocol.propertyForKey("MyURLProtocolHandledKey", inRequest:request) != nil) {
return false;
}
return true;
}
}
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
return request
}
override class func requestIsCacheEquivalent(a:NSURLRequest, toRequest: NSURLRequest) -> Bool {
return super.requestIsCacheEquivalent(a, toRequest:toRequest)
}
override func startLoading() {
if !MockURLProtocol.harvestMode {
// Call got response
let response: NSHTTPURLResponse = getResponseForURL(self.request.URL!)
self.client!.URLProtocol(self, didReceiveResponse:response, cacheStoragePolicy:.NotAllowed)
// Call did load data
let responseData: NSData = 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
var newRequest: NSMutableURLRequest = self.request.mutableCopy() as! NSMutableURLRequest
NSURLProtocol.setProperty(true, forKey:"MyURLProtocolHandledKey", inRequest:newRequest)
self.connection = NSURLConnection(request: newRequest, delegate:self)
}
}
override func stopLoading() {
self.connection!.cancel()
self.connection = nil
}
// MARK: - NSURLConnectionDelegate
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
if MockURLProtocol.harvestMode {
// Dump Response
print("Response of URL \(self.request.URL): \(response)")
}
self.client!.URLProtocol(self, didReceiveResponse:response, cacheStoragePolicy: .NotAllowed)
}
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
// We are only interested in capturing data in harvest mode
if MockURLProtocol.harvestMode {
if self.responseData == nil {
self.responseData = NSMutableData(data: data)
}
else {
self.responseData!.appendData(data)
}
}
self.client!.URLProtocol(self, didLoadData: data)
}
func connectionDidFinishLoading(connection: NSURLConnection) {
if MockURLProtocol.harvestMode {
self.dumpJSONData(self.responseData!)
}
self.client!.URLProtocolDidFinishLoading(self)
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
self.client!.URLProtocol(self, didFailWithError: error)
}
// MARK: - Helpers
func getResponseForURL(URL: NSURL) -> NSHTTPURLResponse {
guard let fileLocation = URL.URLByDeletingPathExtension?.lastPathComponent else {
return getFailureURLResponse()
}
guard let filePath = NSBundle.mainBundle().pathForResource(fileLocation, ofType: "json") else {
return getFailureURLResponse()
}
guard let data = NSData(contentsOfFile: filePath) else {
return getFailureURLResponse()
}
guard let JSONDict: [String: AnyObject] = try! NSJSONSerialization.JSONObjectWithData(data, options: [.AllowFragments]) as? [String: AnyObject] else {
return getFailureURLResponse()
}
guard let responseDict = JSONDict["response"],
let statusCode = (responseDict["statusCode"] as? Int),
let headers = responseDict["headers"] as? [String:String] else {
return getFailureURLResponse()
}
// /*
// {
// "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 let URLResponse = NSHTTPURLResponse(URL: self.request.URL!, statusCode: statusCode, HTTPVersion: "HTTP/1.1", headerFields: headers) {
return URLResponse
} else {
return getFailureURLResponse()
}
}
func getFailureURLResponse() -> NSHTTPURLResponse {
return NSHTTPURLResponse(URL: self.request.URL!, statusCode: 200, HTTPVersion: "HTTP/1.1", headerFields: ["":""])!
}
func getResponseDataForURL(URL: NSURL) -> NSData {
guard let fileLocation = URL.URLByDeletingPathExtension?.lastPathComponent else {
return NSData()
}
guard let filePath = NSBundle.mainBundle().pathForResource(fileLocation, ofType: "json") else {
return NSData()
}
guard let data = NSData(contentsOfFile: filePath) else {
return NSData()
}
guard let JSONDict: [String: AnyObject] = try! NSJSONSerialization.JSONObjectWithData(data, options: [.AllowFragments]) as? [String: AnyObject] else {
return NSData()
}
guard let responseDict = JSONDict["response_data"] else {
return NSData()
}
do {
return try NSJSONSerialization.dataWithJSONObject(responseDict, options: [.PrettyPrinted])
}
catch let error {
print(error)
return NSData()
}
}
class func haveMockJSONForURL(URL: NSURL) -> Bool {
let fileLocation = URL.URLByDeletingPathExtension!.lastPathComponent
let filePath = NSBundle.mainBundle().pathForResource(fileLocation, ofType: "json")
if filePath != nil {
return true
}
else {
return false
}
}
func dumpJSONData(responseData: NSData) {
let JSONString = String(data: responseData, encoding: NSUTF8StringEncoding)
print("/n/n/n ****** /n Response for URL: \(self.request.URL!.absoluteString) /n/n \(JSONString), /n/n *******")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment