From 4b8038986d1d35493f042e779e8a446833745459 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Mon, 16 Oct 2023 21:59:32 +0200 Subject: [PATCH 1/4] Improve style --- Sources/MultipartFormData/Boundary.swift | 9 ++++++--- Tests/MultipartFormDataTests/BoundaryTests.swift | 1 - .../Builder/BodyDataBuilderTests.swift | 1 - .../Builder/HTTPHeaderBuilderTests.swift | 1 - .../Builder/MultipartFormDataBuilderTests.swift | 1 - .../MultipartFormDataTests/ContentDispositionTests.swift | 1 - Tests/MultipartFormDataTests/ContentTypeTests.swift | 1 - Tests/MultipartFormDataTests/HTTPHeaderFieldTests.swift | 1 - .../HTTPHeaderParameterTests.swift | 1 - Tests/MultipartFormDataTests/MediaTypeTests.swift | 1 - .../MultipartFormDataTests/MultipartFormDataTests.swift | 1 - Tests/MultipartFormDataTests/SubpartTests.swift | 1 - Tests/MultipartFormDataTests/URLRequestTests.swift | 1 - 13 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Sources/MultipartFormData/Boundary.swift b/Sources/MultipartFormData/Boundary.swift index 8e9d4da..6bbb99e 100644 --- a/Sources/MultipartFormData/Boundary.swift +++ b/Sources/MultipartFormData/Boundary.swift @@ -38,9 +38,12 @@ extension Boundary { public var debugDescription: String { switch self { - case .empty: return "Boundary must not be empty." - case .tooLong: return "Boundary is too long. Max size is 70 characters." - case .noASCII: return "Boundary contains at least one character that is not ASCII compatible." + case .empty: + return "Boundary must not be empty." + case .tooLong: + return "Boundary is too long. Max size is 70 characters." + case .noASCII: + return "Boundary contains at least one character that is not ASCII compatible." } } } diff --git a/Tests/MultipartFormDataTests/BoundaryTests.swift b/Tests/MultipartFormDataTests/BoundaryTests.swift index 1ee0f05..dd2c11e 100644 --- a/Tests/MultipartFormDataTests/BoundaryTests.swift +++ b/Tests/MultipartFormDataTests/BoundaryTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class BoundaryTests: XCTestCase { - func testEmpty() { XCTAssertThrowsError(try Boundary(uncheckedBoundary: "")) { error in XCTAssertEqual(error as? Boundary.InvalidBoundaryError, .empty) diff --git a/Tests/MultipartFormDataTests/Builder/BodyDataBuilderTests.swift b/Tests/MultipartFormDataTests/Builder/BodyDataBuilderTests.swift index e3c71a3..bb92f5c 100644 --- a/Tests/MultipartFormDataTests/Builder/BodyDataBuilderTests.swift +++ b/Tests/MultipartFormDataTests/Builder/BodyDataBuilderTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class BodyDataBuilderTests: XCTestCase { - func testSingleData() { let data = _buildData { Data("a".utf8) diff --git a/Tests/MultipartFormDataTests/Builder/HTTPHeaderBuilderTests.swift b/Tests/MultipartFormDataTests/Builder/HTTPHeaderBuilderTests.swift index 7b229db..19b82b5 100644 --- a/Tests/MultipartFormDataTests/Builder/HTTPHeaderBuilderTests.swift +++ b/Tests/MultipartFormDataTests/Builder/HTTPHeaderBuilderTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class HTTPHeaderBuilderTests: XCTestCase { - func testAvailableHeaderCombinations() { let dispositionResult = _buildHeader { ContentDisposition(name: "a") diff --git a/Tests/MultipartFormDataTests/Builder/MultipartFormDataBuilderTests.swift b/Tests/MultipartFormDataTests/Builder/MultipartFormDataBuilderTests.swift index 66efb8e..c64d9ca 100644 --- a/Tests/MultipartFormDataTests/Builder/MultipartFormDataBuilderTests.swift +++ b/Tests/MultipartFormDataTests/Builder/MultipartFormDataBuilderTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class MultipartFormDataBuilderTests: XCTestCase { - func testSingleSubpart() throws { let subparts = _buildSubparts { Subpart { diff --git a/Tests/MultipartFormDataTests/ContentDispositionTests.swift b/Tests/MultipartFormDataTests/ContentDispositionTests.swift index a10e182..71ce853 100644 --- a/Tests/MultipartFormDataTests/ContentDispositionTests.swift +++ b/Tests/MultipartFormDataTests/ContentDispositionTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class ContentDispositionTests: XCTestCase { - func testPercentEncodingError() throws { XCTAssertNoThrow(try ContentDisposition(uncheckedName: "a", uncheckedFilename: "a")) diff --git a/Tests/MultipartFormDataTests/ContentTypeTests.swift b/Tests/MultipartFormDataTests/ContentTypeTests.swift index 9f387a6..00afb3c 100644 --- a/Tests/MultipartFormDataTests/ContentTypeTests.swift +++ b/Tests/MultipartFormDataTests/ContentTypeTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class ContentTypeTests: XCTestCase { - func testBoundaryParameters() throws { let contentType = ContentType(boundary: try Boundary(uncheckedBoundary: "test")) diff --git a/Tests/MultipartFormDataTests/HTTPHeaderFieldTests.swift b/Tests/MultipartFormDataTests/HTTPHeaderFieldTests.swift index b67d6cf..99b51d9 100644 --- a/Tests/MultipartFormDataTests/HTTPHeaderFieldTests.swift +++ b/Tests/MultipartFormDataTests/HTTPHeaderFieldTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class HTTPHeaderFieldTests: XCTestCase { - func testDebugDescription() { let parameter = HTTPHeaderParameter("name", value: "value") let testHeaderField = TestHeaderField(value: "value", parameters: [parameter]) diff --git a/Tests/MultipartFormDataTests/HTTPHeaderParameterTests.swift b/Tests/MultipartFormDataTests/HTTPHeaderParameterTests.swift index b1b9420..be76ad0 100644 --- a/Tests/MultipartFormDataTests/HTTPHeaderParameterTests.swift +++ b/Tests/MultipartFormDataTests/HTTPHeaderParameterTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class HTTPHeaderParameterTests: XCTestCase { - func testArrayText() { let singleParameter = [ HTTPHeaderParameter("test", value: "a") diff --git a/Tests/MultipartFormDataTests/MediaTypeTests.swift b/Tests/MultipartFormDataTests/MediaTypeTests.swift index dc4e40d..ed25389 100644 --- a/Tests/MultipartFormDataTests/MediaTypeTests.swift +++ b/Tests/MultipartFormDataTests/MediaTypeTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class MediaTypeTests: XCTestCase { - func testText() { let mediaType = MediaType(type: "type", subtype: "subtype") XCTAssertEqual(mediaType._text, "type/subtype") diff --git a/Tests/MultipartFormDataTests/MultipartFormDataTests.swift b/Tests/MultipartFormDataTests/MultipartFormDataTests.swift index 2dbd111..4a89670 100644 --- a/Tests/MultipartFormDataTests/MultipartFormDataTests.swift +++ b/Tests/MultipartFormDataTests/MultipartFormDataTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class MultipartFormDataTests: XCTestCase { - func testContentType() throws { let boundary = try Boundary(uncheckedBoundary: "test") let multipartFormData = MultipartFormData(boundary: boundary) diff --git a/Tests/MultipartFormDataTests/SubpartTests.swift b/Tests/MultipartFormDataTests/SubpartTests.swift index e7df384..8962458 100644 --- a/Tests/MultipartFormDataTests/SubpartTests.swift +++ b/Tests/MultipartFormDataTests/SubpartTests.swift @@ -9,7 +9,6 @@ import XCTest @testable import MultipartFormData final class SubpartTests: XCTestCase { - func testDataGeneration() throws { let subpart = Subpart( contentDisposition: ContentDisposition(name: "a"), diff --git a/Tests/MultipartFormDataTests/URLRequestTests.swift b/Tests/MultipartFormDataTests/URLRequestTests.swift index fa73084..d163e0c 100644 --- a/Tests/MultipartFormDataTests/URLRequestTests.swift +++ b/Tests/MultipartFormDataTests/URLRequestTests.swift @@ -12,7 +12,6 @@ import FoundationNetworking #endif final class URLRequestTests: XCTestCase { - func testFormDataInit() throws { let boundary = try Boundary(uncheckedBoundary: "test") let multipartFormData = MultipartFormData(boundary: boundary, body: [ From df78f4fdabb22c3e01d88c538172f97397c5bf4f Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Mon, 16 Oct 2023 21:59:52 +0200 Subject: [PATCH 2/4] Add MediaType.textCsv --- Sources/MultipartFormData/MediaType.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/MultipartFormData/MediaType.swift b/Sources/MultipartFormData/MediaType.swift index dd72fa0..ea969c4 100644 --- a/Sources/MultipartFormData/MediaType.swift +++ b/Sources/MultipartFormData/MediaType.swift @@ -37,6 +37,7 @@ extension MediaType { public static let multipartFormData = MediaType(type: "multipart", subtype: "form-data") public static let textPlain = MediaType(type: "text", subtype: "plain") + public static let textCsv = MediaType(type: "text", subtype: "csv") public static let textHtml = MediaType(type: "text", subtype: "html") public static let textCss = MediaType(type: "text", subtype: "css") From ee92f180a5d5ce164f69165781e9fddd801e17e7 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Mon, 16 Oct 2023 22:25:25 +0200 Subject: [PATCH 3/4] Add UTType conversions --- Sources/MultipartFormData/MediaType.swift | 28 +++++++++++++++++++ .../MediaTypeTests.swift | 20 +++++++++++++ 2 files changed, 48 insertions(+) diff --git a/Sources/MultipartFormData/MediaType.swift b/Sources/MultipartFormData/MediaType.swift index ea969c4..0ad9d2e 100644 --- a/Sources/MultipartFormData/MediaType.swift +++ b/Sources/MultipartFormData/MediaType.swift @@ -64,6 +64,34 @@ extension MediaType { } // swiftlint:enable missing_docs +// MARK: - UniformTypeIdentifiers + +#if canImport(UniformTypeIdentifiers) +import UniformTypeIdentifiers + +extension MediaType { + /// Create a media type from a uniform type. + /// - Parameter uniformType: The uniform type (UTType). + @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) + public init?(uniformType: UTType) { + guard let mimeTypeSplit = uniformType.preferredMIMEType?.split(separator: "/") else { return nil } + guard mimeTypeSplit.count == 2 else { return nil } + self.type = String(mimeTypeSplit[0]) + self.subtype = String(mimeTypeSplit[1]) + } +} + +@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) +extension UTType { + /// Create a uniform type from a media type. + /// - Parameter mediaType: The media type. + /// - Parameter supertype: Another UTType instance that the resulting type must conform to; for example, UTTypeData. + public init?(mediaType: MediaType, conformingTo supertype: UTType = .data) { + self.init(mimeType: mediaType._text, conformingTo: supertype) + } +} +#endif + // MARK: - Debug extension MediaType: CustomDebugStringConvertible { diff --git a/Tests/MultipartFormDataTests/MediaTypeTests.swift b/Tests/MultipartFormDataTests/MediaTypeTests.swift index ed25389..1cde915 100644 --- a/Tests/MultipartFormDataTests/MediaTypeTests.swift +++ b/Tests/MultipartFormDataTests/MediaTypeTests.swift @@ -6,6 +6,9 @@ // import XCTest +#if canImport(UniformTypeIdentifiers) +import UniformTypeIdentifiers +#endif @testable import MultipartFormData final class MediaTypeTests: XCTestCase { @@ -20,4 +23,21 @@ final class MediaTypeTests: XCTestCase { let expectedDescription = "type/subtype" XCTAssertEqual(mediaType.debugDescription, expectedDescription) } +#if canImport(UniformTypeIdentifiers) + + @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) + func testFromUTTypeConversion() throws { + let uniformType = try XCTUnwrap(UTType("public.comma-separated-values-text")) + let mediaType = try XCTUnwrap(MediaType(uniformType: uniformType)) + + XCTAssertEqual(mediaType, .textCsv) + } + + @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) + func testToUTTypeConversion() throws { + let uniformType = try XCTUnwrap(UTType(mediaType: .applicationJson)) + + XCTAssertEqual(uniformType.identifier, "public.json") + } +#endif } From 5dc2a36f8a7ebf7d92ec1d9656d9079fa9fa7397 Mon Sep 17 00:00:00 2001 From: Felix Herrmann Date: Mon, 16 Oct 2023 22:31:34 +0200 Subject: [PATCH 4/4] Fix lint --- Sources/MultipartFormData/Boundary.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/MultipartFormData/Boundary.swift b/Sources/MultipartFormData/Boundary.swift index 6bbb99e..8e24c5f 100644 --- a/Sources/MultipartFormData/Boundary.swift +++ b/Sources/MultipartFormData/Boundary.swift @@ -38,11 +38,11 @@ extension Boundary { public var debugDescription: String { switch self { - case .empty: + case .empty: return "Boundary must not be empty." - case .tooLong: + case .tooLong: return "Boundary is too long. Max size is 70 characters." - case .noASCII: + case .noASCII: return "Boundary contains at least one character that is not ASCII compatible." } }