From 4132309e53a71e19ab5ad1b4de4afee76b9780c8 Mon Sep 17 00:00:00 2001 From: Philip Niedertscheider Date: Thu, 30 Jan 2025 22:29:22 +0100 Subject: [PATCH] feat: add annotation RequestCachePolicy (#59) --- .../Configuration/RequestCachePolicy.swift | 20 +++++ Sources/Postie/Encoder/RequestEncoder.swift | 3 + Sources/Postie/Encoder/RequestEncoding.swift | 9 +++ .../RequestKeyedEncodingContainer.swift | 2 + .../RequestCachePolicyCodingTests.swift | 79 +++++++++++++++++++ 5 files changed, 113 insertions(+) create mode 100644 Sources/Postie/Configuration/RequestCachePolicy.swift create mode 100644 Tests/PostieTests/Configuration/RequestCachePolicyCodingTests.swift diff --git a/Sources/Postie/Configuration/RequestCachePolicy.swift b/Sources/Postie/Configuration/RequestCachePolicy.swift new file mode 100644 index 0000000..1c39773 --- /dev/null +++ b/Sources/Postie/Configuration/RequestCachePolicy.swift @@ -0,0 +1,20 @@ +import Foundation + +@propertyWrapper +public struct RequestCachePolicy { + + public var wrappedValue: URLRequest.CachePolicy + + public init(wrappedValue: URLRequest.CachePolicy = .useProtocolCachePolicy) { + self.wrappedValue = wrappedValue + } +} + +// MARK: - Encodable + +extension RequestCachePolicy: Encodable { + public func encode(to encoder: any Encoder) throws { + // This method needs to defined because `URLRequest.CachePolicy` does not conform to `Encodable`, but should never be called anyways + preconditionFailure("\(Self.self).encode(to encoder:) should not be called") + } +} diff --git a/Sources/Postie/Encoder/RequestEncoder.swift b/Sources/Postie/Encoder/RequestEncoder.swift index 7fd52f6..8dbff3a 100644 --- a/Sources/Postie/Encoder/RequestEncoder.swift +++ b/Sources/Postie/Encoder/RequestEncoder.swift @@ -135,6 +135,9 @@ public class RequestEncoder { .requestHeaderFields(with: encoder.cookies) // Merge the Cookie headers with the custom headers, where custom headers have precedence .merging(encoder.headers, uniquingKeysWith: { $1 }) + if let cachePolicy = encoder.cachePolicy { + request.cachePolicy = cachePolicy + } return request } } diff --git a/Sources/Postie/Encoder/RequestEncoding.swift b/Sources/Postie/Encoder/RequestEncoding.swift index 9c31c34..0f4b69f 100644 --- a/Sources/Postie/Encoder/RequestEncoding.swift +++ b/Sources/Postie/Encoder/RequestEncoding.swift @@ -13,6 +13,7 @@ internal class RequestEncoding: Encoder { private(set) var headers: [String: String] = [:] private(set) var pathParameters: [String: RequestPathParameterValue] = [:] private(set) var cookies: [HTTPCookie] = [] + private(set) var cachePolicy: URLRequest.CachePolicy? init(parent: RequestEncoding? = nil, codingPath: [CodingKey] = []) { self.parent = parent @@ -88,6 +89,14 @@ internal class RequestEncoding: Encoder { } } + func setCachePolicy(_ cachePolicy: URLRequest.CachePolicy) { + if let parent = parent { + parent.setCachePolicy(cachePolicy) + } else { + self.cachePolicy = cachePolicy + } + } + // MARK: - Accessors func resolvedPath() throws -> String { diff --git a/Sources/Postie/Encoder/RequestKeyedEncodingContainer.swift b/Sources/Postie/Encoder/RequestKeyedEncodingContainer.swift index 0a853bc..18c3b72 100644 --- a/Sources/Postie/Encoder/RequestKeyedEncodingContainer.swift +++ b/Sources/Postie/Encoder/RequestKeyedEncodingContainer.swift @@ -44,6 +44,8 @@ class RequestKeyedEncodingContainer: KeyedEncodingContainerProtocol where K encoder.setCustomURL(url: customURL) case let cookies as RequestCookies: encoder.setCookies(cookies.wrappedValue) + case let cachePolicy as RequestCachePolicy: + encoder.setCachePolicy(cachePolicy.wrappedValue) default: // ignore any other values break diff --git a/Tests/PostieTests/Configuration/RequestCachePolicyCodingTests.swift b/Tests/PostieTests/Configuration/RequestCachePolicyCodingTests.swift new file mode 100644 index 0000000..fbfaf9f --- /dev/null +++ b/Tests/PostieTests/Configuration/RequestCachePolicyCodingTests.swift @@ -0,0 +1,79 @@ +// swiftlint:disable nesting +@testable import Postie +import XCTest + +class RequestCachePolicyCodingTests: XCTestCase { + let baseURL = URL(string: "https://local.url")! + + func testEncoding_cachePolicyIsNotDefined_shouldUseDefault() { + // Arrange + struct Request: Postie.Request { + typealias Response = EmptyResponse + } + + let request = Request() + let encoder = RequestEncoder(baseURL: baseURL) + + // Act + let encoded: URLRequest + do { + encoded = try encoder.encode(request) + } catch { + XCTFail("Failed to encode: " + error.localizedDescription) + return + } + + // Assert + XCTAssertEqual(encoded.cachePolicy, .useProtocolCachePolicy) + } + + func testEncoding_cachePolicyIsDefined_shouldUseDefault() { + // Arrange + struct Request: Postie.Request { + typealias Response = EmptyResponse + + @RequestCachePolicy var cachePolicy + } + + let request = Request() + let encoder = RequestEncoder(baseURL: baseURL) + + // Act + let encoded: URLRequest + do { + encoded = try encoder.encode(request) + } catch { + XCTFail("Failed to encode: " + error.localizedDescription) + return + } + + // Assert + XCTAssertEqual(encoded.cachePolicy, .useProtocolCachePolicy) + } + + func testEncoding_cachePolicyIsOverwritten_shouldBeSetInRequest() { + // Arrange + struct Request: Postie.Request { + typealias Response = EmptyResponse + + @RequestCachePolicy var cachePolicy = .returnCacheDataDontLoad + } + + let request = Request() + let encoder = RequestEncoder(baseURL: baseURL) + + // Act + let encoded: URLRequest + do { + encoded = try encoder.encode(request) + } catch { + XCTFail("Failed to encode: " + error.localizedDescription) + return + } + + // Assert + XCTAssertEqual(encoded.cachePolicy, .returnCacheDataDontLoad) + } +} + +// swiftlint:enable nesting