import Alamofire
import Foundation
import XCTest
class ParameterEncodingTestCase: BaseTestCase {
let urlRequest = Endpoint().urlRequest
}
final class URLParameterEncodingTestCase: ParameterEncodingTestCase {
let encoding = URLEncoding.default
func testURLParameterEncodeNilParameters() throws {
let urlRequest = try encoding.encode(urlRequest, with: nil)
XCTAssertNil(urlRequest.url?.query)
}
func testURLParameterEncodeEmptyDictionaryParameter() throws {
let parameters: [String: Any] = [:]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertNil(urlRequest.url?.query)
}
func testURLParameterEncodeOneStringKeyStringValueParameter() throws {
let parameters = ["foo": "bar"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=bar")
}
func testURLParameterEncodeOneStringKeyStringValueParameterAppendedToQuery() throws {
var mutableURLRequest = urlRequest
var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false)!
urlComponents.query = "baz=qux"
mutableURLRequest.url = urlComponents.url
let parameters = ["foo": "bar"]
let urlRequest = try encoding.encode(mutableURLRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "baz=qux&foo=bar")
}
func testURLParameterEncodeTwoStringKeyStringValueParameters() throws {
let parameters = ["foo": "bar", "baz": "qux"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "baz=qux&foo=bar")
}
func testURLParameterEncodeStringKeyNSNumberIntegerValueParameter() throws {
let parameters = ["foo": NSNumber(value: 25)]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=25")
}
func testURLParameterEncodeStringKeyNSNumberBoolValueParameter() throws {
let parameters = ["foo": NSNumber(value: false)]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=0")
}
func testURLParameterEncodeStringKeyIntegerValueParameter() throws {
let parameters = ["foo": 1]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=1")
}
func testURLParameterEncodeStringKeyDoubleValueParameter() throws {
let parameters = ["foo": 1.1]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=1.1")
}
func testURLParameterEncodeStringKeyBoolValueParameter() throws {
let parameters = ["foo": true]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=1")
}
func testURLParameterEncodeStringKeyArrayValueParameter() throws {
let parameters = ["foo": ["a", 1, true]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo%5B%5D=a&foo%5B%5D=1&foo%5B%5D=1")
}
func testURLParameterEncodeArrayNestedDictionaryValueParameterWithIndex() throws {
let encoding = URLEncoding(arrayEncoding: .indexInBrackets)
let parameters = ["foo": ["a", 1, true, ["bar": 2], ["qux": 3], ["quy": ["quz": 3]]]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo%5B0%5D=a&foo%5B1%5D=1&foo%5B2%5D=1&foo%5B3%5D%5Bbar%5D=2&foo%5B4%5D%5Bqux%5D=3&foo%5B5%5D%5Bquy%5D%5Bquz%5D=3")
}
func testURLParameterEncodeStringKeyArrayValueParameterWithoutBrackets() throws {
let encoding = URLEncoding(arrayEncoding: .noBrackets)
let parameters = ["foo": ["a", 1, true]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=a&foo=1&foo=1")
}
func testURLParameterEncodeStringKeyArrayValueParameterWithCustomClosure() throws {
let encoding = URLEncoding(arrayEncoding: .custom { key, index in
"\(key).\(index + 1)"
})
let parameters = ["foo": ["a", 1, true]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo.1=a&foo.2=1&foo.3=1")
}
func testURLParameterEncodeStringKeyDictionaryValueParameter() throws {
let parameters = ["foo": ["bar": 1]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo%5Bbar%5D=1")
}
func testURLParameterEncodeStringKeyNestedDictionaryValueParameter() throws {
let parameters = ["foo": ["bar": ["baz": 1]]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo%5Bbar%5D%5Bbaz%5D=1")
}
func testURLParameterEncodeStringKeyNestedDictionaryArrayValueParameter() throws {
let parameters = ["foo": ["bar": ["baz": ["a", 1, true]]]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
let expectedQuery = "foo%5Bbar%5D%5Bbaz%5D%5B%5D=a&foo%5Bbar%5D%5Bbaz%5D%5B%5D=1&foo%5Bbar%5D%5Bbaz%5D%5B%5D=1"
XCTAssertEqual(urlRequest.url?.query, expectedQuery)
}
func testURLParameterEncodeStringKeyNestedDictionaryArrayValueParameterWithoutBrackets() throws {
let encoding = URLEncoding(arrayEncoding: .noBrackets)
let parameters = ["foo": ["bar": ["baz": ["a", 1, true]]]]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
let expectedQuery = "foo%5Bbar%5D%5Bbaz%5D=a&foo%5Bbar%5D%5Bbaz%5D=1&foo%5Bbar%5D%5Bbaz%5D=1"
XCTAssertEqual(urlRequest.url?.query, expectedQuery)
}
func testURLParameterLiteralBoolEncodingWorksAndDoesNotAffectNumbers() throws {
let encoding = URLEncoding(boolEncoding: .literal)
let parameters: [String: Any] = [
"a": 1,
"b": 0,
"c": 1.0,
"d": 0.0,
"e": NSNumber(value: 1),
"f": NSNumber(value: 0),
"g": NSNumber(value: 1.0),
"h": NSNumber(value: 0.0),
"i": true,
"j": false,
"k": NSNumber(value: true),
"l": NSNumber(value: false)
]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "a=1&b=0&c=1&d=0&e=1&f=0&g=1&h=0&i=true&j=false&k=true&l=false")
}
func testThatReservedCharactersArePercentEscapedMinusQuestionMarkAndForwardSlash() throws {
let generalDelimiters = ":#[]@"
let subDelimiters = "!$&'()*+,;="
let parameters = ["reserved": "\(generalDelimiters)\(subDelimiters)"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
let expectedQuery = "reserved=%3A%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D"
XCTAssertEqual(urlRequest.url?.query, expectedQuery)
}
func testThatReservedCharactersQuestionMarkAndForwardSlashAreNotPercentEscaped() throws {
let parameters = ["reserved": "?/"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "reserved=?/")
}
func testThatUnreservedNumericCharactersAreNotPercentEscaped() throws {
let parameters = ["numbers": "0123456789"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "numbers=0123456789")
}
func testThatUnreservedLowercaseCharactersAreNotPercentEscaped() throws {
let parameters = ["lowercase": "abcdefghijklmnopqrstuvwxyz"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "lowercase=abcdefghijklmnopqrstuvwxyz")
}
func testThatUnreservedUppercaseCharactersAreNotPercentEscaped() throws {
let parameters = ["uppercase": "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "uppercase=ABCDEFGHIJKLMNOPQRSTUVWXYZ")
}
func testThatIllegalASCIICharactersArePercentEscaped() throws {
let parameters = ["illegal": " \"#%<>[]\\^`{}|"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
let expectedQuery = "illegal=%20%22%23%25%3C%3E%5B%5D%5C%5E%60%7B%7D%7C"
XCTAssertEqual(urlRequest.url?.query, expectedQuery)
}
func testURLParameterEncodeStringWithAmpersandKeyStringWithAmpersandValueParameter() throws {
let parameters = ["foo&bar": "baz&qux", "foobar": "bazqux"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo%26bar=baz%26qux&foobar=bazqux")
}
func testURLParameterEncodeStringWithQuestionMarkKeyStringWithQuestionMarkValueParameter() throws {
let parameters = ["?foo?": "?bar?"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "?foo?=?bar?")
}
func testURLParameterEncodeStringWithSlashKeyStringWithQuestionMarkValueParameter() throws {
let parameters = ["foo": "/bar/baz/qux"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "foo=/bar/baz/qux")
}
func testURLParameterEncodeStringWithSpaceKeyStringWithSpaceValueParameter() throws {
let parameters = [" foo ": " bar "]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "%20foo%20=%20bar%20")
}
func testURLParameterEncodeStringWithPlusKeyStringWithPlusValueParameter() throws {
let parameters = ["+foo+": "+bar+"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "%2Bfoo%2B=%2Bbar%2B")
}
func testURLParameterEncodeStringKeyPercentEncodedStringValueParameter() throws {
let parameters = ["percent": "%25"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "percent=%2525")
}
func testURLParameterEncodeStringKeyNonLatinStringValueParameter() throws {
let parameters = ["french": "français",
"japanese": "日本語",
"arabic": "العربية",
"emoji": "😃"]
let urlRequest = try encoding.encode(urlRequest, with: parameters)
let expectedParameterValues = ["arabic=%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9",
"emoji=%F0%9F%98%83",
"french=fran%C3%A7ais",
"japanese=%E6%97%A5%E6%9C%AC%E8%AA%9E"]
let expectedQuery = expectedParameterValues.joined(separator: "&")
XCTAssertEqual(urlRequest.url?.query, expectedQuery)
}
func testURLParameterEncodeStringForRequestWithPrecomposedQuery() throws {
let url = URL(string: "https://example.com/movies?hd=[1]")!
let parameters = ["page": "0"]
let urlRequest = try encoding.encode(URLRequest(url: url), with: parameters)
XCTAssertEqual(urlRequest.url?.query, "hd=%5B1%5D&page=0")
}
func testURLParameterEncodeStringWithPlusKeyStringWithPlusValueParameterForRequestWithPrecomposedQuery() throws {
let url = URL(string: "https://example.com/movie?hd=[1]")!
let parameters = ["+foo+": "+bar+"]
let urlRequest = try encoding.encode(URLRequest(url: url), with: parameters)
XCTAssertEqual(urlRequest.url?.query, "hd=%5B1%5D&%2Bfoo%2B=%2Bbar%2B")
}
func testURLParameterEncodeStringWithThousandsOfChineseCharacters() throws {
let repeatedCount = 2000
let url = URL(string: "https://example.com/movies")!
let parameters = ["chinese": String(repeating: "一二三四五六七八九十", count: repeatedCount)]
let urlRequest = try encoding.encode(URLRequest(url: url), with: parameters)
var expected = "chinese="
for _ in 0..<repeatedCount {
expected += "%E4%B8%80%E4%BA%8C%E4%B8%89%E5%9B%9B%E4%BA%94%E5%85%AD%E4%B8%83%E5%85%AB%E4%B9%9D%E5%8D%81"
}
XCTAssertEqual(urlRequest.url?.query, expected)
}
func testThatURLParameterEncodingEncodesGETParametersInURL() throws {
var mutableURLRequest = urlRequest
mutableURLRequest.httpMethod = HTTPMethod.get.rawValue
let parameters = ["foo": 1, "bar": 2]
let urlRequest = try encoding.encode(mutableURLRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "bar=2&foo=1")
XCTAssertNil(urlRequest.value(forHTTPHeaderField: "Content-Type"), "Content-Type should be nil")
XCTAssertNil(urlRequest.httpBody, "HTTPBody should be nil")
}
func testThatURLParameterEncodingEncodesPOSTParametersInHTTPBody() throws {
var mutableURLRequest = urlRequest
mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
let parameters = ["foo": 1, "bar": 2]
let urlRequest = try encoding.encode(mutableURLRequest, with: parameters)
XCTAssertEqual(urlRequest.value(forHTTPHeaderField: "Content-Type"), "application/x-www-form-urlencoded; charset=utf-8")
XCTAssertNotNil(urlRequest.httpBody, "HTTPBody should not be nil")
XCTAssertEqual(urlRequest.httpBody?.asString, "bar=2&foo=1")
}
func testThatURLEncodedInURLParameterEncodingEncodesPOSTParametersInURL() throws {
var mutableURLRequest = urlRequest
mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
let parameters = ["foo": 1, "bar": 2]
let urlRequest = try URLEncoding.queryString.encode(mutableURLRequest, with: parameters)
XCTAssertEqual(urlRequest.url?.query, "bar=2&foo=1")
XCTAssertNil(urlRequest.value(forHTTPHeaderField: "Content-Type"))
XCTAssertNil(urlRequest.httpBody, "HTTPBody should be nil")
}
}
final class JSONParameterEncodingTestCase: ParameterEncodingTestCase {
let encoding = JSONEncoding.default
func testJSONParameterEncodeNilParameters() throws {
let request = try encoding.encode(urlRequest, with: nil)
XCTAssertNil(request.url?.query, "query should be nil")
XCTAssertNil(request.value(forHTTPHeaderField: "Content-Type"))
XCTAssertNil(request.httpBody, "HTTPBody should be nil")
}
func testJSONParameterEncodeComplexParameters() throws {
let parameters: [String: Any] = ["foo": "bar",
"baz": ["a", 1, true],
"qux": ["a": 1,
"b": [2, 2],
"c": [3, 3, 3]]]
let request = try encoding.encode(urlRequest, with: parameters)
XCTAssertNil(request.url?.query)
XCTAssertNotNil(request.value(forHTTPHeaderField: "Content-Type"))
XCTAssertEqual(request.value(forHTTPHeaderField: "Content-Type"), "application/json")
XCTAssertNotNil(request.httpBody)
XCTAssertEqual(try request.httpBody?.asJSONObject() as? NSObject,
parameters as NSObject,
"Decoded request body and parameters should be equal.")
}
func testJSONParameterEncodeArray() throws {
let array = ["foo", "bar", "baz"]
let request = try encoding.encode(urlRequest, withJSONObject: array)
XCTAssertNil(request.url?.query)
XCTAssertNotNil(request.value(forHTTPHeaderField: "Content-Type"))
XCTAssertEqual(request.value(forHTTPHeaderField: "Content-Type"), "application/json")
XCTAssertNotNil(request.httpBody)
XCTAssertEqual(try request.httpBody?.asJSONObject() as? NSObject,
array as NSObject,
"Decoded request body and parameters should be equal.")
}
func testJSONParameterEncodeParametersRetainsCustomContentType() throws {
let request = Endpoint(headers: [.contentType("application/custom-json-type+json")]).urlRequest
let parameters = ["foo": "bar"]
let urlRequest = try encoding.encode(request, with: parameters)
XCTAssertNil(urlRequest.url?.query)
XCTAssertEqual(urlRequest.headers["Content-Type"], "application/custom-json-type+json")
}
func testJSONParameterEncodeParametersThrowsErrorWithInvalidValue() {
struct Value {}
let value = Value()
let result = Result { try encoding.encode(urlRequest, with: ["key": value]) }
XCTAssertTrue(result.failure?.asAFError?.isJSONEncodingFailed == true)
}
func testJSONParameterEncodeObjectThrowsErrorWithInvalidValue() {
struct Value {}
let value = Value()
let result = Result { try encoding.encode(urlRequest, withJSONObject: value) }
XCTAssertTrue(result.failure?.asAFError?.isJSONEncodingFailed == true)
}
}