forked from loafle/openapi-generator-original
[Swift] fix URLSession file upload (#5546)
* [swift5] - fix URLSession file upload * [swift5] - fix URLSession file upload * [swift5] fix file upload * [swift5] - fix URLSession file upload * [swift] add unit tests for file upload * [swift] update samples copyright
This commit is contained in:
@@ -29,7 +29,7 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -84,7 +84,7 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
guard let url = URL(string: URLString) else {
|
||||
throw DownloadException.requestMissingURL
|
||||
}
|
||||
|
||||
|
||||
var originalRequest = URLRequest(url: url)
|
||||
|
||||
originalRequest.httpMethod = method.rawValue
|
||||
@@ -110,9 +110,9 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
if fileKeys.count > 0 {
|
||||
encoding = FileUploadEncoding(contentTypeForFormPart: contentTypeForFormPart(fileURL:))
|
||||
@@ -135,13 +135,13 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers)
|
||||
|
||||
let dataTask = urlSession.dataTask(with: request) { [weak self] data, response, error in
|
||||
|
||||
|
||||
guard let self = self else { return }
|
||||
|
||||
if let taskCompletionShouldRetry = self.taskCompletionShouldRetry {
|
||||
|
||||
taskCompletionShouldRetry(data, response, error) { [weak self] shouldRetry in
|
||||
|
||||
|
||||
guard let self = self else { return }
|
||||
|
||||
if shouldRetry {
|
||||
@@ -170,7 +170,7 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
}
|
||||
|
||||
dataTask.resume()
|
||||
|
||||
|
||||
} catch {
|
||||
apiResponseQueue.async {
|
||||
cleanupRequest()
|
||||
@@ -266,7 +266,7 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
|
||||
let items = contentDisposition.components(separatedBy: ";")
|
||||
|
||||
var filename : String? = nil
|
||||
var filename: String?
|
||||
|
||||
for contentItem in items {
|
||||
|
||||
@@ -366,7 +366,7 @@ private var urlSessionStore = SynchronizedDictionary<String, URLSession>()
|
||||
fileprivate class SessionDelegate: NSObject, URLSessionDelegate, URLSessionDataDelegate {
|
||||
|
||||
var credential: URLCredential?
|
||||
|
||||
|
||||
var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
|
||||
|
||||
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
|
||||
@@ -430,76 +430,117 @@ fileprivate class URLEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
|
||||
let contentTypeForFormPart: (_ fileURL: URL) -> String?
|
||||
|
||||
init(contentTypeForFormPart: @escaping (_ fileURL: URL) -> String?) {
|
||||
self.contentTypeForFormPart = contentTypeForFormPart
|
||||
}
|
||||
|
||||
func encode(_ urlRequest: URLRequest, with parameters: [String : Any]?) throws -> URLRequest {
|
||||
|
||||
|
||||
func encode(_ urlRequest: URLRequest, with parameters: [String: Any]?) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
|
||||
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
|
||||
}
|
||||
|
||||
|
||||
func mimeType(for url: URL) -> String {
|
||||
let pathExtension = url.pathExtension
|
||||
|
||||
@@ -510,15 +551,15 @@ fileprivate class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
return "application/octet-stream"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -20,4 +20,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 509bec696cc1d8641751b52e4fe4bef04ac4542c
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.0
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB41C693BE200B96B06 /* PetAPITests.swift */; };
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */; };
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */; };
|
||||
A5EA12542419387200E30FC3 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA12522419387100E30FC3 /* FileUtils.swift */; };
|
||||
A5EA12552419387200E30FC3 /* UIImage+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA12532419387100E30FC3 /* UIImage+Extras.swift */; };
|
||||
FB5CCC7EFA680BB2746B695B /* Pods_SwaggerClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83FDC034BBA2A07AE9975250 /* Pods_SwaggerClientTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -47,6 +49,8 @@
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAPITests.swift; sourceTree = "<group>"; };
|
||||
7F98CC8B18E5FA9213F6A68D /* Pods_SwaggerClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
83FDC034BBA2A07AE9975250 /* Pods_SwaggerClientTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClientTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A5EA12522419387100E30FC3 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
A5EA12532419387100E30FC3 /* UIImage+Extras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extras.swift"; sourceTree = "<group>"; };
|
||||
ACB80AC61FA8D8916D4559AA /* Pods-SwaggerClient.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClient.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C07EC0A94AA0F86D60668B32 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E43FC34A9681D65ED44EE914 /* Pods-SwaggerClientTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -135,6 +139,8 @@
|
||||
6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */,
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */,
|
||||
1A501F47219C3DC600F372F6 /* DateFormatTests.swift */,
|
||||
A5EA12522419387100E30FC3 /* FileUtils.swift */,
|
||||
A5EA12532419387100E30FC3 /* UIImage+Extras.swift */,
|
||||
);
|
||||
path = SwaggerClientTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -323,8 +329,10 @@
|
||||
files = (
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */,
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */,
|
||||
A5EA12552419387200E30FC3 /* UIImage+Extras.swift in Sources */,
|
||||
1A501F48219C3DC600F372F6 /* DateFormatTests.swift in Sources */,
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */,
|
||||
A5EA12542419387200E30FC3 /* FileUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FileUtils.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FileUtils {
|
||||
static func saveImage(imageName: String, image: UIImage) -> URL? {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let fileName = imageName
|
||||
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||
|
||||
//Checks if file exists, removes it if so.
|
||||
deleteFile(fileURL: fileURL)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("error saving file with error", error)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func deleteFile(fileURL: URL) -> Bool {
|
||||
if FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: fileURL.path)
|
||||
print("Removed old image")
|
||||
return true
|
||||
} catch let removeError {
|
||||
print("couldn't remove file at path", removeError)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,8 +61,35 @@ class PetAPITests: XCTestCase {
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test3UploadFile() {
|
||||
let expectation = self.expectation(description: "testUploadFile")
|
||||
|
||||
func test3DeletePet() {
|
||||
let imageName = UUID().uuidString + ".png"
|
||||
|
||||
guard
|
||||
let image = UIImage(color: .red, size: CGSize(width: 10, height: 10)),
|
||||
let imageURL = FileUtils.saveImage(imageName: imageName, image: image)
|
||||
else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
PetAPI.uploadFile(petId: 1000, additionalMetadata: "additionalMetadata", file: imageURL) { (_, error) in
|
||||
guard error == nil else {
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
XCTFail("error uploading file")
|
||||
return
|
||||
}
|
||||
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
|
||||
func test4DeletePet() {
|
||||
let expectation = self.expectation(description: "testDeletePet")
|
||||
|
||||
PetAPI.deletePet(petId: 1000) { (_, error) in
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIImage+Extras.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIImage {
|
||||
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
color.setFill()
|
||||
UIRectFill(rect)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
guard let cgImage = image?.cgImage else { return nil }
|
||||
self.init(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -13,4 +13,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 509bec696cc1d8641751b52e4fe4bef04ac4542c
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.0
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
A5EA12582419390400E30FC3 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA12562419390400E30FC3 /* FileUtils.swift */; };
|
||||
A5EA12592419390400E30FC3 /* UIImage+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA12572419390400E30FC3 /* UIImage+Extras.swift */; };
|
||||
B024164FBFF71BF644D4419A /* Pods_SwaggerClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 177A58DD5CF63F2989335DCC /* Pods_SwaggerClient.framework */; };
|
||||
B1D0246C8960F47A60098F37 /* Pods_SwaggerClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F96A0131101344CC5406CB3 /* Pods_SwaggerClientTests.framework */; };
|
||||
B596E4BD205657A500B46F03 /* APIHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596E4BC205657A500B46F03 /* APIHelperTests.swift */; };
|
||||
@@ -36,6 +38,8 @@
|
||||
4EF2021609D112A6F5AE0F55 /* Pods-SwaggerClientTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
6F96A0131101344CC5406CB3 /* Pods_SwaggerClientTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClientTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8D99518E8E05FD856A952698 /* Pods-SwaggerClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClient.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A5EA12562419390400E30FC3 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
A5EA12572419390400E30FC3 /* UIImage+Extras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extras.swift"; sourceTree = "<group>"; };
|
||||
B596E4BC205657A500B46F03 /* APIHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIHelperTests.swift; sourceTree = "<group>"; };
|
||||
EAEC0BBE1D4E30CE00C908A3 /* SwaggerClient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwaggerClient.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EAEC0BC11D4E30CE00C908A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -133,6 +137,8 @@
|
||||
EAEC0BE51D4E379000C908A3 /* StoreAPITests.swift */,
|
||||
EAEC0BE71D4E38CB00C908A3 /* UserAPITests.swift */,
|
||||
B596E4BC205657A500B46F03 /* APIHelperTests.swift */,
|
||||
A5EA12562419390400E30FC3 /* FileUtils.swift */,
|
||||
A5EA12572419390400E30FC3 /* UIImage+Extras.swift */,
|
||||
);
|
||||
path = SwaggerClientTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -311,8 +317,10 @@
|
||||
files = (
|
||||
B596E4BD205657A500B46F03 /* APIHelperTests.swift in Sources */,
|
||||
EAEC0BE81D4E38CB00C908A3 /* UserAPITests.swift in Sources */,
|
||||
A5EA12592419390400E30FC3 /* UIImage+Extras.swift in Sources */,
|
||||
EAEC0BE61D4E379000C908A3 /* StoreAPITests.swift in Sources */,
|
||||
EAEC0BE41D4E330700C908A3 /* PetAPITests.swift in Sources */,
|
||||
A5EA12582419390400E30FC3 /* FileUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FileUtils.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FileUtils {
|
||||
static func saveImage(imageName: String, image: UIImage) -> URL? {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let fileName = imageName
|
||||
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||
|
||||
//Checks if file exists, removes it if so.
|
||||
deleteFile(fileURL: fileURL)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("error saving file with error", error)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func deleteFile(fileURL: URL) -> Bool {
|
||||
if FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: fileURL.path)
|
||||
print("Removed old image")
|
||||
return true
|
||||
} catch let removeError {
|
||||
print("couldn't remove file at path", removeError)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,7 +76,35 @@ class PetAPITests: XCTestCase {
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test3DeletePet() {
|
||||
func test3UploadFile() {
|
||||
let expectation = self.expectation(description: "testUploadFile")
|
||||
|
||||
let imageName = UUID().uuidString + ".png"
|
||||
|
||||
guard
|
||||
let image = UIImage(color: .red, size: CGSize(width: 10, height: 10)),
|
||||
let imageURL = FileUtils.saveImage(imageName: imageName, image: image)
|
||||
else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
PetAPI.uploadFile(petId: 1000, additionalMetadata: "additionalMetadata", file: imageURL).sink(receiveCompletion: { (completion) in
|
||||
switch completion {
|
||||
case .failure:
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
XCTFail("error uploading file")
|
||||
case .finished:()
|
||||
}
|
||||
}, receiveValue: { _ in
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
|
||||
expectation.fulfill()
|
||||
}).store(in: &anyCancellables)
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test4DeletePet() {
|
||||
let expectation = self.expectation(description: "testDeletePet")
|
||||
PetAPI.deletePet(petId: 1000).sink(receiveCompletion: { (completion) in
|
||||
switch completion {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIImage+Extras.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIImage {
|
||||
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
color.setFill()
|
||||
UIRectFill(rect)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
guard let cgImage = image?.cgImage else { return nil }
|
||||
self.init(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -13,4 +13,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 509bec696cc1d8641751b52e4fe4bef04ac4542c
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.0
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB41C693BE200B96B06 /* PetAPITests.swift */; };
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */; };
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */; };
|
||||
A5EA124F241901AA00E30FC3 /* UIImage+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA124E241901AA00E30FC3 /* UIImage+Extras.swift */; };
|
||||
A5EA1251241905F000E30FC3 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA1250241905F000E30FC3 /* FileUtils.swift */; };
|
||||
FB5CCC7EFA680BB2746B695B /* Pods_SwaggerClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83FDC034BBA2A07AE9975250 /* Pods_SwaggerClientTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -47,6 +49,8 @@
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAPITests.swift; sourceTree = "<group>"; };
|
||||
7F98CC8B18E5FA9213F6A68D /* Pods_SwaggerClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
83FDC034BBA2A07AE9975250 /* Pods_SwaggerClientTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClientTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A5EA124E241901AA00E30FC3 /* UIImage+Extras.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extras.swift"; sourceTree = "<group>"; };
|
||||
A5EA1250241905F000E30FC3 /* FileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
ACB80AC61FA8D8916D4559AA /* Pods-SwaggerClient.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClient.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C07EC0A94AA0F86D60668B32 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E43FC34A9681D65ED44EE914 /* Pods-SwaggerClientTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -135,6 +139,8 @@
|
||||
6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */,
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */,
|
||||
1A501F47219C3DC600F372F6 /* DateFormatTests.swift */,
|
||||
A5EA124E241901AA00E30FC3 /* UIImage+Extras.swift */,
|
||||
A5EA1250241905F000E30FC3 /* FileUtils.swift */,
|
||||
);
|
||||
path = SwaggerClientTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -322,7 +328,9 @@
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */,
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */,
|
||||
1A501F48219C3DC600F372F6 /* DateFormatTests.swift in Sources */,
|
||||
A5EA1251241905F000E30FC3 /* FileUtils.swift in Sources */,
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */,
|
||||
A5EA124F241901AA00E30FC3 /* UIImage+Extras.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FileUtils.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FileUtils {
|
||||
static func saveImage(imageName: String, image: UIImage) -> URL? {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let fileName = imageName
|
||||
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||
|
||||
//Checks if file exists, removes it if so.
|
||||
deleteFile(fileURL: fileURL)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("error saving file with error", error)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func deleteFile(fileURL: URL) -> Bool {
|
||||
if FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: fileURL.path)
|
||||
print("Removed old image")
|
||||
return true
|
||||
} catch let removeError {
|
||||
print("couldn't remove file at path", removeError)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,33 @@ class PetAPITests: XCTestCase {
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test3DeletePet() {
|
||||
func test3UploadFile() {
|
||||
let expectation = self.expectation(description: "testUploadFile")
|
||||
|
||||
let imageName = UUID().uuidString + ".png"
|
||||
|
||||
guard
|
||||
let image = UIImage(color: .red, size: CGSize(width: 10, height: 10)),
|
||||
let imageURL = FileUtils.saveImage(imageName: imageName, image: image)
|
||||
else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
PetAPI.uploadFile(petId: 1000, additionalMetadata: "additionalMetadata", file: imageURL) { (_, error) in
|
||||
guard error == nil else {
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
XCTFail("error uploading file")
|
||||
return
|
||||
}
|
||||
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test4DeletePet() {
|
||||
let expectation = self.expectation(description: "testDeletePet")
|
||||
|
||||
PetAPI.deletePet(petId: 1000) { (_, error) in
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIImage+Extras.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIImage {
|
||||
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
color.setFill()
|
||||
UIRectFill(rect)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
guard let cgImage = image?.cgImage else { return nil }
|
||||
self.init(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ internal class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ internal class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -20,4 +20,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 509bec696cc1d8641751b52e4fe4bef04ac4542c
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.0
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */; };
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */; };
|
||||
751C65B82F596107A3DC8ED9 /* Pods_SwaggerClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F60AECFF321A25553B6A5B0 /* Pods_SwaggerClient.framework */; };
|
||||
A5EA125C2419398500E30FC3 /* UIImage+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA125A2419398500E30FC3 /* UIImage+Extras.swift */; };
|
||||
A5EA125D2419398500E30FC3 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA125B2419398500E30FC3 /* FileUtils.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -44,6 +46,8 @@
|
||||
6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreAPITests.swift; sourceTree = "<group>"; };
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAPITests.swift; sourceTree = "<group>"; };
|
||||
8F60AECFF321A25553B6A5B0 /* Pods_SwaggerClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A5EA125A2419398500E30FC3 /* UIImage+Extras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extras.swift"; sourceTree = "<group>"; };
|
||||
A5EA125B2419398500E30FC3 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
A638467ACFB30852DEA51F7A /* Pods-SwaggerClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClient.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B4B2BEC2ECA535C616F2F3FE /* Pods-SwaggerClientTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C07EC0A94AA0F86D60668B32 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -132,6 +136,8 @@
|
||||
6D4EFBB41C693BE200B96B06 /* PetAPITests.swift */,
|
||||
6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */,
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */,
|
||||
A5EA125B2419398500E30FC3 /* FileUtils.swift */,
|
||||
A5EA125A2419398500E30FC3 /* UIImage+Extras.swift */,
|
||||
);
|
||||
path = SwaggerClientTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -312,7 +318,9 @@
|
||||
files = (
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */,
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */,
|
||||
A5EA125C2419398500E30FC3 /* UIImage+Extras.swift in Sources */,
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */,
|
||||
A5EA125D2419398500E30FC3 /* FileUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FileUtils.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FileUtils {
|
||||
static func saveImage(imageName: String, image: UIImage) -> URL? {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let fileName = imageName
|
||||
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||
|
||||
//Checks if file exists, removes it if so.
|
||||
deleteFile(fileURL: fileURL)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("error saving file with error", error)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func deleteFile(fileURL: URL) -> Bool {
|
||||
if FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: fileURL.path)
|
||||
print("Removed old image")
|
||||
return true
|
||||
} catch let removeError {
|
||||
print("couldn't remove file at path", removeError)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,8 +50,32 @@ class PetAPITests: XCTestCase {
|
||||
}
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test3UploadFile() {
|
||||
let expectation = self.expectation(description: "testUploadFile")
|
||||
|
||||
func test3DeletePet() {
|
||||
let imageName = UUID().uuidString + ".png"
|
||||
|
||||
guard
|
||||
let image = UIImage(color: .red, size: CGSize(width: 10, height: 10)),
|
||||
let imageURL = FileUtils.saveImage(imageName: imageName, image: image)
|
||||
else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
PetAPI.uploadFile(petId: 1000, additionalMetadata: "additionalMetadata", file: imageURL).done { _ in
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
expectation.fulfill()
|
||||
}.catch { _ in
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
XCTFail("error uploading file")
|
||||
}
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
|
||||
func test4DeletePet() {
|
||||
let expectation = self.expectation(description: "testDeletePet")
|
||||
PetAPI.deletePet(petId: 1000).done {
|
||||
expectation.fulfill()
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIImage+Extras.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIImage {
|
||||
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
color.setFill()
|
||||
UIRectFill(rect)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
guard let cgImage = image?.cgImage else { return nil }
|
||||
self.init(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -20,4 +20,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 509bec696cc1d8641751b52e4fe4bef04ac4542c
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.0
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
A5EA1260241941BE00E30FC3 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA125E241941BE00E30FC3 /* FileUtils.swift */; };
|
||||
A5EA1261241941BE00E30FC3 /* UIImage+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA125F241941BE00E30FC3 /* UIImage+Extras.swift */; };
|
||||
B024164FBFF71BF644D4419A /* Pods_SwaggerClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 177A58DD5CF63F2989335DCC /* Pods_SwaggerClient.framework */; };
|
||||
B1D0246C8960F47A60098F37 /* Pods_SwaggerClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F96A0131101344CC5406CB3 /* Pods_SwaggerClientTests.framework */; };
|
||||
B596E4BD205657A500B46F03 /* APIHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B596E4BC205657A500B46F03 /* APIHelperTests.swift */; };
|
||||
@@ -36,6 +38,8 @@
|
||||
4EF2021609D112A6F5AE0F55 /* Pods-SwaggerClientTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
6F96A0131101344CC5406CB3 /* Pods_SwaggerClientTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClientTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8D99518E8E05FD856A952698 /* Pods-SwaggerClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClient.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A5EA125E241941BE00E30FC3 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
A5EA125F241941BE00E30FC3 /* UIImage+Extras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extras.swift"; sourceTree = "<group>"; };
|
||||
B596E4BC205657A500B46F03 /* APIHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIHelperTests.swift; sourceTree = "<group>"; };
|
||||
EAEC0BBE1D4E30CE00C908A3 /* SwaggerClient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwaggerClient.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EAEC0BC11D4E30CE00C908A3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -133,6 +137,8 @@
|
||||
EAEC0BE51D4E379000C908A3 /* StoreAPITests.swift */,
|
||||
EAEC0BE71D4E38CB00C908A3 /* UserAPITests.swift */,
|
||||
B596E4BC205657A500B46F03 /* APIHelperTests.swift */,
|
||||
A5EA125E241941BE00E30FC3 /* FileUtils.swift */,
|
||||
A5EA125F241941BE00E30FC3 /* UIImage+Extras.swift */,
|
||||
);
|
||||
path = SwaggerClientTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -313,8 +319,10 @@
|
||||
files = (
|
||||
B596E4BD205657A500B46F03 /* APIHelperTests.swift in Sources */,
|
||||
EAEC0BE81D4E38CB00C908A3 /* UserAPITests.swift in Sources */,
|
||||
A5EA1261241941BE00E30FC3 /* UIImage+Extras.swift in Sources */,
|
||||
EAEC0BE61D4E379000C908A3 /* StoreAPITests.swift in Sources */,
|
||||
EAEC0BE41D4E330700C908A3 /* PetAPITests.swift in Sources */,
|
||||
A5EA1260241941BE00E30FC3 /* FileUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FileUtils.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FileUtils {
|
||||
static func saveImage(imageName: String, image: UIImage) -> URL? {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let fileName = imageName
|
||||
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||
|
||||
//Checks if file exists, removes it if so.
|
||||
deleteFile(fileURL: fileURL)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("error saving file with error", error)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func deleteFile(fileURL: URL) -> Bool {
|
||||
if FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: fileURL.path)
|
||||
print("Removed old image")
|
||||
return true
|
||||
} catch let removeError {
|
||||
print("couldn't remove file at path", removeError)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,7 +66,30 @@ class PetAPITests: XCTestCase {
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test3DeletePet() {
|
||||
func test3UploadFile() {
|
||||
let expectation = self.expectation(description: "testUploadFile")
|
||||
|
||||
let imageName = UUID().uuidString + ".png"
|
||||
|
||||
guard
|
||||
let image = UIImage(color: .red, size: CGSize(width: 10, height: 10)),
|
||||
let imageURL = FileUtils.saveImage(imageName: imageName, image: image)
|
||||
else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
PetAPI.uploadFile(petId: 1000, additionalMetadata: "additionalMetadata", file: imageURL).subscribe(onNext: { pet in
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
expectation.fulfill()
|
||||
}, onError: { _ in
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
XCTFail("error uploading file")
|
||||
}).disposed(by: disposeBag)
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test4DeletePet() {
|
||||
let expectation = self.expectation(description: "testDeletePet")
|
||||
PetAPI.deletePet(petId: 1000).subscribe(onNext: {
|
||||
expectation.fulfill()
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIImage+Extras.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIImage {
|
||||
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
color.setFill()
|
||||
UIRectFill(rect)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
guard let cgImage = image?.cgImage else { return nil }
|
||||
self.init(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
@@ -13,4 +13,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 509bec696cc1d8641751b52e4fe4bef04ac4542c
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
COCOAPODS: 1.9.0
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB41C693BE200B96B06 /* PetAPITests.swift */; };
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */; };
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */; };
|
||||
A5EA12642419439700E30FC3 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA12622419439700E30FC3 /* FileUtils.swift */; };
|
||||
A5EA12652419439700E30FC3 /* UIImage+Extras.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5EA12632419439700E30FC3 /* UIImage+Extras.swift */; };
|
||||
FB5CCC7EFA680BB2746B695B /* Pods_SwaggerClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83FDC034BBA2A07AE9975250 /* Pods_SwaggerClientTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -47,6 +49,8 @@
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAPITests.swift; sourceTree = "<group>"; };
|
||||
7F98CC8B18E5FA9213F6A68D /* Pods_SwaggerClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
83FDC034BBA2A07AE9975250 /* Pods_SwaggerClientTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwaggerClientTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A5EA12622419439700E30FC3 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
A5EA12632419439700E30FC3 /* UIImage+Extras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extras.swift"; sourceTree = "<group>"; };
|
||||
ACB80AC61FA8D8916D4559AA /* Pods-SwaggerClient.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClient.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C07EC0A94AA0F86D60668B32 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E43FC34A9681D65ED44EE914 /* Pods-SwaggerClientTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -135,6 +139,8 @@
|
||||
6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */,
|
||||
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */,
|
||||
1A501F47219C3DC600F372F6 /* DateFormatTests.swift */,
|
||||
A5EA12622419439700E30FC3 /* FileUtils.swift */,
|
||||
A5EA12632419439700E30FC3 /* UIImage+Extras.swift */,
|
||||
);
|
||||
path = SwaggerClientTests;
|
||||
sourceTree = "<group>";
|
||||
@@ -321,8 +327,10 @@
|
||||
files = (
|
||||
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */,
|
||||
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */,
|
||||
A5EA12652419439700E30FC3 /* UIImage+Extras.swift in Sources */,
|
||||
1A501F48219C3DC600F372F6 /* DateFormatTests.swift in Sources */,
|
||||
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */,
|
||||
A5EA12642419439700E30FC3 /* FileUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FileUtils.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FileUtils {
|
||||
static func saveImage(imageName: String, image: UIImage) -> URL? {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let fileName = imageName
|
||||
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||
|
||||
//Checks if file exists, removes it if so.
|
||||
deleteFile(fileURL: fileURL)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("error saving file with error", error)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fileURL
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func deleteFile(fileURL: URL) -> Bool {
|
||||
if FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: fileURL.path)
|
||||
print("Removed old image")
|
||||
return true
|
||||
} catch let removeError {
|
||||
print("couldn't remove file at path", removeError)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,33 @@ class PetAPITests: XCTestCase {
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test3DeletePet() {
|
||||
func test3UploadFile() {
|
||||
let expectation = self.expectation(description: "testUploadFile")
|
||||
|
||||
let imageName = UUID().uuidString + ".png"
|
||||
|
||||
guard
|
||||
let image = UIImage(color: .red, size: CGSize(width: 10, height: 10)),
|
||||
let imageURL = FileUtils.saveImage(imageName: imageName, image: image)
|
||||
else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
PetAPI.uploadFile(petId: 1000, additionalMetadata: "additionalMetadata", file: imageURL) { (_, error) in
|
||||
guard error == nil else {
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
XCTFail("error uploading file")
|
||||
return
|
||||
}
|
||||
|
||||
FileUtils.deleteFile(fileURL: imageURL)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
self.waitForExpectations(timeout: testTimeout, handler: nil)
|
||||
}
|
||||
|
||||
func test4DeletePet() {
|
||||
let expectation = self.expectation(description: "testDeletePet")
|
||||
|
||||
PetAPI.deletePet(petId: 1000) { (_, error) in
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIImage+Extras.swift
|
||||
// SwaggerClientTests
|
||||
//
|
||||
// Created by Bruno Coelho on 11/03/2020.
|
||||
// Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIImage {
|
||||
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
color.setFill()
|
||||
UIRectFill(rect)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
guard let cgImage = image?.cgImage else { return nil }
|
||||
self.init(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
private var observation: NSKeyValueObservation?
|
||||
|
||||
deinit {
|
||||
observation?.invalidate()
|
||||
observation?.invalidate()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@@ -110,7 +110,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
|
||||
|
||||
let parameters: [String: Any] = self.parameters ?? [:]
|
||||
|
||||
let fileKeys = parameters.filter { $1 is NSURL }
|
||||
let fileKeys = parameters.filter { $1 is URL }
|
||||
.map { $0.0 }
|
||||
|
||||
let encoding: ParameterEncoding
|
||||
@@ -441,58 +441,99 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
for (k, v) in parameters ?? [:] {
|
||||
switch v {
|
||||
guard let parameters = parameters, !parameters.isEmpty else {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
|
||||
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
for (key, value) in parameters {
|
||||
switch value {
|
||||
case let fileURL as URL:
|
||||
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: fileURL.lastPathComponent, data: fileData, mimeType: mimetype)
|
||||
urlRequest = try configureFileUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
fileURL: fileURL
|
||||
)
|
||||
|
||||
case let string as String:
|
||||
|
||||
if let data = string.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
case let number as NSNumber:
|
||||
|
||||
if let data = number.stringValue.data(using: .utf8) {
|
||||
urlRequest = configureFileUploadRequest(urlRequest: urlRequest, name: k, data: data, mimeType: nil)
|
||||
urlRequest = configureDataUploadRequest(
|
||||
urlRequest: urlRequest,
|
||||
boundary: boundary,
|
||||
name: key,
|
||||
data: data
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
fatalError("Unprocessable value \(v) with key \(k)")
|
||||
fatalError("Unprocessable value \(value) with key \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)--")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, name: String, data: Data, mimeType: String?) -> URLRequest {
|
||||
private func configureFileUploadRequest(urlRequest: URLRequest, boundary: String, name: String, fileURL: URL) throws -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody ?? Data()
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
// https://stackoverflow.com/a/26163136/976628
|
||||
let boundary = "Boundary-\(UUID().uuidString)"
|
||||
urlRequest.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let fileData = try Data(contentsOf: fileURL)
|
||||
|
||||
let mimetype = self.contentTypeForFormPart(fileURL) ?? mimeType(for: fileURL)
|
||||
|
||||
let fileName = fileURL.lastPathComponent
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fileName)\"\r\n\r\n")
|
||||
|
||||
if let mimeType = mimeType {
|
||||
body.append("Content-Type: \(mimeType)\r\n\r\n")
|
||||
}
|
||||
body.append("Content-Type: \(mimetype)\r\n\r\n")
|
||||
|
||||
body.append(fileData)
|
||||
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
private func configureDataUploadRequest(urlRequest: URLRequest, boundary: String, name: String, data: Data) -> URLRequest {
|
||||
|
||||
var urlRequest = urlRequest
|
||||
|
||||
var body = urlRequest.httpBody.orEmpty
|
||||
|
||||
body.append("--\(boundary)\r\n")
|
||||
body.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
|
||||
|
||||
body.append(data)
|
||||
|
||||
body.append("\r\n")
|
||||
|
||||
body.append("--\(boundary)--\r\n")
|
||||
body.append("\r\n\r\n")
|
||||
|
||||
urlRequest.httpBody = body
|
||||
|
||||
@@ -514,11 +555,11 @@ private class FileUploadEncoding: ParameterEncoding {
|
||||
}
|
||||
|
||||
fileprivate extension Data {
|
||||
/// Append string to NSMutableData
|
||||
/// Append string to Data
|
||||
///
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to NSData, and then add that data to the NSMutableData, this wraps it in a nice convenient little extension to NSMutableData. This converts using UTF-8.
|
||||
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to Data, and then add that data to the Data, this wraps it in a nice convenient little extension to Data. This converts using UTF-8.
|
||||
///
|
||||
/// - parameter string: The string to be added to the `NSMutableData`.
|
||||
/// - parameter string: The string to be added to the `Data`.
|
||||
|
||||
mutating func append(_ string: String) {
|
||||
if let data = string.data(using: .utf8) {
|
||||
@@ -527,4 +568,10 @@ fileprivate extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional where Wrapped == Data {
|
||||
var orEmpty: Data {
|
||||
self ?? Data()
|
||||
}
|
||||
}
|
||||
|
||||
extension JSONDataEncoding: ParameterEncoding {}
|
||||
|
||||
Reference in New Issue
Block a user