// Copyright © 2020 Metabolist. All rights reserved. import Foundation import HTTP public class StubbingURLProtocol: URLProtocol { private static var targetsForURLs = [URL: Target]() private static var stubsForURLs = [URL: HTTPStub]() override public class func canInit(with task: URLSessionTask) -> Bool { true } override public class func canInit(with request: URLRequest) -> Bool { true } override public class func canonicalRequest(for request: URLRequest) -> URLRequest { request } override public func startLoading() { guard let url = request.url, let stub = Self.stubsForURLs[url] ?? Self.stub(request: request, target: Self.targetsForURLs[url]) else { return } switch stub { case let .success((response, data)): client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed) client?.urlProtocol(self, didLoad: data) case let .failure(error): client?.urlProtocol(self, didFailWithError: error) } client?.urlProtocolDidFinishLoading(self) } override public func stopLoading() {} } public extension StubbingURLProtocol { static func setStub(_ stub: HTTPStub, forURL url: URL) { stubsForURLs[url] = stub } } private extension StubbingURLProtocol { class func stub( request: URLRequest, target: Target? = nil, userInfo: [String: Any] = [:]) -> HTTPStub? { guard let url = request.url else { return nil } return (target as? Stubbing)?.stub(url: url) } } extension StubbingURLProtocol: TargetProcessing { public static func process(target: Target) { if let url = try? target.asURLRequest().url { targetsForURLs[url] = target } } }