Skip to content

Commit

Permalink
Return decoding error on Combine client
Browse files Browse the repository at this point in the history
  • Loading branch information
marinofelipe committed May 31, 2020
1 parent 0f5937d commit 9ecb64e
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Sources/CombineHTTPClient/CombineHTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public struct CombineHTTPClient {
.mapError { error -> HTTPResponseError in
if let urlError = error as? URLError {
return .underlying(urlError)
} else if let decodingError = error as? DecodingError {
return .decoding(decodingError)
}
return .unknown
}
Expand Down
38 changes: 37 additions & 1 deletion Sources/HTTPClientCore/HTTPRequestError.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Foundation

/// Possible errors for an HTTP response.
public enum HTTPResponseError: Error, Equatable, CustomDebugStringConvertible {
public enum HTTPResponseError: Error, CustomDebugStringConvertible {
case invalidResponse(_ urlResponse: URLResponse)
case underlying(_ error: URLError)
case decoding(_ error: DecodingError)
case unknown

public var debugDescription: String {
Expand All @@ -12,8 +13,43 @@ public enum HTTPResponseError: Error, Equatable, CustomDebugStringConvertible {
return "Received response is not a HTTPURLResponse. Response: \(urlResponse)"
case let .underlying(urlError):
return "Underlying URL error: \(urlError)"
case let .decoding(error):
return "Decoding failed with error: \(error)"
case .unknown:
return "Failed by unknown reasons"
}
}
}

// MARK: - Equatable

extension HTTPResponseError: Equatable {
public static func == (lhs: HTTPResponseError, rhs: HTTPResponseError) -> Bool {
switch lhs {
case let invalidResponse(lhsURLResponse):
switch rhs {
case let invalidResponse(rhsURLResponse):
return lhsURLResponse === rhsURLResponse
default: return false
}
case let .underlying(lhsURLError):
switch rhs {
case let .underlying(rhsURLError):
return lhsURLError == rhsURLError
default: return false
}
case let .decoding(lhsError):
switch rhs {
case let .decoding(rhsError):
return lhsError.failureReason == rhsError.failureReason
default: return false
}
case .unknown:
switch rhs {
case .unknown:
return true
default: return false
}
}
}
}
43 changes: 43 additions & 0 deletions Tests/CombineHTTPClientTests/CombineHTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,49 @@ final class CombineHTTPClientTests: XCTestCase {
XCTAssertEqual(URLProtocolMock.stopLoadingCallsCount, 1, "It calls `stopLoading` once")
}

func testRunWithFailureByDecodingError() throws {
let runExpectation = expectation(description: "Client to run over mocked URLSession")

let fakeBody = FakeResponseBody(id: 10, description: "desc")
let encodedFakeBody = try JSONEncoder().encode(fakeBody)

let request = try HTTPRequestBuilder(scheme: .https, host: "www.apple.com").build()
let url = try XCTUnwrap(request.url)

URLProtocolMock.stubbedRequestHandler = { request in
let response = try XCTUnwrap(HTTPURLResponse(url: url, statusCode: 500, httpVersion: nil, headerFields: nil))
return (response, encodedFakeBody)
}

var receivedError: HTTPResponseError?
let publisher: AnyPublisher<HTTPResponse<EmptyBody, Int>, HTTPResponseError> = sut.run(request, receiveOn: .main)

publisher.sink(receiveCompletion: { completion in
guard case let .failure(error) = completion else {
XCTFail("Should receive a error completion")
return
}
receivedError = error
runExpectation.fulfill()
}) { response in
XCTFail("Should not receive a valid response")
}.store(in: &disposeBag)

waitForExpectations(timeout: 1, handler: nil)

XCTAssertNotNil(receivedError, "It is not nil")

guard case .decoding = receivedError else {
XCTFail("Should have received an HTTPResponseError.underlying()")
return
}

XCTAssertEqual(URLProtocolMock.startLoadingCallsCount, 1, "It calls `startLoading` once")
XCTAssertEqual(URLProtocolMock.stopLoadingCallsCount, 1, "It calls `stopLoading` once")
}

// MARK: - Middleware

func testWithMiddleware() throws {
// TODO: Tbi. after middleware support is added
}
Expand Down

0 comments on commit 9ecb64e

Please sign in to comment.