From 22f56c457b54888ddd7a0bed27b77d0ee3eb8b78 Mon Sep 17 00:00:00 2001 From: Yosuke Ishikawa Date: Mon, 29 Oct 2018 23:19:35 +0900 Subject: [PATCH 01/61] Set version 4.1.0 --- APIKit.podspec | 2 +- Sources/APIKit/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index 4a32f309..7e23ce11 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "APIKit" - s.version = "4.0.0" + s.version = "4.1.0" s.summary = "Type-safe networking abstraction layer that associates request type with response type." s.homepage = "https://github.com/ishkawa/APIKit" diff --git a/Sources/APIKit/Info.plist b/Sources/APIKit/Info.plist index 0e9f1f71..517e7de8 100644 --- a/Sources/APIKit/Info.plist +++ b/Sources/APIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 4.0.0 + 4.1.0 CFBundleSignature ???? CFBundleVersion From b0b10ae5f08c1dfb3dd5c2b926e128d01e45401a Mon Sep 17 00:00:00 2001 From: lau Date: Tue, 2 Apr 2019 11:05:20 +0800 Subject: [PATCH 02/61] Support Swift 5.0 --- .gitmodules | 3 -- APIKit.xcodeproj/project.pbxproj | 28 +++++++++---------- .../xcshareddata/xcschemes/APIKit.xcscheme | 2 +- APIKit.xcworkspace/contents.xcworkspacedata | 3 -- Cartfile | 1 - Cartfile.resolved | 1 - Carthage/Checkouts/Result | 1 - README.md | 12 ++++---- .../MultipartFormDataBodyParameters.swift | 2 +- Sources/APIKit/Info.plist | 2 +- Sources/APIKit/Request.swift | 19 ++++++------- Sources/APIKit/Session.swift | 1 - Sources/APIKit/Unavailable.swift | 2 -- Tests/APIKitTests/SessionTests.swift | 1 - .../APIKitTests/TestComponents/HTTPStub.swift | 1 - 15 files changed, 33 insertions(+), 46 deletions(-) delete mode 100644 Cartfile delete mode 100644 Cartfile.resolved delete mode 160000 Carthage/Checkouts/Result diff --git a/.gitmodules b/.gitmodules index 00f2c4d7..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "Carthage/Checkouts/Result"] - path = Carthage/Checkouts/Result - url = https://github.com/antitypical/Result.git diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 0e672020..6f193f5d 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -7,9 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 141F12201C1C9ABE0026D415 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD5115241B1FFBA900514240 /* Result.framework */; }; - 141F12311C1C9AC70026D415 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD5115241B1FFBA900514240 /* Result.framework */; }; - 141F12361C1C9AC70026D415 /* Result.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = CD5115241B1FFBA900514240 /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 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 */; }; @@ -56,7 +53,7 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 7F4A73AC1CA839AE002554B1 /* PBXContainerItemProxy */ = { + BDFB151A2253060A00D8C94B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 7F45FCD41A94D02C006863BB /* Project object */; proxyType = 1; @@ -72,7 +69,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 141F12361C1C9AC70026D415 /* Result.framework in Copy Frameworks */, ); name = "Copy Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -129,7 +125,6 @@ 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = URLEncodedSerialization.swift; path = Sources/APIKit/Serializations/URLEncodedSerialization.swift; sourceTree = SOURCE_ROOT; }; 7F8ECDFD1B6A799E00234E04 /* Demo.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Demo.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPStub.swift; sourceTree = ""; }; - CD5115241B1FFBA900514240 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufDataParser.swift; path = Sources/APIKit/DataParser/ProtobufDataParser.swift; sourceTree = SOURCE_ROOT; }; ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtobufDataParserTests.swift; sourceTree = ""; }; ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufBodyParameters.swift; path = Sources/APIKit/BodyParameters/ProtobufBodyParameters.swift; sourceTree = SOURCE_ROOT; }; @@ -141,7 +136,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 141F12201C1C9ABE0026D415 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -149,7 +143,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 141F12311C1C9AC70026D415 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -308,7 +301,6 @@ children = ( 7F7048C61D9D89BE003C99F6 /* APIKit.h */, 7F7048C91D9D89BE003C99F6 /* Info.plist */, - CD5115241B1FFBA900514240 /* Result.framework */, ); name = "Supporting Files"; sourceTree = ""; @@ -388,7 +380,7 @@ buildRules = ( ); dependencies = ( - 7F4A73AD1CA839AE002554B1 /* PBXTargetDependency */, + BDFB151B2253060A00D8C94B /* PBXTargetDependency */, ); name = Tests; productName = APIKitTests; @@ -402,7 +394,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = "Yosuke Ishikawa"; TargetAttributes = { 141F12161C1C9ABE0026D415 = { @@ -415,7 +407,7 @@ }; buildConfigurationList = 7F45FCD71A94D02C006863BB /* Build configuration list for PBXProject "APIKit" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -509,10 +501,10 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 7F4A73AD1CA839AE002554B1 /* PBXTargetDependency */ = { + BDFB151B2253060A00D8C94B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 141F12161C1C9ABE0026D415 /* APIKit */; - targetProxy = 7F4A73AC1CA839AE002554B1 /* PBXContainerItemProxy */; + targetProxy = BDFB151A2253060A00D8C94B /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -524,8 +516,10 @@ CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -536,8 +530,10 @@ CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -546,6 +542,7 @@ baseConfigurationReference = 141F12401C1C9EA30026D415 /* Tests.xcconfig */; buildSettings = { INFOPLIST_FILE = Tests/APIKitTests/Info.plist; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -555,6 +552,7 @@ buildSettings = { INFOPLIST_FILE = Tests/APIKitTests/Info.plist; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -562,6 +560,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 141F12101C1C96820026D415 /* Debug.xcconfig */; buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; @@ -583,6 +582,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 141F12111C1C96820026D415 /* Release.xcconfig */; buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; diff --git a/APIKit.xcodeproj/xcshareddata/xcschemes/APIKit.xcscheme b/APIKit.xcodeproj/xcshareddata/xcschemes/APIKit.xcscheme index 8125e06b..762479b4 100644 --- a/APIKit.xcodeproj/xcshareddata/xcschemes/APIKit.xcscheme +++ b/APIKit.xcodeproj/xcshareddata/xcschemes/APIKit.xcscheme @@ -1,6 +1,6 @@ - - diff --git a/Cartfile b/Cartfile deleted file mode 100644 index e9bc3ad0..00000000 --- a/Cartfile +++ /dev/null @@ -1 +0,0 @@ -github "antitypical/Result" ~> 4.0 diff --git a/Cartfile.resolved b/Cartfile.resolved deleted file mode 100644 index 23aa9709..00000000 --- a/Cartfile.resolved +++ /dev/null @@ -1 +0,0 @@ -github "antitypical/Result" "4.0.0" diff --git a/Carthage/Checkouts/Result b/Carthage/Checkouts/Result deleted file mode 160000 index 8fc088dc..00000000 --- a/Carthage/Checkouts/Result +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8fc088dcf72802801efeecba76ea8fb041fb773d diff --git a/README.md b/README.md index 6dd793e3..f9036697 100644 --- a/README.md +++ b/README.md @@ -30,28 +30,30 @@ Session.send(request) { result in ## Requirements -- Swift 3.0 or later +- Swift 5.0 or later - iOS 8.0 or later -- Mac OS 10.10 or later +- Mac OS 10.11 or later - watchOS 2.0 or later - tvOS 9.0 or later If you use Swift 2.2 or 2.3, try [APIKit 2.0.5](https://github.com/ishkawa/APIKit/tree/2.0.5). +If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/APIKit/tree/release/4.1.0). + ## Installation #### [Carthage](https://github.com/Carthage/Carthage) -- Insert `github "ishkawa/APIKit" ~> 3.1` to your Cartfile. +- Insert `github "ishkawa/APIKit" ~> 5.0` to your Cartfile. - Run `carthage update`. - Link your app with `APIKit.framework` and `Result.framework` in `Carthage/Build`. #### [CocoaPods](https://github.com/cocoapods/cocoapods) -- Insert `pod 'APIKit', '~> 3.1'` to your Podfile. +- Insert `pod 'APIKit', '~> 5.0'` to your Podfile. - Run `pod install`. -Note: CocoaPods 1.1.0 is required to install APIKit 3. +Note: CocoaPods 1.1.0 is required to install APIKit 5. ## Documentation diff --git a/Sources/APIKit/BodyParameters/MultipartFormDataBodyParameters.swift b/Sources/APIKit/BodyParameters/MultipartFormDataBodyParameters.swift index 0b1e2d2d..d1337978 100644 --- a/Sources/APIKit/BodyParameters/MultipartFormDataBodyParameters.swift +++ b/Sources/APIKit/BodyParameters/MultipartFormDataBodyParameters.swift @@ -58,7 +58,7 @@ public struct MultipartFormDataBodyParameters: BodyParameters { public extension MultipartFormDataBodyParameters { /// Part represents single part of multipart/form-data. - public struct Part { + struct Part { public enum Error: Swift.Error { case illegalValue(Any) case illegalFileURL(URL) diff --git a/Sources/APIKit/Info.plist b/Sources/APIKit/Info.plist index 0e9f1f71..ebe40223 100644 --- a/Sources/APIKit/Info.plist +++ b/Sources/APIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 4.0.0 + 5.0.0 CFBundleSignature ???? CFBundleVersion diff --git a/Sources/APIKit/Request.swift b/Sources/APIKit/Request.swift index e65e3819..efe68c97 100644 --- a/Sources/APIKit/Request.swift +++ b/Sources/APIKit/Request.swift @@ -1,5 +1,4 @@ import Foundation -import Result /// `Request` protocol represents a request for Web API. /// Following 5 items must be implemented. @@ -62,11 +61,11 @@ public protocol Request { } public extension Request { - public var parameters: Any? { + var parameters: Any? { return nil } - public var queryParameters: [String: Any]? { + var queryParameters: [String: Any]? { guard let parameters = parameters as? [String: Any], method.prefersQueryParameters else { return nil } @@ -74,7 +73,7 @@ public extension Request { return parameters } - public var bodyParameters: BodyParameters? { + var bodyParameters: BodyParameters? { guard let parameters = parameters, !method.prefersQueryParameters else { return nil } @@ -82,19 +81,19 @@ public extension Request { return JSONBodyParameters(JSONObject: parameters) } - public var headerFields: [String: String] { + var headerFields: [String: String] { return [:] } - public var dataParser: DataParser { + var dataParser: DataParser { return JSONDataParser(readingOptions: []) } - public func intercept(urlRequest: URLRequest) throws -> URLRequest { + func intercept(urlRequest: URLRequest) throws -> URLRequest { return urlRequest } - public func intercept(object: Any, urlResponse: HTTPURLResponse) throws -> Any { + func intercept(object: Any, urlResponse: HTTPURLResponse) throws -> Any { guard 200..<300 ~= urlResponse.statusCode else { throw ResponseError.unacceptableStatusCode(urlResponse.statusCode) } @@ -103,7 +102,7 @@ public extension Request { /// Builds `URLRequest` from properties of `self`. /// - Throws: `RequestError`, `Error` - public func buildURLRequest() throws -> URLRequest { + func buildURLRequest() throws -> URLRequest { let url = path.isEmpty ? baseURL : baseURL.appendingPathComponent(path) guard var components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { throw RequestError.invalidBaseURL(baseURL) @@ -140,7 +139,7 @@ public extension Request { /// Builds `Response` from response `Data`. /// - Throws: `ResponseError`, `Error` - public func parse(data: Data, urlResponse: HTTPURLResponse) throws -> Response { + func parse(data: Data, urlResponse: HTTPURLResponse) throws -> Response { let parsedObject = try dataParser.parse(data: data) let passedObject = try intercept(object: parsedObject, urlResponse: urlResponse) return try response(from: passedObject, urlResponse: urlResponse) diff --git a/Sources/APIKit/Session.swift b/Sources/APIKit/Session.swift index 72a9405e..606531a6 100644 --- a/Sources/APIKit/Session.swift +++ b/Sources/APIKit/Session.swift @@ -1,5 +1,4 @@ import Foundation -import Result private var taskRequestKey = 0 diff --git a/Sources/APIKit/Unavailable.swift b/Sources/APIKit/Unavailable.swift index 92765230..2c05f7f6 100644 --- a/Sources/APIKit/Unavailable.swift +++ b/Sources/APIKit/Unavailable.swift @@ -6,8 +6,6 @@ // Copyright © 2016 Yosuke Ishikawa. All rights reserved. // -import Result - // MARK: - Protocols @available(*, unavailable, renamed: "Request") diff --git a/Tests/APIKitTests/SessionTests.swift b/Tests/APIKitTests/SessionTests.swift index 138fdf9f..d65a235e 100644 --- a/Tests/APIKitTests/SessionTests.swift +++ b/Tests/APIKitTests/SessionTests.swift @@ -1,7 +1,6 @@ import Foundation import APIKit import XCTest -import Result class SessionTests: XCTestCase { var adapter: TestSessionAdapter! diff --git a/Tests/APIKitTests/TestComponents/HTTPStub.swift b/Tests/APIKitTests/TestComponents/HTTPStub.swift index b56ff6d5..6170d79f 100644 --- a/Tests/APIKitTests/TestComponents/HTTPStub.swift +++ b/Tests/APIKitTests/TestComponents/HTTPStub.swift @@ -1,6 +1,5 @@ import Foundation import Dispatch -import Result class HTTPStub: URLProtocol { static var stubResult: Result = .success(Data()) From c2832defe67521c24e3aa880bc589834ef40cc4f Mon Sep 17 00:00:00 2001 From: lau Date: Tue, 2 Apr 2019 14:52:44 +0800 Subject: [PATCH 03/61] edit podspec file --- APIKit.podspec | 8 +++----- Package.swift | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index 4a32f309..c0a36453 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "APIKit" - s.version = "4.0.0" + s.version = "5.0.0" s.summary = "Type-safe networking abstraction layer that associates request type with response type." s.homepage = "https://github.com/ishkawa/APIKit" @@ -9,7 +9,7 @@ Pod::Spec.new do |s| } s.ios.deployment_target = "8.0" - s.osx.deployment_target = "10.10" + s.osx.deployment_target = "10.11" if s.respond_to?(:watchos) s.watchos.deployment_target = "2.0" end @@ -23,7 +23,7 @@ Pod::Spec.new do |s| :tag => "#{s.version}", } - s.swift_version = "4.0" + s.swift_version = "5.0" s.license = { :type => "MIT", @@ -34,6 +34,4 @@ Pod::Spec.new do |s| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. LICENSE } - - s.dependency "Result", "~> 4.0" end diff --git a/Package.swift b/Package.swift index 0b9f1c72..747e0c65 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let package = Package( .library(name: "APIKit", targets: ["APIKit"]), ], dependencies: [ - .package(url: "https://github.com/antitypical/Result.git", from: "4.0.0"), + .package(url: "https://github.com/antitypical/Result.git", from: "5.0.0"), ], targets: [ .target( @@ -20,5 +20,5 @@ let package = Package( dependencies: ["APIKit"] ), ], - swiftLanguageVersions: [4] + swiftLanguageVersions: [5] ) From fb60af3eb3adcba98ff6ee1caf1f0e902da8609f Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Sat, 6 Apr 2019 10:00:00 +0900 Subject: [PATCH 04/61] [CI] Refactor .travis.yml --- .travis.yml | 52 +++++++------------ .../ProtobufBodyParametersTests.swift | 3 ++ .../ProtobufDataParserTests.swift | 3 ++ 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index 53d24f72..cc4bfba4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,29 +4,16 @@ env: matrix: include: - - os: osx + - &podspec + os: osx language: objective-c - osx_image: xcode9.2 + osx_image: xcode10.2 script: - - set -o pipefail - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 6s" ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c - after_success: - - bash <(curl -s https://codecov.io/bash) - - os: osx - language: objective-c - osx_image: xcode9.4 - script: - - set -o pipefail - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 6s" ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c - after_success: - - bash <(curl -s https://codecov.io/bash) - - os: osx + - pod lib lint --allow-warnings + - &xcode + os: osx language: objective-c - osx_image: xcode10 + osx_image: xcode9.2 script: - set -o pipefail - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c @@ -34,24 +21,25 @@ matrix: - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c after_success: - bash <(curl -s https://codecov.io/bash) - - os: osx + - <<: *xcode + osx_image: xcode9.4 + - <<: *xcode + osx_image: xcode10.1 + - <<: *xcode + osx_image: xcode10.2 + - &swiftpm + os: osx language: generic osx_image: xcode9.2 script: - swift build - swift test - - os: osx - language: generic + - <<: *swiftpm osx_image: xcode9.4 - script: - - swift build - - swift test - - os: osx - language: generic - osx_image: xcode10 - script: - - swift build - - swift test + - <<: *swiftpm + osx_image: xcode10.1 + - <<: *swiftpm + osx_image: xcode10.2 notifications: email: false diff --git a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift index 844ea00d..e58102d3 100644 --- a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift @@ -4,6 +4,8 @@ import APIKit class ProtobufBodyParametersTests: XCTestCase { func testProtobufSuccess() { + // Temporarily gated due to https://openradar.appspot.com/49262697 + if #available(macOS 10.11, *) { let object = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) let parameters = ProtobufBodyParameters(protobufObject: object) XCTAssertEqual(parameters.contentType, "application/protobuf") @@ -21,5 +23,6 @@ class ProtobufBodyParametersTests: XCTestCase { } catch { XCTFail() } + } } } diff --git a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift index e517e5c7..968b31e0 100644 --- a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift @@ -9,6 +9,8 @@ class ProtobufDataParserTests: XCTestCase { } func testProtobufSuccess() { + // Temporarily gated due to https://openradar.appspot.com/49262697 + if #available(macOS 10.11, *) { let data = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) let parser = ProtobufDataParser() @@ -21,5 +23,6 @@ class ProtobufDataParserTests: XCTestCase { } catch { XCTFail() } + } } } From e80306f22b93f29c3f10feb36a7dfefd79c51635 Mon Sep 17 00:00:00 2001 From: lau Date: Mon, 8 Apr 2019 10:32:30 +0800 Subject: [PATCH 05/61] update --- APIKit.xcodeproj/project.pbxproj | 4 ++-- Package.swift | 6 +----- README.md | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 6f193f5d..6f4ec7b0 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -574,7 +574,7 @@ ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; ONLY_ACTIVE_ARCH = YES; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -594,7 +594,7 @@ CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; GCC_NO_COMMON_BLOCKS = YES; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Package.swift b/Package.swift index 747e0c65..e0cb808f 100644 --- a/Package.swift +++ b/Package.swift @@ -6,13 +6,9 @@ let package = Package( products: [ .library(name: "APIKit", targets: ["APIKit"]), ], - dependencies: [ - .package(url: "https://github.com/antitypical/Result.git", from: "5.0.0"), - ], targets: [ .target( - name: "APIKit", - dependencies: ["Result"], + name: "APIKit", exclude: ["BodyParameters/AbstractInputStream.m"] ), .testTarget( diff --git a/README.md b/README.md index f9036697..0df78d17 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/AP - Insert `pod 'APIKit', '~> 5.0'` to your Podfile. - Run `pod install`. -Note: CocoaPods 1.1.0 is required to install APIKit 5. +Note: CocoaPods 1.4.0 is required to install APIKit 5. ## Documentation From 55ba93da64e221635e0fa79f27cd218730309935 Mon Sep 17 00:00:00 2001 From: lau Date: Mon, 8 Apr 2019 11:09:13 +0800 Subject: [PATCH 06/61] Merge pull request #270 --- .travis.yml | 52 +++++++------------ APIKit.podspec | 2 +- APIKit.xcodeproj/project.pbxproj | 4 +- .../ProtobufBodyParametersTests.swift | 3 ++ .../ProtobufDataParserTests.swift | 3 ++ 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/.travis.yml b/.travis.yml index 53d24f72..cc4bfba4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,29 +4,16 @@ env: matrix: include: - - os: osx + - &podspec + os: osx language: objective-c - osx_image: xcode9.2 + osx_image: xcode10.2 script: - - set -o pipefail - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 6s" ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c - after_success: - - bash <(curl -s https://codecov.io/bash) - - os: osx - language: objective-c - osx_image: xcode9.4 - script: - - set -o pipefail - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 6s" ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c - after_success: - - bash <(curl -s https://codecov.io/bash) - - os: osx + - pod lib lint --allow-warnings + - &xcode + os: osx language: objective-c - osx_image: xcode10 + osx_image: xcode9.2 script: - set -o pipefail - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c @@ -34,24 +21,25 @@ matrix: - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c after_success: - bash <(curl -s https://codecov.io/bash) - - os: osx + - <<: *xcode + osx_image: xcode9.4 + - <<: *xcode + osx_image: xcode10.1 + - <<: *xcode + osx_image: xcode10.2 + - &swiftpm + os: osx language: generic osx_image: xcode9.2 script: - swift build - swift test - - os: osx - language: generic + - <<: *swiftpm osx_image: xcode9.4 - script: - - swift build - - swift test - - os: osx - language: generic - osx_image: xcode10 - script: - - swift build - - swift test + - <<: *swiftpm + osx_image: xcode10.1 + - <<: *swiftpm + osx_image: xcode10.2 notifications: email: false diff --git a/APIKit.podspec b/APIKit.podspec index c0a36453..ac95ba79 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| } s.ios.deployment_target = "8.0" - s.osx.deployment_target = "10.11" + s.osx.deployment_target = "10.10" if s.respond_to?(:watchos) s.watchos.deployment_target = "2.0" end diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 6f4ec7b0..2795a54a 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -516,7 +516,7 @@ CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.10; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -530,7 +530,7 @@ CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.10; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; diff --git a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift index 844ea00d..e58102d3 100644 --- a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift @@ -4,6 +4,8 @@ import APIKit class ProtobufBodyParametersTests: XCTestCase { func testProtobufSuccess() { + // Temporarily gated due to https://openradar.appspot.com/49262697 + if #available(macOS 10.11, *) { let object = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) let parameters = ProtobufBodyParameters(protobufObject: object) XCTAssertEqual(parameters.contentType, "application/protobuf") @@ -21,5 +23,6 @@ class ProtobufBodyParametersTests: XCTestCase { } catch { XCTFail() } + } } } diff --git a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift index e517e5c7..968b31e0 100644 --- a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift @@ -9,6 +9,8 @@ class ProtobufDataParserTests: XCTestCase { } func testProtobufSuccess() { + // Temporarily gated due to https://openradar.appspot.com/49262697 + if #available(macOS 10.11, *) { let data = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) let parser = ProtobufDataParser() @@ -21,5 +23,6 @@ class ProtobufDataParserTests: XCTestCase { } catch { XCTFail() } + } } } From bb985f10dfb6b2f1fce69aa13d09e78bb923c1f7 Mon Sep 17 00:00:00 2001 From: commandZi Date: Mon, 8 Apr 2019 11:13:25 +0800 Subject: [PATCH 07/61] Update README.md Fixed requirements. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0df78d17..56c38bdd 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Session.send(request) { result in - Swift 5.0 or later - iOS 8.0 or later -- Mac OS 10.11 or later +- Mac OS 10.10 or later - watchOS 2.0 or later - tvOS 9.0 or later From 723c099bc55bd77adbc2951a903815289ff5e58a Mon Sep 17 00:00:00 2001 From: lau Date: Tue, 9 Apr 2019 15:53:23 +0800 Subject: [PATCH 08/61] Remove the `.swift-version` file which is now deprecated. --- .swift-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .swift-version diff --git a/.swift-version b/.swift-version deleted file mode 100644 index 5186d070..00000000 --- a/.swift-version +++ /dev/null @@ -1 +0,0 @@ -4.0 From f775ccb97f1311a1cfb7bc472ebfc60acbe53125 Mon Sep 17 00:00:00 2001 From: lau Date: Wed, 10 Apr 2019 12:17:28 +0800 Subject: [PATCH 09/61] Revert "Remove the `.swift-version` file which is now deprecated." This reverts commit 723c099bc55bd77adbc2951a903815289ff5e58a. --- .swift-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 00000000..5186d070 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +4.0 From 9867fc3aa8e7cea970a986a020fb92054d7a0b8f Mon Sep 17 00:00:00 2001 From: lau Date: Wed, 10 Apr 2019 14:19:53 +0800 Subject: [PATCH 10/61] Fix .swift-version file --- .swift-version | 2 +- Package.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.swift-version b/.swift-version index 5186d070..819e07a2 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.0 +5.0 diff --git a/Package.swift b/Package.swift index e0cb808f..13644d4f 100644 --- a/Package.swift +++ b/Package.swift @@ -16,5 +16,5 @@ let package = Package( dependencies: ["APIKit"] ), ], - swiftLanguageVersions: [5] + swiftLanguageVersions: [.v5] ) From 92a498316b89c02ed9198bc39144547533592937 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:38:11 +0900 Subject: [PATCH 11/61] Update .travis.yml --- .travis.yml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc4bfba4..9e4550f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ matrix: - &xcode os: osx language: objective-c - osx_image: xcode9.2 + osx_image: xcode10.2 script: - set -o pipefail - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c @@ -21,25 +21,13 @@ matrix: - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c after_success: - bash <(curl -s https://codecov.io/bash) - - <<: *xcode - osx_image: xcode9.4 - - <<: *xcode - osx_image: xcode10.1 - - <<: *xcode - osx_image: xcode10.2 - &swiftpm os: osx language: generic - osx_image: xcode9.2 + osx_image: xcode10.2 script: - swift build - swift test - - <<: *swiftpm - osx_image: xcode9.4 - - <<: *swiftpm - osx_image: xcode10.1 - - <<: *swiftpm - osx_image: xcode10.2 notifications: email: false From a476ca91c24304de4982db7cc1e62cae31efacdf Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:39:48 +0900 Subject: [PATCH 12/61] Remove target level SWIFT_VERSION build settings --- APIKit.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 2795a54a..76d608d8 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -519,7 +519,6 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -533,7 +532,6 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; }; name = Release; }; @@ -542,7 +540,6 @@ baseConfigurationReference = 141F12401C1C9EA30026D415 /* Tests.xcconfig */; buildSettings = { INFOPLIST_FILE = Tests/APIKitTests/Info.plist; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -552,7 +549,6 @@ buildSettings = { INFOPLIST_FILE = Tests/APIKitTests/Info.plist; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; }; name = Release; }; From 8b1c2bea2d7f482fe866eb08c2be943adf60fd63 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:49:04 +0900 Subject: [PATCH 13/61] Remove empty .gitmodules --- .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29b..00000000 From 868117fe528bf10e5b89dd7970d74114e2e5398a Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:53:24 +0900 Subject: [PATCH 14/61] Revert unnecessary changes --- APIKit.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 76d608d8..1f476eb1 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -53,7 +53,7 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - BDFB151A2253060A00D8C94B /* PBXContainerItemProxy */ = { + 7F4A73AC1CA839AE002554B1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 7F45FCD41A94D02C006863BB /* Project object */; proxyType = 1; @@ -380,7 +380,7 @@ buildRules = ( ); dependencies = ( - BDFB151B2253060A00D8C94B /* PBXTargetDependency */, + 7F4A73AD1CA839AE002554B1 /* PBXTargetDependency */, ); name = Tests; productName = APIKitTests; @@ -501,10 +501,10 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - BDFB151B2253060A00D8C94B /* PBXTargetDependency */ = { + 7F4A73AD1CA839AE002554B1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 141F12161C1C9ABE0026D415 /* APIKit */; - targetProxy = BDFB151A2253060A00D8C94B /* PBXContainerItemProxy */; + targetProxy = 7F4A73AC1CA839AE002554B1 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ From 7a92725fda2ddfcbda76ee62a6f1770f36c43d22 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:54:54 +0900 Subject: [PATCH 15/61] Remove unnecessary target level MACOSX_DEPLOYMENT_TARGET --- APIKit.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 1f476eb1..11a6bbc0 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -516,7 +516,6 @@ CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -529,7 +528,6 @@ CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; From af39702140e54d68c775bffc50d007c3478472ce Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:56:34 +0900 Subject: [PATCH 16/61] Fix README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56c38bdd..d927057a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Session.send(request) { result in If you use Swift 2.2 or 2.3, try [APIKit 2.0.5](https://github.com/ishkawa/APIKit/tree/2.0.5). -If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/APIKit/tree/release/4.1.0). +If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/APIKit/tree/4.1.0). ## Installation From d06fce0898384881d19a79277b3a656a24d94e79 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 20:59:15 +0900 Subject: [PATCH 17/61] Fix up Package.swift --- Package.resolved | 16 ---------------- Package.swift | 6 ++++-- Package@swift-4.2.swift | 24 ------------------------ 3 files changed, 4 insertions(+), 42 deletions(-) delete mode 100644 Package.resolved delete mode 100644 Package@swift-4.2.swift diff --git a/Package.resolved b/Package.resolved deleted file mode 100644 index dc09c894..00000000 --- a/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "Result", - "repositoryURL": "https://github.com/antitypical/Result.git", - "state": { - "branch": null, - "revision": "8fc088dcf72802801efeecba76ea8fb041fb773d", - "version": "4.0.0" - } - } - ] - }, - "version": 1 -} diff --git a/Package.swift b/Package.swift index 13644d4f..3f30b4ef 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.0 +// swift-tools-version:5.0 import PackageDescription let package = Package( @@ -6,9 +6,11 @@ let package = Package( products: [ .library(name: "APIKit", targets: ["APIKit"]), ], + dependencies: [], targets: [ .target( - name: "APIKit", + name: "APIKit", + dependencies: [], exclude: ["BodyParameters/AbstractInputStream.m"] ), .testTarget( diff --git a/Package@swift-4.2.swift b/Package@swift-4.2.swift deleted file mode 100644 index 9021d1eb..00000000 --- a/Package@swift-4.2.swift +++ /dev/null @@ -1,24 +0,0 @@ -// swift-tools-version:4.2 -import PackageDescription - -let package = Package( - name: "APIKit", - products: [ - .library(name: "APIKit", targets: ["APIKit"]), - ], - dependencies: [ - .package(url: "https://github.com/antitypical/Result.git", from: "4.0.0"), - ], - targets: [ - .target( - name: "APIKit", - dependencies: ["Result"], - exclude: ["BodyParameters/AbstractInputStream.m"] - ), - .testTarget( - name: "APIKitTests", - dependencies: ["APIKit"] - ), - ], - swiftLanguageVersions: [.v4, .v4_2] -) From 8ebce4272998e39bb556b12820bdf0a7dae20ff7 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 21:02:15 +0900 Subject: [PATCH 18/61] [CI] Add name to build matrix --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9e4550f1..5835af9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,14 @@ env: matrix: include: - &podspec + name: CocoaPods Lint os: osx language: objective-c osx_image: xcode10.2 script: - pod lib lint --allow-warnings - &xcode + name: Xcode 10.2 / Swift 5.0 os: osx language: objective-c osx_image: xcode10.2 @@ -22,6 +24,7 @@ matrix: after_success: - bash <(curl -s https://codecov.io/bash) - &swiftpm + name: SwiftPM / Darwin / Swift 5.0 os: osx language: generic osx_image: xcode10.2 From 5f4b96bd81f9475cce28bfa2cd1655a9f8d86e7c Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Fri, 12 Apr 2019 21:17:13 +0900 Subject: [PATCH 19/61] Add platforms to Package.swift --- Package.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Package.swift b/Package.swift index 3f30b4ef..9ce875e0 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,9 @@ import PackageDescription let package = Package( name: "APIKit", + platforms: [ + .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2) + ], products: [ .library(name: "APIKit", targets: ["APIKit"]), ], From 18ceb6a230be44145b373a85cabeb3f610439a98 Mon Sep 17 00:00:00 2001 From: jumperson Date: Fri, 26 Jul 2019 10:36:09 +0900 Subject: [PATCH 20/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d927057a..9bc26fcb 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/AP - Insert `github "ishkawa/APIKit" ~> 5.0` to your Cartfile. - Run `carthage update`. -- Link your app with `APIKit.framework` and `Result.framework` in `Carthage/Build`. +- Link your app with `APIKit.framework` in `Carthage/Build`. #### [CocoaPods](https://github.com/cocoapods/cocoapods) From 8521bf047937ea639d64f0f3e79dbd00f042e3ec Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Tue, 24 Sep 2019 17:43:37 +0900 Subject: [PATCH 21/61] ExpressibleByDictionaryLiteral for JSONBodyParameters --- .../BodyParameters/JSONBodyParameters.swift | 9 ++++++++ .../JSONBodyParametersTests.swift | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Sources/APIKit/BodyParameters/JSONBodyParameters.swift b/Sources/APIKit/BodyParameters/JSONBodyParameters.swift index 3f541917..4388ce34 100644 --- a/Sources/APIKit/BodyParameters/JSONBodyParameters.swift +++ b/Sources/APIKit/BodyParameters/JSONBodyParameters.swift @@ -32,3 +32,12 @@ public struct JSONBodyParameters: BodyParameters { return .data(try JSONSerialization.data(withJSONObject: JSONObject, options: writingOptions)) } } + +extension JSONBodyParameters: ExpressibleByDictionaryLiteral { + public typealias Key = String + public typealias Value = Any + + public init(dictionaryLiteral elements: (Key, Value)...) { + self.init(JSONObject: Dictionary(uniqueKeysWithValues: elements)) + } +} diff --git a/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift b/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift index 006c8e04..512eb749 100644 --- a/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift @@ -36,4 +36,25 @@ class JSONBodyParametersTests: XCTestCase { XCTAssertEqual(nserror.code, 3840) } } + + func testDictionaryLiteral() { + let object = ["foo": 1, "bar": 2, "baz": 3] + + let parameters1: JSONBodyParameters = .init(JSONObject: object) + let parameters2: JSONBodyParameters = ["foo": 1, "bar": 2, "baz": 3] + do { + guard case .data(let data1) = try parameters1.buildEntity(), + case .data(let data2) = try parameters2.buildEntity() else { + XCTFail() + return + } + let dictionary1 = try JSONSerialization.jsonObject(with: data1, options: []) + let dictionary2 = try JSONSerialization.jsonObject(with: data2, options: []) + XCTAssertEqual((dictionary1 as? [String: Int])?["foo"], (dictionary2 as? [String: Int])?["foo"]) + XCTAssertEqual((dictionary1 as? [String: Int])?["bar"], (dictionary2 as? [String: Int])?["bar"]) + XCTAssertEqual((dictionary1 as? [String: Int])?["baz"], (dictionary2 as? [String: Int])?["baz"]) + } catch { + XCTFail() + } + } } From afb1f0dd4bec16d975bdd0da1cef1b4a25b82333 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 8 Oct 2019 10:52:49 +0900 Subject: [PATCH 22/61] Fix typo --- Sources/APIKit/SessionAdapter/URLSessionAdapter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift b/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift index 6caad171..aa909dc1 100644 --- a/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift +++ b/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift @@ -15,7 +15,7 @@ private var taskAssociatedObjectCompletionHandlerKey = 0 /// `URLSession(_:task: didCompleteWithError:)` and `URLSession(_:dataTask:didReceiveData:)`, you have to call /// `super` in these methods if you implement them. open class URLSessionAdapter: NSObject, SessionAdapter, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate { - /// The undelying `URLSession` instance. + /// The underlying `URLSession` instance. open var urlSession: URLSession! /// Returns `URLSessionAdapter` initialized with `URLSessionConfiguration`. From 8c80624800af9aa898e41066fc941545df5b28af Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Mon, 18 Nov 2019 11:54:48 +0900 Subject: [PATCH 23/61] [Swift 5.1] Enable Module Stability https://swift.org/blog/swift-5-1-released/#module-stability --- .travis.yml | 16 +++++++++++----- Configurations/APIKit.xcconfig | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5835af9b..e8f4a929 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,29 +8,35 @@ matrix: name: CocoaPods Lint os: osx language: objective-c - osx_image: xcode10.2 + osx_image: xcode10.3 script: - pod lib lint --allow-warnings - &xcode - name: Xcode 10.2 / Swift 5.0 + name: Xcode 10.3 / Swift 5.0 os: osx language: objective-c - osx_image: xcode10.2 + osx_image: xcode10.3 script: - set -o pipefail - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 6s" ENABLE_TESTABILITY=YES | xcpretty -c + - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 8" ENABLE_TESTABILITY=YES | xcpretty -c - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c after_success: - bash <(curl -s https://codecov.io/bash) + - <<: *xcode + name: Xcode 11.2 / Swift 5.1 + osx_image: xcode11.2 - &swiftpm name: SwiftPM / Darwin / Swift 5.0 os: osx language: generic - osx_image: xcode10.2 + osx_image: xcode10.3 script: - swift build - swift test + - <<: *swiftpm + name: SwiftPM / Darwin / Swift 5.1 + osx_image: xcode11.2 notifications: email: false diff --git a/Configurations/APIKit.xcconfig b/Configurations/APIKit.xcconfig index f84c0571..8b0bdbfc 100644 --- a/Configurations/APIKit.xcconfig +++ b/Configurations/APIKit.xcconfig @@ -22,3 +22,4 @@ LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = $(inherited) @executable_path/Frameworks @ LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = $(inherited) @executable_path/Frameworks @loader_path/Frameworks APPLICATION_EXTENSION_API_ONLY = YES; +BUILD_LIBRARY_FOR_DISTRIBUTION = YES; From c3d981075b83a314445f90e559bd6771ffb239be Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Sat, 28 Dec 2019 16:00:39 +0900 Subject: [PATCH 24/61] Set version 5.1.0 --- APIKit.podspec | 2 +- Sources/APIKit/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index ac95ba79..d4d08ba5 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "APIKit" - s.version = "5.0.0" + s.version = "5.1.0" s.summary = "Type-safe networking abstraction layer that associates request type with response type." s.homepage = "https://github.com/ishkawa/APIKit" diff --git a/Sources/APIKit/Info.plist b/Sources/APIKit/Info.plist index ebe40223..206d86b6 100644 --- a/Sources/APIKit/Info.plist +++ b/Sources/APIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.0.0 + 5.1.0 CFBundleSignature ???? CFBundleVersion From 89619a8eb238526817b2914d7b1ce835b2dbd50b Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Sat, 16 May 2020 10:32:26 +0900 Subject: [PATCH 25/61] Remove unnecessary code --- .travis.yml | 4 ++++ Sources/APIKit/Session.swift | 2 +- Sources/APIKit/SessionAdapter/URLSessionAdapter.swift | 7 ++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index e8f4a929..a8928888 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +branches: + only: + - master + env: global: - LC_CTYPE=en_US.UTF-8 diff --git a/Sources/APIKit/Session.swift b/Sources/APIKit/Session.swift index 606531a6..c772247f 100644 --- a/Sources/APIKit/Session.swift +++ b/Sources/APIKit/Session.swift @@ -101,7 +101,7 @@ open class Session { /// - parameter test: The test closure that determines if a request should be cancelled or not. open func cancelRequests(with requestType: Request.Type, passingTest test: @escaping (Request) -> Bool = { _ in true }) { adapter.getTasks { [weak self] tasks in - return tasks + tasks .filter { task in if let request = self?.requestForTask(task) as Request? { return test(request) diff --git a/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift b/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift index aa909dc1..38ac15ef 100644 --- a/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift +++ b/Sources/APIKit/SessionAdapter/URLSessionAdapter.swift @@ -37,11 +37,8 @@ open class URLSessionAdapter: NSObject, SessionAdapter, URLSessionDelegate, URLS /// Aggregates `URLSessionTask` instances in `URLSession` using `getTasksWithCompletionHandler(_:)`. open func getTasks(with handler: @escaping ([SessionTask]) -> Void) { urlSession.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in - let allTasks = dataTasks as [URLSessionTask] - + uploadTasks as [URLSessionTask] - + downloadTasks as [URLSessionTask] - - handler(allTasks.map { $0 }) + let allTasks: [URLSessionTask] = dataTasks + uploadTasks + downloadTasks + handler(allTasks) } } From 35c4ce95cf7c2708ea5cf56cc4365478743c7c73 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Sat, 16 May 2020 10:55:47 +0900 Subject: [PATCH 26/61] [CI] Use GitHub Actions --- .github/workflows/ci.yml | 53 ++++++++++++++++++++++++++++++++++++++++ .travis.yml | 25 ------------------- 2 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..464450cd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +jobs: + podspec: + runs-on: macos-latest + name: CocoaPods Lint + env: + DEVELOPER_DIR: "/Applications/Xcode_11.4.1.app" + steps: + - uses: actions/checkout@v2 + - run: pod lib lint --allow-warnings + + xcode: + runs-on: macos-latest + strategy: + matrix: + xcode: [10.3, 11.3.1, 11.4.1] + fail-fast: false + name: Xcode ${{ matrix.xcode }} + env: + DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app" + steps: + - uses: actions/checkout@v2 + - name: test + run: | + set -o pipefail + xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c + xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 8" ENABLE_TESTABILITY=YES | xcpretty -c + xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c + - name: codecov + run: bash <(curl -s https://codecov.io/bash) + if: success() + + swiftpm: + runs-on: macos-latest + strategy: + matrix: + xcode: [11.3.1, 11.4.1] + fail-fast: false + name: SwiftPM (Xcode ${{ matrix.xcode }}) + env: + DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app" + steps: + - uses: actions/checkout@v2 + - name: build and test + run: | + swift build + swift test diff --git a/.travis.yml b/.travis.yml index a8928888..34e8b0db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,28 +8,6 @@ env: matrix: include: - - &podspec - name: CocoaPods Lint - os: osx - language: objective-c - osx_image: xcode10.3 - script: - - pod lib lint --allow-warnings - - &xcode - name: Xcode 10.3 / Swift 5.0 - os: osx - language: objective-c - osx_image: xcode10.3 - script: - - set -o pipefail - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 8" ENABLE_TESTABILITY=YES | xcpretty -c - - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c - after_success: - - bash <(curl -s https://codecov.io/bash) - - <<: *xcode - name: Xcode 11.2 / Swift 5.1 - osx_image: xcode11.2 - &swiftpm name: SwiftPM / Darwin / Swift 5.0 os: osx @@ -38,9 +16,6 @@ matrix: script: - swift build - swift test - - <<: *swiftpm - name: SwiftPM / Darwin / Swift 5.1 - osx_image: xcode11.2 notifications: email: false From 14ce87687ec8194ff1b76f5900305c839897252f Mon Sep 17 00:00:00 2001 From: keisukeYamagishi Date: Tue, 19 Jan 2021 22:11:54 +0900 Subject: [PATCH 27/61] fix PBXGroup reference at the project.pbxproj file --- APIKit.xcodeproj/project.pbxproj | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 11a6bbc0..b538939e 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -180,7 +180,8 @@ ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */, 7F7048D81D9D89FB003C99F6 /* AbstractInputStream.m */, ); - path = BodyParameters; + path = APIKit/BodyParameters; + name = BodyParameters; sourceTree = ""; }; 7F18BD161C9730ED003A31DF /* Serializations */ = { @@ -188,7 +189,8 @@ children = ( 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */, ); - path = Serializations; + path = APIKit/Serializations; + name = Serializations; sourceTree = ""; }; 7F45FCD31A94D02C006863BB = { @@ -311,7 +313,8 @@ 7F7048D41D9D89F2003C99F6 /* SessionAdapter.swift */, 7F7048D51D9D89F2003C99F6 /* URLSessionAdapter.swift */, ); - path = SessionAdapter; + path = APIKit/SessionAdapter; + name = SessionAdapter; sourceTree = ""; }; 7FA19A3D1C9CBF2A005D25AE /* Error */ = { @@ -321,7 +324,8 @@ 7F7048EC1D9D8A12003C99F6 /* RequestError.swift */, 7F7048ED1D9D8A12003C99F6 /* ResponseError.swift */, ); - path = Error; + path = APIKit/Error; + name = Error; sourceTree = ""; }; 7FA19A441C9CC9A2005D25AE /* DataParser */ = { @@ -333,7 +337,8 @@ ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */, 7F7048E71D9D8A08003C99F6 /* StringDataParser.swift */, ); - path = DataParser; + path = APIKit/DataParser; + name = DataParser; sourceTree = ""; }; /* End PBXGroup section */ From 367fbc07d6f8e18c9feb2631b23fca485ccca130 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 21 Feb 2021 11:55:35 +0900 Subject: [PATCH 28/61] [CI] Remove .travis.yml --- .travis.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 34e8b0db..00000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -branches: - only: - - master - -env: - global: - - LC_CTYPE=en_US.UTF-8 - -matrix: - include: - - &swiftpm - name: SwiftPM / Darwin / Swift 5.0 - os: osx - language: generic - osx_image: xcode10.3 - script: - - swift build - - swift test - -notifications: - email: false From dccd409bd269332fe19bd5cf3723f268249ea002 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Tue, 23 Feb 2021 16:23:29 +0900 Subject: [PATCH 29/61] [CI] Update Xcode versions --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 464450cd..ae7521d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: macos-latest name: CocoaPods Lint env: - DEVELOPER_DIR: "/Applications/Xcode_11.4.1.app" + DEVELOPER_DIR: "/Applications/Xcode_12.3.app" steps: - uses: actions/checkout@v2 - run: pod lib lint --allow-warnings @@ -19,7 +19,7 @@ jobs: runs-on: macos-latest strategy: matrix: - xcode: [10.3, 11.3.1, 11.4.1] + xcode: [10.3, 11.7, 12.3] fail-fast: false name: Xcode ${{ matrix.xcode }} env: @@ -40,7 +40,7 @@ jobs: runs-on: macos-latest strategy: matrix: - xcode: [11.3.1, 11.4.1] + xcode: [11.7, 12.3] fail-fast: false name: SwiftPM (Xcode ${{ matrix.xcode }}) env: From fab58f3afa708ad4719e428a6e4384a4988cfbb5 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Wed, 24 Feb 2021 16:03:55 +0900 Subject: [PATCH 30/61] [CI] Fix generate correct coverage files with Xcode12 --- .github/workflows/ci.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae7521d8..a3a6f6b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,15 +26,17 @@ jobs: DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app" steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: test run: | set -o pipefail - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release ENABLE_TESTABILITY=YES | xcpretty -c - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk iphonesimulator -destination "name=iPhone 8" ENABLE_TESTABILITY=YES | xcpretty -c - xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -configuration Release -sdk appletvsimulator -destination "name=Apple TV" ENABLE_TESTABILITY=YES | xcpretty -c - - name: codecov - run: bash <(curl -s https://codecov.io/bash) - if: success() + xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit | xcpretty -c + xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -sdk iphonesimulator -destination "name=iPhone 8" | xcpretty -c + xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit -sdk appletvsimulator -destination "name=Apple TV" | xcpretty -c + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1.2.1 + if: ${{ success() }} swiftpm: runs-on: macos-latest From 6ec27bc7369ecb0ce8ab140b2039fe260ffedd96 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Wed, 24 Feb 2021 16:44:09 +0900 Subject: [PATCH 31/61] [CI] Fix fetch-depth --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3a6f6b1..b339704b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: steps: - uses: actions/checkout@v2 with: - fetch-depth: 0 + fetch-depth: 2 - name: test run: | set -o pipefail From a1f8917c671d3f8de74e9850eb7b8577feafeb95 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Thu, 31 Dec 2020 21:44:05 +0900 Subject: [PATCH 32/61] 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 33/61] 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 34/61] 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 35/61] 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 36/61] 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 37/61] 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) From ad0743d7cf53100fea816c74561c52bfc5e46fe5 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Thu, 25 Feb 2021 00:31:56 +0900 Subject: [PATCH 38/61] Set version 5.2.0 --- APIKit.podspec | 2 +- Sources/APIKit/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index d4d08ba5..df51df1f 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "APIKit" - s.version = "5.1.0" + s.version = "5.2.0" s.summary = "Type-safe networking abstraction layer that associates request type with response type." s.homepage = "https://github.com/ishkawa/APIKit" diff --git a/Sources/APIKit/Info.plist b/Sources/APIKit/Info.plist index 206d86b6..10e795d9 100644 --- a/Sources/APIKit/Info.plist +++ b/Sources/APIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.1.0 + 5.2.0 CFBundleSignature ???? CFBundleVersion From f095a9ccfe68bd083dc37937d885d85f94fbe22d Mon Sep 17 00:00:00 2001 From: Econa77 Date: Thu, 25 Feb 2021 22:42:04 +0900 Subject: [PATCH 39/61] Fix Demo.playground settings --- Demo.playground/contents.xcplayground | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Demo.playground/contents.xcplayground b/Demo.playground/contents.xcplayground index b1148fc5..a8211e59 100644 --- a/Demo.playground/contents.xcplayground +++ b/Demo.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 1213937f9dcbdee9f69bea3fc94a7cf51099f56a Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 1 Jan 2022 12:03:37 +0900 Subject: [PATCH 40/61] [CI] Fix DEVELOPER_DIR --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b339704b..c3da7132 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: macos-latest name: CocoaPods Lint env: - DEVELOPER_DIR: "/Applications/Xcode_12.3.app" + DEVELOPER_DIR: "/Applications/Xcode_12.3.app/Contents/Developer" steps: - uses: actions/checkout@v2 - run: pod lib lint --allow-warnings @@ -23,7 +23,7 @@ jobs: fail-fast: false name: Xcode ${{ matrix.xcode }} env: - DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app" + DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer" steps: - uses: actions/checkout@v2 with: @@ -46,7 +46,7 @@ jobs: fail-fast: false name: SwiftPM (Xcode ${{ matrix.xcode }}) env: - DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app" + DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer" steps: - uses: actions/checkout@v2 - name: build and test From a433a2e869255f5dd13b79c7ced75cfb65b48423 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 1 Jan 2022 12:17:27 +0900 Subject: [PATCH 41/61] [CI] Change macOS image --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3da7132..696b1930 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: jobs: podspec: - runs-on: macos-latest + runs-on: macos-10.15 name: CocoaPods Lint env: DEVELOPER_DIR: "/Applications/Xcode_12.3.app/Contents/Developer" @@ -16,7 +16,7 @@ jobs: - run: pod lib lint --allow-warnings xcode: - runs-on: macos-latest + runs-on: macos-10.15 strategy: matrix: xcode: [10.3, 11.7, 12.3] @@ -39,7 +39,7 @@ jobs: if: ${{ success() }} swiftpm: - runs-on: macos-latest + runs-on: macos-10.15 strategy: matrix: xcode: [11.7, 12.3] From 3e4729d397d98520a87c681bfc85a0171b846e3e Mon Sep 17 00:00:00 2001 From: noppe Date: Sun, 17 Jan 2021 03:00:40 +0900 Subject: [PATCH 42/61] Change iOS deployment target for Xcode 12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the warning about iOS 8 no longer being supported in Xcode 12 while maintaining support for older versions of Xcode. Technically checking the compiler version isn’t an exact 1:1 for checking for Xcode version, but in practice should work in all scenarios. --- Package.swift | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 9ce875e0..53cfe938 100644 --- a/Package.swift +++ b/Package.swift @@ -1,11 +1,22 @@ // swift-tools-version:5.0 import PackageDescription +var platforms: [SupportedPlatform] { + #if compiler(<5.3) + return [ + .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2) + ] + #else + // Xcode 12 (which ships with Swift 5.3) drops support for iOS 8 + return [ + .macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2) + ] + #endif +} + let package = Package( name: "APIKit", - platforms: [ - .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2) - ], + platforms: platforms, products: [ .library(name: "APIKit", targets: ["APIKit"]), ], From c3562f37db2bc7cd3c4e6d12b354cb1d7e6ce9a2 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 1 Jan 2022 11:48:36 +0900 Subject: [PATCH 43/61] Change iOS deployment target version --- Package.swift | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Package.swift b/Package.swift index 53cfe938..a9bf0445 100644 --- a/Package.swift +++ b/Package.swift @@ -1,22 +1,11 @@ // swift-tools-version:5.0 import PackageDescription -var platforms: [SupportedPlatform] { - #if compiler(<5.3) - return [ - .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v2) - ] - #else - // Xcode 12 (which ships with Swift 5.3) drops support for iOS 8 - return [ - .macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2) - ] - #endif -} - let package = Package( name: "APIKit", - platforms: platforms, + platforms: [ + .macOS(.v10_10), .iOS(.v9), .tvOS(.v9), .watchOS(.v2) + ], products: [ .library(name: "APIKit", targets: ["APIKit"]), ], From 2292b02513c676826f479fd96054fdaab7c29e94 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 1 Jan 2022 11:57:20 +0900 Subject: [PATCH 44/61] Also supported for CocoaPods and Carthage --- APIKit.podspec | 2 +- Configurations/Base.xcconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index df51df1f..908cfadd 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| "Yosuke Ishikawa" => "y@ishkawa.org" } - s.ios.deployment_target = "8.0" + s.ios.deployment_target = "9.0" s.osx.deployment_target = "10.10" if s.respond_to?(:watchos) s.watchos.deployment_target = "2.0" diff --git a/Configurations/Base.xcconfig b/Configurations/Base.xcconfig index cf59d8cd..3a036335 100644 --- a/Configurations/Base.xcconfig +++ b/Configurations/Base.xcconfig @@ -27,6 +27,6 @@ VERSIONING_SYSTEM = apple-generic CODE_SIGNING_REQUIRED = NO CODE_SIGN_IDENTITY = MACOSX_DEPLOYMENT_TARGET = 10.10 -IPHONEOS_DEPLOYMENT_TARGET = 8.0 +IPHONEOS_DEPLOYMENT_TARGET = 9.0 WATCHOS_DEPLOYMENT_TARGET = 2.0 TVOS_DEPLOYMENT_TARGET = 9.0 From 4e7f42d93afb787b0bc502171f9b5c12cf49d0ca Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 1 Jan 2022 12:48:49 +0900 Subject: [PATCH 45/61] Set version 5.3.0 --- APIKit.podspec | 2 +- README.md | 2 +- Sources/APIKit/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index 908cfadd..7afab61b 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "APIKit" - s.version = "5.2.0" + s.version = "5.3.0" s.summary = "Type-safe networking abstraction layer that associates request type with response type." s.homepage = "https://github.com/ishkawa/APIKit" diff --git a/README.md b/README.md index 9bc26fcb..e6b06ebb 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Session.send(request) { result in ## Requirements - Swift 5.0 or later -- iOS 8.0 or later +- iOS 9.0 or later - Mac OS 10.10 or later - watchOS 2.0 or later - tvOS 9.0 or later diff --git a/Sources/APIKit/Info.plist b/Sources/APIKit/Info.plist index 10e795d9..2b29ada6 100644 --- a/Sources/APIKit/Info.plist +++ b/Sources/APIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.2.0 + 5.3.0 CFBundleSignature ???? CFBundleVersion From 551afaa735a2d6639237a2ff42c0b0da8ed0d30b Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 1 Jan 2022 13:03:32 +0900 Subject: [PATCH 46/61] Fix deprecated `class` keyword --- Sources/APIKit/SessionAdapter/SessionAdapter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/APIKit/SessionAdapter/SessionAdapter.swift b/Sources/APIKit/SessionAdapter/SessionAdapter.swift index d123dae0..aa71ac5d 100644 --- a/Sources/APIKit/SessionAdapter/SessionAdapter.swift +++ b/Sources/APIKit/SessionAdapter/SessionAdapter.swift @@ -1,7 +1,7 @@ import Foundation /// `SessionTask` protocol represents a task for a request. -public protocol SessionTask: class { +public protocol SessionTask: AnyObject { func resume() func cancel() } From 3cfeeae3a5e8d8c1bd7fb57f88875498d4e39a4b Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 01:36:42 +0900 Subject: [PATCH 47/61] [CI] Update Xcode & macOS versions --- .github/workflows/ci.yml | 53 ++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 696b1930..76f4852f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,28 +7,40 @@ on: jobs: podspec: - runs-on: macos-10.15 + runs-on: macos-12 name: CocoaPods Lint env: - DEVELOPER_DIR: "/Applications/Xcode_12.3.app/Contents/Developer" + DEVELOPER_DIR: "/Applications/Xcode_13.4.1.app/Contents/Developer" steps: - uses: actions/checkout@v2 - run: pod lib lint --allow-warnings xcode: - runs-on: macos-10.15 + name: ${{ matrix.xcode }} + runs-on: ${{ matrix.runsOn }} + env: + DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer" strategy: - matrix: - xcode: [10.3, 11.7, 12.3] fail-fast: false - name: Xcode ${{ matrix.xcode }} - env: - DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer" + matrix: + include: + - xcode: "Xcode_13.4.1" + runsOn: macOS-12 + name: "macOS 12, Xcode 13.4.1, Swift 5.6.1" + - xcode: "Xcode_12.5.1" + runsOn: macOS-11 + name: "macOS 11, Xcode 12.5.1, Swift 5.4.2" + - xcode: "Xcode_11.7" + runsOn: macOS-10.15 + name: "macOS 10.15, Xcode 11.7, Swift 5.2.4" + - xcode: "Xcode_10.3" + runsOn: macOS-10.15 + name: "macOS 10.15, Xcode 10.3, Swift 5.0.1" steps: - uses: actions/checkout@v2 with: fetch-depth: 2 - - name: test + - name: ${{ matrix.name }} run: | set -o pipefail xcodebuild build-for-testing test-without-building -workspace APIKit.xcworkspace -scheme APIKit | xcpretty -c @@ -39,17 +51,26 @@ jobs: if: ${{ success() }} swiftpm: - runs-on: macos-10.15 + name: SPM with ${{ matrix.xcode }} + runs-on: ${{ matrix.runsOn }} + env: + DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer" strategy: - matrix: - xcode: [11.7, 12.3] fail-fast: false - name: SwiftPM (Xcode ${{ matrix.xcode }}) - env: - DEVELOPER_DIR: "/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer" + matrix: + include: + - xcode: "Xcode_13.4.1" + runsOn: macOS-12 + name: "macOS 12, Xcode 13.4.1, Swift 5.6.1" + - xcode: "Xcode_12.5.1" + runsOn: macOS-11 + name: "macOS 11, Xcode 12.5.1, Swift 5.4.2" + - xcode: "Xcode_11.7" + runsOn: macOS-10.15 + name: "macOS 10.15, Xcode 11.7, Swift 5.2.4" steps: - uses: actions/checkout@v2 - - name: build and test + - name: ${{ matrix.name }} run: | swift build swift test From 646305d4038aa362b9ef63508439a9f198652224 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 03:06:33 +0900 Subject: [PATCH 48/61] Rerunning tests that were not run in SPM --- APIKit.xcodeproj/project.pbxproj | 26 ++++++++++++------- Package.swift | 5 ++-- .../MultipartFormDataParametersTests.swift | 12 +++++---- Tests/APIKitTests/{ => Resources}/test.json | 0 4 files changed, 27 insertions(+), 16 deletions(-) rename Tests/APIKitTests/{ => Resources}/test.json (100%) diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 8fc0f748..16ded583 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -21,7 +21,6 @@ 7F698E5A1D9D680C00F1561D /* URLSessionAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E481D9D680C00F1561D /* URLSessionAdapterTests.swift */; }; 7F698E5B1D9D680C00F1561D /* SessionCallbackQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */; }; 7F698E5C1D9D680C00F1561D /* SessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4A1D9D680C00F1561D /* SessionTests.swift */; }; - 7F698E5D1D9D680C00F1561D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = 7F698E4B1D9D680C00F1561D /* test.json */; }; 7F698E5E1D9D680C00F1561D /* TestRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4D1D9D680C00F1561D /* TestRequest.swift */; }; 7F698E5F1D9D680C00F1561D /* TestSessionAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4E1D9D680C00F1561D /* TestSessionAdapter.swift */; }; 7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F698E4F1D9D680C00F1561D /* TestSessionTask.swift */; }; @@ -48,6 +47,7 @@ 7F7048F11D9D8A12003C99F6 /* SessionTaskError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048EE1D9D8A12003C99F6 /* SessionTaskError.swift */; }; 7F7048F31D9D8A1F003C99F6 /* URLEncodedSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */; }; 7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */; }; + C5FF1DC128A80FFD0059573D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = C5FF1DC028A80FFD0059573D /* test.json */; }; ECA831481DE4DDBF004EB1B5 /* ProtobufDataParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */; }; ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */; }; ECA8314C1DE4E677004EB1B5 /* ProtobufBodyParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */; }; @@ -100,7 +100,6 @@ 7F698E481D9D680C00F1561D /* URLSessionAdapterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionAdapterTests.swift; sourceTree = ""; }; 7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionCallbackQueueTests.swift; sourceTree = ""; }; 7F698E4A1D9D680C00F1561D /* SessionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionTests.swift; sourceTree = ""; }; - 7F698E4B1D9D680C00F1561D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = ""; }; 7F698E4D1D9D680C00F1561D /* TestRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestRequest.swift; sourceTree = ""; }; 7F698E4E1D9D680C00F1561D /* TestSessionAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSessionAdapter.swift; sourceTree = ""; }; 7F698E4F1D9D680C00F1561D /* TestSessionTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSessionTask.swift; sourceTree = ""; }; @@ -129,6 +128,7 @@ 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = URLEncodedSerialization.swift; path = Sources/APIKit/Serializations/URLEncodedSerialization.swift; sourceTree = SOURCE_ROOT; }; 7F8ECDFD1B6A799E00234E04 /* Demo.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Demo.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPStub.swift; sourceTree = ""; }; + C5FF1DC028A80FFD0059573D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = ""; }; ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufDataParser.swift; path = Sources/APIKit/DataParser/ProtobufDataParser.swift; sourceTree = SOURCE_ROOT; }; ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtobufDataParserTests.swift; sourceTree = ""; }; ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufBodyParameters.swift; path = Sources/APIKit/BodyParameters/ProtobufBodyParameters.swift; sourceTree = SOURCE_ROOT; }; @@ -201,8 +201,8 @@ ECA8314B1DE4E677004EB1B5 /* ProtobufBodyParameters.swift */, 7F7048D81D9D89FB003C99F6 /* AbstractInputStream.m */, ); - path = APIKit/BodyParameters; name = BodyParameters; + path = APIKit/BodyParameters; sourceTree = ""; }; 7F18BD161C9730ED003A31DF /* Serializations */ = { @@ -210,8 +210,8 @@ children = ( 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */, ); - path = APIKit/Serializations; name = Serializations; + path = APIKit/Serializations; sourceTree = ""; }; 7F45FCD31A94D02C006863BB = { @@ -245,6 +245,7 @@ 7F698E401D9D680C00F1561D /* DataParserType */, 7F698E461D9D680C00F1561D /* SessionAdapterType */, 7F698E4C1D9D680C00F1561D /* TestComponents */, + C5FF1DBF28A80FFD0059573D /* Resources */, 7F698E611D9D681500F1561D /* Supporting Files */, ); path = APIKitTests; @@ -297,7 +298,6 @@ isa = PBXGroup; children = ( 7F698E441D9D680C00F1561D /* Info.plist */, - 7F698E4B1D9D680C00F1561D /* test.json */, ); name = "Supporting Files"; sourceTree = ""; @@ -336,8 +336,8 @@ 7F7048D41D9D89F2003C99F6 /* SessionAdapter.swift */, 7F7048D51D9D89F2003C99F6 /* URLSessionAdapter.swift */, ); - path = APIKit/SessionAdapter; name = SessionAdapter; + path = APIKit/SessionAdapter; sourceTree = ""; }; 7FA19A3D1C9CBF2A005D25AE /* Error */ = { @@ -347,8 +347,8 @@ 7F7048EC1D9D8A12003C99F6 /* RequestError.swift */, 7F7048ED1D9D8A12003C99F6 /* ResponseError.swift */, ); - path = APIKit/Error; name = Error; + path = APIKit/Error; sourceTree = ""; }; 7FA19A441C9CC9A2005D25AE /* DataParser */ = { @@ -360,8 +360,16 @@ ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */, 7F7048E71D9D8A08003C99F6 /* StringDataParser.swift */, ); - path = APIKit/DataParser; name = DataParser; + path = APIKit/DataParser; + sourceTree = ""; + }; + C5FF1DBF28A80FFD0059573D /* Resources */ = { + isa = PBXGroup; + children = ( + C5FF1DC028A80FFD0059573D /* test.json */, + ); + path = Resources; sourceTree = ""; }; /* End PBXGroup section */ @@ -464,7 +472,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7F698E5D1D9D680C00F1561D /* test.json in Resources */, + C5FF1DC128A80FFD0059573D /* test.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Package.swift b/Package.swift index a9bf0445..e55d20b6 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.3 import PackageDescription let package = Package( @@ -18,7 +18,8 @@ let package = Package( ), .testTarget( name: "APIKitTests", - dependencies: ["APIKit"] + dependencies: ["APIKit"], + resources: [.process("Resources")] ), ], swiftLanguageVersions: [.v5] diff --git a/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift b/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift index 4a0536dc..9cedcf04 100644 --- a/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift @@ -71,11 +71,14 @@ class MultipartFormDataParametersTests: XCTestCase { // MARK: Values - // Skip test cases that uses files until SwiftPM supports resources. - #if !SWIFT_PACKAGE - func testFileValue() { - let fileURL = Bundle(for: type(of: self)).url(forResource: "test", withExtension: "json")! let part = try! MultipartFormDataBodyParameters.Part(fileURL: fileURL, name: "test") + func testFileValue() throws { + #if SWIFT_PACKAGE + let bundle = Bundle.module + #else + let bundle = Bundle(for: type(of: self)) + #endif + let fileURL = try XCTUnwrap(bundle.url(forResource: "test", withExtension: "json")) let parameters = MultipartFormDataBodyParameters(parts: [part]) do { @@ -103,7 +106,6 @@ class MultipartFormDataParametersTests: XCTestCase { XCTFail() } } - #endif func testStringValue() { let part = try! MultipartFormDataBodyParameters.Part(value: "abcdef", name: "foo") diff --git a/Tests/APIKitTests/test.json b/Tests/APIKitTests/Resources/test.json similarity index 100% rename from Tests/APIKitTests/test.json rename to Tests/APIKitTests/Resources/test.json From 872402da2035058d568ac8a2d9f169eab8b4e826 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 03:09:18 +0900 Subject: [PATCH 49/61] Improve tests that throw errors --- .../JSONBodyParametersTests.swift | 47 ++--- .../MultipartFormDataParametersTests.swift | 175 ++++++++---------- .../ProtobufBodyParametersTests.swift | 22 +-- .../URLEncodedSerializationTests.swift | 23 +-- Tests/APIKitTests/Combine/CombineTests.swift | 4 +- .../FormURLEncodedDataParserTests.swift | 21 +-- .../DataParserType/JSONDataParserTests.swift | 16 +- .../ProtobufDataParserTests.swift | 19 +- .../StringDataParserTests.swift | 15 +- Tests/APIKitTests/RequestTests.swift | 41 ++-- .../SessionCallbackQueueTests.swift | 10 +- Tests/APIKitTests/SessionTests.swift | 4 +- 12 files changed, 158 insertions(+), 239 deletions(-) diff --git a/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift b/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift index 512eb749..0bc9b535 100644 --- a/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/JSONBodyParametersTests.swift @@ -3,58 +3,47 @@ import XCTest import APIKit class JSONBodyParametersTests: XCTestCase { - func testJSONSuccess() { + func testJSONSuccess() throws { let object = ["foo": 1, "bar": 2, "baz": 3] let parameters = JSONBodyParameters(JSONObject: object) XCTAssertEqual(parameters.contentType, "application/json") - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let dictionary = try JSONSerialization.jsonObject(with: data, options: []) - XCTAssertEqual((dictionary as? [String: Int])?["foo"], 1) - XCTAssertEqual((dictionary as? [String: Int])?["bar"], 2) - XCTAssertEqual((dictionary as? [String: Int])?["baz"], 3) - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } + let dictionary = try JSONSerialization.jsonObject(with: data, options: []) + XCTAssertEqual((dictionary as? [String: Int])?["foo"], 1) + XCTAssertEqual((dictionary as? [String: Int])?["bar"], 2) + XCTAssertEqual((dictionary as? [String: Int])?["baz"], 3) } func testJSONFailure() { let object = NSObject() let parameters = JSONBodyParameters(JSONObject: object) - do { - try _ = parameters.buildEntity() - XCTFail() - } catch { + XCTAssertThrowsError(try parameters.buildEntity()) { error in let nserror = error as NSError XCTAssertEqual(nserror.domain, NSCocoaErrorDomain) XCTAssertEqual(nserror.code, 3840) } } - func testDictionaryLiteral() { + func testDictionaryLiteral() throws { let object = ["foo": 1, "bar": 2, "baz": 3] let parameters1: JSONBodyParameters = .init(JSONObject: object) let parameters2: JSONBodyParameters = ["foo": 1, "bar": 2, "baz": 3] - do { - guard case .data(let data1) = try parameters1.buildEntity(), - case .data(let data2) = try parameters2.buildEntity() else { - XCTFail() - return - } - let dictionary1 = try JSONSerialization.jsonObject(with: data1, options: []) - let dictionary2 = try JSONSerialization.jsonObject(with: data2, options: []) - XCTAssertEqual((dictionary1 as? [String: Int])?["foo"], (dictionary2 as? [String: Int])?["foo"]) - XCTAssertEqual((dictionary1 as? [String: Int])?["bar"], (dictionary2 as? [String: Int])?["bar"]) - XCTAssertEqual((dictionary1 as? [String: Int])?["baz"], (dictionary2 as? [String: Int])?["baz"]) - } catch { + + guard case .data(let data1) = try parameters1.buildEntity(), + case .data(let data2) = try parameters2.buildEntity() else { XCTFail() + return } + let dictionary1 = try JSONSerialization.jsonObject(with: data1, options: []) + let dictionary2 = try JSONSerialization.jsonObject(with: data2, options: []) + XCTAssertEqual((dictionary1 as? [String: Int])?["foo"], (dictionary2 as? [String: Int])?["foo"]) + XCTAssertEqual((dictionary1 as? [String: Int])?["bar"], (dictionary2 as? [String: Int])?["bar"]) + XCTAssertEqual((dictionary1 as? [String: Int])?["baz"], (dictionary2 as? [String: Int])?["baz"]) } } diff --git a/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift b/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift index 9cedcf04..faf68949 100644 --- a/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/MultipartFormDataParametersTests.swift @@ -4,74 +4,65 @@ import XCTest class MultipartFormDataParametersTests: XCTestCase { // MARK: Entity - func testDataEntitySuccess() { - let value1 = "1".data(using: .utf8)! - let value2 = "2".data(using: .utf8)! + func testDataEntitySuccess() throws { + let value1 = try XCTUnwrap("1".data(using: .utf8)) + let value2 = try XCTUnwrap("2".data(using: .utf8)) let parameters = MultipartFormDataBodyParameters(parts: [ MultipartFormDataBodyParameters.Part(data: value1, name: "foo"), MultipartFormDataBodyParameters.Part(data: value2, name: "bar"), ]) - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let encodedData = String(data: data, encoding:.utf8)! - let returnCode = "\r\n" - - let pattern = "^multipart/form-data; boundary=([\\w.]+)$" - let regexp = try NSRegularExpression(pattern: pattern, options: []) - let range = NSRange(location: 0, length: parameters.contentType.count) - let match = regexp.matches(in: parameters.contentType, options: [], range: range) - XCTAssertTrue(match.count > 0) - - let boundary = (parameters.contentType as NSString).substring(with: match.first!.range(at: 1)) - XCTAssertEqual(parameters.contentType, "multipart/form-data; boundary=\(boundary)") - XCTAssertEqual(encodedData, "--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"foo\"\(returnCode)\(returnCode)1\(returnCode)--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"bar\"\(returnCode)\(returnCode)2\(returnCode)--\(boundary)--\(returnCode)") - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } + let encodedData = try XCTUnwrap(String(data: data, encoding:.utf8)) + let returnCode = "\r\n" + + let pattern = "^multipart/form-data; boundary=([\\w.]+)$" + let regexp = try NSRegularExpression(pattern: pattern, options: []) + let range = NSRange(location: 0, length: parameters.contentType.count) + let match = regexp.matches(in: parameters.contentType, options: [], range: range) + XCTAssertTrue(match.count > 0) + + let firstRange = try XCTUnwrap(match.first?.range(at: 1)) + let boundary = (parameters.contentType as NSString).substring(with: firstRange) + XCTAssertEqual(parameters.contentType, "multipart/form-data; boundary=\(boundary)") + XCTAssertEqual(encodedData, "--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"foo\"\(returnCode)\(returnCode)1\(returnCode)--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"bar\"\(returnCode)\(returnCode)2\(returnCode)--\(boundary)--\(returnCode)") } - func testInputStreamEntitySuccess() { - let value1 = "1".data(using: .utf8)! - let value2 = "2".data(using: .utf8)! + func testInputStreamEntitySuccess() throws { + let value1 = try XCTUnwrap("1".data(using: .utf8)) + let value2 = try XCTUnwrap("2".data(using: .utf8)) let parameters = MultipartFormDataBodyParameters(parts: [ MultipartFormDataBodyParameters.Part(data: value1, name: "foo"), MultipartFormDataBodyParameters.Part(data: value2, name: "bar"), ], entityType: .inputStream) - do { - guard case .inputStream(let inputStream) = try parameters.buildEntity() else { - XCTFail() - return - } - - let data = try Data(inputStream: inputStream) - let encodedData = String(data: data, encoding:.utf8)! - let returnCode = "\r\n" - - let pattern = "^multipart/form-data; boundary=([\\w.]+)$" - let regexp = try NSRegularExpression(pattern: pattern, options: []) - let range = NSRange(location: 0, length: parameters.contentType.count) - let match = regexp.matches(in: parameters.contentType, options: [], range: range) - XCTAssertTrue(match.count > 0) - - let boundary = (parameters.contentType as NSString).substring(with: match.first!.range(at: 1)) - XCTAssertEqual(parameters.contentType, "multipart/form-data; boundary=\(boundary)") - XCTAssertEqual(encodedData, "--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"foo\"\(returnCode)\(returnCode)1\(returnCode)--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"bar\"\(returnCode)\(returnCode)2\(returnCode)--\(boundary)--\(returnCode)") - } catch { + guard case .inputStream(let inputStream) = try parameters.buildEntity() else { XCTFail() + return } + let data = try Data(inputStream: inputStream) + let encodedData = try XCTUnwrap(String(data: data, encoding:.utf8)) + let returnCode = "\r\n" + + let pattern = "^multipart/form-data; boundary=([\\w.]+)$" + let regexp = try NSRegularExpression(pattern: pattern, options: []) + let range = NSRange(location: 0, length: parameters.contentType.count) + let match = regexp.matches(in: parameters.contentType, options: [], range: range) + XCTAssertTrue(match.count > 0) + + let firstRange = try XCTUnwrap(match.first?.range(at: 1)) + let boundary = (parameters.contentType as NSString).substring(with: firstRange) + XCTAssertEqual(parameters.contentType, "multipart/form-data; boundary=\(boundary)") + XCTAssertEqual(encodedData, "--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"foo\"\(returnCode)\(returnCode)1\(returnCode)--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"bar\"\(returnCode)\(returnCode)2\(returnCode)--\(boundary)--\(returnCode)") } // MARK: Values - let part = try! MultipartFormDataBodyParameters.Part(fileURL: fileURL, name: "test") func testFileValue() throws { #if SWIFT_PACKAGE let bundle = Bundle.module @@ -79,82 +70,64 @@ class MultipartFormDataParametersTests: XCTestCase { let bundle = Bundle(for: type(of: self)) #endif let fileURL = try XCTUnwrap(bundle.url(forResource: "test", withExtension: "json")) + let part = try MultipartFormDataBodyParameters.Part(fileURL: fileURL, name: "test") let parameters = MultipartFormDataBodyParameters(parts: [part]) - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let testData = try! Data(contentsOf: fileURL) - let testString = String(data: testData, encoding: .utf8)! - - let encodedData = String(data: data, encoding:.utf8)! - let returnCode = "\r\n" - - let pattern = "^multipart/form-data; boundary=([\\w.]+)$" - let regexp = try NSRegularExpression(pattern: pattern, options: []) - let range = NSRange(location: 0, length: parameters.contentType.count) - let match = regexp.matches(in: parameters.contentType, options: [], range: range) - XCTAssertTrue(match.count > 0) - - let boundary = (parameters.contentType as NSString).substring(with: match.first!.range(at: 1)) - XCTAssertEqual(parameters.contentType, "multipart/form-data; boundary=\(boundary)") - XCTAssertEqual(encodedData, "--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"test\"; filename=\"test.json\"\r\nContent-Type: application/json\(returnCode)\(returnCode)\(testString)\(returnCode)--\(boundary)--\(returnCode)") - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } + let testData = try Data(contentsOf: fileURL) + let testString = try XCTUnwrap(String(data: testData, encoding: .utf8)) + + let encodedData = try XCTUnwrap(String(data: data, encoding:.utf8)) + let returnCode = "\r\n" + + let pattern = "^multipart/form-data; boundary=([\\w.]+)$" + let regexp = try NSRegularExpression(pattern: pattern, options: []) + let range = NSRange(location: 0, length: parameters.contentType.count) + let match = regexp.matches(in: parameters.contentType, options: [], range: range) + XCTAssertTrue(match.count > 0) + + let firstRange = try XCTUnwrap(match.first?.range(at: 1)) + let boundary = (parameters.contentType as NSString).substring(with: firstRange) + XCTAssertEqual(parameters.contentType, "multipart/form-data; boundary=\(boundary)") + XCTAssertEqual(encodedData, "--\(boundary)\(returnCode)Content-Disposition: form-data; name=\"test\"; filename=\"test.json\"\r\nContent-Type: application/json\(returnCode)\(returnCode)\(testString)\(returnCode)--\(boundary)--\(returnCode)") } - func testStringValue() { - let part = try! MultipartFormDataBodyParameters.Part(value: "abcdef", name: "foo") + func testStringValue() throws { + let part = try MultipartFormDataBodyParameters.Part(value: "abcdef", name: "foo") let parameters = MultipartFormDataBodyParameters(parts: [part]) - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let string = String(data: data, encoding:.utf8)! - XCTAssertEqual(string, "--\(parameters.boundary)\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nabcdef\r\n--\(parameters.boundary)--\r\n") - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } + let string = String(data: data, encoding:.utf8) + XCTAssertEqual(string, "--\(parameters.boundary)\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nabcdef\r\n--\(parameters.boundary)--\r\n") } - func testIntValue() { - let part = try! MultipartFormDataBodyParameters.Part(value: 123, name: "foo") + func testIntValue() throws { + let part = try MultipartFormDataBodyParameters.Part(value: 123, name: "foo") let parameters = MultipartFormDataBodyParameters(parts: [part]) - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let string = String(data: data, encoding:.utf8)! - XCTAssertEqual(string, "--\(parameters.boundary)\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\n123\r\n--\(parameters.boundary)--\r\n") - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } + let string = String(data: data, encoding:.utf8) + XCTAssertEqual(string, "--\(parameters.boundary)\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\n123\r\n--\(parameters.boundary)--\r\n") } - func testDoubleValue() { - let part = try! MultipartFormDataBodyParameters.Part(value: 3.14, name: "foo") + func testDoubleValue() throws { + let part = try MultipartFormDataBodyParameters.Part(value: 3.14, name: "foo") let parameters = MultipartFormDataBodyParameters(parts: [part]) - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let string = String(data: data, encoding:.utf8)! - XCTAssertEqual(string, "--\(parameters.boundary)\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\n3.14\r\n--\(parameters.boundary)--\r\n") - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } + let string = String(data: data, encoding:.utf8) + XCTAssertEqual(string, "--\(parameters.boundary)\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\n3.14\r\n--\(parameters.boundary)--\r\n") } } diff --git a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift index e58102d3..3f5da8b4 100644 --- a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift @@ -3,26 +3,18 @@ import XCTest import APIKit class ProtobufBodyParametersTests: XCTestCase { - func testProtobufSuccess() { - // Temporarily gated due to https://openradar.appspot.com/49262697 - if #available(macOS 10.11, *) { + func testProtobufSuccess() throws { let object = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) let parameters = ProtobufBodyParameters(protobufObject: object) XCTAssertEqual(parameters.contentType, "application/protobuf") - do { - guard case .data(let data) = try parameters.buildEntity() else { - XCTFail() - return - } - - let dictionary = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: Int] - XCTAssertEqual(dictionary?["foo"], 1) - XCTAssertEqual(dictionary?["bar"], 2) - XCTAssertEqual(dictionary?["baz"], 3) - } catch { + guard case .data(let data) = try parameters.buildEntity() else { XCTFail() + return } - } + let dictionary = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: Int] + XCTAssertEqual(dictionary?["foo"], 1) + XCTAssertEqual(dictionary?["bar"], 2) + XCTAssertEqual(dictionary?["baz"], 3) } } diff --git a/Tests/APIKitTests/BodyParametersType/URLEncodedSerializationTests.swift b/Tests/APIKitTests/BodyParametersType/URLEncodedSerializationTests.swift index 89702e4d..64d33cf4 100644 --- a/Tests/APIKitTests/BodyParametersType/URLEncodedSerializationTests.swift +++ b/Tests/APIKitTests/BodyParametersType/URLEncodedSerializationTests.swift @@ -4,21 +4,18 @@ import APIKit class URLEncodedSerializationTests: XCTestCase { // MARK: NSData -> Any - func testObjectFromData() { - let data = "key1=value1&key2=value2".data(using: .utf8)! + func testObjectFromData() throws { + let data = try XCTUnwrap("key1=value1&key2=value2".data(using: .utf8)) let object = try? URLEncodedSerialization.object(from: data, encoding: .utf8) XCTAssertEqual(object?["key1"], "value1") XCTAssertEqual(object?["key2"], "value2") } - func testInvalidFormatString() { + func testInvalidFormatString() throws { let string = "key==value&" - do { - let data = string.data(using: .utf8)! - try _ = URLEncodedSerialization.object(from: data, encoding: .utf8) - XCTFail() - } catch { + let data = try XCTUnwrap(string.data(using: .utf8)) + XCTAssertThrowsError(try URLEncodedSerialization.object(from: data, encoding: .utf8)) { error in guard let error = error as? URLEncodedSerialization.Error, case .invalidFormatString(let invalidString) = error else { XCTFail() @@ -33,10 +30,7 @@ class URLEncodedSerializationTests: XCTestCase { var bytes = [UInt8]([0xed, 0xa0, 0x80]) // U+D800 (high surrogate) let data = Data(bytes: &bytes, count: bytes.count) - do { - try _ = URLEncodedSerialization.object(from: data, encoding: .utf8) - XCTFail() - } catch { + XCTAssertThrowsError(try URLEncodedSerialization.object(from: data, encoding: .utf8)) { error in guard let error = error as? URLEncodedSerialization.Error, case .cannotGetStringFromData(let invalidData, let encoding) = error else { XCTFail() @@ -59,10 +53,7 @@ class URLEncodedSerializationTests: XCTestCase { func testNonDictionaryObject() { let dictionaries = [["hey": "yo"]] as Any - do { - try _ = URLEncodedSerialization.data(from: dictionaries, encoding: .utf8) - XCTFail() - } catch { + XCTAssertThrowsError(try URLEncodedSerialization.data(from: dictionaries, encoding: .utf8)) { error in guard let error = error as? URLEncodedSerialization.Error, case .cannotCastObjectToDictionary(let object) = error else { XCTFail() diff --git a/Tests/APIKitTests/Combine/CombineTests.swift b/Tests/APIKitTests/Combine/CombineTests.swift index a253067b..32c548b9 100644 --- a/Tests/APIKitTests/Combine/CombineTests.swift +++ b/Tests/APIKitTests/Combine/CombineTests.swift @@ -23,9 +23,9 @@ final class CombineTests: XCTestCase { cancellables = [] } - func testSuccess() { + func testSuccess() throws { let dictionary = ["key": "value"] - adapter.data = try! JSONSerialization.data(withJSONObject: dictionary, options: []) + adapter.data = try XCTUnwrap(JSONSerialization.data(withJSONObject: dictionary, options: [])) let expectation = self.expectation(description: "wait for response") let request = TestRequest() diff --git a/Tests/APIKitTests/DataParserType/FormURLEncodedDataParserTests.swift b/Tests/APIKitTests/DataParserType/FormURLEncodedDataParserTests.swift index 8bf66a77..cb2f5357 100644 --- a/Tests/APIKitTests/DataParserType/FormURLEncodedDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/FormURLEncodedDataParserTests.swift @@ -8,20 +8,16 @@ class FormURLEncodedDataParserTests: XCTestCase { XCTAssertEqual(parser.contentType, "application/x-www-form-urlencoded") } - func testURLSuccess() { + func testURLSuccess() throws { let string = "foo=1&bar=2&baz=3" let data = string.data(using: .utf8, allowLossyConversion: false)! let parser = FormURLEncodedDataParser(encoding: .utf8) - do { - let object = try parser.parse(data: data) - let dictionary = object as? [String: String] - XCTAssertEqual(dictionary?["foo"], "1") - XCTAssertEqual(dictionary?["bar"], "2") - XCTAssertEqual(dictionary?["baz"], "3") - } catch { - XCTFail() - } + let object = try parser.parse(data: data) + let dictionary = object as? [String: String] + XCTAssertEqual(dictionary?["foo"], "1") + XCTAssertEqual(dictionary?["bar"], "2") + XCTAssertEqual(dictionary?["baz"], "3") } func testInvalidString() { @@ -29,10 +25,7 @@ class FormURLEncodedDataParserTests: XCTestCase { let data = Data(bytes: &bytes, count: bytes.count) let parser = FormURLEncodedDataParser(encoding: .utf8) - do { - try _ = parser.parse(data: data) - XCTFail() - } catch { + XCTAssertThrowsError(try parser.parse(data: data)) { error in guard let error = error as? FormURLEncodedDataParser.Error, case .cannotGetStringFromData(let invalidData) = error else { XCTFail() diff --git a/Tests/APIKitTests/DataParserType/JSONDataParserTests.swift b/Tests/APIKitTests/DataParserType/JSONDataParserTests.swift index e7faaca4..3cf81427 100644 --- a/Tests/APIKitTests/DataParserType/JSONDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/JSONDataParserTests.swift @@ -8,19 +8,15 @@ class JSONDataParserTests: XCTestCase { XCTAssertEqual(parser.contentType, "application/json") } - func testJSONSuccess() { + func testJSONSuccess() throws { let string = "{\"foo\": 1, \"bar\": 2, \"baz\": 3}" let data = string.data(using: .utf8, allowLossyConversion: false)! let parser = JSONDataParser(readingOptions: []) - do { - let object = try parser.parse(data: data) - let dictionary = object as? [String: Int] - XCTAssertEqual(dictionary?["foo"], 1) - XCTAssertEqual(dictionary?["bar"], 2) - XCTAssertEqual(dictionary?["baz"], 3) - } catch { - XCTFail() - } + let object = try parser.parse(data: data) + let dictionary = object as? [String: Int] + XCTAssertEqual(dictionary?["foo"], 1) + XCTAssertEqual(dictionary?["bar"], 2) + XCTAssertEqual(dictionary?["baz"], 3) } } diff --git a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift index 968b31e0..6752bee9 100644 --- a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift @@ -8,21 +8,14 @@ class ProtobufDataParserTests: XCTestCase { XCTAssertEqual(parser.contentType, "application/protobuf") } - func testProtobufSuccess() { - // Temporarily gated due to https://openradar.appspot.com/49262697 - if #available(macOS 10.11, *) { + func testProtobufSuccess() throws { let data = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) let parser = ProtobufDataParser() - do { - let object = try parser.parse(data: data) as! Data - let dictionary = NSKeyedUnarchiver.unarchiveObject(with: object) as? [String: Int] - XCTAssertEqual(dictionary?["foo"], 1) - XCTAssertEqual(dictionary?["bar"], 2) - XCTAssertEqual(dictionary?["baz"], 3) - } catch { - XCTFail() - } - } + let object = try XCTUnwrap(try parser.parse(data: data) as? Data) + let dictionary = NSKeyedUnarchiver.unarchiveObject(with: object) as? [String: Int] + XCTAssertEqual(dictionary?["foo"], 1) + XCTAssertEqual(dictionary?["bar"], 2) + XCTAssertEqual(dictionary?["baz"], 3) } } diff --git a/Tests/APIKitTests/DataParserType/StringDataParserTests.swift b/Tests/APIKitTests/DataParserType/StringDataParserTests.swift index 0dc0255a..d932501a 100644 --- a/Tests/APIKitTests/DataParserType/StringDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/StringDataParserTests.swift @@ -8,17 +8,13 @@ class StringDataParserTests: XCTestCase { XCTAssertNil(parser.contentType) } - func testParseData() { + func testParseData() throws { let string = "abcdef" let data = string.data(using: .utf8, allowLossyConversion: false)! let parser = StringDataParser(encoding: .utf8) - do { - let object = try parser.parse(data: data) - XCTAssertEqual(object as? String, string) - } catch { - XCTFail() - } + let object = try parser.parse(data: data) + XCTAssertEqual(object as? String, string) } func testInvalidString() { @@ -26,10 +22,7 @@ class StringDataParserTests: XCTestCase { let data = Data(bytes: &bytes, count: bytes.count) let parser = StringDataParser(encoding: .utf8) - do { - try _ = parser.parse(data: data) - XCTFail() - } catch { + XCTAssertThrowsError(try parser.parse(data: data)) { error in guard let error = error as? StringDataParser.Error, case .invalidData(let invalidData) = error else { XCTFail() diff --git a/Tests/APIKitTests/RequestTests.swift b/Tests/APIKitTests/RequestTests.swift index bd10942b..88bfa72c 100644 --- a/Tests/APIKitTests/RequestTests.swift +++ b/Tests/APIKitTests/RequestTests.swift @@ -2,33 +2,33 @@ import XCTest import APIKit class RequestTests: XCTestCase { - func testJapanesesQueryParameters() { + func testJapanesesQueryParameters() throws { let request = TestRequest(parameters: ["q": "こんにちは"]) - let urlRequest = try? request.buildURLRequest() - XCTAssertEqual(urlRequest?.url?.query, "q=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF") + let urlRequest = try request.buildURLRequest() + XCTAssertEqual(urlRequest.url?.query, "q=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF") } - func testSymbolQueryParameters() { + func testSymbolQueryParameters() throws { let request = TestRequest(parameters: ["q": "!\"#$%&'()0=~|`{}*+<>?/_"]) - let urlRequest = try? request.buildURLRequest() - XCTAssertEqual(urlRequest?.url?.query, "q=%21%22%23%24%25%26%27%28%290%3D~%7C%60%7B%7D%2A%2B%3C%3E?/_") + let urlRequest = try request.buildURLRequest() + XCTAssertEqual(urlRequest.url?.query, "q=%21%22%23%24%25%26%27%28%290%3D~%7C%60%7B%7D%2A%2B%3C%3E?/_") } - func testNullQueryParameters() { + func testNullQueryParameters() throws { let request = TestRequest(parameters: ["null": NSNull()]) - let urlRequest = try? request.buildURLRequest() - XCTAssertEqual(urlRequest?.url?.query, "null") + let urlRequest = try request.buildURLRequest() + XCTAssertEqual(urlRequest.url?.query, "null") } - func testheaderFields() { + func testheaderFields() throws { let request = TestRequest(headerFields: ["Foo": "f", "Accept": "a", "Content-Type": "c"]) - let urlReqeust = try? request.buildURLRequest() - XCTAssertEqual(urlReqeust?.value(forHTTPHeaderField: "Foo"), "f") - XCTAssertEqual(urlReqeust?.value(forHTTPHeaderField: "Accept"), "a") - XCTAssertEqual(urlReqeust?.value(forHTTPHeaderField: "Content-Type"), "c") + let urlReqeust = try request.buildURLRequest() + XCTAssertEqual(urlReqeust.value(forHTTPHeaderField: "Foo"), "f") + XCTAssertEqual(urlReqeust.value(forHTTPHeaderField: "Accept"), "a") + XCTAssertEqual(urlReqeust.value(forHTTPHeaderField: "Content-Type"), "c") } - func testPOSTJSONRequest() { + func testPOSTJSONRequest() throws { let parameters: [Any] = [ ["id": "1"], ["id": "2"], @@ -38,10 +38,9 @@ class RequestTests: XCTestCase { let request = TestRequest(method: .post, parameters: parameters) XCTAssert((request.parameters as? [Any])?.count == 3) - let urlRequest = try? request.buildURLRequest() - XCTAssertNotNil(urlRequest?.httpBody) + let urlRequest = try request.buildURLRequest() - let json = urlRequest?.httpBody.flatMap { try? JSONSerialization.jsonObject(with: $0, options: []) } as? [AnyObject] + let json = urlRequest.httpBody.flatMap { try? JSONSerialization.jsonObject(with: $0, options: []) } as? [AnyObject] XCTAssertEqual(json?.count, 3) XCTAssertEqual((json?[0] as? [String: String])?["id"], "1") XCTAssertEqual((json?[1] as? [String: String])?["id"], "2") @@ -409,12 +408,12 @@ class RequestTests: XCTestCase { ) } - func testInterceptURLRequest() { - let url = URL(string: "https://example.com/customize")! + func testInterceptURLRequest() throws { + let url = try XCTUnwrap(URL(string: "https://example.com/customize")) let request = TestRequest() { _ in return URLRequest(url: url) } - XCTAssertEqual((try? request.buildURLRequest())?.url, url) + XCTAssertEqual(try request.buildURLRequest().url, url) } } diff --git a/Tests/APIKitTests/SessionCallbackQueueTests.swift b/Tests/APIKitTests/SessionCallbackQueueTests.swift index 66f2f494..b9d961f9 100644 --- a/Tests/APIKitTests/SessionCallbackQueueTests.swift +++ b/Tests/APIKitTests/SessionCallbackQueueTests.swift @@ -6,11 +6,11 @@ class SessionCallbackQueueTests: XCTestCase { var adapter: TestSessionAdapter! var session: Session! - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() adapter = TestSessionAdapter() - adapter.data = try! JSONSerialization.data(withJSONObject: ["key": "value"], options: []) + adapter.data = try XCTUnwrap(JSONSerialization.data(withJSONObject: ["key": "value"], options: [])) session = Session(adapter: adapter, callbackQueue: .main) } @@ -33,7 +33,7 @@ class SessionCallbackQueueTests: XCTestCase { session.send(request, callbackQueue: .sessionQueue) { result in // This depends on implementation of TestSessionAdapter - XCTAssert(Thread.isMainThread) + XCTAssertTrue(Thread.isMainThread) expectation.fulfill() } @@ -60,7 +60,7 @@ class SessionCallbackQueueTests: XCTestCase { session.send(request, callbackQueue: .dispatchQueue(dispatchQueue)) { result in // There is no way to test current dispatch queue. - XCTAssert(!Thread.isMainThread) + XCTAssertFalse(Thread.isMainThread) expectation.fulfill() } diff --git a/Tests/APIKitTests/SessionTests.swift b/Tests/APIKitTests/SessionTests.swift index d65a235e..fa9e4fb9 100644 --- a/Tests/APIKitTests/SessionTests.swift +++ b/Tests/APIKitTests/SessionTests.swift @@ -13,9 +13,9 @@ class SessionTests: XCTestCase { session = Session(adapter: adapter) } - func testSuccess() { + func testSuccess() throws { let dictionary = ["key": "value"] - adapter.data = try! JSONSerialization.data(withJSONObject: dictionary, options: []) + adapter.data = try XCTUnwrap(JSONSerialization.data(withJSONObject: dictionary, options: [])) let expectation = self.expectation(description: "wait for response") let request = TestRequest() From cf72a213a60ac0dce0401dac4499aeb58fe51482 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 03:21:48 +0900 Subject: [PATCH 50/61] Drop support for swift 5.3 and below --- .github/workflows/ci.yml | 11 ++++------- .swift-version | 1 - 2 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 .swift-version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76f4852f..57a55945 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,12 +30,9 @@ jobs: - xcode: "Xcode_12.5.1" runsOn: macOS-11 name: "macOS 11, Xcode 12.5.1, Swift 5.4.2" - - xcode: "Xcode_11.7" + - xcode: "Xcode_12" runsOn: macOS-10.15 - name: "macOS 10.15, Xcode 11.7, Swift 5.2.4" - - xcode: "Xcode_10.3" - runsOn: macOS-10.15 - name: "macOS 10.15, Xcode 10.3, Swift 5.0.1" + name: "macOS 10.15, Xcode 12.0.1, Swift 5.3" steps: - uses: actions/checkout@v2 with: @@ -65,9 +62,9 @@ jobs: - xcode: "Xcode_12.5.1" runsOn: macOS-11 name: "macOS 11, Xcode 12.5.1, Swift 5.4.2" - - xcode: "Xcode_11.7" + - xcode: "Xcode_12" runsOn: macOS-10.15 - name: "macOS 10.15, Xcode 11.7, Swift 5.2.4" + name: "macOS 10.15, Xcode 12.0.1, Swift 5.3" steps: - uses: actions/checkout@v2 - name: ${{ matrix.name }} diff --git a/.swift-version b/.swift-version deleted file mode 100644 index 819e07a2..00000000 --- a/.swift-version +++ /dev/null @@ -1 +0,0 @@ -5.0 From 6235703b893ace8d45c14ba34058967aed30234b Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 03:33:54 +0900 Subject: [PATCH 51/61] Change commands depending on execution environment --- .github/workflows/ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57a55945..6f8a1880 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,15 +59,16 @@ jobs: - xcode: "Xcode_13.4.1" runsOn: macOS-12 name: "macOS 12, Xcode 13.4.1, Swift 5.6.1" + action: swift test -c debug - xcode: "Xcode_12.5.1" runsOn: macOS-11 name: "macOS 11, Xcode 12.5.1, Swift 5.4.2" + action: swift test -c debug - xcode: "Xcode_12" runsOn: macOS-10.15 name: "macOS 10.15, Xcode 12.0.1, Swift 5.3" + action: swift build -c debug steps: - uses: actions/checkout@v2 - name: ${{ matrix.name }} - run: | - swift build - swift test + run: ${{ matrix.action }} From b4903640d3081d728926d0f071d45c99a017cc3e Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 03:36:39 +0900 Subject: [PATCH 52/61] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e6b06ebb..45c1bed7 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Session.send(request) { result in ## Requirements -- Swift 5.0 or later +- Swift 5.3 or later - iOS 9.0 or later - Mac OS 10.10 or later - watchOS 2.0 or later @@ -40,6 +40,8 @@ If you use Swift 2.2 or 2.3, try [APIKit 2.0.5](https://github.com/ishkawa/APIKi If you use Swift 4.2 or before, try [APIKit 4.1.0](https://github.com/ishkawa/APIKit/tree/4.1.0). +If you use Swift 5.2 or before, try [APIKit 5.3.0](https://github.com/ishkawa/APIKit/tree/5.3.0). + ## Installation #### [Carthage](https://github.com/Carthage/Carthage) From a001b653819e49bdd4629ea7159efdb4d06497ad Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 14 Aug 2022 04:05:09 +0900 Subject: [PATCH 53/61] Added default implementation of `response(from:urlResponse:)` when Response is Void --- Sources/APIKit/Request.swift | 6 ++++++ Tests/APIKitTests/SessionTests.swift | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/APIKit/Request.swift b/Sources/APIKit/Request.swift index efe68c97..ea6c5dae 100644 --- a/Sources/APIKit/Request.swift +++ b/Sources/APIKit/Request.swift @@ -145,3 +145,9 @@ public extension Request { return try response(from: passedObject, urlResponse: urlResponse) } } + +public extension Request where Response == Void { + func response(from object: Any, urlResponse: HTTPURLResponse) throws { + return + } +} diff --git a/Tests/APIKitTests/SessionTests.swift b/Tests/APIKitTests/SessionTests.swift index d65a235e..28777736 100644 --- a/Tests/APIKitTests/SessionTests.swift +++ b/Tests/APIKitTests/SessionTests.swift @@ -188,10 +188,6 @@ class SessionTests: XCTestCase { var path: String { return "/" } - - func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response { - return () - } } func testCancelOtherRequest() { From 26a94b0721c25ae5871bbd733b8740735dde4bf7 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Mon, 7 Feb 2022 02:28:46 +0900 Subject: [PATCH 54/61] Try Swift Concurrency --- APIKit.xcodeproj/project.pbxproj | 13 ++++++ Sources/APIKit/Concurrency/Concurrency.swift | 45 ++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 Sources/APIKit/Concurrency/Concurrency.swift diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index 16ded583..c3c90aa0 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 7F7048F11D9D8A12003C99F6 /* SessionTaskError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048EE1D9D8A12003C99F6 /* SessionTaskError.swift */; }; 7F7048F31D9D8A1F003C99F6 /* URLEncodedSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */; }; 7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */; }; + C5725F4B28D8C36500810D7C /* Concurrency.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5725F4A28D8C36500810D7C /* Concurrency.swift */; }; C5FF1DC128A80FFD0059573D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = C5FF1DC028A80FFD0059573D /* test.json */; }; ECA831481DE4DDBF004EB1B5 /* ProtobufDataParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */; }; ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */; }; @@ -128,6 +129,7 @@ 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = URLEncodedSerialization.swift; path = Sources/APIKit/Serializations/URLEncodedSerialization.swift; sourceTree = SOURCE_ROOT; }; 7F8ECDFD1B6A799E00234E04 /* Demo.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Demo.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPStub.swift; sourceTree = ""; }; + C5725F4A28D8C36500810D7C /* Concurrency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Concurrency.swift; sourceTree = ""; }; C5FF1DC028A80FFD0059573D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = ""; }; ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufDataParser.swift; path = Sources/APIKit/DataParser/ProtobufDataParser.swift; sourceTree = SOURCE_ROOT; }; ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtobufDataParserTests.swift; sourceTree = ""; }; @@ -310,6 +312,7 @@ 7F7048CA1D9D89BE003C99F6 /* Request.swift */, 7F7048CB1D9D89BE003C99F6 /* Session.swift */, 7F7048CC1D9D89BE003C99F6 /* Unavailable.swift */, + C5725F4928D8C36500810D7C /* Concurrency */, 0969AE0D259DEC3C00C498AF /* Combine */, 7F85FB8B1C9D317300CEE132 /* SessionAdapter */, 7F18BD0D1C972C38003A31DF /* BodyParameters */, @@ -364,6 +367,15 @@ path = APIKit/DataParser; sourceTree = ""; }; + C5725F4928D8C36500810D7C /* Concurrency */ = { + isa = PBXGroup; + children = ( + C5725F4A28D8C36500810D7C /* Concurrency.swift */, + ); + name = Concurrency; + path = APIKit/Concurrency; + sourceTree = ""; + }; C5FF1DBF28A80FFD0059573D /* Resources */ = { isa = PBXGroup; children = ( @@ -495,6 +507,7 @@ 7F7048E01D9D89FB003C99F6 /* Data+InputStream.swift in Sources */, 7F7048DF1D9D89FB003C99F6 /* BodyParameters.swift in Sources */, 7F7048E21D9D89FB003C99F6 /* JSONBodyParameters.swift in Sources */, + C5725F4B28D8C36500810D7C /* Concurrency.swift in Sources */, 7F7048D61D9D89F2003C99F6 /* SessionAdapter.swift in Sources */, 7F7048EF1D9D8A12003C99F6 /* RequestError.swift in Sources */, 7F7048E91D9D8A08003C99F6 /* FormURLEncodedDataParser.swift in Sources */, diff --git a/Sources/APIKit/Concurrency/Concurrency.swift b/Sources/APIKit/Concurrency/Concurrency.swift new file mode 100644 index 00000000..ca9e5233 --- /dev/null +++ b/Sources/APIKit/Concurrency/Concurrency.swift @@ -0,0 +1,45 @@ +#if compiler(>=5.5.2) && canImport(_Concurrency) + +import Foundation + +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +private actor SessionTaskActor { + private weak var sessionTask: SessionTask? + + func send(_ sessionTask: SessionTask?) { + self.sessionTask = sessionTask + } + + func cancel() { + sessionTask?.cancel() + } +} + +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +public extension Session { + static func response(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response { + return try await shared.response(for: request, callbackQueue: callbackQueue) + } + + func response(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response { + let sessionTaskActor = SessionTaskActor() + return try await withTaskCancellationHandler(operation: { + return try await withUnsafeThrowingContinuation { continuation in + Task { + await sessionTaskActor.send(send(request, callbackQueue: callbackQueue) { result in + switch result { + case .success(let response): + continuation.resume(returning: response) + case .failure(let error): + continuation.resume(throwing: error) + } + }) + } + } + }, onCancel: { + Task { await sessionTaskActor.cancel() } + }) + } +} + +#endif From eebbc027901b450cb4522fd403f669a0b02f78d8 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Tue, 20 Sep 2022 02:00:10 +0900 Subject: [PATCH 55/61] Rename SessionTask Actor to SessionTaskCancellationHandler --- Sources/APIKit/Concurrency/Concurrency.swift | 37 +++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Sources/APIKit/Concurrency/Concurrency.swift b/Sources/APIKit/Concurrency/Concurrency.swift index ca9e5233..03866e95 100644 --- a/Sources/APIKit/Concurrency/Concurrency.swift +++ b/Sources/APIKit/Concurrency/Concurrency.swift @@ -2,19 +2,6 @@ import Foundation -@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -private actor SessionTaskActor { - private weak var sessionTask: SessionTask? - - func send(_ sessionTask: SessionTask?) { - self.sessionTask = sessionTask - } - - func cancel() { - sessionTask?.cancel() - } -} - @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Session { static func response(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response { @@ -22,24 +9,40 @@ public extension Session { } func response(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response { - let sessionTaskActor = SessionTaskActor() + let cancellationHandler = SessionTaskCancellationHandler() return try await withTaskCancellationHandler(operation: { return try await withUnsafeThrowingContinuation { continuation in Task { - await sessionTaskActor.send(send(request, callbackQueue: callbackQueue) { result in + let sessionTask = send(request, callbackQueue: callbackQueue) { result in switch result { case .success(let response): continuation.resume(returning: response) case .failure(let error): continuation.resume(throwing: error) } - }) + } + await cancellationHandler.register(with: sessionTask) } } }, onCancel: { - Task { await sessionTaskActor.cancel() } + Task { await cancellationHandler.cancel() } }) } } +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +private actor SessionTaskCancellationHandler { + private var sessionTask: SessionTask? + + func register(with task: SessionTask?) { + guard sessionTask == nil else { return } + sessionTask = task + } + + func cancel() { + sessionTask?.cancel() + sessionTask = nil + } +} + #endif From c09b881350d7bfe9642e584ad5b611fc6b6a765c Mon Sep 17 00:00:00 2001 From: Econa77 Date: Tue, 20 Sep 2022 03:29:26 +0900 Subject: [PATCH 56/61] Add concurrency tests --- APIKit.xcodeproj/project.pbxproj | 12 ++++ Sources/APIKit/Combine/Combine.swift | 1 + Sources/APIKit/Concurrency/Concurrency.swift | 23 +++++-- Sources/APIKit/Error/SessionTaskError.swift | 3 + .../Concurrency/ConcurrencyTests.swift | 68 +++++++++++++++++++ 5 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 Tests/APIKitTests/Concurrency/ConcurrencyTests.swift diff --git a/APIKit.xcodeproj/project.pbxproj b/APIKit.xcodeproj/project.pbxproj index c3c90aa0..e460ab57 100644 --- a/APIKit.xcodeproj/project.pbxproj +++ b/APIKit.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 7F7048F31D9D8A1F003C99F6 /* URLEncodedSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7048F21D9D8A1F003C99F6 /* URLEncodedSerialization.swift */; }; 7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */; }; C5725F4B28D8C36500810D7C /* Concurrency.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5725F4A28D8C36500810D7C /* Concurrency.swift */; }; + C5B144D828D8D7DC00E30ECD /* ConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */; }; C5FF1DC128A80FFD0059573D /* test.json in Resources */ = {isa = PBXBuildFile; fileRef = C5FF1DC028A80FFD0059573D /* test.json */; }; ECA831481DE4DDBF004EB1B5 /* ProtobufDataParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */; }; ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */; }; @@ -130,6 +131,7 @@ 7F8ECDFD1B6A799E00234E04 /* Demo.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Demo.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 7FA1690C1D9D8C80006C982B /* HTTPStub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPStub.swift; sourceTree = ""; }; C5725F4A28D8C36500810D7C /* Concurrency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Concurrency.swift; sourceTree = ""; }; + C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrencyTests.swift; sourceTree = ""; }; C5FF1DC028A80FFD0059573D /* test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test.json; sourceTree = ""; }; ECA831471DE4DDBF004EB1B5 /* ProtobufDataParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtobufDataParser.swift; path = Sources/APIKit/DataParser/ProtobufDataParser.swift; sourceTree = SOURCE_ROOT; }; ECA831491DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtobufDataParserTests.swift; sourceTree = ""; }; @@ -242,6 +244,7 @@ 7F698E451D9D680C00F1561D /* RequestTests.swift */, 7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */, 7F698E4A1D9D680C00F1561D /* SessionTests.swift */, + C5B144D628D8D7D000E30ECD /* Concurrency */, 0973EE33259E2DD000879BA2 /* Combine */, 7F698E3B1D9D680C00F1561D /* BodyParametersType */, 7F698E401D9D680C00F1561D /* DataParserType */, @@ -376,6 +379,14 @@ path = APIKit/Concurrency; sourceTree = ""; }; + C5B144D628D8D7D000E30ECD /* Concurrency */ = { + isa = PBXGroup; + children = ( + C5B144D728D8D7DC00E30ECD /* ConcurrencyTests.swift */, + ); + path = Concurrency; + sourceTree = ""; + }; C5FF1DBF28A80FFD0059573D /* Resources */ = { isa = PBXGroup; children = ( @@ -534,6 +545,7 @@ 7F698E581D9D680C00F1561D /* RequestTests.swift in Sources */, ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */, 7F698E5E1D9D680C00F1561D /* TestRequest.swift in Sources */, + C5B144D828D8D7DC00E30ECD /* ConcurrencyTests.swift in Sources */, 7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */, 0973EE35259E2DDC00879BA2 /* CombineTests.swift in Sources */, 7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */, diff --git a/Sources/APIKit/Combine/Combine.swift b/Sources/APIKit/Combine/Combine.swift index 0b4db3f4..6e3223c0 100644 --- a/Sources/APIKit/Combine/Combine.swift +++ b/Sources/APIKit/Combine/Combine.swift @@ -68,6 +68,7 @@ public struct SessionTaskPublisher: Publisher { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Session { /// 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: A publisher that wraps a session task for the request. diff --git a/Sources/APIKit/Concurrency/Concurrency.swift b/Sources/APIKit/Concurrency/Concurrency.swift index 03866e95..2555fc92 100644 --- a/Sources/APIKit/Concurrency/Concurrency.swift +++ b/Sources/APIKit/Concurrency/Concurrency.swift @@ -4,22 +4,31 @@ import Foundation @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public extension Session { + /// Calls `response(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: `Request.Response` static func response(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response { return try await shared.response(for: request, callbackQueue: callbackQueue) } + /// Convenience method to load `Request.Response` using an `Request`, creates and resumes an `SessionTask` internally. + /// + /// - 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: `Request.Response` func response(for request: Request, callbackQueue: CallbackQueue? = nil) async throws -> Request.Response { let cancellationHandler = SessionTaskCancellationHandler() return try await withTaskCancellationHandler(operation: { - return try await withUnsafeThrowingContinuation { continuation in + return try await withCheckedThrowingContinuation { continuation in + guard !Task.isCancelled else { + continuation.resume(throwing: SessionTaskError.taskAlreadyCancelledError) + return + } Task { let sessionTask = send(request, callbackQueue: callbackQueue) { result in - switch result { - case .success(let response): - continuation.resume(returning: response) - case .failure(let error): - continuation.resume(throwing: error) - } + continuation.resume(with: result) } await cancellationHandler.register(with: sessionTask) } diff --git a/Sources/APIKit/Error/SessionTaskError.swift b/Sources/APIKit/Error/SessionTaskError.swift index 864d9287..c019714d 100644 --- a/Sources/APIKit/Error/SessionTaskError.swift +++ b/Sources/APIKit/Error/SessionTaskError.swift @@ -10,4 +10,7 @@ public enum SessionTaskError: Error { /// Error while creating `Request.Response` from `(Data, URLResponse)`. case responseError(Error) + + /// Error when the `Task` in Concurrency was cancelled before execution. + case taskAlreadyCancelledError } diff --git a/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift b/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift new file mode 100644 index 00000000..39b51c2a --- /dev/null +++ b/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift @@ -0,0 +1,68 @@ +#if compiler(>=5.6.0) && canImport(_Concurrency) + +import XCTest +import APIKit + +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +final class ConcurrencyTests: XCTestCase { + var adapter: TestSessionAdapter! + var session: Session! + + override func setUp() { + super.setUp() + adapter = TestSessionAdapter() + session = Session(adapter: adapter) + } + + func testSuccess() async throws { + let dictionary = ["key": "value"] + adapter.data = try XCTUnwrap(JSONSerialization.data(withJSONObject: dictionary, options: [])) + + let request = TestRequest() + let value = try await session.response(for: request) + XCTAssertEqual((value as? [String: String])?["key"], "value") + } + + func testParseDataError() async throws { + adapter.data = "{\"broken\": \"json}".data(using: .utf8, allowLossyConversion: false) + + let request = TestRequest() + do { + _ = try await session.response(for: request) + XCTFail() + } catch { + let sessionError = try XCTUnwrap(error as? SessionTaskError) + if case .responseError(let responseError as NSError) = sessionError { + XCTAssertEqual(responseError.domain, NSCocoaErrorDomain) + XCTAssertEqual(responseError.code, 3840) + } else { + XCTFail() + } + } + } + + func testCancel() async throws { + let request = TestRequest() + + let task = Task { + do { + _ = try await session.response(for: request) + XCTFail() + } catch { + let sessionError = try XCTUnwrap(error as? SessionTaskError) + switch sessionError { + case .taskAlreadyCancelledError: + XCTAssertTrue(Task.isCancelled) + default: + XCTFail() + } + } + } + task.cancel() + _ = try await task.value + + XCTAssertTrue(task.isCancelled) + } +} + +#endif From 1695c58ace4b192f9e6b9c8fe007cb40cb6adc3b Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 2 Oct 2022 13:42:11 +0900 Subject: [PATCH 57/61] Optimize concurrency task cancellation --- Sources/APIKit/Concurrency/Concurrency.swift | 15 ++++--- Sources/APIKit/Error/SessionTaskError.swift | 3 -- Sources/APIKit/Session.swift | 42 ++++++++++--------- .../Concurrency/ConcurrencyTests.swift | 6 +-- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/Sources/APIKit/Concurrency/Concurrency.swift b/Sources/APIKit/Concurrency/Concurrency.swift index 2555fc92..c0518e35 100644 --- a/Sources/APIKit/Concurrency/Concurrency.swift +++ b/Sources/APIKit/Concurrency/Concurrency.swift @@ -22,15 +22,16 @@ public extension Session { let cancellationHandler = SessionTaskCancellationHandler() return try await withTaskCancellationHandler(operation: { return try await withCheckedThrowingContinuation { continuation in - guard !Task.isCancelled else { - continuation.resume(throwing: SessionTaskError.taskAlreadyCancelledError) - return - } Task { - let sessionTask = send(request, callbackQueue: callbackQueue) { result in + let sessionTask = createSessionTask(request, callbackQueue: callbackQueue) { result in continuation.resume(with: result) } await cancellationHandler.register(with: sessionTask) + if await cancellationHandler.isTaskCancelled { + sessionTask?.cancel() + } else { + sessionTask?.resume() + } } } }, onCancel: { @@ -42,15 +43,17 @@ public extension Session { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) private actor SessionTaskCancellationHandler { private var sessionTask: SessionTask? + private(set) var isTaskCancelled = false func register(with task: SessionTask?) { + guard !isTaskCancelled else { return } guard sessionTask == nil else { return } sessionTask = task } func cancel() { + isTaskCancelled = true sessionTask?.cancel() - sessionTask = nil } } diff --git a/Sources/APIKit/Error/SessionTaskError.swift b/Sources/APIKit/Error/SessionTaskError.swift index c019714d..864d9287 100644 --- a/Sources/APIKit/Error/SessionTaskError.swift +++ b/Sources/APIKit/Error/SessionTaskError.swift @@ -10,7 +10,4 @@ public enum SessionTaskError: Error { /// Error while creating `Request.Response` from `(Data, URLResponse)`. case responseError(Error) - - /// Error when the `Task` in Concurrency was cancelled before execution. - case taskAlreadyCancelledError } diff --git a/Sources/APIKit/Session.swift b/Sources/APIKit/Session.swift index 4406fca9..85fb9615 100644 --- a/Sources/APIKit/Session.swift +++ b/Sources/APIKit/Session.swift @@ -55,8 +55,30 @@ open class Session { /// - returns: The new session task. @discardableResult open func send(_ request: Request, callbackQueue: CallbackQueue? = nil, handler: @escaping (Result) -> Void = { _ in }) -> SessionTask? { - let callbackQueue = callbackQueue ?? self.callbackQueue + let task = createSessionTask(request, callbackQueue: callbackQueue, handler: handler) + task?.resume() + return task + } + + /// Cancels requests that passes the test. + /// - parameter requestType: The request type to cancel. + /// - parameter test: The test closure that determines if a request should be cancelled or not. + open func cancelRequests(with requestType: Request.Type, passingTest test: @escaping (Request) -> Bool = { _ in true }) { + adapter.getTasks { [weak self] tasks in + tasks + .filter { task in + if let request = self?.requestForTask(task) as Request? { + return test(request) + } else { + return false + } + } + .forEach { $0.cancel() } + } + } + internal func createSessionTask(_ request: Request, callbackQueue: CallbackQueue?, handler: @escaping (Result) -> Void) -> SessionTask? { + let callbackQueue = callbackQueue ?? self.callbackQueue let urlRequest: URLRequest do { urlRequest = try request.buildURLRequest() @@ -91,28 +113,10 @@ open class Session { } setRequest(request, forTask: task) - task.resume() return task } - /// Cancels requests that passes the test. - /// - parameter requestType: The request type to cancel. - /// - parameter test: The test closure that determines if a request should be cancelled or not. - open func cancelRequests(with requestType: Request.Type, passingTest test: @escaping (Request) -> Bool = { _ in true }) { - adapter.getTasks { [weak self] tasks in - tasks - .filter { task in - if let request = self?.requestForTask(task) as Request? { - return test(request) - } else { - return false - } - } - .forEach { $0.cancel() } - } - } - private func setRequest(_ request: Request, forTask task: SessionTask) { objc_setAssociatedObject(task, &taskRequestKey, request, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } diff --git a/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift b/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift index 39b51c2a..30052335 100644 --- a/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift +++ b/Tests/APIKitTests/Concurrency/ConcurrencyTests.swift @@ -50,10 +50,10 @@ final class ConcurrencyTests: XCTestCase { XCTFail() } catch { let sessionError = try XCTUnwrap(error as? SessionTaskError) - switch sessionError { - case .taskAlreadyCancelledError: + if case .connectionError(let connectionError as NSError) = sessionError { + XCTAssertEqual(connectionError.code, 0) XCTAssertTrue(Task.isCancelled) - default: + } else { XCTFail() } } From 18e3611e543694d508e5956cda3f10324c401916 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 2 Oct 2022 14:53:32 +0900 Subject: [PATCH 58/61] [CI] Add Xcode14 and Swift 5.7 --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f8a1880..431dc0ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: macos-12 name: CocoaPods Lint env: - DEVELOPER_DIR: "/Applications/Xcode_13.4.1.app/Contents/Developer" + DEVELOPER_DIR: "/Applications/Xcode_14.0.1.app/Contents/Developer" steps: - uses: actions/checkout@v2 - run: pod lib lint --allow-warnings @@ -24,6 +24,9 @@ jobs: fail-fast: false matrix: include: + - xcode: "Xcode_14.0.1" + runsOn: macOS-12 + name: "macOS 12, Xcode 14.0.1, Swift 5.7" - xcode: "Xcode_13.4.1" runsOn: macOS-12 name: "macOS 12, Xcode 13.4.1, Swift 5.6.1" @@ -56,6 +59,10 @@ jobs: fail-fast: false matrix: include: + - xcode: "Xcode_14.0.1" + runsOn: macOS-12 + name: "macOS 12, Xcode 14.0.1, Swift 5.7" + action: swift test -c debug - xcode: "Xcode_13.4.1" runsOn: macOS-12 name: "macOS 12, Xcode 13.4.1, Swift 5.6.1" From 77fb3c5ec7ded310399a933da0521a153f03b36b Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 2 Oct 2022 15:08:18 +0900 Subject: [PATCH 59/61] [CI] Revert CocoaPods Lint execution to Xcode13.4.1 https://github.com/CocoaPods/CocoaPods/issues/11558 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 431dc0ae..9a0800f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: macos-12 name: CocoaPods Lint env: - DEVELOPER_DIR: "/Applications/Xcode_14.0.1.app/Contents/Developer" + DEVELOPER_DIR: "/Applications/Xcode_13.4.1.app/Contents/Developer" steps: - uses: actions/checkout@v2 - run: pod lib lint --allow-warnings From b839e53b870104798035b279d2a6168b0a2227b1 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sun, 2 Oct 2022 15:40:08 +0900 Subject: [PATCH 60/61] Set version 5.4.0 --- APIKit.podspec | 2 +- Sources/APIKit/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/APIKit.podspec b/APIKit.podspec index 7afab61b..f93510f8 100644 --- a/APIKit.podspec +++ b/APIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "APIKit" - s.version = "5.3.0" + s.version = "5.4.0" s.summary = "Type-safe networking abstraction layer that associates request type with response type." s.homepage = "https://github.com/ishkawa/APIKit" diff --git a/Sources/APIKit/Info.plist b/Sources/APIKit/Info.plist index 2b29ada6..9b01e54a 100644 --- a/Sources/APIKit/Info.plist +++ b/Sources/APIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.3.0 + 5.4.0 CFBundleSignature ???? CFBundleVersion From 528ad4e4e601e79bf5665dfa3ad76c3496afa387 Mon Sep 17 00:00:00 2001 From: Econa77 Date: Sat, 22 Oct 2022 16:52:21 +0900 Subject: [PATCH 61/61] Remove deprecated NSKeyedArchiver / NSKeyedUnarchiver in tests --- .../BodyParametersType/ProtobufBodyParametersTests.swift | 8 +++----- .../DataParserType/ProtobufDataParserTests.swift | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift index 3f5da8b4..ccbc2515 100644 --- a/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift +++ b/Tests/APIKitTests/BodyParametersType/ProtobufBodyParametersTests.swift @@ -4,7 +4,7 @@ import APIKit class ProtobufBodyParametersTests: XCTestCase { func testProtobufSuccess() throws { - let object = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) + let object = try XCTUnwrap("data".data(using: .utf8)) let parameters = ProtobufBodyParameters(protobufObject: object) XCTAssertEqual(parameters.contentType, "application/protobuf") @@ -12,9 +12,7 @@ class ProtobufBodyParametersTests: XCTestCase { XCTFail() return } - let dictionary = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: Int] - XCTAssertEqual(dictionary?["foo"], 1) - XCTAssertEqual(dictionary?["bar"], 2) - XCTAssertEqual(dictionary?["baz"], 3) + let string = String(data: data, encoding: .utf8) + XCTAssertEqual(string, "data") } } diff --git a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift index 6752bee9..63e91853 100644 --- a/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift +++ b/Tests/APIKitTests/DataParserType/ProtobufDataParserTests.swift @@ -9,13 +9,11 @@ class ProtobufDataParserTests: XCTestCase { } func testProtobufSuccess() throws { - let data = NSKeyedArchiver.archivedData(withRootObject: ["foo": 1, "bar": 2, "baz": 3]) + let data = try XCTUnwrap("data".data(using: .utf8)) let parser = ProtobufDataParser() let object = try XCTUnwrap(try parser.parse(data: data) as? Data) - let dictionary = NSKeyedUnarchiver.unarchiveObject(with: object) as? [String: Int] - XCTAssertEqual(dictionary?["foo"], 1) - XCTAssertEqual(dictionary?["bar"], 2) - XCTAssertEqual(dictionary?["baz"], 3) + let string = String(data: object, encoding: .utf8) + XCTAssertEqual(string, "data") } }