From 2bb4373f6fca9ffcb14320c553074039bf2131cf Mon Sep 17 00:00:00 2001 From: Otavio Cordeiro Date: Sun, 16 Aug 2026 22:12:02 +0200 Subject: [PATCH 1/2] Add Linux support and CI Adds conditional FoundationNetworking imports across Sources and Tests, removes a leftover Combine import, fixes a Linux-incompatible URLResponse() initializer in the test mock, and adds a Linux job to CI matrixed on Swift 6.0/6.3. Docs updated to reflect Linux support. --- .github/workflows/ci.yml | 34 +++++++++++++++++++ .github/workflows/release.yml | 3 +- CLAUDE.md | 3 +- README.md | 16 ++++++++- .../MicroClient/Extensions/URLRequest.swift | 3 ++ .../MicroClient/Extensions/URLResponse.swift | 3 ++ .../Extensions/URLSessionProtocol.swift | 3 ++ .../Interceptors/APIKeyInterceptor.swift | 3 ++ .../AcceptHeaderInterceptor.swift | 3 ++ .../Interceptors/BasicAuthInterceptor.swift | 3 ++ .../BearerAuthorizationInterceptor.swift | 3 ++ .../CacheControlInterceptor.swift | 3 ++ .../Interceptors/ContentTypeInterceptor.swift | 3 ++ .../MetricsCollectionInterceptor.swift | 3 ++ .../Interceptors/RequestIDInterceptor.swift | 3 ++ .../ResponseLoggingInterceptor.swift | 3 ++ .../Interceptors/RetryAfterInterceptor.swift | 3 ++ .../StatusCodeValidationInterceptor.swift | 3 ++ .../Interceptors/TimeoutInterceptor.swift | 3 ++ .../Interceptors/UserAgentInterceptor.swift | 3 ++ Sources/MicroClient/NetworkClient.swift | 3 ++ Sources/MicroClient/NetworkClientError.swift | 3 ++ .../MicroClient/NetworkConfiguration.swift | 3 ++ .../NetworkRequestInterceptor.swift | 3 ++ Sources/MicroClient/NetworkResponse.swift | 3 ++ .../NetworkResponseInterceptor.swift | 3 ++ .../APIKeyInterceptorTests.swift | 3 ++ .../AcceptHeaderInterceptorTests.swift | 3 ++ .../BasicAuthInterceptorTests.swift | 3 ++ .../BearerAuthorizationInterceptorTests.swift | 3 ++ .../CacheControlInterceptorTests.swift | 3 ++ .../ContentTypeInterceptorTests.swift | 3 ++ .../Doubles/HeaderInterceptor.swift | 3 ++ .../Doubles/InterceptorMock.swift | 3 ++ .../Doubles/ThrowingInterceptor.swift | 3 ++ .../Doubles/URLSessionMock.swift | 10 +++++- .../Fixtures/NetworkClientMother.swift | 3 ++ .../MetricsCollectionInterceptorTests.swift | 3 ++ .../NetworkClientErrorHandlingTests.swift | 4 ++- .../NetworkClientRetryTests.swift | 3 ++ .../NetworkConfigurationTests.swift | 3 ++ .../NetworkResponseComplexModelsTests.swift | 3 ++ .../NetworkResponseTests.swift | 3 ++ .../RequestIDInterceptorTests.swift | 3 ++ .../ResponseLoggingInterceptorTests.swift | 3 ++ .../RetryAfterInterceptorTests.swift | 3 ++ ...StatusCodeValidationInterceptorTests.swift | 11 +++--- .../TimeoutInterceptorTests.swift | 3 ++ .../UserAgentInterceptorTests.swift | 3 ++ 49 files changed, 197 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7901c9a..ce1a3ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,3 +51,37 @@ jobs: uses: codecov/codecov-action@v5 with: slug: otaviocc/MicroClient + + test-linux: + name: Test on Linux (Swift ${{ matrix.swift-version }}) + runs-on: ubuntu-latest + + strategy: + matrix: + swift-version: ["6.0", "6.3"] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Swift + uses: swift-actions/setup-swift@v2 + with: + swift-version: ${{ matrix.swift-version }} + + - name: Cache Swift Package Manager + uses: actions/cache@v4 + with: + path: | + .build + ~/.cache/org.swift.swiftpm + key: ${{ runner.os }}-spm-${{ matrix.swift-version }}-v1 + restore-keys: | + ${{ runner.os }}-spm-${{ matrix.swift-version }}- + ${{ runner.os }}-spm- + + - name: Build + run: swift build + + - name: Run tests + run: swift test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bf259fe..59246d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -83,6 +83,7 @@ jobs: - **macOS**: 12.0+ - **iOS**: 15.0+ + - **Linux**: Swift 6.0+ toolchain - **Swift**: 6.0+ ### 📚 Installation @@ -139,7 +140,7 @@ jobs: - ✅ **Modern Swift**: Built with async/await and Swift concurrency - ✅ **Zero dependencies**: Pure Swift implementation - ✅ **Flexible**: Configurable encoders, decoders, and interceptors - - ✅ **Combine support**: Publisher for client status monitoring + - ✅ **Cross-platform**: macOS, iOS, and Linux - ✅ **Comprehensive testing**: Extensive test coverage with Swift Testing EOF diff --git a/CLAUDE.md b/CLAUDE.md index db68d1c..b17e3b0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Overview -MicroClient is a lightweight, zero-dependency Swift networking library designed for type-safe HTTP requests using modern Swift concurrency. The package targets macOS 12+ and iOS 15+, using Swift tools version 6.0. +MicroClient is a lightweight, zero-dependency Swift networking library designed for type-safe HTTP requests using modern Swift concurrency. The package targets macOS 12+, iOS 15+, and Linux, using Swift tools version 6.0. ## Development Commands @@ -37,7 +37,6 @@ The library is built around four main types that work together: 1. **NetworkClient** - The main client interface (`NetworkClientProtocol` + `NetworkClient`) - Async/await API for making requests - - Combine integration with status publisher - Request interceptor support for middleware 2. **NetworkRequest** - Type-safe request definitions diff --git a/README.md b/README.md index 1cca713..f7b2ee4 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,13 @@ A lightweight, zero-dependency Swift networking library designed for type-safe H - 🔁 **Automatic Retries**: Built-in support for request retries - 🪵 **Advanced Logging**: Customizable logging for requests and responses - ❌ **Task Cancellation**: Full support for Swift structured concurrency cancellation -- 📱 **Cross-platform**: Supports macOS 12+ and iOS 15+ +- 📱 **Cross-platform**: Supports macOS 12+, iOS 15+, and Linux ## Requirements - Swift 6.0+ - macOS 12.0+ / iOS 15.0+ +- Linux (Swift 6.0+ toolchain) ## Installation @@ -35,6 +36,19 @@ dependencies: [ ] ``` +### Linux + +MicroClient builds and runs on Linux. Because Foundation's URL loading system (`URLRequest`, +`URLResponse`, `URLSession`) lives in the separate `FoundationNetworking` module there, add the +standard conditional import wherever you name those types: + +```swift +import MicroClient +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif +``` + ## Quick Start ### 1. Create a Configuration diff --git a/Sources/MicroClient/Extensions/URLRequest.swift b/Sources/MicroClient/Extensions/URLRequest.swift index b77a231..0cf21d3 100644 --- a/Sources/MicroClient/Extensions/URLRequest.swift +++ b/Sources/MicroClient/Extensions/URLRequest.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif extension URLRequest { diff --git a/Sources/MicroClient/Extensions/URLResponse.swift b/Sources/MicroClient/Extensions/URLResponse.swift index 02fd81a..6867890 100644 --- a/Sources/MicroClient/Extensions/URLResponse.swift +++ b/Sources/MicroClient/Extensions/URLResponse.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif public extension URLResponse { diff --git a/Sources/MicroClient/Extensions/URLSessionProtocol.swift b/Sources/MicroClient/Extensions/URLSessionProtocol.swift index ec141c0..b8a4679 100644 --- a/Sources/MicroClient/Extensions/URLSessionProtocol.swift +++ b/Sources/MicroClient/Extensions/URLSessionProtocol.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// Protocol for URLSession to enable dependency injection and testing public protocol URLSessionProtocol: Sendable { diff --git a/Sources/MicroClient/Interceptors/APIKeyInterceptor.swift b/Sources/MicroClient/Interceptors/APIKeyInterceptor.swift index 6d9617d..41886aa 100644 --- a/Sources/MicroClient/Interceptors/APIKeyInterceptor.swift +++ b/Sources/MicroClient/Interceptors/APIKeyInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds API key authentication to HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/AcceptHeaderInterceptor.swift b/Sources/MicroClient/Interceptors/AcceptHeaderInterceptor.swift index 0ee14e6..09ceaa3 100644 --- a/Sources/MicroClient/Interceptors/AcceptHeaderInterceptor.swift +++ b/Sources/MicroClient/Interceptors/AcceptHeaderInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds Accept headers to HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/BasicAuthInterceptor.swift b/Sources/MicroClient/Interceptors/BasicAuthInterceptor.swift index 8e7f39b..ca23d30 100644 --- a/Sources/MicroClient/Interceptors/BasicAuthInterceptor.swift +++ b/Sources/MicroClient/Interceptors/BasicAuthInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds Basic authentication to HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/BearerAuthorizationInterceptor.swift b/Sources/MicroClient/Interceptors/BearerAuthorizationInterceptor.swift index 6c4edaa..b0a6ff2 100644 --- a/Sources/MicroClient/Interceptors/BearerAuthorizationInterceptor.swift +++ b/Sources/MicroClient/Interceptors/BearerAuthorizationInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds Bearer token authorization to HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/CacheControlInterceptor.swift b/Sources/MicroClient/Interceptors/CacheControlInterceptor.swift index cc61d7d..37e8e34 100644 --- a/Sources/MicroClient/Interceptors/CacheControlInterceptor.swift +++ b/Sources/MicroClient/Interceptors/CacheControlInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds Cache-Control headers to HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/ContentTypeInterceptor.swift b/Sources/MicroClient/Interceptors/ContentTypeInterceptor.swift index 2ae711c..d3e46db 100644 --- a/Sources/MicroClient/Interceptors/ContentTypeInterceptor.swift +++ b/Sources/MicroClient/Interceptors/ContentTypeInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds Content-Type headers to HTTP requests with a body. /// diff --git a/Sources/MicroClient/Interceptors/MetricsCollectionInterceptor.swift b/Sources/MicroClient/Interceptors/MetricsCollectionInterceptor.swift index d74808c..25a44a4 100644 --- a/Sources/MicroClient/Interceptors/MetricsCollectionInterceptor.swift +++ b/Sources/MicroClient/Interceptors/MetricsCollectionInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// A protocol for receiving metrics collected from network responses. public protocol MetricsCollector: Sendable { diff --git a/Sources/MicroClient/Interceptors/RequestIDInterceptor.swift b/Sources/MicroClient/Interceptors/RequestIDInterceptor.swift index 34f5159..de108a8 100644 --- a/Sources/MicroClient/Interceptors/RequestIDInterceptor.swift +++ b/Sources/MicroClient/Interceptors/RequestIDInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds unique request IDs to HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/ResponseLoggingInterceptor.swift b/Sources/MicroClient/Interceptors/ResponseLoggingInterceptor.swift index 6ede36f..900a6ed 100644 --- a/Sources/MicroClient/Interceptors/ResponseLoggingInterceptor.swift +++ b/Sources/MicroClient/Interceptors/ResponseLoggingInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that logs response information including status code, headers, and body data. /// diff --git a/Sources/MicroClient/Interceptors/RetryAfterInterceptor.swift b/Sources/MicroClient/Interceptors/RetryAfterInterceptor.swift index 11819ec..2afa049 100644 --- a/Sources/MicroClient/Interceptors/RetryAfterInterceptor.swift +++ b/Sources/MicroClient/Interceptors/RetryAfterInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// Error thrown when a Retry-After header indicates the client should wait before retrying. public struct RetryAfterError: Error { diff --git a/Sources/MicroClient/Interceptors/StatusCodeValidationInterceptor.swift b/Sources/MicroClient/Interceptors/StatusCodeValidationInterceptor.swift index 160dccd..00a7b5c 100644 --- a/Sources/MicroClient/Interceptors/StatusCodeValidationInterceptor.swift +++ b/Sources/MicroClient/Interceptors/StatusCodeValidationInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that validates HTTP status codes against a custom range or set of acceptable codes. /// diff --git a/Sources/MicroClient/Interceptors/TimeoutInterceptor.swift b/Sources/MicroClient/Interceptors/TimeoutInterceptor.swift index 839377d..988940c 100644 --- a/Sources/MicroClient/Interceptors/TimeoutInterceptor.swift +++ b/Sources/MicroClient/Interceptors/TimeoutInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that configures custom timeout intervals for HTTP requests. /// diff --git a/Sources/MicroClient/Interceptors/UserAgentInterceptor.swift b/Sources/MicroClient/Interceptors/UserAgentInterceptor.swift index 0d0267e..3659c51 100644 --- a/Sources/MicroClient/Interceptors/UserAgentInterceptor.swift +++ b/Sources/MicroClient/Interceptors/UserAgentInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An interceptor that adds a User-Agent header to HTTP requests. /// diff --git a/Sources/MicroClient/NetworkClient.swift b/Sources/MicroClient/NetworkClient.swift index 1322975..d48b795 100644 --- a/Sources/MicroClient/NetworkClient.swift +++ b/Sources/MicroClient/NetworkClient.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// The network client interface. public protocol NetworkClientProtocol: Sendable { diff --git a/Sources/MicroClient/NetworkClientError.swift b/Sources/MicroClient/NetworkClientError.swift index 7c4b126..7e4b54b 100644 --- a/Sources/MicroClient/NetworkClientError.swift +++ b/Sources/MicroClient/NetworkClientError.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// An enum representing possible errors that can occur during a network request. public enum NetworkClientError: Error { diff --git a/Sources/MicroClient/NetworkConfiguration.swift b/Sources/MicroClient/NetworkConfiguration.swift index 53086df..8cce418 100644 --- a/Sources/MicroClient/NetworkConfiguration.swift +++ b/Sources/MicroClient/NetworkConfiguration.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// The network client configuration. public struct NetworkConfiguration: Sendable { diff --git a/Sources/MicroClient/NetworkRequestInterceptor.swift b/Sources/MicroClient/NetworkRequestInterceptor.swift index f885473..cafd9d6 100644 --- a/Sources/MicroClient/NetworkRequestInterceptor.swift +++ b/Sources/MicroClient/NetworkRequestInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// A protocol for intercepting and modifying network requests before they are sent. public protocol NetworkRequestInterceptor: Sendable { diff --git a/Sources/MicroClient/NetworkResponse.swift b/Sources/MicroClient/NetworkResponse.swift index e38de06..e74957e 100644 --- a/Sources/MicroClient/NetworkResponse.swift +++ b/Sources/MicroClient/NetworkResponse.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// The network response. It has the type /// used as response model. diff --git a/Sources/MicroClient/NetworkResponseInterceptor.swift b/Sources/MicroClient/NetworkResponseInterceptor.swift index 9e7e40c..7df98da 100644 --- a/Sources/MicroClient/NetworkResponseInterceptor.swift +++ b/Sources/MicroClient/NetworkResponseInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif /// A protocol for intercepting and processing network responses after they are received and decoded. public protocol NetworkResponseInterceptor: Sendable { diff --git a/Tests/MicroClientTests/APIKeyInterceptorTests.swift b/Tests/MicroClientTests/APIKeyInterceptorTests.swift index fff36f7..3a0ae3e 100644 --- a/Tests/MicroClientTests/APIKeyInterceptorTests.swift +++ b/Tests/MicroClientTests/APIKeyInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/AcceptHeaderInterceptorTests.swift b/Tests/MicroClientTests/AcceptHeaderInterceptorTests.swift index 9254632..3cd2b9e 100644 --- a/Tests/MicroClientTests/AcceptHeaderInterceptorTests.swift +++ b/Tests/MicroClientTests/AcceptHeaderInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/BasicAuthInterceptorTests.swift b/Tests/MicroClientTests/BasicAuthInterceptorTests.swift index 02d1f88..c4e3351 100644 --- a/Tests/MicroClientTests/BasicAuthInterceptorTests.swift +++ b/Tests/MicroClientTests/BasicAuthInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/BearerAuthorizationInterceptorTests.swift b/Tests/MicroClientTests/BearerAuthorizationInterceptorTests.swift index 58f19ee..b816880 100644 --- a/Tests/MicroClientTests/BearerAuthorizationInterceptorTests.swift +++ b/Tests/MicroClientTests/BearerAuthorizationInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/CacheControlInterceptorTests.swift b/Tests/MicroClientTests/CacheControlInterceptorTests.swift index fca7af1..a698d50 100644 --- a/Tests/MicroClientTests/CacheControlInterceptorTests.swift +++ b/Tests/MicroClientTests/CacheControlInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/ContentTypeInterceptorTests.swift b/Tests/MicroClientTests/ContentTypeInterceptorTests.swift index e3dcfa9..de52071 100644 --- a/Tests/MicroClientTests/ContentTypeInterceptorTests.swift +++ b/Tests/MicroClientTests/ContentTypeInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/Doubles/HeaderInterceptor.swift b/Tests/MicroClientTests/Doubles/HeaderInterceptor.swift index 2fede8d..f364b59 100644 --- a/Tests/MicroClientTests/Doubles/HeaderInterceptor.swift +++ b/Tests/MicroClientTests/Doubles/HeaderInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif @testable import MicroClient struct HeaderInterceptor: NetworkRequestInterceptor { diff --git a/Tests/MicroClientTests/Doubles/InterceptorMock.swift b/Tests/MicroClientTests/Doubles/InterceptorMock.swift index 8fe1f56..16ea2e5 100644 --- a/Tests/MicroClientTests/Doubles/InterceptorMock.swift +++ b/Tests/MicroClientTests/Doubles/InterceptorMock.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif @testable import MicroClient struct InterceptorMock: NetworkRequestInterceptor { diff --git a/Tests/MicroClientTests/Doubles/ThrowingInterceptor.swift b/Tests/MicroClientTests/Doubles/ThrowingInterceptor.swift index a4ccf8b..30f4e8b 100644 --- a/Tests/MicroClientTests/Doubles/ThrowingInterceptor.swift +++ b/Tests/MicroClientTests/Doubles/ThrowingInterceptor.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif @testable import MicroClient struct ThrowingInterceptor: NetworkRequestInterceptor { diff --git a/Tests/MicroClientTests/Doubles/URLSessionMock.swift b/Tests/MicroClientTests/Doubles/URLSessionMock.swift index d22cceb..391b2d9 100644 --- a/Tests/MicroClientTests/Doubles/URLSessionMock.swift +++ b/Tests/MicroClientTests/Doubles/URLSessionMock.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif @testable import MicroClient final class URLSessionMock: URLSessionProtocol, @unchecked Sendable { @@ -30,7 +33,12 @@ final class URLSessionMock: URLSessionProtocol, @unchecked Sendable { private(set) var lastRequest: URLRequest? private(set) var requestCount = 0 private var stubbedDataToReturn = Data() - private var stubbedResponseToReturn = URLResponse() + private var stubbedResponseToReturn = URLResponse( + url: URL(string: "https://example.com")!, + mimeType: nil, + expectedContentLength: 0, + textEncodingName: nil + ) private var stubbedErrorToThrow: Error? var succeedAfter = 0 var delay: TimeInterval = 0 diff --git a/Tests/MicroClientTests/Fixtures/NetworkClientMother.swift b/Tests/MicroClientTests/Fixtures/NetworkClientMother.swift index 0bf8eff..828fb48 100644 --- a/Tests/MicroClientTests/Fixtures/NetworkClientMother.swift +++ b/Tests/MicroClientTests/Fixtures/NetworkClientMother.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif @testable import MicroClient // swiftlint:disable force_unwrapping diff --git a/Tests/MicroClientTests/MetricsCollectionInterceptorTests.swift b/Tests/MicroClientTests/MetricsCollectionInterceptorTests.swift index d238a49..55294c9 100644 --- a/Tests/MicroClientTests/MetricsCollectionInterceptorTests.swift +++ b/Tests/MicroClientTests/MetricsCollectionInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/NetworkClientErrorHandlingTests.swift b/Tests/MicroClientTests/NetworkClientErrorHandlingTests.swift index 9fd7970..5d74342 100644 --- a/Tests/MicroClientTests/NetworkClientErrorHandlingTests.swift +++ b/Tests/MicroClientTests/NetworkClientErrorHandlingTests.swift @@ -20,8 +20,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import Combine import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/NetworkClientRetryTests.swift b/Tests/MicroClientTests/NetworkClientRetryTests.swift index 551b601..ddc984c 100644 --- a/Tests/MicroClientTests/NetworkClientRetryTests.swift +++ b/Tests/MicroClientTests/NetworkClientRetryTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/NetworkConfigurationTests.swift b/Tests/MicroClientTests/NetworkConfigurationTests.swift index 1370e7e..900c22e 100644 --- a/Tests/MicroClientTests/NetworkConfigurationTests.swift +++ b/Tests/MicroClientTests/NetworkConfigurationTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/NetworkResponseComplexModelsTests.swift b/Tests/MicroClientTests/NetworkResponseComplexModelsTests.swift index d8655f4..f2c9364 100644 --- a/Tests/MicroClientTests/NetworkResponseComplexModelsTests.swift +++ b/Tests/MicroClientTests/NetworkResponseComplexModelsTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/NetworkResponseTests.swift b/Tests/MicroClientTests/NetworkResponseTests.swift index 3cb65f6..6ab3126 100644 --- a/Tests/MicroClientTests/NetworkResponseTests.swift +++ b/Tests/MicroClientTests/NetworkResponseTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/RequestIDInterceptorTests.swift b/Tests/MicroClientTests/RequestIDInterceptorTests.swift index 92e24e1..680332b 100644 --- a/Tests/MicroClientTests/RequestIDInterceptorTests.swift +++ b/Tests/MicroClientTests/RequestIDInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/ResponseLoggingInterceptorTests.swift b/Tests/MicroClientTests/ResponseLoggingInterceptorTests.swift index 1c01620..8be6cfd 100644 --- a/Tests/MicroClientTests/ResponseLoggingInterceptorTests.swift +++ b/Tests/MicroClientTests/ResponseLoggingInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/RetryAfterInterceptorTests.swift b/Tests/MicroClientTests/RetryAfterInterceptorTests.swift index fdf3806..5660aec 100644 --- a/Tests/MicroClientTests/RetryAfterInterceptorTests.swift +++ b/Tests/MicroClientTests/RetryAfterInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/StatusCodeValidationInterceptorTests.swift b/Tests/MicroClientTests/StatusCodeValidationInterceptorTests.swift index f488bcc..29b1701 100644 --- a/Tests/MicroClientTests/StatusCodeValidationInterceptorTests.swift +++ b/Tests/MicroClientTests/StatusCodeValidationInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient @@ -30,7 +33,7 @@ struct StatusCodeValidationInterceptorTests { @Test("It should pass valid status codes from set") func passesValidStatusCodesFromSet() async throws { // Given - let acceptableCodes: Set = [200, 201, 204] + let acceptableCodes: Set = [200, 201, 204] let interceptor = StatusCodeValidationInterceptor(acceptableStatusCodes: acceptableCodes) let url = try #require(URL(string: "https://example.com/api")) let httpResponse = HTTPURLResponse( @@ -57,7 +60,7 @@ struct StatusCodeValidationInterceptorTests { @Test("It should throw error for invalid status codes from set") func throwsErrorForInvalidStatusCodesFromSet() async throws { // Given - let acceptableCodes: Set = [200, 201] + let acceptableCodes: Set = [200, 201] let interceptor = StatusCodeValidationInterceptor(acceptableStatusCodes: acceptableCodes) let url = try #require(URL(string: "https://example.com/api")) let httpResponse = HTTPURLResponse( @@ -196,7 +199,7 @@ struct StatusCodeValidationInterceptorTests { @Test("It should handle non-HTTP responses") func handlesNonHTTPResponses() async throws { // Given - let acceptableCodes: Set = [200] + let acceptableCodes: Set = [200] let interceptor = StatusCodeValidationInterceptor(acceptableStatusCodes: acceptableCodes) let url = try #require(URL(string: "https://example.com")) let response = URLResponse( @@ -223,7 +226,7 @@ struct StatusCodeValidationInterceptorTests { @Test("It should accept 304 Not Modified with custom validation") func accepts304WithCustomValidation() async throws { // Given - let acceptableCodes: Set = [200, 201, 304] + let acceptableCodes: Set = [200, 201, 304] let interceptor = StatusCodeValidationInterceptor(acceptableStatusCodes: acceptableCodes) let url = try #require(URL(string: "https://example.com/api")) let httpResponse = HTTPURLResponse( diff --git a/Tests/MicroClientTests/TimeoutInterceptorTests.swift b/Tests/MicroClientTests/TimeoutInterceptorTests.swift index 9f3bc4a..6b6d23b 100644 --- a/Tests/MicroClientTests/TimeoutInterceptorTests.swift +++ b/Tests/MicroClientTests/TimeoutInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient diff --git a/Tests/MicroClientTests/UserAgentInterceptorTests.swift b/Tests/MicroClientTests/UserAgentInterceptorTests.swift index c909ba7..a5cdff3 100644 --- a/Tests/MicroClientTests/UserAgentInterceptorTests.swift +++ b/Tests/MicroClientTests/UserAgentInterceptorTests.swift @@ -21,6 +21,9 @@ // SOFTWARE. import Foundation +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif import Testing @testable import MicroClient From b1b1682f7c29616368d65fc0cb2444734638aa30 Mon Sep 17 00:00:00 2001 From: Otavio Cordeiro Date: Sun, 16 Aug 2026 22:15:38 +0200 Subject: [PATCH 2/2] Fix Linux CI: pin to a version setup-swift@v2 supports swift-actions/setup-swift@v2 ships a hardcoded version manifest that tops out at 6.2.1 and doesn't yet know about 6.3, so the "6.3" leg failed at setup with "Version 6.3 is not available". Also add fail-fast: false so one bad matrix leg doesn't cancel its sibling. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce1a3ae..5fc1aa6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,9 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - swift-version: ["6.0", "6.3"] + swift-version: ["6.0", "6.2"] steps: - name: Checkout code