| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- //
- // ParameterEncodingTests.swift
- //
- // Copyright (c) 2014-2020 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
- class ParameterEncodingTestCase: BaseTestCase {
- let urlRequest = Endpoint().urlRequest
- }
- // MARK: -
- final class URLParameterEncodingTestCase: ParameterEncodingTestCase {
- // MARK: Properties
- let encoding = URLEncoding.default
- // MARK: Tests - Parameter Types
- func testURLParameterEncodeNilParameters() throws {
- // Given, When
- let urlRequest = try encoding.encode(urlRequest, with: nil)
- // Then
- XCTAssertNil(urlRequest.url?.query)
- }
- func testURLParameterEncodeEmptyDictionaryParameter() throws {
- // Given
- let parameters: [String: Any] = [:]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertNil(urlRequest.url?.query)
- }
- func testURLParameterEncodeOneStringKeyStringValueParameter() throws {
- // Given
- let parameters = ["foo": "bar"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=bar")
- }
- func testURLParameterEncodeOneStringKeyStringValueParameterAppendedToQuery() throws {
- // Given
- var mutableURLRequest = urlRequest
- var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false)!
- urlComponents.query = "baz=qux"
- mutableURLRequest.url = urlComponents.url
- let parameters = ["foo": "bar"]
- // When
- let urlRequest = try encoding.encode(mutableURLRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "baz=qux&foo=bar")
- }
- func testURLParameterEncodeTwoStringKeyStringValueParameters() throws {
- // Given
- let parameters = ["foo": "bar", "baz": "qux"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "baz=qux&foo=bar")
- }
- func testURLParameterEncodeStringKeyNSNumberIntegerValueParameter() throws {
- // Given
- let parameters = ["foo": NSNumber(value: 25)]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=25")
- }
- func testURLParameterEncodeStringKeyNSNumberBoolValueParameter() throws {
- // Given
- let parameters = ["foo": NSNumber(value: false)]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=0")
- }
- func testURLParameterEncodeStringKeyIntegerValueParameter() throws {
- // Given
- let parameters = ["foo": 1]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=1")
- }
- func testURLParameterEncodeStringKeyDoubleValueParameter() throws {
- // Given
- let parameters = ["foo": 1.1]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=1.1")
- }
- func testURLParameterEncodeStringKeyBoolValueParameter() throws {
- // Given
- let parameters = ["foo": true]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=1")
- }
- func testURLParameterEncodeStringKeyArrayValueParameter() throws {
- // Given
- let parameters = ["foo": ["a", 1, true]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo%5B%5D=a&foo%5B%5D=1&foo%5B%5D=1")
- }
- func testURLParameterEncodeArrayNestedDictionaryValueParameterWithIndex() throws {
- // Given
- let encoding = URLEncoding(arrayEncoding: .indexInBrackets)
- let parameters = ["foo": ["a", 1, true, ["bar": 2], ["qux": 3], ["quy": ["quz": 3]]]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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 {
- // Given
- let encoding = URLEncoding(arrayEncoding: .noBrackets)
- let parameters = ["foo": ["a", 1, true]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=a&foo=1&foo=1")
- }
- func testURLParameterEncodeStringKeyArrayValueParameterWithCustomClosure() throws {
- // Given
- let encoding = URLEncoding(arrayEncoding: .custom { key, index in
- "\(key).\(index + 1)"
- })
- let parameters = ["foo": ["a", 1, true]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo.1=a&foo.2=1&foo.3=1")
- }
- func testURLParameterEncodeStringKeyDictionaryValueParameter() throws {
- // Given
- let parameters = ["foo": ["bar": 1]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo%5Bbar%5D=1")
- }
- func testURLParameterEncodeStringKeyNestedDictionaryValueParameter() throws {
- // Given
- let parameters = ["foo": ["bar": ["baz": 1]]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo%5Bbar%5D%5Bbaz%5D=1")
- }
- func testURLParameterEncodeStringKeyNestedDictionaryArrayValueParameter() throws {
- // Given
- let parameters = ["foo": ["bar": ["baz": ["a", 1, true]]]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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 {
- // Given
- let encoding = URLEncoding(arrayEncoding: .noBrackets)
- let parameters = ["foo": ["bar": ["baz": ["a", 1, true]]]]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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 {
- // Given
- let encoding = URLEncoding(boolEncoding: .literal)
- let parameters: [String: Any] = [ // Must still encode to numbers
- "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),
- // Must encode to literals
- "i": true,
- "j": false,
- "k": NSNumber(value: true),
- "l": NSNumber(value: false)
- ]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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")
- }
- // MARK: Tests - All Reserved / Unreserved / Illegal Characters According to RFC 3986
- func testThatReservedCharactersArePercentEscapedMinusQuestionMarkAndForwardSlash() throws {
- // Given
- let generalDelimiters = ":#[]@"
- let subDelimiters = "!$&'()*+,;="
- let parameters = ["reserved": "\(generalDelimiters)\(subDelimiters)"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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 {
- // Given
- let parameters = ["reserved": "?/"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "reserved=?/")
- }
- func testThatUnreservedNumericCharactersAreNotPercentEscaped() throws {
- // Given
- let parameters = ["numbers": "0123456789"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "numbers=0123456789")
- }
- func testThatUnreservedLowercaseCharactersAreNotPercentEscaped() throws {
- // Given
- let parameters = ["lowercase": "abcdefghijklmnopqrstuvwxyz"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "lowercase=abcdefghijklmnopqrstuvwxyz")
- }
- func testThatUnreservedUppercaseCharactersAreNotPercentEscaped() throws {
- // Given
- let parameters = ["uppercase": "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "uppercase=ABCDEFGHIJKLMNOPQRSTUVWXYZ")
- }
- func testThatIllegalASCIICharactersArePercentEscaped() throws {
- // Given
- let parameters = ["illegal": " \"#%<>[]\\^`{}|"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- let expectedQuery = "illegal=%20%22%23%25%3C%3E%5B%5D%5C%5E%60%7B%7D%7C"
- XCTAssertEqual(urlRequest.url?.query, expectedQuery)
- }
- // MARK: Tests - Special Character Queries
- func testURLParameterEncodeStringWithAmpersandKeyStringWithAmpersandValueParameter() throws {
- // Given
- let parameters = ["foo&bar": "baz&qux", "foobar": "bazqux"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo%26bar=baz%26qux&foobar=bazqux")
- }
- func testURLParameterEncodeStringWithQuestionMarkKeyStringWithQuestionMarkValueParameter() throws {
- // Given
- let parameters = ["?foo?": "?bar?"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "?foo?=?bar?")
- }
- func testURLParameterEncodeStringWithSlashKeyStringWithQuestionMarkValueParameter() throws {
- // Given
- let parameters = ["foo": "/bar/baz/qux"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "foo=/bar/baz/qux")
- }
- func testURLParameterEncodeStringWithSpaceKeyStringWithSpaceValueParameter() throws {
- // Given
- let parameters = [" foo ": " bar "]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "%20foo%20=%20bar%20")
- }
- func testURLParameterEncodeStringWithPlusKeyStringWithPlusValueParameter() throws {
- // Given
- let parameters = ["+foo+": "+bar+"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "%2Bfoo%2B=%2Bbar%2B")
- }
- func testURLParameterEncodeStringKeyPercentEncodedStringValueParameter() throws {
- // Given
- let parameters = ["percent": "%25"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "percent=%2525")
- }
- func testURLParameterEncodeStringKeyNonLatinStringValueParameter() throws {
- // Given
- let parameters = ["french": "français",
- "japanese": "日本語",
- "arabic": "العربية",
- "emoji": "😃"]
- // When
- let urlRequest = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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 {
- // Given
- let url = URL(string: "https://example.com/movies?hd=[1]")!
- let parameters = ["page": "0"]
- // When
- let urlRequest = try encoding.encode(URLRequest(url: url), with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "hd=%5B1%5D&page=0")
- }
- func testURLParameterEncodeStringWithPlusKeyStringWithPlusValueParameterForRequestWithPrecomposedQuery() throws {
- // Given
- let url = URL(string: "https://example.com/movie?hd=[1]")!
- let parameters = ["+foo+": "+bar+"]
- // When
- let urlRequest = try encoding.encode(URLRequest(url: url), with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "hd=%5B1%5D&%2Bfoo%2B=%2Bbar%2B")
- }
- func testURLParameterEncodeStringWithThousandsOfChineseCharacters() throws {
- // Given
- let repeatedCount = 2000
- let url = URL(string: "https://example.com/movies")!
- let parameters = ["chinese": String(repeating: "一二三四五六七八九十", count: repeatedCount)]
- // When
- let urlRequest = try encoding.encode(URLRequest(url: url), with: parameters)
- // Then
- 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)
- }
- // MARK: Tests - Varying HTTP Methods
- func testThatURLParameterEncodingEncodesGETParametersInURL() throws {
- // Given
- var mutableURLRequest = urlRequest
- mutableURLRequest.httpMethod = HTTPMethod.get.rawValue
- let parameters = ["foo": 1, "bar": 2]
- // When
- let urlRequest = try encoding.encode(mutableURLRequest, with: parameters)
- // Then
- 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 {
- // Given
- var mutableURLRequest = urlRequest
- mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
- let parameters = ["foo": 1, "bar": 2]
- // When
- let urlRequest = try encoding.encode(mutableURLRequest, with: parameters)
- // Then
- 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 {
- // Given
- var mutableURLRequest = urlRequest
- mutableURLRequest.httpMethod = HTTPMethod.post.rawValue
- let parameters = ["foo": 1, "bar": 2]
- // When
- let urlRequest = try URLEncoding.queryString.encode(mutableURLRequest, with: parameters)
- // Then
- XCTAssertEqual(urlRequest.url?.query, "bar=2&foo=1")
- XCTAssertNil(urlRequest.value(forHTTPHeaderField: "Content-Type"))
- XCTAssertNil(urlRequest.httpBody, "HTTPBody should be nil")
- }
- }
- // MARK: -
- final class JSONParameterEncodingTestCase: ParameterEncodingTestCase {
- // MARK: Properties
- let encoding = JSONEncoding.default
- // MARK: Tests
- func testJSONParameterEncodeNilParameters() throws {
- // Given, When
- let request = try encoding.encode(urlRequest, with: nil)
- // Then
- XCTAssertNil(request.url?.query, "query should be nil")
- XCTAssertNil(request.value(forHTTPHeaderField: "Content-Type"))
- XCTAssertNil(request.httpBody, "HTTPBody should be nil")
- }
- func testJSONParameterEncodeComplexParameters() throws {
- // Given
- let parameters: [String: Any] = ["foo": "bar",
- "baz": ["a", 1, true],
- "qux": ["a": 1,
- "b": [2, 2],
- "c": [3, 3, 3]]]
- // When
- let request = try encoding.encode(urlRequest, with: parameters)
- // Then
- 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 {
- // Given
- let array = ["foo", "bar", "baz"]
- // When
- let request = try encoding.encode(urlRequest, withJSONObject: array)
- // Then
- 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 {
- // Given
- let request = Endpoint(headers: [.contentType("application/custom-json-type+json")]).urlRequest
- let parameters = ["foo": "bar"]
- // When
- let urlRequest = try encoding.encode(request, with: parameters)
- // Then
- XCTAssertNil(urlRequest.url?.query)
- XCTAssertEqual(urlRequest.headers["Content-Type"], "application/custom-json-type+json")
- }
- func testJSONParameterEncodeParametersThrowsErrorWithInvalidValue() {
- // Given
- struct Value {}
- let value = Value()
- // When
- let result = Result { try encoding.encode(urlRequest, with: ["key": value]) }
- // Then
- XCTAssertTrue(result.failure?.asAFError?.isJSONEncodingFailed == true)
- }
- func testJSONParameterEncodeObjectThrowsErrorWithInvalidValue() {
- // Given
- struct Value {}
- let value = Value()
- // When
- let result = Result { try encoding.encode(urlRequest, withJSONObject: value) }
- // Then
- XCTAssertTrue(result.failure?.asAFError?.isJSONEncodingFailed == true)
- }
- }
|