Fix encoding empty fields and flesh out tests

This commit is contained in:
Sami Samhuri 2021-02-03 16:07:03 -08:00
parent a0789e95da
commit bb21568d17
No known key found for this signature in database
GPG key ID: 4B4195422742FC16
5 changed files with 98 additions and 19 deletions

View file

@ -23,6 +23,10 @@ let package = Package(
dependencies: []),
.testTarget(
name: "OsirisTests",
dependencies: ["Osiris"]),
dependencies: ["Osiris"],
resources: [
.copy("Resources/lorem.txt"),
.copy("Resources/notbad.jpg"),
]),
]
)

View file

@ -39,8 +39,8 @@ extension MultipartFormEncoder {
let contentLength: Int64
}
struct Part {
enum Content {
struct Part: Equatable {
enum Content: Equatable {
case text(String)
case binaryData(Data, type: String, filename: String)
case binaryFile(URL, size: Int64, type: String, filename: String)
@ -72,7 +72,6 @@ final class MultipartFormEncoder {
case invalidFile(URL)
case invalidOutputFile(URL)
case streamError
case emptyData
case tooMuchDataForMemory
}
@ -184,13 +183,12 @@ final class MultipartFormEncoder {
}
private func encode(data: Data, to stream: OutputStream) throws {
guard !data.isEmpty else {
throw Error.emptyData
}
guard !data.isEmpty else { return }
try data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let uint8Bytes = bytes.baseAddress!.bindMemory(to: UInt8.self, capacity: bytes.count)
let written = stream.write(uint8Bytes, maxLength: bytes.count)
if written < 0 {
if written != bytes.count {
throw Error.streamError
}
}
@ -216,11 +214,11 @@ final class MultipartFormEncoder {
while inStream.hasBytesAvailable {
let bytesRead = inStream.read(buffer, maxLength: bufferSize)
guard bytesRead > 0 else {
throw Error.streamError
break
}
let bytesWritten = stream.write(buffer, maxLength: bytesRead)
if bytesWritten < 0 {
if bytesWritten != bytesRead {
throw Error.streamError
}
}

View file

@ -9,10 +9,10 @@
@testable import Osiris
import XCTest
func AssertStringDataEqual(_ expression1: @autoclosure () throws -> Data, _ expression2: @autoclosure () throws -> String, _ message: @autoclosure () -> String? = nil, file: StaticString = #filePath, line: UInt = #line) {
let data1 = try! expression1()
func AssertStringDataEqual(_ expression1: @autoclosure () throws -> Data, _ expression2: @autoclosure () throws -> String, _ message: @autoclosure () -> String? = nil, file: StaticString = #filePath, line: UInt = #line) throws {
let data1 = try expression1()
let string1 = String(bytes: data1, encoding: .utf8)!
let string2 = try! expression2()
let string2 = try expression2()
let message = message() ?? "\"\(string1)\" is not equal to \"\(string2)\""
XCTAssertEqual(data1, Data(string2.utf8), message, file: file, line: line)
}
@ -28,14 +28,40 @@ class MultipartFormEncoderTests: XCTestCase {
subject = nil
}
func testConstructTextPart() {
let part = MultipartFormEncoder.Part.text("value", name: "name")
XCTAssertEqual(part, MultipartFormEncoder.Part(name: "name", content: .text("value")))
}
func testConstructDataPart() {
let data = Data("value".utf8)
let part = MultipartFormEncoder.Part.data(data, name: "name", type: "text/plain", filename: "something.txt")
let expected = MultipartFormEncoder.Part(name: "name", content: .binaryData(data, type: "text/plain", filename: "something.txt"))
XCTAssertEqual(part, expected)
}
func testConstructBinaryFilePart() throws {
let url = Bundle.module.url(forResource: "notbad", withExtension: "jpg")!
let part = try MultipartFormEncoder.Part.file(url, name: "name", type: "image/jpeg")
let expected = MultipartFormEncoder.Part(name: "name", content: .binaryFile(url, size: 22_680, type: "image/jpeg", filename: "notbad.jpg"))
XCTAssertEqual(part, expected)
}
func testConstructInvalidFilePart() {
let url = Bundle.module.url(forResource: "notbad", withExtension: "jpg")!
.appendingPathComponent("busted")
XCTAssertThrowsError(try MultipartFormEncoder.Part.file(url, name: "name", type: "image/jpeg"))
}
func testEncodeNothing() throws {
let body = try subject.encodeData(parts: [])
XCTAssertEqual(body.contentType, "multipart/form-data; boundary=\"SuperAwesomeBoundary\"")
AssertStringDataEqual(body.data, "--SuperAwesomeBoundary--")
XCTAssertEqual(body.contentLength, 24)
try AssertStringDataEqual(body.data, "--SuperAwesomeBoundary--")
}
func testEncodeText() throws {
AssertStringDataEqual(
try AssertStringDataEqual(
try subject.encodeData(parts: [.text("Tina", name: "name")]).data,
[
"--SuperAwesomeBoundary",
@ -47,9 +73,22 @@ class MultipartFormEncoderTests: XCTestCase {
)
}
func testEncodeEmptyText() throws {
try AssertStringDataEqual(
try subject.encodeData(parts: [.text("", name: "name")]).data,
[
"--SuperAwesomeBoundary",
"Content-Disposition: form-data; name=\"name\"",
"",
"",
"--SuperAwesomeBoundary--",
].joined(separator: "\r\n")
)
}
func testEncodeData() throws {
let data = Data("phony video data".utf8)
AssertStringDataEqual(
try AssertStringDataEqual(
try subject.encodeData(parts: [
.data(data, name: "video", type: "video/mp4", filename: "LiesSex&VideoTape.mp4"),
]).data,
@ -60,20 +99,42 @@ class MultipartFormEncoderTests: XCTestCase {
"Content-Length: 16",
"",
"phony video data",
"--SuperAwesomeBoundary--"
"--SuperAwesomeBoundary--",
].joined(separator: "\r\n")
)
}
func testEncodeFile() throws {
let url = Bundle.module.url(forResource: "lorem", withExtension: "txt")!
let body = try subject.encodeFile(parts: [
.file(url, name: "lorem", type: "text/plain"),
])
XCTAssertEqual(body.contentType, "multipart/form-data; boundary=SuperAwesomeBoundary")
XCTAssertEqual(body.contentLength, 3586)
XCTAssertEqual(try FileManager.default.attributesOfItem(atPath: body.url.path)[.size] as! UInt64, 3586)
XCTAssertEqual(try String(contentsOf: body.url), [
"--SuperAwesomeBoundary",
"Content-Disposition: form-data; name=\"lorem\"; filename=\"lorem.txt\"",
"Content-Type: text/plain",
"Content-Length: 3418",
"",
try! String(contentsOf: url),
"--SuperAwesomeBoundary--",
].joined(separator: "\r\n"))
}
func testEncodeEverything() throws {
let imageData = Data("phony image data".utf8)
let videoData = Data("phony video data".utf8)
AssertStringDataEqual(
let url = Bundle.module.url(forResource: "lorem", withExtension: "txt")!
try AssertStringDataEqual(
try subject.encodeData(parts: [
.text("Queso", name: "name"),
.data(imageData, name: "image", type: "image/jpeg", filename: "feltcute.jpg"),
.text("top of the bbq", name: "spot"),
.data(videoData, name: "video", type: "video/mp4", filename: "LiesSex&VideoTape.mp4"),
.file(url, name: "lorem", type: "text/plain"),
]).data,
[
"--SuperAwesomeBoundary",
@ -100,7 +161,14 @@ class MultipartFormEncoderTests: XCTestCase {
"",
"phony video data",
"--SuperAwesomeBoundary--"
"--SuperAwesomeBoundary",
"Content-Disposition: form-data; name=\"lorem\"; filename=\"lorem.txt\"",
"Content-Type: text/plain",
"Content-Length: 3418",
"",
try! String(contentsOf: url),
"--SuperAwesomeBoundary--",
].joined(separator: "\r\n")
)
}

View file

@ -0,0 +1,9 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vulputate massa eget turpis auctor, bibendum tincidunt purus tempus. Aliquam id risus quis est porttitor mollis a vitae mauris. Nam magna odio, egestas ut viverra vitae, pretium vel sem. Fusce imperdiet enim non orci placerat, quis eleifend nunc malesuada. Suspendisse scelerisque lacinia volutpat. Duis efficitur ut dolor at iaculis. Donec consequat eros nec augue pellentesque, ut dapibus mauris pharetra. Maecenas eget pharetra justo. Proin bibendum a lectus sed rutrum. In faucibus dolor commodo, ornare lacus ac, vulputate quam.
Nam mollis tortor et elit aliquam suscipit. Maecenas eget erat et justo vehicula scelerisque ac quis erat. Nullam placerat felis sit amet nibh ullamcorper, at volutpat est congue. Fusce in pharetra eros. Phasellus laoreet arcu a libero imperdiet commodo. Suspendisse facilisis, libero in pellentesque aliquam, enim libero pulvinar nibh, ac aliquam nibh ante nec velit. Proin condimentum elit ex, ut dictum tellus volutpat ac. Nunc fermentum nisl id est gravida, nec pellentesque libero blandit. Etiam vitae pellentesque eros. Pellentesque consequat urna ligula, id imperdiet lorem efficitur non. Cras at placerat nulla, vel luctus odio. Phasellus a posuere velit. Ut in magna in augue sagittis elementum ac vitae turpis. Quisque ornare velit nec cursus dignissim.
In hac habitasse platea dictumst. Morbi lectus leo, rhoncus non scelerisque imperdiet, porttitor non neque. In vehicula posuere convallis. Nullam eu varius nisi. Ut euismod egestas mi. Phasellus eget urna egestas, suscipit ex sed, ultricies leo. Suspendisse consequat in massa quis ullamcorper. Sed eleifend nulla tellus, vitae posuere augue vulputate ac. Curabitur iaculis vulputate dui ornare laoreet.
Maecenas ac eros cursus, ultricies diam vitae, sollicitudin metus. Suspendisse quis mattis ex. Ut vel ullamcorper sapien. Sed in mauris sed ante imperdiet consectetur vitae sed dui. Aliquam in tempus mi. Phasellus vitae augue volutpat, sodales augue sit amet, pellentesque ante. Integer nec lacinia nunc. Morbi magna eros, placerat vitae eros sed, varius imperdiet sem. Vestibulum ultrices finibus ultrices. Cras condimentum vestibulum nisi mattis posuere. Sed sed nisl nec odio posuere ullamcorper sit amet sed quam. Ut id suscipit turpis. Aliquam et sem quis ligula bibendum aliquam. Praesent efficitur vel nibh in commodo. Donec porta, nunc at aliquam consectetur, ante diam eleifend ante, at elementum est neque in ante. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Donec tincidunt massa urna, in ultrices arcu vulputate in. Quisque placerat nisi ipsum, eget aliquet enim dictum vel. Ut sed nulla odio. Etiam in vulputate dui. Nunc elementum sodales neque, quis tristique massa feugiat eget. Donec ultrices erat facilisis ipsum volutpat tincidunt. Etiam efficitur luctus ipsum eu convallis. Ut elementum, nisl id aliquet ultrices, nunc quam gravida lectus, non ullamcorper elit justo non lorem. Sed tincidunt efficitur lectus ac molestie. Sed vel tellus eu tortor finibus fermentum a elementum mi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus suscipit sed tortor tempor congue. Proin molestie bibendum metus. Nam ullamcorper, nunc placerat commodo egestas, ante odio faucibus nisi, vel vulputate augue nulla at ex. Duis scelerisque interdum felis, sed fringilla urna. Mauris lacinia felis gravida egestas dictum.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB