diff --git a/Source/NetworkError.swift b/Source/NetworkError.swift index 4e341a4..11e5d91 100644 --- a/Source/NetworkError.swift +++ b/Source/NetworkError.swift @@ -36,7 +36,7 @@ public enum NetworkError: Error, Sendable { /// Error on the server (HTTP Error 500...511) case serverError(response: HTTPURLResponse?, data: Data?) /// Parsing the body into expected type failed. - case serializationError(error: Error, data: Data?) + case serializationError(error: Error, response: HTTPURLResponse, data: Data?) /// Complete request failed. case requestError(error: Error) @@ -75,21 +75,21 @@ extension NetworkError: CustomDebugStringConvertible { case .cancelled: return "Request cancelled" case .unauthorized(let response, let data): - return "Authorization error: \(response), response: ".appendingContentsOf(data: data) + return "Authorization error, response headers: \(response), response body: ".appendingContentsOf(data: data) case .clientError(let response, let data): if let response = response { - return "Client error: \((response)), response: ".appendingContentsOf(data: data) + return "Client error, response headers: \((response)), response body: ".appendingContentsOf(data: data) } - return "Client error, response: ".appendingContentsOf(data: data) - case .serializationError(let description, let data): - return "Serialization error: \(description), response: ".appendingContentsOf(data: data) + return "Client error, response headers: nil, response body: ".appendingContentsOf(data: data) + case .serializationError(let error, let response, let data): + return "Serialization error: \(error), response headers: \(response), response body: ".appendingContentsOf(data: data) case .requestError(let error): return "Request error: \(error)" case .serverError(let response, let data): - if let response = response { - return "Server error: \(String(describing: response)), response: ".appendingContentsOf(data: data) + if let response { + return "Server error, response headers: \(String(describing: response)), response body: ".appendingContentsOf(data: data) } else { - return "Server error: nil, response: ".appendingContentsOf(data: data) + return "Server error: nil, response body: ".appendingContentsOf(data: data) } } } diff --git a/Source/NetworkServices/BasicNetworkService.swift b/Source/NetworkServices/BasicNetworkService.swift index ec91b10..c874653 100644 --- a/Source/NetworkServices/BasicNetworkService.swift +++ b/Source/NetworkServices/BasicNetworkService.swift @@ -86,7 +86,7 @@ public final class BasicNetworkService: NetworkService { do { return .success((try resource.parse(data), response)) } catch let error { - return .failure(.serializationError(error: error, data: data)) + return .failure(.serializationError(error: error, response: response, data: data)) } } catch let error { if case URLError.cancelled = error { diff --git a/Source/Resource+Decodable.swift b/Source/Resource+Decodable.swift index 949fb43..731dfbb 100644 --- a/Source/Resource+Decodable.swift +++ b/Source/Resource+Decodable.swift @@ -33,7 +33,11 @@ extension Resource where Model: Decodable { /// - decoder: a decoder which can decode the payload into the model type /// - mapError: a closure which maps to Error public init(request: URLRequest, decoder: JSONDecoder, mapError: @escaping @Sendable (_ networkError: NetworkError) -> E) { - self.init(request: request, parse: { try decoder.decode(Model.self, from: $0) }, mapError: mapError) + self.init(request: request, parse: { + try decoder.decode(Model.self, from: $0) + }, + mapError: mapError + ) } } @@ -47,6 +51,12 @@ extension Resource where Model: Decodable, E: NetworkErrorConvertible { /// - decoder: a decoder which can decode the payload into the model type /// - mapError: a closure which maps to Error public init(request: URLRequest, decoder: JSONDecoder) { - self.init(request: request, parse: { try decoder.decode(Model.self, from: $0) }, mapError: { E(networkError: $0) }) + self.init(request: request, parse: { + try decoder.decode(Model.self, from: $0) + }, + mapError: { + E(networkError: $0) + } + ) } } diff --git a/Source/Resource+Inspect.swift b/Source/Resource+Inspect.swift index 8c9a56e..5ad717c 100644 --- a/Source/Resource+Inspect.swift +++ b/Source/Resource+Inspect.swift @@ -36,7 +36,7 @@ extension Resource { - parameter inspector: closure which gets passed the data - returns: a new resource which gets instepcted before parsing */ - public func inspectData(_ inspector: @escaping @Sendable (Data) -> Void) -> Resource { + public func inspectData(_ inspector: @escaping @Sendable (Data) -> Void) -> Resource { let parse: @Sendable (Data) throws -> Model = { data in inspector(data) return try self.parse(data) diff --git a/Source/Resource+Map.swift b/Source/Resource+Map.swift index f33df20..aefb9a8 100644 --- a/Source/Resource+Map.swift +++ b/Source/Resource+Map.swift @@ -30,7 +30,9 @@ extension Resource { public func map(transform: @escaping @Sendable (Model) throws -> T) -> Resource { return Resource( request: request, - parse: { return try transform(try self.parse($0)) }, + parse: { data in + return try transform(try self.parse(data)) + }, mapError: mapError ) } diff --git a/Tests/DecodableResoureTest.swift b/Tests/DecodableResoureTest.swift index b70be21..2282fbb 100644 --- a/Tests/DecodableResoureTest.swift +++ b/Tests/DecodableResoureTest.swift @@ -34,7 +34,7 @@ class DecodableResoureTest: XCTestCase { func testResource_withValidData() { //When let fetchedTrain = try? resource.parse(Train.validJSONData) - + //Then XCTAssertEqual(fetchedTrain?.name, "ICE") } @@ -43,7 +43,7 @@ class DecodableResoureTest: XCTestCase { //When let nameResource = resource.map { $0.name } let fetchedTrainName = try? nameResource.parse(Train.validJSONData) - + //Then XCTAssertEqual(fetchedTrainName, "ICE") } diff --git a/Tests/ModifyRequestNetworkService.swift b/Tests/ModifyRequestNetworkService.swift index c25dde6..9133082 100644 --- a/Tests/ModifyRequestNetworkService.swift +++ b/Tests/ModifyRequestNetworkService.swift @@ -36,12 +36,12 @@ class ModifyRequestNetworkServiceTest: XCTestCase { let networkService = ModifyRequestNetworkService(networkService: networkServiceMock, requestModifications: modification) let request = URLRequest(path: "/trains", baseURL: .defaultMock) let resource = Resource(request: request, parse: { _ in return 1 }) - + //When await networkService.requestResult(for: resource) //Then - let lastRequest = await networkServiceMock.lastRequest + let lastRequest = networkServiceMock.lastRequest let lastRequestURL = try XCTUnwrap(lastRequest?.url) XCTAssert(lastRequestURL.absoluteString.contains("key=1")) } diff --git a/Tests/NetworkErrorTest.swift b/Tests/NetworkErrorTest.swift index 8f0af49..5dc8a75 100644 --- a/Tests/NetworkErrorTest.swift +++ b/Tests/NetworkErrorTest.swift @@ -135,8 +135,8 @@ class NetworkErrorTest: XCTestCase { let debugDescription = error.debugDescription //Then - XCTAssert(debugDescription.hasPrefix("Authorization error: (nil) + let capturedInspectedData = Container(nil) + let resource = Resource(request: URLRequest.defaultMock, parse: { data in - capuredParsingData = data + capturedParsingData.setValue(data) return 1 }) //When let inspectedResource = resource.inspectData({ data in - capturedInspectedData = data + capturedInspectedData.setValue(data) }) let result = try? inspectedResource.parse(data) - + //Then XCTAssertNotNil(result) - XCTAssertEqual(capuredParsingData, capturedInspectedData) - XCTAssertEqual(data, capturedInspectedData) - XCTAssertEqual(capuredParsingData, data) + XCTAssertEqual(capturedParsingData.getValue(), capturedInspectedData.getValue()) + XCTAssertEqual(data, capturedInspectedData.getValue()) + XCTAssertEqual(capturedParsingData.getValue(), data) + } +} + +private class Container { + private var value: T + + init(_ value: T) { + self.value = value + } + + /// caller should manage concurrent access to its own state + func setValue(_ newValue: T) { + value = newValue + } + + /// caller should manage concurrent access to its own state + func getValue() -> T { + value } } diff --git a/Tests/ResourceTest.swift b/Tests/ResourceTest.swift index ed9fc22..c4ecd43 100644 --- a/Tests/ResourceTest.swift +++ b/Tests/ResourceTest.swift @@ -35,7 +35,7 @@ class ResourceTest: XCTestCase { //When let name = try resource.parse(validData) - + //Then XCTAssertEqual(name, "ICE") } diff --git a/Tests/ResourceWithErrorTest.swift b/Tests/ResourceWithErrorTest.swift index ab81d4c..c073f9b 100644 --- a/Tests/ResourceWithErrorTest.swift +++ b/Tests/ResourceWithErrorTest.swift @@ -39,7 +39,7 @@ class ResourceWithErrorTest: XCTestCase { //When let name = try resource.parse(validData) - + //Then XCTAssertEqual(name, "ICE") } diff --git a/Tests/RetryNetworkserviceTest.swift b/Tests/RetryNetworkserviceTest.swift index ad588f1..0c3a70b 100644 --- a/Tests/RetryNetworkserviceTest.swift +++ b/Tests/RetryNetworkserviceTest.swift @@ -32,7 +32,6 @@ class RetryNetworkserviceTest: XCTestCase { func testRetryRequest_shouldRetry() async throws { //Given - let errorCount = 2 let numberOfRetries = 2 let networkServiceMock = NetworkServiceMock( Result.failure(.unknownError),