AutoCat2/AutoCatCoreTests/Api/Lib/MockURLProtocol.swift

97 lines
3.2 KiB
Swift

import Foundation
extension URL {
public var queryParameters: [String: String]? {
guard
let components = URLComponents(url: self, resolvingAgainstBaseURL: true),
let queryItems = components.queryItems else { return nil }
return queryItems.reduce(into: [String: String]()) { (result, item) in
result[item.name] = item.value
}
}
}
extension URLRequest {
func bodySteamAsJSON() -> [String: Any]? {
guard let bodyStream = self.httpBodyStream else { return nil }
bodyStream.open()
// Will read 16 chars per iteration. Can use bigger buffer if needed
let bufferSize: Int = 16
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
var dat = Data()
while bodyStream.hasBytesAvailable {
let readDat = bodyStream.read(buffer, maxLength: bufferSize)
dat.append(buffer, count: readDat)
}
buffer.deallocate()
bodyStream.close()
return try? JSONSerialization.jsonObject(with: dat, options: JSONSerialization.ReadingOptions.allowFragments) as? [String: Any]
}
}
class MockURLProtocol: URLProtocol {
static var baseUrl: String = ""
static var apiMethodMocks: [ApiMethodMockProtocol] = []
override class func canInit(with request: URLRequest) -> Bool {
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
guard let requestUrl = request.url else { return }
let methodMock = MockURLProtocol.apiMethodMocks.first {
return request.url?.absoluteString == MockURLProtocol.baseUrl + $0.path
&& request.httpMethod == $0.httpMethod
}
guard let methodMock = methodMock else {
if let response = HTTPURLResponse(url: requestUrl, statusCode: 404, httpVersion: "HTTP/2", headerFields: [:]) {
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
client?.urlProtocolDidFinishLoading(self)
}
return
}
// Assuming we use url parameters in GET requests and JSON-encoded body in everything else
var params: [String: Any] = [:]
if request.httpBodyStream != nil {
if let bodyDict = request.bodySteamAsJSON() {
params = bodyDict
}
} else {
if let urlParams = requestUrl.queryParameters {
params = urlParams
}
}
let result = methodMock.response(headers: request.allHTTPHeaderFields ?? [:], params: params)
guard let response = HTTPURLResponse(url: requestUrl, statusCode: result.status, httpVersion: "HTTP/2", headerFields: [:]) else { return }
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
if let data = result.data {
client?.urlProtocol(self, didLoad: data)
}
client?.urlProtocolDidFinishLoading(self)
//client?.urlProtocol(self, didFailWithError: error)
}
override func stopLoading() {
}
}