         }
     }
 }
+
+// MARK: -
+
+class UploadMultipartFormDataTestCase: BaseTestCase {
+
+    // MARK: Tests
+
+    func testThatUploadingMultipartFormDataSucceedsWithDefaultParameters() {
+        // Given
+        let URLString = "http://httpbin.org/post"
+        let french = "français".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+        let japanese = "日本語".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+
+        let expectation = expectationWithDescription("multipart form data upload should succeed")
+
+        var request: NSURLRequest?
+        var response: NSHTTPURLResponse?
+        var data: AnyObject?
+        var error: NSError?
+
+        // When
+        Alamofire.upload(
+            .POST,
+            URLString: URLString,
+            multipartFormData: { multipartFormData in
+                multipartFormData.appendBodyPart(data: french, name: "french")
+                multipartFormData.appendBodyPart(data: japanese, name: "japanese")
+            },
+            encodingCompletion: { result in
+                switch result {
+                case .Success(let upload, _, _):
+                    upload.response { responseRequest, responseResponse, responseData, responseError in
+                        request = responseRequest
+                        response = responseResponse
+                        data = responseData
+                        error = responseError
+
+                        expectation.fulfill()
+                    }
+                case .Failure:
+                    expectation.fulfill()
+                }
+            }
+        )
+
+        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(request, "request should not be nil")
+        XCTAssertNotNil(response, "response should not be nil")
+        XCTAssertNotNil(data, "data should not be nil")
+        XCTAssertNil(error, "error should be nil")
+    }
+
+    func testThatUploadingMultipartFormDataWhileStreamingFromMemoryMonitorsProgress() {
+        executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: false)
+    }
+
+    func testThatUploadingMultipartFormDataWhileStreamingFromDiskMonitorsProgress() {
+        executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: true)
+    }
+
+    func testThatUploadingMultipartFormDataBelowMemoryThresholdStreamsFromMemory() {
+        // Given
+        let URLString = "http://httpbin.org/post"
+        let french = "français".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+        let japanese = "日本語".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+
+        let expectation = expectationWithDescription("multipart form data upload should succeed")
+
+        var streamingFromDisk: Bool?
+        var streamFileURL: NSURL?
+
+        // When
+        Alamofire.upload(
+            .POST,
+            URLString: URLString,
+            multipartFormData: { multipartFormData in
+                multipartFormData.appendBodyPart(data: french, name: "french")
+                multipartFormData.appendBodyPart(data: japanese, name: "japanese")
+            },
+            encodingCompletion: { result in
+                switch result {
+                case let .Success(upload, uploadStreamingFromDisk, uploadStreamFileURL):
+                    streamingFromDisk = uploadStreamingFromDisk
+                    streamFileURL = uploadStreamFileURL
+
+                    upload.response { _, _, _, _ in
+                        expectation.fulfill()
+                    }
+                case .Failure:
+                    expectation.fulfill()
+                }
+            }
+        )
+
+        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(streamingFromDisk, "streaming from disk should not be nil")
+        XCTAssertNil(streamFileURL, "stream file URL should be nil")
+
+        if let streamingFromDisk = streamingFromDisk {
+            XCTAssertFalse(streamingFromDisk, "streaming from disk should be false")
+        }
+    }
+
+    func testThatUploadingMultipartFormDataAboveMemoryThresholdStreamsFromDisk() {
+        // Given
+        let URLString = "http://httpbin.org/post"
+        let french = "français".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+        let japanese = "日本語".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+
+        let expectation = expectationWithDescription("multipart form data upload should succeed")
+
+        var streamingFromDisk: Bool?
+        var streamFileURL: NSURL?
+
+        // When
+        Alamofire.upload(
+            .POST,
+            URLString: URLString,
+            multipartFormData: { multipartFormData in
+                multipartFormData.appendBodyPart(data: french, name: "french")
+                multipartFormData.appendBodyPart(data: japanese, name: "japanese")
+            },
+            encodingMemoryThreshold: 0,
+            encodingCompletion: { result in
+                switch result {
+                case let .Success(upload, uploadStreamingFromDisk, uploadStreamFileURL):
+                    streamingFromDisk = uploadStreamingFromDisk
+                    streamFileURL = uploadStreamFileURL
+
+                    upload.response { _, _, _, _ in
+                        expectation.fulfill()
+                    }
+                case .Failure:
+                    expectation.fulfill()
+                }
+            }
+        )
+
+        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(streamingFromDisk, "streaming from disk should not be nil")
+        XCTAssertNotNil(streamFileURL, "stream file URL should not be nil")
+
+        if let
+            streamingFromDisk = streamingFromDisk,
+            streamFilePath = streamFileURL?.path
+        {
+            XCTAssertTrue(streamingFromDisk, "streaming from disk should be true")
+            XCTAssertTrue(NSFileManager.defaultManager().fileExistsAtPath(streamFilePath), "stream file path should exist")
+        }
+    }
+
+    // MARK: Combined Test Execution
+
+    private func executeMultipartFormDataUploadRequestWithProgress(#streamFromDisk: Bool) {
+        // Given
+        let URLString = "http://httpbin.org/post"
+        let loremData1: NSData = {
+            var loremValues: [String] = []
+            for _ in 1...1_500 {
+                loremValues.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
+            }
+
+            return join(" ", loremValues).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+        }()
+        let loremData2: NSData = {
+            var loremValues: [String] = []
+            for _ in 1...1_500 {
+                loremValues.append("Lorem ipsum dolor sit amet, nam no graeco recusabo appellantur.")
+            }
+
+            return join(" ", loremValues).dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
+        }()
+
+        let expectation = expectationWithDescription("multipart form data upload should succeed")
+
+        var byteValues: [(bytes: Int64, totalBytes: Int64, totalBytesExpected: Int64)] = []
+        var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = []
+        var request: NSURLRequest?
+        var response: NSHTTPURLResponse?
+        var data: AnyObject?
+        var error: NSError?
+
+        // When
+        Alamofire.upload(
+            .POST,
+            URLString: URLString,
+            multipartFormData: { multipartFormData in
+                multipartFormData.appendBodyPart(data: loremData1, name: "lorem1")
+                multipartFormData.appendBodyPart(data: loremData2, name: "lorem2")
+            },
+            encodingMemoryThreshold: streamFromDisk ? 0 : 100_000_000,
+            encodingCompletion: { result in
+                switch result {
+                case .Success(let upload, let streamingFromDisk, _):
+                    upload.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
+                        let bytes = (bytes: bytesWritten, totalBytes: totalBytesWritten, totalBytesExpected: totalBytesExpectedToWrite)
+                        byteValues.append(bytes)
+
+                        let progress = (completedUnitCount: upload.progress.completedUnitCount, totalUnitCount: upload.progress.totalUnitCount)
+                        progressValues.append(progress)
+                    }
+                    upload.response { responseRequest, responseResponse, responseData, responseError in
+                        request = responseRequest
+                        response = responseResponse
+                        data = responseData
+                        error = responseError
+
+                        expectation.fulfill()
+                    }
+                case .Failure:
+                    expectation.fulfill()
+                }
+            }
+        )
+
+        waitForExpectationsWithTimeout(self.defaultTimeout, handler: nil)
+
+        // Then
+        XCTAssertNotNil(request, "request should not be nil")
+        XCTAssertNotNil(response, "response should not be nil")
+        XCTAssertNotNil(data, "data should not be nil")
+        XCTAssertNil(error, "error should be nil")
+
+        XCTAssertEqual(byteValues.count, progressValues.count, "byteValues count should equal progressValues count")
+
+        if byteValues.count == progressValues.count {
+            for index in 0..<byteValues.count {
+                let byteValue = byteValues[index]
+                let progressValue = progressValues[index]
+
+                XCTAssertGreaterThan(byteValue.bytes, 0, "reported bytes should always be greater than 0")
+                XCTAssertEqual(byteValue.totalBytes, progressValue.completedUnitCount, "total bytes should be equal to completed unit count")
+                XCTAssertEqual(byteValue.totalBytesExpected, progressValue.totalUnitCount, "total bytes expected should be equal to total unit count")
+            }
+        }
+
+        if let
+            lastByteValue = byteValues.last,
+            lastProgressValue = progressValues.last
+        {
+            let byteValueFractionalCompletion = Double(lastByteValue.totalBytes) / Double(lastByteValue.totalBytesExpected)
+            let progressValueFractionalCompletion = Double(lastProgressValue.0) / Double(lastProgressValue.1)
+
+            XCTAssertEqual(byteValueFractionalCompletion, 1.0, "byte value fractional completion should equal 1.0")
+            XCTAssertEqual(progressValueFractionalCompletion, 1.0, "progress value fractional completion should equal 1.0")
+        } else {
+            XCTFail("last item in bytesValues and progressValues should not be nil")
+        }
+    }
+}

            }
        }

        if let lastByteValue = byteValues.last,
            lastProgressValue = progressValues.last
        {
            let byteValueFractionalCompletion = Double(lastByteValue.totalBytes) / Double(lastByteValue.totalBytesExpected)

        XCTAssertNil(error, "error should be nil")
    }

    func testUploadDataRequestWithProgress() {
        // Given
        let URLString = "http://httpbin.org/post"
        let data: NSData = {
