From a1f8917c671d3f8de74e9850eb7b8577feafeb95 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Thu, 31 Dec 2020 21:44:05 +0900 Subject: [PATCH 1/6] Add support for Combine.framework --- APIKit.xcodeproj/project.pbxproj | 13 +++++ Sources/APIKit/Combine/Combine.swift | 86 ++++++++++++++++++++++++++++ Sources/APIKit/Session.swift | 2 +- 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 Sources/APIKit/Combine/Combine.swift diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index b538939e..17dc7182 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0969AE0F259DEC6D00C498AF /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0969AE0E259DEC6D00C498AF /* Combine.swift */; }; 7F698E501D9D680C00F1561D /* FormURLEncodedBodyParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E3C1D9D680C00F1561D /* FormURLEncodedBodyParametersTests.swift */; }; 7F698E511D9D680C00F1561D /* JSONBodyParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E3D1D9D680C00F1561D /* JSONBodyParametersTests.swift */; }; 7F698E521D9D680C00F1561D /* MultipartFormDataParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E3E1D9D680C00F1561D /* MultipartFormDataParametersTests.swift */; }; @@ -76,6 +77,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0969AE0E259DEC6D00C498AF /* Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Combine.swift; sourceTree = ""; }; 141F120F1C1C96820026D415 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = Configurations/Base.xcconfig; sourceTree = ""; }; 141F12101C1C96820026D415 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = ""; }; 141F12111C1C96820026D415 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = ""; }; @@ -149,6 +151,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0969AE0D259DEC3C00C498AF /* Combine */ = { + isa = PBXGroup; + children = ( + 0969AE0E259DEC6D00C498AF /* Combine.swift */, + ); + name = Combine; + path = APIKit/Combine; + sourceTree = ""; + }; 141F120E1C1C96690026D415 /* Configurations */ = { isa = PBXGroup; children = ( @@ -288,6 +299,7 @@ 7F7048CA1D9D89BE003C99F6 /* Request.swift */, 7F7048CB1D9D89BE003C99F6 /* Session.swift */, 7F7048CC1D9D89BE003C99F6 /* Unavailable.swift */, + 0969AE0D259DEC3C00C498AF /* Combine */, 7F85FB8B1C9D317300CEE132 /* SessionAdapter */, 7F18BD0D1C972C38003A31DF /* BodyParameters */, 7FA19A441C9CC9A2005D25AE /* DataParser */, @@ -473,6 +485,7 @@ ECA831481DE4DDBF004EB1B5 /* ProtobufDataParser.swift in Sources */, 7F7048F31D9D8A1F003C99F6 /* URLEncodedSerialization.swift in Sources */, 7F7048D71D9D89F2003C99F6 /* URLSessionAdapter.swift in Sources */, + 0969AE0F259DEC6D00C498AF /* Combine.swift in Sources */, 7F7048EB1D9D8A08003C99F6 /* StringDataParser.swift in Sources */, 7F7048CF1D9D89BE003C99F6 /* HTTPMethod.swift in Sources */, ); diff --git a/Sources/APIKit/Combine/Combine.swift b/Sources/APIKit/Combine/Combine.swift new file mode 100644 index 00000000..5f11a00e --- /dev/null +++ b/Sources/APIKit/Combine/Combine.swift @@ -0,0 +1,86 @@ +#if canImport(Combine) + +import Foundation +import Combine + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public struct RequestPublisher: Publisher { + public typealias Output = Request.Response + public typealias Failure = SessionTaskError + + private let session: Session + private let request: Request + private let callbackQueue: CallbackQueue? + + public init(session: Session, request: Request, callbackQueue: CallbackQueue?) { + self.session = session + self.request = request + self.callbackQueue = callbackQueue + } + + public func receive(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input { + subscriber.receive(subscription: RequestSubscription(session: session, + request: request, + callbackQueue: callbackQueue, + downstream: subscriber)) + } + + private final class RequestSubscription: Subscription where Downstream.Input == Request.Response, Downstream.Failure == Failure { + + private let session: Session + private let request: Request + private let callbackQueue: CallbackQueue? + private var downstream: Downstream? + private var task: SessionTask? + + init(session: Session, request: Request, callbackQueue: CallbackQueue?, downstream: Downstream) { + self.session = session + self.request = request + self.callbackQueue = callbackQueue + self.downstream = downstream + } + + func request(_ demand: Subscribers.Demand) { + assert(demand > 0) + guard let downstream = self.downstream else { return } + self.downstream = nil + task = session.send(request, callbackQueue: callbackQueue) { result in + switch result { + case .success(let response): + _ = downstream.receive(response) + downstream.receive(completion: .finished) + case .failure(let error): + downstream.receive(completion: .failure(error)) + } + } + } + + func cancel() { + task?.cancel() + downstream = nil + } + } +} + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public extension Session { + /// Calls `publisher(_:callbackQueue:)` of `shared`. + /// - parameter request: The request to be sent. + /// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used. + /// - returns: The new request publisher. + static func publisher(_ request: Request, callbackQueue: CallbackQueue? = nil) -> RequestPublisher { + return RequestPublisher(session: .shared, request: request, callbackQueue: callbackQueue) + } + + /// Returns a publisher that wraps a task for a given `Request`. + /// + /// The publisher publishes `Request.Response` when the task completes, or terminates if the task fails with an error. + /// - parameter request: The request to be sent. + /// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used. + /// - returns: The new request publisher. + func publisher(_ request: Request, callbackQueue: CallbackQueue? = nil) -> RequestPublisher { + return RequestPublisher(session: self, request: request, callbackQueue: callbackQueue) + } +} + +#endif diff --git a/Sources/APIKit/Session.swift b/Sources/APIKit/Session.swift index c772247f..a3e14d07 100644 --- a/Sources/APIKit/Session.swift +++ b/Sources/APIKit/Session.swift @@ -30,7 +30,7 @@ open class Session { return privateShared } - /// Calls `send(_:handler:)` of `sharedSession`. + /// Calls `send(_:callbackQueue:handler:)` of `shared`. /// - parameter request: The request to be sent. /// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used. /// - parameter handler: The closure that receives result of the request. From 8e8c2774e29da87da3810ded4144bdfc55783f55 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Fri, 1 Jan 2021 00:36:10 +0900 Subject: [PATCH 2/6] fix compile error --- Sources/APIKit/Combine/Combine.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/APIKit/Combine/Combine.swift b/Sources/APIKit/Combine/Combine.swift index 5f11a00e..617e2228 100644 --- a/Sources/APIKit/Combine/Combine.swift +++ b/Sources/APIKit/Combine/Combine.swift @@ -18,7 +18,7 @@ public struct RequestPublisher: Publisher { self.callbackQueue = callbackQueue } - public func receive(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input { + public func receive(subscriber: S) where S : Subscriber, RequestPublisher.Failure == S.Failure, RequestPublisher.Output == S.Input { subscriber.receive(subscription: RequestSubscription(session: session, request: request, callbackQueue: callbackQueue, From d2d512b5ac357146daa7c17869443050eb0979ad Mon Sep 17 00:00:00 2001 From: Econa77 Date: Fri, 1 Jan 2021 01:25:40 +0900 Subject: [PATCH 3/6] Add tests --- APIKit.xcodeproj/project.pbxproj | 12 +++ Tests/APIKitTests/Combine/CombineTests.swift | 95 ++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 Tests/APIKitTests/Combine/CombineTests.swift diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 17dc7182..8fc0f748 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 0969AE0F259DEC6D00C498AF /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0969AE0E259DEC6D00C498AF /* Combine.swift */; }; + 0973EE35259E2DDC00879BA2 /* CombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0973EE34259E2DDC00879BA2 /* CombineTests.swift */; }; 7F698E501D9D680C00F1561D /* FormURLEncodedBodyParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E3C1D9D680C00F1561D /* FormURLEncodedBodyParametersTests.swift */; }; 7F698E511D9D680C00F1561D /* JSONBodyParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E3D1D9D680C00F1561D /* JSONBodyParametersTests.swift */; }; 7F698E521D9D680C00F1561D /* MultipartFormDataParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E3E1D9D680C00F1561D /* MultipartFormDataParametersTests.swift */; }; @@ -78,6 +79,7 @@ /* Begin PBXFileReference section */ 0969AE0E259DEC6D00C498AF /* Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Combine.swift; sourceTree = ""; }; + 0973EE34259E2DDC00879BA2 /* CombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineTests.swift; sourceTree = ""; }; 141F120F1C1C96820026D415 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = Configurations/Base.xcconfig; sourceTree = ""; }; 141F12101C1C96820026D415 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = ""; }; 141F12111C1C96820026D415 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = ""; }; @@ -160,6 +162,14 @@ path = APIKit/Combine; sourceTree = ""; }; + 0973EE33259E2DD000879BA2 /* Combine */ = { + isa = PBXGroup; + children = ( + 0973EE34259E2DDC00879BA2 /* CombineTests.swift */, + ); + path = Combine; + sourceTree = ""; + }; 141F120E1C1C96690026D415 /* Configurations */ = { isa = PBXGroup; children = ( @@ -230,6 +240,7 @@ 7F698E451D9D680C00F1561D /* RequestTests.swift */, 7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */, 7F698E4A1D9D680C00F1561D /* SessionTests.swift */, + 0973EE33259E2DD000879BA2 /* Combine */, 7F698E3B1D9D680C00F1561D /* BodyParametersType */, 7F698E401D9D680C00F1561D /* DataParserType */, 7F698E461D9D680C00F1561D /* SessionAdapterType */, @@ -503,6 +514,7 @@ ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */, 7F698E5E1D9D680C00F1561D /* TestRequest.swift in Sources */, 7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */, + 0973EE35259E2DDC00879BA2 /* CombineTests.swift in Sources */, 7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */, 7F698E5A1D9D680C00F1561D /* URLSessionAdapterTests.swift in Sources */, 7F698E561D9D680C00F1561D /* StringDataParserTests.swift in Sources */, diff --git a/Tests/APIKitTests/Combine/CombineTests.swift b/Tests/APIKitTests/Combine/CombineTests.swift new file mode 100644 index 00000000..812b0670 --- /dev/null +++ b/Tests/APIKitTests/Combine/CombineTests.swift @@ -0,0 +1,95 @@ +#if canImport(Combine) + +import Foundation +import XCTest +import Combine +import APIKit + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +final class CombineTests: XCTestCase { + + var adapter: TestSessionAdapter! + var session: Session! + var cancellables: Set = [] + + override func setUp() { + super.setUp() + adapter = TestSessionAdapter() + session = Session(adapter: adapter) + } + + override func tearDown() { + super.tearDown() + cancellables = [] + } + + func testSuccess() { + let dictionary = ["key": "value"] + adapter.data = try! JSONSerialization.data(withJSONObject: dictionary, options: []) + + let expectation = self.expectation(description: "wait for response") + let request = TestRequest() + + session.publisher(request) + .sink { completion in + switch completion { + case .failure: + XCTFail() + case .finished: + expectation.fulfill() + } + } receiveValue: { response in + XCTAssertEqual((response as? [String: String])?["key"], "value") + } + .store(in: &cancellables) + + waitForExpectations(timeout: 1.0, handler: nil) + } + + func testParseDataError() { + adapter.data = "{\"broken\": \"json}".data(using: .utf8, allowLossyConversion: false) + + let expectation = self.expectation(description: "wait for response") + let request = TestRequest() + + session.publisher(request) + .sink { completion in + if case .failure(let error) = completion, case .responseError(let responseError as NSError) = error { + XCTAssertEqual(responseError.domain, NSCocoaErrorDomain) + XCTAssertEqual(responseError.code, 3840) + } else { + XCTFail() + } + expectation.fulfill() + } receiveValue: { response in + XCTFail() + } + .store(in: &cancellables) + + waitForExpectations(timeout: 1.0, handler: nil) + } + + func testCancel() { + let expectation = self.expectation(description: "wait for response") + let request = TestRequest() + + let cancellable = session.publisher(request) + .sink { completion in + if case .failure(let error) = completion, case .connectionError(let connectionError as NSError) = error { + XCTAssertEqual(connectionError.code, 0) + } else { + XCTFail() + } + expectation.fulfill() + } receiveValue: { response in + XCTFail() + } + + cancellable.cancel() + + waitForExpectations(timeout: 1.0, handler: nil) + } + +} + +#endif From ec4383a24055d780861a7a1903d7f09a214039ab Mon Sep 17 00:00:00 2001 From: Econa77 Date: Fri, 1 Jan 2021 01:31:16 +0900 Subject: [PATCH 4/6] fix compile error --- Tests/APIKitTests/Combine/CombineTests.swift | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Tests/APIKitTests/Combine/CombineTests.swift b/Tests/APIKitTests/Combine/CombineTests.swift index 812b0670..809af613 100644 --- a/Tests/APIKitTests/Combine/CombineTests.swift +++ b/Tests/APIKitTests/Combine/CombineTests.swift @@ -31,16 +31,16 @@ final class CombineTests: XCTestCase { let request = TestRequest() session.publisher(request) - .sink { completion in + .sink(receiveCompletion: { completion in switch completion { case .failure: XCTFail() case .finished: expectation.fulfill() } - } receiveValue: { response in + }, receiveValue: { response in XCTAssertEqual((response as? [String: String])?["key"], "value") - } + }) .store(in: &cancellables) waitForExpectations(timeout: 1.0, handler: nil) @@ -53,17 +53,17 @@ final class CombineTests: XCTestCase { let request = TestRequest() session.publisher(request) - .sink { completion in + .sink(receiveCompletion: { completion in if case .failure(let error) = completion, case .responseError(let responseError as NSError) = error { XCTAssertEqual(responseError.domain, NSCocoaErrorDomain) XCTAssertEqual(responseError.code, 3840) + expectation.fulfill() } else { XCTFail() } - expectation.fulfill() - } receiveValue: { response in + }, receiveValue: { response in XCTFail() - } + }) .store(in: &cancellables) waitForExpectations(timeout: 1.0, handler: nil) @@ -74,16 +74,16 @@ final class CombineTests: XCTestCase { let request = TestRequest() let cancellable = session.publisher(request) - .sink { completion in + .sink(receiveCompletion: { completion in if case .failure(let error) = completion, case .connectionError(let connectionError as NSError) = error { XCTAssertEqual(connectionError.code, 0) + expectation.fulfill() } else { XCTFail() } - expectation.fulfill() - } receiveValue: { response in + }, receiveValue: { response in XCTFail() - } + }) cancellable.cancel() From 1dcee7d9a9a4d1031498c8b0d194cf306e3ad0c4 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Tue, 23 Feb 2021 16:14:58 +0900 Subject: [PATCH 5/6] Rename publisher() to sessionTaskPublisher(for:) --- Sources/APIKit/Combine/Combine.swift | 49 +++++++++++--------- Sources/APIKit/Session.swift | 4 +- Tests/APIKitTests/Combine/CombineTests.swift | 6 +-- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/Sources/APIKit/Combine/Combine.swift b/Sources/APIKit/Combine/Combine.swift index 617e2228..0b4db3f4 100644 --- a/Sources/APIKit/Combine/Combine.swift +++ b/Sources/APIKit/Combine/Combine.swift @@ -3,39 +3,42 @@ import Foundation import Combine -@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) -public struct RequestPublisher: Publisher { +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +public struct SessionTaskPublisher: Publisher { + /// The kind of values published by this publisher. public typealias Output = Request.Response + + /// The kind of errors this publisher might publish. public typealias Failure = SessionTaskError - private let session: Session private let request: Request + private let session: Session private let callbackQueue: CallbackQueue? - public init(session: Session, request: Request, callbackQueue: CallbackQueue?) { - self.session = session + public init(request: Request, session: Session, callbackQueue: CallbackQueue?) { self.request = request + self.session = session self.callbackQueue = callbackQueue } - public func receive(subscriber: S) where S : Subscriber, RequestPublisher.Failure == S.Failure, RequestPublisher.Output == S.Input { - subscriber.receive(subscription: RequestSubscription(session: session, - request: request, - callbackQueue: callbackQueue, - downstream: subscriber)) + public func receive(subscriber: S) where S: Subscriber, S.Failure == SessionTaskPublisher.Failure, S.Input == SessionTaskPublisher.Output { + subscriber.receive(subscription: SessionTaskSubscription(request: request, + session: session, + callbackQueue: callbackQueue, + downstream: subscriber)) } - private final class RequestSubscription: Subscription where Downstream.Input == Request.Response, Downstream.Failure == Failure { + private final class SessionTaskSubscription: Subscription where Request.Response == Downstream.Input, Downstream.Failure == Failure { - private let session: Session private let request: Request + private let session: Session private let callbackQueue: CallbackQueue? private var downstream: Downstream? private var task: SessionTask? - init(session: Session, request: Request, callbackQueue: CallbackQueue?, downstream: Downstream) { - self.session = session + init(request: Request, session: Session, callbackQueue: CallbackQueue?, downstream: Downstream) { self.request = request + self.session = session self.callbackQueue = callbackQueue self.downstream = downstream } @@ -62,24 +65,24 @@ public struct RequestPublisher: Publisher { } } -@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Session { - /// Calls `publisher(_:callbackQueue:)` of `shared`. + /// Calls `sessionTaskPublisher(for:callbackQueue:)` of `Session.shared`. /// - parameter request: The request to be sent. /// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used. - /// - returns: The new request publisher. - static func publisher(_ request: Request, callbackQueue: CallbackQueue? = nil) -> RequestPublisher { - return RequestPublisher(session: .shared, request: request, callbackQueue: callbackQueue) + /// - returns: A publisher that wraps a session task for the request. + static func sessionTaskPublisher(for request: Request, callbackQueue: CallbackQueue? = nil) -> SessionTaskPublisher { + return SessionTaskPublisher(request: request, session: .shared, callbackQueue: callbackQueue) } - /// Returns a publisher that wraps a task for a given `Request`. + /// Returns a publisher that wraps a session task for the request. /// /// The publisher publishes `Request.Response` when the task completes, or terminates if the task fails with an error. /// - parameter request: The request to be sent. /// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used. - /// - returns: The new request publisher. - func publisher(_ request: Request, callbackQueue: CallbackQueue? = nil) -> RequestPublisher { - return RequestPublisher(session: self, request: request, callbackQueue: callbackQueue) + /// - returns: A publisher that wraps a session task for the request. + func sessionTaskPublisher(for request: Request, callbackQueue: CallbackQueue? = nil) -> SessionTaskPublisher { + return SessionTaskPublisher(request: request, session: self, callbackQueue: callbackQueue) } } diff --git a/Sources/APIKit/Session.swift b/Sources/APIKit/Session.swift index a3e14d07..4406fca9 100644 --- a/Sources/APIKit/Session.swift +++ b/Sources/APIKit/Session.swift @@ -30,7 +30,7 @@ open class Session { return privateShared } - /// Calls `send(_:callbackQueue:handler:)` of `shared`. + /// Calls `send(_:callbackQueue:handler:)` of `Session.shared`. /// - parameter request: The request to be sent. /// - parameter callbackQueue: The queue where the handler runs. If this parameters is `nil`, default `callbackQueue` of `Session` will be used. /// - parameter handler: The closure that receives result of the request. @@ -40,7 +40,7 @@ open class Session { return shared.send(request, callbackQueue: callbackQueue, handler: handler) } - /// Calls `cancelRequests(with:passingTest:)` of `sharedSession`. + /// Calls `cancelRequests(with:passingTest:)` of `Session.shared`. open class func cancelRequests(with requestType: Request.Type, passingTest test: @escaping (Request) -> Bool = { _ in true }) { shared.cancelRequests(with: requestType, passingTest: test) } diff --git a/Tests/APIKitTests/Combine/CombineTests.swift b/Tests/APIKitTests/Combine/CombineTests.swift index 809af613..54795439 100644 --- a/Tests/APIKitTests/Combine/CombineTests.swift +++ b/Tests/APIKitTests/Combine/CombineTests.swift @@ -30,7 +30,7 @@ final class CombineTests: XCTestCase { let expectation = self.expectation(description: "wait for response") let request = TestRequest() - session.publisher(request) + session.sessionTaskPublisher(for: request) .sink(receiveCompletion: { completion in switch completion { case .failure: @@ -52,7 +52,7 @@ final class CombineTests: XCTestCase { let expectation = self.expectation(description: "wait for response") let request = TestRequest() - session.publisher(request) + session.sessionTaskPublisher(for: request) .sink(receiveCompletion: { completion in if case .failure(let error) = completion, case .responseError(let responseError as NSError) = error { XCTAssertEqual(responseError.domain, NSCocoaErrorDomain) @@ -73,7 +73,7 @@ final class CombineTests: XCTestCase { let expectation = self.expectation(description: "wait for response") let request = TestRequest() - let cancellable = session.publisher(request) + let cancellable = session.sessionTaskPublisher(for: request) .sink(receiveCompletion: { completion in if case .failure(let error) = completion, case .connectionError(let connectionError as NSError) = error { XCTAssertEqual(connectionError.code, 0) From 5cc72bcd527653468d36f1764e44c291b4cd1f9f Mon Sep 17 00:00:00 2001 From: Econa77 Date: Tue, 23 Feb 2021 17:09:55 +0900 Subject: [PATCH 6/6] Fix tests --- Tests/APIKitTests/Combine/CombineTests.swift | 35 ++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Tests/APIKitTests/Combine/CombineTests.swift b/Tests/APIKitTests/Combine/CombineTests.swift index 54795439..a253067b 100644 --- a/Tests/APIKitTests/Combine/CombineTests.swift +++ b/Tests/APIKitTests/Combine/CombineTests.swift @@ -69,22 +69,51 @@ final class CombineTests: XCTestCase { waitForExpectations(timeout: 1.0, handler: nil) } - func testCancel() { - let expectation = self.expectation(description: "wait for response") + func testBefore2020OSVersionsCancel() throws { + if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { + throw XCTSkip("Skip on After 2020 OS versions, as Combine cancellation no longer emits a value.") + } + + let cancelExpectation = self.expectation(description: "wait for cancel") + let completionExpectation = self.expectation(description: "wait for response") let request = TestRequest() let cancellable = session.sessionTaskPublisher(for: request) + .handleEvents(receiveCancel: { + cancelExpectation.fulfill() + }) .sink(receiveCompletion: { completion in if case .failure(let error) = completion, case .connectionError(let connectionError as NSError) = error { XCTAssertEqual(connectionError.code, 0) - expectation.fulfill() + completionExpectation.fulfill() } else { XCTFail() } }, receiveValue: { response in XCTFail() }) + cancellable.cancel() + + waitForExpectations(timeout: 1.0, handler: nil) + } + + func testAfter2020OSVersionsCancel() throws { + guard #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) else { + throw XCTSkip("Skip on Before 2020 OS versions.") + } + let expectation = self.expectation(description: "wait for cancel") + let request = TestRequest() + + let cancellable = session.sessionTaskPublisher(for: request) + .handleEvents(receiveCancel: { + expectation.fulfill() + }) + .sink(receiveCompletion: { completion in + XCTFail() + }, receiveValue: { response in + XCTFail() + }) cancellable.cancel() waitForExpectations(timeout: 1.0, handler: nil)