blob: 7418ece268fbd0fa5decd96e82d7fa9322b6eb2f [file] [log] [blame]
// MultipartFormDataTests.swift
//
// Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Alamofire
import Foundation
import XCTest
struct EncodingCharacters {
static let CRLF = "\r\n"
}
struct BoundaryGenerator {
enum BoundaryType {
case Initial, Encapsulated, Final
}
static func boundary(boundaryType boundaryType: BoundaryType, boundaryKey: String) -> String {
let boundary: String
switch boundaryType {
case .Initial:
boundary = "--\(boundaryKey)\(EncodingCharacters.CRLF)"
case .Encapsulated:
boundary = "\(EncodingCharacters.CRLF)--\(boundaryKey)\(EncodingCharacters.CRLF)"
case .Final:
boundary = "\(EncodingCharacters.CRLF)--\(boundaryKey)--\(EncodingCharacters.CRLF)"
}
return boundary
}
static func boundaryData(boundaryType boundaryType: BoundaryType, boundaryKey: String) -> NSData {
return BoundaryGenerator.boundary(
boundaryType: boundaryType,
boundaryKey: boundaryKey
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
}
}
private func temporaryFileURL() -> NSURL {
let tempDirectoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
let directoryURL = tempDirectoryURL.URLByAppendingPathComponent("com.alamofire.test/multipart.form.data")
let fileManager = NSFileManager.defaultManager()
do {
try fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil)
} catch {
// No-op - will cause tests to fail, not crash
}
let fileName = NSUUID().UUIDString
let fileURL = directoryURL.URLByAppendingPathComponent(fileName)
return fileURL
}
// MARK: -
class MultipartFormDataPropertiesTestCase: BaseTestCase {
func testThatContentTypeContainsBoundary() {
// Given
let multipartFormData = MultipartFormData()
// When
let boundary = multipartFormData.boundary
// Then
let expectedContentType = "multipart/form-data; boundary=\(boundary)"
XCTAssertEqual(multipartFormData.contentType, expectedContentType, "contentType should match expected value")
}
func testThatContentLengthMatchesTotalBodyPartSize() {
// Given
let multipartFormData = MultipartFormData()
let data1 = "Lorem ipsum dolor sit amet.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let data2 = "Vim at integre alterum.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// When
multipartFormData.appendBodyPart(data: data1, name: "data1")
multipartFormData.appendBodyPart(data: data2, name: "data2")
// Then
let expectedContentLength = UInt64(data1.length + data2.length)
XCTAssertEqual(multipartFormData.contentLength, expectedContentLength, "content length should match expected value")
}
}
// MARK: -
class MultipartFormDataEncodingTestCase: BaseTestCase {
let CRLF = EncodingCharacters.CRLF
func testEncodingDataBodyPart() {
// Given
let multipartFormData = MultipartFormData()
let data = "Lorem ipsum dolor sit amet.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
multipartFormData.appendBodyPart(data: data, name: "data")
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = (
BoundaryGenerator.boundary(boundaryType: .Initial, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"data\"\(CRLF)\(CRLF)" +
"Lorem ipsum dolor sit amet." +
BoundaryGenerator.boundary(boundaryType: .Final, boundaryKey: boundary)
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
XCTAssertEqual(encodedData, expectedData, "encoded data should match expected data")
}
}
func testEncodingMultipleDataBodyParts() {
// Given
let multipartFormData = MultipartFormData()
let french = "français".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let japanese = "日本語".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let emoji = "😃👍🏻🍻🎉".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
multipartFormData.appendBodyPart(data: french, name: "french")
multipartFormData.appendBodyPart(data: japanese, name: "japanese", mimeType: "text/plain")
multipartFormData.appendBodyPart(data: emoji, name: "emoji", mimeType: "text/plain")
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = (
BoundaryGenerator.boundary(boundaryType: .Initial, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"french\"\(CRLF)\(CRLF)" +
"français" +
BoundaryGenerator.boundary(boundaryType: .Encapsulated, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"japanese\"\(CRLF)" +
"Content-Type: text/plain\(CRLF)\(CRLF)" +
"日本語" +
BoundaryGenerator.boundary(boundaryType: .Encapsulated, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"emoji\"\(CRLF)" +
"Content-Type: text/plain\(CRLF)\(CRLF)" +
"😃👍🏻🍻🎉" +
BoundaryGenerator.boundary(boundaryType: .Final, boundaryKey: boundary)
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
XCTAssertEqual(encodedData, expectedData, "encoded data should match expected data")
}
}
func testEncodingFileBodyPart() {
// Given
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = NSMutableData()
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(encodedData, expectedData, "data should match expected data")
}
}
func testEncodingMultipleFileBodyParts() {
// Given
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let rainbowImageURL = URLForResource("rainbow", withExtension: "jpg")
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = NSMutableData()
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"rainbow\"; filename=\"rainbow.jpg\"\(CRLF)" +
"Content-Type: image/jpeg\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: rainbowImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(encodedData, expectedData, "data should match expected data")
}
}
func testEncodingStreamBodyPart() {
// Given
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let unicornDataLength = UInt64(NSData(contentsOfURL: unicornImageURL)!.length)
let unicornStream = NSInputStream(URL: unicornImageURL)!
multipartFormData.appendBodyPart(
stream: unicornStream,
length: unicornDataLength,
name: "unicorn",
fileName: "unicorn.png",
mimeType: "image/png"
)
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = NSMutableData()
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(encodedData, expectedData, "data should match expected data")
}
}
func testEncodingMultipleStreamBodyParts() {
// Given
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let unicornDataLength = UInt64(NSData(contentsOfURL: unicornImageURL)!.length)
let unicornStream = NSInputStream(URL: unicornImageURL)!
let rainbowImageURL = URLForResource("rainbow", withExtension: "jpg")
let rainbowDataLength = UInt64(NSData(contentsOfURL: rainbowImageURL)!.length)
let rainbowStream = NSInputStream(URL: rainbowImageURL)!
multipartFormData.appendBodyPart(
stream: unicornStream,
length: unicornDataLength,
name: "unicorn",
fileName: "unicorn.png",
mimeType: "image/png"
)
multipartFormData.appendBodyPart(
stream: rainbowStream,
length: rainbowDataLength,
name: "rainbow",
fileName: "rainbow.jpg",
mimeType: "image/jpeg"
)
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = NSMutableData()
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"rainbow\"; filename=\"rainbow.jpg\"\(CRLF)" +
"Content-Type: image/jpeg\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: rainbowImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(encodedData, expectedData, "data should match expected data")
}
}
func testEncodingMultipleBodyPartsWithVaryingTypes() {
// Given
let multipartFormData = MultipartFormData()
let loremData = "Lorem ipsum.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let rainbowImageURL = URLForResource("rainbow", withExtension: "jpg")
let rainbowDataLength = UInt64(NSData(contentsOfURL: rainbowImageURL)!.length)
let rainbowStream = NSInputStream(URL: rainbowImageURL)!
multipartFormData.appendBodyPart(data: loremData, name: "lorem")
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(
stream: rainbowStream,
length: rainbowDataLength,
name: "rainbow",
fileName: "rainbow.jpg",
mimeType: "image/jpeg"
)
var encodedData: NSData?
// When
do {
encodedData = try multipartFormData.encode()
} catch {
// No-op
}
// Then
XCTAssertNotNil(encodedData, "encoded data should not be nil")
if let encodedData = encodedData {
let boundary = multipartFormData.boundary
let expectedData = NSMutableData()
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"lorem\"\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(loremData)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedData.appendData((
"Content-Disposition: form-data; name=\"rainbow\"; filename=\"rainbow.jpg\"\(CRLF)" +
"Content-Type: image/jpeg\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedData.appendData(NSData(contentsOfURL: rainbowImageURL)!)
expectedData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(encodedData, expectedData, "data should match expected data")
}
}
}
// MARK: -
class MultipartFormDataWriteEncodedDataToDiskTestCase: BaseTestCase {
let CRLF = EncodingCharacters.CRLF
func testWritingEncodedDataBodyPartToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let data = "Lorem ipsum dolor sit amet.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
multipartFormData.appendBodyPart(data: data, name: "data")
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = (
BoundaryGenerator.boundary(boundaryType: .Initial, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"data\"\(CRLF)\(CRLF)" +
"Lorem ipsum dolor sit amet." +
BoundaryGenerator.boundary(boundaryType: .Final, boundaryKey: boundary)
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
func testWritingMultipleEncodedDataBodyPartsToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let french = "français".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let japanese = "日本語".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let emoji = "😃👍🏻🍻🎉".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
multipartFormData.appendBodyPart(data: french, name: "french")
multipartFormData.appendBodyPart(data: japanese, name: "japanese")
multipartFormData.appendBodyPart(data: emoji, name: "emoji")
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = (
BoundaryGenerator.boundary(boundaryType: .Initial, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"french\"\(CRLF)\(CRLF)" +
"français" +
BoundaryGenerator.boundary(boundaryType: .Encapsulated, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"japanese\"\(CRLF)\(CRLF)" +
"日本語" +
BoundaryGenerator.boundary(boundaryType: .Encapsulated, boundaryKey: boundary) +
"Content-Disposition: form-data; name=\"emoji\"\(CRLF)\(CRLF)" +
"😃👍🏻🍻🎉" +
BoundaryGenerator.boundary(boundaryType: .Final, boundaryKey: boundary)
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
func testWritingEncodedFileBodyPartToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = NSMutableData()
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
func testWritingMultipleEncodedFileBodyPartsToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let rainbowImageURL = URLForResource("rainbow", withExtension: "jpg")
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = NSMutableData()
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"rainbow\"; filename=\"rainbow.jpg\"\(CRLF)" +
"Content-Type: image/jpeg\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: rainbowImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
func testWritingEncodedStreamBodyPartToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let unicornDataLength = UInt64(NSData(contentsOfURL: unicornImageURL)!.length)
let unicornStream = NSInputStream(URL: unicornImageURL)!
multipartFormData.appendBodyPart(
stream: unicornStream,
length: unicornDataLength,
name: "unicorn",
fileName: "unicorn.png",
mimeType: "image/png"
)
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = NSMutableData()
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
func testWritingMultipleEncodedStreamBodyPartsToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let unicornDataLength = UInt64(NSData(contentsOfURL: unicornImageURL)!.length)
let unicornStream = NSInputStream(URL: unicornImageURL)!
let rainbowImageURL = URLForResource("rainbow", withExtension: "jpg")
let rainbowDataLength = UInt64(NSData(contentsOfURL: rainbowImageURL)!.length)
let rainbowStream = NSInputStream(URL: rainbowImageURL)!
multipartFormData.appendBodyPart(
stream: unicornStream,
length: unicornDataLength,
name: "unicorn",
fileName: "unicorn.png",
mimeType: "image/png"
)
multipartFormData.appendBodyPart(
stream: rainbowStream,
length: rainbowDataLength,
name: "rainbow",
fileName: "rainbow.jpg",
mimeType: "image/jpeg"
)
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = NSMutableData()
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"rainbow\"; filename=\"rainbow.jpg\"\(CRLF)" +
"Content-Type: image/jpeg\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: rainbowImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
func testWritingMultipleEncodedBodyPartsWithVaryingTypesToDisk() {
// Given
let fileURL = temporaryFileURL()
let multipartFormData = MultipartFormData()
let loremData = "Lorem ipsum.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
let unicornImageURL = URLForResource("unicorn", withExtension: "png")
let rainbowImageURL = URLForResource("rainbow", withExtension: "jpg")
let rainbowDataLength = UInt64(NSData(contentsOfURL: rainbowImageURL)!.length)
let rainbowStream = NSInputStream(URL: rainbowImageURL)!
multipartFormData.appendBodyPart(data: loremData, name: "lorem")
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(
stream: rainbowStream,
length: rainbowDataLength,
name: "rainbow",
fileName: "rainbow.jpg",
mimeType: "image/jpeg"
)
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(encodingError, "encoding error should be nil")
if let fileData = NSData(contentsOfURL: fileURL) {
let boundary = multipartFormData.boundary
let expectedFileData = NSMutableData()
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Initial, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"lorem\"\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(loremData)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"unicorn\"; filename=\"unicorn.png\"\(CRLF)" +
"Content-Type: image/png\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: unicornImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Encapsulated, boundaryKey: boundary))
expectedFileData.appendData((
"Content-Disposition: form-data; name=\"rainbow\"; filename=\"rainbow.jpg\"\(CRLF)" +
"Content-Type: image/jpeg\(CRLF)\(CRLF)"
).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
)
expectedFileData.appendData(NSData(contentsOfURL: rainbowImageURL)!)
expectedFileData.appendData(BoundaryGenerator.boundaryData(boundaryType: .Final, boundaryKey: boundary))
XCTAssertEqual(fileData, expectedFileData, "file data should match expected file data")
} else {
XCTFail("file data should not be nil")
}
}
}
// MARK: -
class MultipartFormDataFailureTestCase: BaseTestCase {
func testThatAppendingFileBodyPartWithInvalidLastPathComponentReturnsError() {
// Given
let fileURL = NSURL(string: "")!
let multipartFormData = MultipartFormData()
multipartFormData.appendBodyPart(fileURL: fileURL, name: "empty_data")
var encodingError: NSError?
// When
do {
try multipartFormData.encode()
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNotNil(encodingError, "encoding error should not be nil")
if let error = encodingError {
XCTAssertEqual(error.domain, "com.alamofire.error", "error domain does not match expected value")
XCTAssertEqual(error.code, NSURLErrorBadURL, "error code does not match expected value")
if let failureReason = error.userInfo[NSLocalizedFailureReasonErrorKey] as? String {
let expectedFailureReason = "Failed to extract the fileName of the provided URL: \(fileURL)"
XCTAssertEqual(failureReason, expectedFailureReason, "failure reason does not match expected value")
} else {
XCTFail("failure reason should not be nil")
}
}
}
func testThatAppendingFileBodyPartThatIsNotFileURLReturnsError() {
// Given
let fileURL = NSURL(string: "https://example.com/image.jpg")!
let multipartFormData = MultipartFormData()
multipartFormData.appendBodyPart(fileURL: fileURL, name: "empty_data")
var encodingError: NSError?
// When
do {
try multipartFormData.encode()
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNotNil(encodingError, "encoding error should not be nil")
if let error = encodingError {
XCTAssertEqual(error.domain, "com.alamofire.error", "error domain does not match expected value")
XCTAssertEqual(error.code, NSURLErrorBadURL, "error code does not match expected value")
if let failureReason = error.userInfo[NSLocalizedFailureReasonErrorKey] as? String {
let expectedFailureReason = "The file URL does not point to a file URL: \(fileURL)"
XCTAssertEqual(failureReason, expectedFailureReason, "error failure reason does not match expected value")
} else {
XCTFail("failure reason should not be nil")
}
}
}
func testThatAppendingFileBodyPartThatIsNotReachableReturnsError() {
// Given
let filePath = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("does_not_exist.jpg")
let fileURL = NSURL(fileURLWithPath: filePath)
let multipartFormData = MultipartFormData()
multipartFormData.appendBodyPart(fileURL: fileURL, name: "empty_data")
var encodingError: NSError?
// When
do {
try multipartFormData.encode()
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNotNil(encodingError, "encoding error should not be nil")
if let error = encodingError {
XCTAssertEqual(error.domain, "com.alamofire.error", "error domain does not match expected value")
XCTAssertEqual(error.code, NSURLErrorBadURL, "error code does not match expected value")
if let failureReason = error.userInfo[NSLocalizedFailureReasonErrorKey] as? String {
let expectedFailureReason = "The file URL is not reachable: \(fileURL)"
XCTAssertEqual(failureReason, expectedFailureReason, "error failure reason does not match expected value")
} else {
XCTFail("failure reason should not be nil")
}
}
}
func testThatAppendingFileBodyPartThatIsDirectoryReturnsError() {
// Given
let directoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let multipartFormData = MultipartFormData()
multipartFormData.appendBodyPart(fileURL: directoryURL, name: "empty_data")
var encodingError: NSError?
// When
do {
try multipartFormData.encode()
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNotNil(encodingError, "encoding error should not be nil")
if let error = encodingError {
XCTAssertEqual(error.domain, "com.alamofire.error", "error domain does not match expected value")
XCTAssertEqual(error.code, NSURLErrorBadURL, "error code does not match expected value")
if let failureReason = error.userInfo[NSLocalizedFailureReasonErrorKey] as? String {
let expectedFailureReason = "The file URL is a directory, not a file: \(directoryURL)"
XCTAssertEqual(failureReason, expectedFailureReason, "error failure reason does not match expected value")
} else {
XCTFail("failure reason should not be nil")
}
}
}
func testThatWritingEncodedDataToExistingFileURLFails() {
// Given
let fileURL = temporaryFileURL()
var writerError: NSError?
do {
try "dummy data".writeToURL(fileURL, atomically: true, encoding: NSUTF8StringEncoding)
} catch {
writerError = error as NSError
}
let multipartFormData = MultipartFormData()
let data = "Lorem ipsum dolor sit amet.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
multipartFormData.appendBodyPart(data: data, name: "data")
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNil(writerError, "writer error should be nil")
XCTAssertNotNil(encodingError, "encoding error should not be nil")
if let encodingError = encodingError {
XCTAssertEqual(encodingError.domain, "com.alamofire.error", "encoding error domain does not match expected value")
XCTAssertEqual(encodingError.code, NSURLErrorBadURL, "encoding error code does not match expected value")
}
}
func testThatWritingEncodedDataToBadURLFails() {
// Given
let fileURL = NSURL(string: "/this/is/not/a/valid/url")!
let multipartFormData = MultipartFormData()
let data = "Lorem ipsum dolor sit amet.".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
multipartFormData.appendBodyPart(data: data, name: "data")
var encodingError: NSError?
// When
do {
try multipartFormData.writeEncodedDataToDisk(fileURL)
} catch {
encodingError = error as NSError
}
// Then
XCTAssertNotNil(encodingError, "encoding error should not be nil")
if let encodingError = encodingError {
XCTAssertEqual(encodingError.domain, "com.alamofire.error", "encoding error domain does not match expected value")
XCTAssertEqual(encodingError.code, NSURLErrorBadURL, "encoding error code does not match expected value")
}
}
}