ParameterEncoderTests.swift 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. //
  2. // ParameterEncoderTests.swift
  3. //
  4. // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. import Alamofire
  25. import XCTest
  26. final class JSONParameterEncoderTests: BaseTestCase {
  27. func testThatDataIsProperlyEncodedAndProperContentTypeIsSet() throws {
  28. // Given
  29. let encoder = JSONParameterEncoder()
  30. let request = Endpoint().urlRequest
  31. // When
  32. let newRequest = try encoder.encode(TestParameters.default, into: request)
  33. // Then
  34. XCTAssertEqual(newRequest.headers["Content-Type"], "application/json")
  35. XCTAssertEqual(newRequest.httpBody?.asString, "{\"property\":\"property\"}")
  36. }
  37. func testThatDataIsProperlyEncodedButContentTypeIsNotSetIfRequestAlreadyHasAContentType() throws {
  38. // Given
  39. let encoder = JSONParameterEncoder()
  40. var request = Endpoint().urlRequest
  41. request.headers.update(.contentType("type"))
  42. // When
  43. let newRequest = try encoder.encode(TestParameters.default, into: request)
  44. // Then
  45. XCTAssertEqual(newRequest.headers["Content-Type"], "type")
  46. XCTAssertEqual(newRequest.httpBody?.asString, "{\"property\":\"property\"}")
  47. }
  48. func testThatJSONEncoderCanBeCustomized() throws {
  49. // Given
  50. let jsonEncoder = JSONEncoder()
  51. jsonEncoder.outputFormatting = .prettyPrinted
  52. let encoder = JSONParameterEncoder(encoder: jsonEncoder)
  53. let request = Endpoint().urlRequest
  54. // When
  55. let newRequest = try encoder.encode(TestParameters.default, into: request)
  56. // Then
  57. let expected = """
  58. {
  59. "property" : "property"
  60. }
  61. """
  62. XCTAssertEqual(newRequest.httpBody?.asString, expected)
  63. }
  64. func testThatJSONEncoderDefaultWorks() throws {
  65. // Given
  66. let encoder = JSONParameterEncoder.default
  67. let request = Endpoint().urlRequest
  68. // When
  69. let encoded = try encoder.encode(TestParameters.default, into: request)
  70. // Then
  71. let expected = """
  72. {"property":"property"}
  73. """
  74. XCTAssertEqual(encoded.httpBody?.asString, expected)
  75. }
  76. func testThatJSONEncoderPrettyPrintedPrintsPretty() throws {
  77. // Given
  78. let encoder = JSONParameterEncoder.prettyPrinted
  79. let request = Endpoint().urlRequest
  80. // When
  81. let encoded = try encoder.encode(TestParameters.default, into: request)
  82. // Then
  83. let expected = """
  84. {
  85. "property" : "property"
  86. }
  87. """
  88. XCTAssertEqual(encoded.httpBody?.asString, expected)
  89. }
  90. }
  91. final class SortedKeysJSONParameterEncoderTests: BaseTestCase {
  92. func testTestJSONEncoderSortedKeysHasSortedKeys() throws {
  93. // Given
  94. let encoder = JSONParameterEncoder.sortedKeys
  95. let request = Endpoint().urlRequest
  96. // When
  97. let encoded = try encoder.encode(["z": "z", "a": "a", "p": "p"], into: request)
  98. // Then
  99. let expected = """
  100. {"a":"a","p":"p","z":"z"}
  101. """
  102. XCTAssertEqual(encoded.httpBody?.asString, expected)
  103. }
  104. }
  105. final class URLEncodedFormParameterEncoderTests: BaseTestCase {
  106. func testThatQueryIsBodyEncodedAndProperContentTypeIsSetForPOSTRequest() throws {
  107. // Given
  108. let encoder = URLEncodedFormParameterEncoder()
  109. let request = Endpoint(method: .post).urlRequest
  110. // When
  111. let newRequest = try encoder.encode(TestParameters.default, into: request)
  112. // Then
  113. XCTAssertEqual(newRequest.headers["Content-Type"], "application/x-www-form-urlencoded; charset=utf-8")
  114. XCTAssertEqual(newRequest.httpBody?.asString, "property=property")
  115. }
  116. func testThatQueryIsBodyEncodedButContentTypeIsNotSetWhenRequestAlreadyHasContentType() throws {
  117. // Given
  118. let encoder = URLEncodedFormParameterEncoder()
  119. var request = Endpoint(method: .post).urlRequest
  120. request.headers.update(.contentType("type"))
  121. // When
  122. let newRequest = try encoder.encode(TestParameters.default, into: request)
  123. // Then
  124. XCTAssertEqual(newRequest.headers["Content-Type"], "type")
  125. XCTAssertEqual(newRequest.httpBody?.asString, "property=property")
  126. }
  127. func testThatEncoderCanBeCustomized() throws {
  128. // Given
  129. let urlEncoder = URLEncodedFormEncoder(boolEncoding: .literal)
  130. let encoder = URLEncodedFormParameterEncoder(encoder: urlEncoder)
  131. let request = Endpoint().urlRequest
  132. // When
  133. let newRequest = try encoder.encode(["bool": true], into: request)
  134. // Then
  135. let components = URLComponents(url: newRequest.url!, resolvingAgainstBaseURL: false)
  136. XCTAssertEqual(components?.percentEncodedQuery, "bool=true")
  137. }
  138. func testThatQueryIsInURLWhenDestinationIsURLAndMethodIsPOST() throws {
  139. // Given
  140. let encoder = URLEncodedFormParameterEncoder(destination: .queryString)
  141. let request = Endpoint(method: .post).urlRequest
  142. // When
  143. let newRequest = try encoder.encode(TestParameters.default, into: request)
  144. // Then
  145. let components = URLComponents(url: newRequest.url!, resolvingAgainstBaseURL: false)
  146. XCTAssertEqual(components?.percentEncodedQuery, "property=property")
  147. }
  148. func testThatQueryIsNilWhenEncodableResultsInAnEmptyString() throws {
  149. // Given
  150. let encoder = URLEncodedFormParameterEncoder(destination: .queryString)
  151. let request = Endpoint().urlRequest
  152. // When
  153. let newRequest = try encoder.encode([String: String](), into: request)
  154. // Then
  155. let components = URLComponents(url: newRequest.url!, resolvingAgainstBaseURL: false)
  156. XCTAssertNil(components?.percentEncodedQuery)
  157. }
  158. }
  159. final class URLEncodedFormEncoderTests: BaseTestCase {
  160. func testEncoderCanEncodeDictionary() {
  161. // Given
  162. let encoder = URLEncodedFormEncoder()
  163. let parameters = ["a": "a"]
  164. // When
  165. let result = Result<String, Error> { try encoder.encode(parameters) }
  166. // Then
  167. XCTAssertEqual(result.success, "a=a")
  168. }
  169. func testEncoderCanEncodeDecimal() {
  170. // Given
  171. let encoder = URLEncodedFormEncoder()
  172. let decimal: Decimal = 1.0
  173. let parameters = ["a": decimal]
  174. // When
  175. let result = Result<String, Error> { try encoder.encode(parameters) }
  176. // Then
  177. XCTAssertEqual(result.success, "a=1")
  178. }
  179. func testEncoderCanEncodeDecimalWithHighPrecision() {
  180. // Given
  181. let encoder = URLEncodedFormEncoder()
  182. let decimal: Decimal = 1.123456
  183. let parameters = ["a": decimal]
  184. // When
  185. let result = Result<String, Error> { try encoder.encode(parameters) }
  186. // Then
  187. XCTAssertEqual(result.success, "a=1.123456")
  188. }
  189. func testEncoderCanEncodeDouble() {
  190. // Given
  191. let encoder = URLEncodedFormEncoder()
  192. let parameters = ["a": 1.0]
  193. // When
  194. let result = Result<String, Error> { try encoder.encode(parameters) }
  195. // Then
  196. XCTAssertEqual(result.success, "a=1.0")
  197. }
  198. func testEncoderCanEncodeFloat() {
  199. // Given
  200. let encoder = URLEncodedFormEncoder()
  201. let parameters: [String: Float] = ["a": 1.0]
  202. // When
  203. let result = Result<String, Error> { try encoder.encode(parameters) }
  204. // Then
  205. XCTAssertEqual(result.success, "a=1.0")
  206. }
  207. func testEncoderCanEncodeInt8() {
  208. // Given
  209. let encoder = URLEncodedFormEncoder()
  210. let parameters: [String: Int8] = ["a": 1]
  211. // When
  212. let result = Result<String, Error> { try encoder.encode(parameters) }
  213. // Then
  214. XCTAssertEqual(result.success, "a=1")
  215. }
  216. func testEncoderCanEncodeInt16() {
  217. // Given
  218. let encoder = URLEncodedFormEncoder()
  219. let parameters: [String: Int16] = ["a": 1]
  220. // When
  221. let result = Result<String, Error> { try encoder.encode(parameters) }
  222. // Then
  223. XCTAssertEqual(result.success, "a=1")
  224. }
  225. func testEncoderCanEncodeInt32() {
  226. // Given
  227. let encoder = URLEncodedFormEncoder()
  228. let parameters: [String: Int32] = ["a": 1]
  229. // When
  230. let result = Result<String, Error> { try encoder.encode(parameters) }
  231. // Then
  232. XCTAssertEqual(result.success, "a=1")
  233. }
  234. func testEncoderCanEncodeInt64() {
  235. // Given
  236. let encoder = URLEncodedFormEncoder()
  237. let parameters: [String: Int64] = ["a": 1]
  238. // When
  239. let result = Result<String, Error> { try encoder.encode(parameters) }
  240. // Then
  241. XCTAssertEqual(result.success, "a=1")
  242. }
  243. func testEncoderCanEncodeUInt() {
  244. // Given
  245. let encoder = URLEncodedFormEncoder()
  246. let parameters: [String: UInt] = ["a": 1]
  247. // When
  248. let result = Result<String, Error> { try encoder.encode(parameters) }
  249. // Then
  250. XCTAssertEqual(result.success, "a=1")
  251. }
  252. func testEncoderCanEncodeUInt8() {
  253. // Given
  254. let encoder = URLEncodedFormEncoder()
  255. let parameters: [String: UInt8] = ["a": 1]
  256. // When
  257. let result = Result<String, Error> { try encoder.encode(parameters) }
  258. // Then
  259. XCTAssertEqual(result.success, "a=1")
  260. }
  261. func testEncoderCanEncodeUInt16() {
  262. // Given
  263. let encoder = URLEncodedFormEncoder()
  264. let parameters: [String: UInt16] = ["a": 1]
  265. // When
  266. let result = Result<String, Error> { try encoder.encode(parameters) }
  267. // Then
  268. XCTAssertEqual(result.success, "a=1")
  269. }
  270. func testEncoderCanEncodeUInt32() {
  271. // Given
  272. let encoder = URLEncodedFormEncoder()
  273. let parameters: [String: UInt32] = ["a": 1]
  274. // When
  275. let result = Result<String, Error> { try encoder.encode(parameters) }
  276. // Then
  277. XCTAssertEqual(result.success, "a=1")
  278. }
  279. func testEncoderCanEncodeUInt64() {
  280. // Given
  281. let encoder = URLEncodedFormEncoder()
  282. let parameters: [String: UInt64] = ["a": 1]
  283. // When
  284. let result = Result<String, Error> { try encoder.encode(parameters) }
  285. // Then
  286. XCTAssertEqual(result.success, "a=1")
  287. }
  288. func testThatNestedDictionariesCanHaveBracketKeyPathsByDefault() {
  289. // Given
  290. let encoder = URLEncodedFormEncoder()
  291. let parameters = ["a": ["b": "b"]]
  292. // When
  293. let result = Result<String, Error> { try encoder.encode(parameters) }
  294. // Then
  295. XCTAssertEqual(result.success, "a%5Bb%5D=b")
  296. }
  297. func testThatNestedDictionariesCanHaveExplicitBracketKeyPaths() {
  298. // Given
  299. let encoder = URLEncodedFormEncoder(keyPathEncoding: .brackets)
  300. let parameters = ["a": ["b": "b"]]
  301. // When
  302. let result = Result<String, Error> { try encoder.encode(parameters) }
  303. // Then
  304. XCTAssertEqual(result.success, "a%5Bb%5D=b")
  305. }
  306. func testThatNestedDictionariesCanHaveDottedKeyPaths() {
  307. // Given
  308. let encoder = URLEncodedFormEncoder(keyPathEncoding: .dots)
  309. let parameters = ["a": ["b": "b"]]
  310. // When
  311. let result = Result<String, Error> { try encoder.encode(parameters) }
  312. // Then
  313. XCTAssertEqual(result.success, "a.b=b")
  314. }
  315. func testThatNestedDictionariesCanHaveCustomKeyPaths() {
  316. // Given
  317. let encoder = URLEncodedFormEncoder(keyPathEncoding: .init { "-\($0)" })
  318. let parameters = ["a": ["b": "b"]]
  319. // When
  320. let result = Result<String, Error> { try encoder.encode(parameters) }
  321. // Then
  322. XCTAssertEqual(result.success, "a-b=b")
  323. }
  324. func testThatEncodableStructCanBeEncoded() {
  325. // Given
  326. let encoder = URLEncodedFormEncoder()
  327. let parameters = EncodableStruct()
  328. // When
  329. let result = Result<String, Error> { try encoder.encode(parameters) }
  330. // Then
  331. let expected = "five%5Ba%5D=a&four%5B%5D=1&four%5B%5D=2&four%5B%5D=3&one=one&seven%5Ba%5D=a&six%5Ba%5D%5Bb%5D=b&three=1&two=2"
  332. XCTAssertEqual(result.success, expected)
  333. }
  334. func testThatManuallyEncodableStructCanBeEncoded() {
  335. // Given
  336. let encoder = URLEncodedFormEncoder()
  337. let parameters = ManuallyEncodableStruct()
  338. // When
  339. let result = Result<String, Error> { try encoder.encode(parameters) }
  340. // Then
  341. let expected = "root%5B%5D%5B%5D%5B%5D=1&root%5B%5D%5B%5D%5B%5D=2&root%5B%5D%5B%5D%5B%5D=3&root%5B%5D%5B%5D=1&root%5B%5D%5B%5D=2&root%5B%5D%5B%5D=3&root%5B%5D%5Ba%5D%5Bstring%5D=string"
  342. XCTAssertEqual(result.success, expected)
  343. }
  344. func testThatEncodableClassWithNoInheritanceCanBeEncoded() {
  345. // Given
  346. let encoder = URLEncodedFormEncoder()
  347. let parameters = EncodableSuperclass()
  348. // When
  349. let result = Result<String, Error> { try encoder.encode(parameters) }
  350. // Then
  351. XCTAssertEqual(result.success, "one=one&three=1&two=2")
  352. }
  353. func testThatEncodableSubclassCanBeEncoded() {
  354. // Given
  355. let encoder = URLEncodedFormEncoder()
  356. let parameters = EncodableSubclass()
  357. // When
  358. let result = Result<String, Error> { try encoder.encode(parameters) }
  359. // Then
  360. let expected = "five%5Ba%5D=a&five%5Bb%5D=b&four%5B%5D=1&four%5B%5D=2&four%5B%5D=3&one=one&three=1&two=2"
  361. XCTAssertEqual(result.success, expected)
  362. }
  363. func testThatEncodableSubclassCanBeEncodedInImplementationOrderWhenAlphabetizeKeysIsFalse() {
  364. // Given
  365. let encoder = URLEncodedFormEncoder(alphabetizeKeyValuePairs: false)
  366. let parameters = EncodableStruct()
  367. // When
  368. let result = Result<String, Error> { try encoder.encode(parameters) }
  369. // Then
  370. let expected = "one=one&two=2&three=1&four%5B%5D=1&four%5B%5D=2&four%5B%5D=3&five%5Ba%5D=a&six%5Ba%5D%5Bb%5D=b&seven%5Ba%5D=a"
  371. XCTAssertEqual(result.success, expected)
  372. }
  373. func testThatManuallyEncodableSubclassCanBeEncoded() {
  374. // Given
  375. let encoder = URLEncodedFormEncoder()
  376. let parameters = ManuallyEncodableSubclass()
  377. // When
  378. let result = Result<String, Error> { try encoder.encode(parameters) }
  379. // Then
  380. let expected = "five%5Ba%5D=a&five%5Bb%5D=b&four%5Bfive%5D=2&four%5Bfour%5D=one"
  381. XCTAssertEqual(result.success, expected)
  382. }
  383. func testThatARootArrayCannotBeEncoded() {
  384. // Given
  385. let encoder = URLEncodedFormEncoder()
  386. let parameters = [1]
  387. // When
  388. let result = Result<String, Error> { try encoder.encode(parameters) }
  389. // Then
  390. XCTAssertFalse(result.isSuccess)
  391. }
  392. func testThatARootValueCannotBeEncoded() {
  393. // Given
  394. let encoder = URLEncodedFormEncoder()
  395. let parameters = "string"
  396. // When
  397. let result = Result<String, Error> { try encoder.encode(parameters) }
  398. // Then
  399. XCTAssertFalse(result.isSuccess)
  400. }
  401. func testThatEncodableSuperclassCanBeEncodedWithIndexInBrackets() {
  402. // Given
  403. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  404. let parameters = ["foo": [EncodableSuperclass()]]
  405. // When
  406. let result = Result<String, Error> { try encoder.encode(parameters) }
  407. // Then
  408. XCTAssertEqual(result.success, "foo%5B0%5D%5Bone%5D=one&foo%5B0%5D%5Bthree%5D=1&foo%5B0%5D%5Btwo%5D=2")
  409. }
  410. func testThatEncodableSubclassCanBeEncodedWithIndexInBrackets() {
  411. // Given
  412. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  413. let parameters = EncodableSubclass()
  414. // When
  415. let result = Result<String, Error> { try encoder.encode(parameters) }
  416. // Then
  417. let expected = "five%5Ba%5D=a&five%5Bb%5D=b&four%5B0%5D=1&four%5B1%5D=2&four%5B2%5D=3&one=one&three=1&two=2"
  418. XCTAssertEqual(result.success, expected)
  419. }
  420. func testThatManuallyEncodableSubclassCanBeEncodedWithIndexInBrackets() {
  421. // Given
  422. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  423. let parameters = ManuallyEncodableSubclass()
  424. // When
  425. let result = Result<String, Error> { try encoder.encode(parameters) }
  426. // Then
  427. let expected = "five%5Ba%5D=a&five%5Bb%5D=b&four%5Bfive%5D=2&four%5Bfour%5D=one"
  428. XCTAssertEqual(result.success, expected)
  429. }
  430. func testThatEncodableStructCanBeEncodedWithIndexInBrackets() {
  431. // Given
  432. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  433. let parameters = EncodableStruct()
  434. // When
  435. let result = Result<String, Error> { try encoder.encode(parameters) }
  436. // Then
  437. let expected = "five%5Ba%5D=a&four%5B0%5D=1&four%5B1%5D=2&four%5B2%5D=3&one=one&seven%5Ba%5D=a&six%5Ba%5D%5Bb%5D=b&three=1&two=2"
  438. XCTAssertEqual(result.success, expected)
  439. }
  440. func testThatManuallyEncodableStructCanBeEncodedWithIndexInBrackets() {
  441. // Given
  442. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  443. let parameters = ManuallyEncodableStruct()
  444. // When
  445. let result = Result<String, Error> { try encoder.encode(parameters) }
  446. // then
  447. let expected = "root%5B0%5D%5B0%5D=1&root%5B0%5D%5B1%5D=2&root%5B0%5D%5B2%5D=3&root%5B1%5D%5Ba%5D%5Bstring%5D=string&root%5B2%5D%5B0%5D%5B0%5D=1&root%5B2%5D%5B0%5D%5B1%5D=2&root%5B2%5D%5B0%5D%5B2%5D=3"
  448. XCTAssertEqual(result.success, expected)
  449. }
  450. func testThatArrayNestedDictionaryIntValueCanBeEncodedWithIndexInBrackets() {
  451. // Given
  452. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  453. let parameters = ["foo": [["bar": 2], ["qux": 3], ["quy": 4]]]
  454. // When
  455. let result = Result<String, Error> { try encoder.encode(parameters) }
  456. // Then
  457. XCTAssertEqual(result.success, "foo%5B0%5D%5Bbar%5D=2&foo%5B1%5D%5Bqux%5D=3&foo%5B2%5D%5Bquy%5D=4")
  458. }
  459. func testThatArrayNestedDictionaryStringValueCanBeEncodedWithIndexInBrackets() {
  460. // Given
  461. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  462. let parameters = ["foo": [["bar": "2"], ["qux": "3"], ["quy": "4"]]]
  463. // When
  464. let result = Result<String, Error> { try encoder.encode(parameters) }
  465. // Then
  466. XCTAssertEqual(result.success, "foo%5B0%5D%5Bbar%5D=2&foo%5B1%5D%5Bqux%5D=3&foo%5B2%5D%5Bquy%5D=4")
  467. }
  468. func testThatArrayNestedDictionaryBoolValueCanBeEncodedWithIndexInBrackets() {
  469. // Given
  470. let encoder = URLEncodedFormEncoder(arrayEncoding: .indexInBrackets)
  471. let parameters = ["foo": [["bar": true], ["qux": false], ["quy": true]]]
  472. // When
  473. let result = Result<String, Error> { try encoder.encode(parameters) }
  474. // Then
  475. XCTAssertEqual(result.success, "foo%5B0%5D%5Bbar%5D=1&foo%5B1%5D%5Bqux%5D=0&foo%5B2%5D%5Bquy%5D=1")
  476. }
  477. func testThatArraysCanBeEncodedWithoutBrackets() {
  478. // Given
  479. let encoder = URLEncodedFormEncoder(arrayEncoding: .noBrackets)
  480. let parameters = ["array": [1, 2]]
  481. // When
  482. let result = Result<String, Error> { try encoder.encode(parameters) }
  483. // Then
  484. XCTAssertEqual(result.success, "array=1&array=2")
  485. }
  486. func testThatArraysCanBeEncodedWithCustomClosure() {
  487. // Given
  488. let encoder = URLEncodedFormEncoder(arrayEncoding: .custom({ key, index in
  489. "\(key).\(index + 1)"
  490. }))
  491. let parameters = ["array": [1, 2]]
  492. // When
  493. let result = Result<String, Error> { try encoder.encode(parameters) }
  494. // Then
  495. XCTAssertEqual(result.success, "array.1=1&array.2=2")
  496. }
  497. func testThatBoolsCanBeLiteralEncoded() {
  498. // Given
  499. let encoder = URLEncodedFormEncoder(boolEncoding: .literal)
  500. let parameters = ["bool": true]
  501. // When
  502. let result = Result<String, Error> { try encoder.encode(parameters) }
  503. // Then
  504. XCTAssertEqual(result.success, "bool=true")
  505. }
  506. func testThatDataCanBeEncoded() {
  507. // Given
  508. let encoder = URLEncodedFormEncoder()
  509. let parameters = ["data": Data("data".utf8)]
  510. // When
  511. let result = Result<String, Error> { try encoder.encode(parameters) }
  512. // Then
  513. XCTAssertEqual(result.success, "data=ZGF0YQ%3D%3D")
  514. }
  515. func testThatCustomDataEncodingFailsWhenErrorIsThrown() {
  516. // Given
  517. struct DataEncodingError: Error {}
  518. let encoder = URLEncodedFormEncoder(dataEncoding: .custom { _ in throw DataEncodingError() })
  519. let parameters = ["data": Data("data".utf8)]
  520. // When
  521. let result = Result<String, Error> { try encoder.encode(parameters) }
  522. // Then
  523. XCTAssertTrue(result.isFailure)
  524. XCTAssertTrue(result.failure is DataEncodingError)
  525. }
  526. func testThatDatesCanBeEncoded() {
  527. // Given
  528. let encoder = URLEncodedFormEncoder(dateEncoding: .deferredToDate)
  529. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  530. // When
  531. let result = Result<String, Error> { try encoder.encode(parameters) }
  532. // Then
  533. XCTAssertEqual(result.success, "date=123.456")
  534. }
  535. func testThatDatesCanBeEncodedAsSecondsSince1970() {
  536. // Given
  537. let encoder = URLEncodedFormEncoder(dateEncoding: .secondsSince1970)
  538. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  539. // When
  540. let result = Result<String, Error> { try encoder.encode(parameters) }
  541. // Then
  542. XCTAssertEqual(result.success, "date=978307323.456")
  543. }
  544. func testThatDatesCanBeEncodedAsMillisecondsSince1970() {
  545. // Given
  546. let encoder = URLEncodedFormEncoder(dateEncoding: .millisecondsSince1970)
  547. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  548. // When
  549. let result = Result<String, Error> { try encoder.encode(parameters) }
  550. // Then
  551. XCTAssertEqual(result.success, "date=978307323456.0")
  552. }
  553. func testThatDatesCanBeEncodedAsISO8601Formatted() {
  554. // Given
  555. let encoder = URLEncodedFormEncoder(dateEncoding: .iso8601)
  556. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  557. // When
  558. let result = Result<String, Error> { try encoder.encode(parameters) }
  559. // Then
  560. XCTAssertEqual(result.success, "date=2001-01-01T00%3A02%3A03Z")
  561. }
  562. func testThatDatesCanBeEncodedAsFormatted() {
  563. // Given
  564. let dateFormatter = DateFormatter()
  565. dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSSS"
  566. dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
  567. let encoder = URLEncodedFormEncoder(dateEncoding: .formatted(dateFormatter))
  568. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  569. // When
  570. let result = Result<String, Error> { try encoder.encode(parameters) }
  571. // Then
  572. XCTAssertEqual(result.success, "date=2001-01-01%2000%3A02%3A03.4560")
  573. }
  574. func testThatDatesCanBeEncodedAsCustomFormatted() {
  575. // Given
  576. let encoder = URLEncodedFormEncoder(dateEncoding: .custom { "\($0.timeIntervalSinceReferenceDate)" })
  577. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  578. // When
  579. let result = Result<String, Error> { try encoder.encode(parameters) }
  580. // Then
  581. XCTAssertEqual(result.success, "date=123.456")
  582. }
  583. func testEncoderThrowsErrorWhenCustomDateEncodingFails() {
  584. // Given
  585. struct DateEncodingError: Error {}
  586. let encoder = URLEncodedFormEncoder(dateEncoding: .custom { _ in throw DateEncodingError() })
  587. let parameters = ["date": Date(timeIntervalSinceReferenceDate: 123.456)]
  588. // When
  589. let result = Result<String, Error> { try encoder.encode(parameters) }
  590. // Then
  591. XCTAssertTrue(result.isFailure)
  592. XCTAssertTrue(result.failure is DateEncodingError)
  593. }
  594. func testThatKeysCanBeEncodedIntoSnakeCase() {
  595. // Given
  596. let encoder = URLEncodedFormEncoder(keyEncoding: .convertToSnakeCase)
  597. let parameters = ["oneTwoThree": "oneTwoThree"]
  598. // When
  599. let result = Result<String, Error> { try encoder.encode(parameters) }
  600. // Then
  601. XCTAssertEqual(result.success, "one_two_three=oneTwoThree")
  602. }
  603. func testThatKeysCanBeEncodedIntoKebabCase() {
  604. // Given
  605. let encoder = URLEncodedFormEncoder(keyEncoding: .convertToKebabCase)
  606. let parameters = ["oneTwoThree": "oneTwoThree"]
  607. // When
  608. let result = Result<String, Error> { try encoder.encode(parameters) }
  609. // Then
  610. XCTAssertEqual(result.success, "one-two-three=oneTwoThree")
  611. }
  612. func testThatKeysCanBeEncodedIntoACapitalizedString() {
  613. // Given
  614. let encoder = URLEncodedFormEncoder(keyEncoding: .capitalized)
  615. let parameters = ["oneTwoThree": "oneTwoThree"]
  616. // When
  617. let result = Result<String, Error> { try encoder.encode(parameters) }
  618. // Then
  619. XCTAssertEqual(result.success, "OneTwoThree=oneTwoThree")
  620. }
  621. func testThatKeysCanBeEncodedIntoALowercasedString() {
  622. // Given
  623. let encoder = URLEncodedFormEncoder(keyEncoding: .lowercased)
  624. let parameters = ["oneTwoThree": "oneTwoThree"]
  625. // When
  626. let result = Result<String, Error> { try encoder.encode(parameters) }
  627. // Then
  628. XCTAssertEqual(result.success, "onetwothree=oneTwoThree")
  629. }
  630. func testThatKeysCanBeEncodedIntoAnUppercasedString() {
  631. // Given
  632. let encoder = URLEncodedFormEncoder(keyEncoding: .uppercased)
  633. let parameters = ["oneTwoThree": "oneTwoThree"]
  634. // When
  635. let result = Result<String, Error> { try encoder.encode(parameters) }
  636. // Then
  637. XCTAssertEqual(result.success, "ONETWOTHREE=oneTwoThree")
  638. }
  639. func testThatKeysCanBeCustomEncoded() {
  640. // Given
  641. let encoder = URLEncodedFormEncoder(keyEncoding: .custom { _ in "A" })
  642. let parameters = ["oneTwoThree": "oneTwoThree"]
  643. // When
  644. let result = Result<String, Error> { try encoder.encode(parameters) }
  645. // Then
  646. XCTAssertEqual(result.success, "A=oneTwoThree")
  647. }
  648. func testThatNilCanBeEncodedByDroppingTheKeyByDefault() {
  649. // Given
  650. let encoder = URLEncodedFormEncoder()
  651. let parameters: [String: String?] = ["a": nil]
  652. // When
  653. let result = Result<String, Error> { try encoder.encode(parameters) }
  654. // Then
  655. XCTAssertEqual(result.success, "")
  656. }
  657. func testThatNilCanBeEncodedAsNull() {
  658. // Given
  659. let encoder = URLEncodedFormEncoder(nilEncoding: .null)
  660. let parameters: [String: String?] = ["a": nil]
  661. // When
  662. let result = Result<String, Error> { try encoder.encode(parameters) }
  663. // Then
  664. XCTAssertEqual(result.success, "a=null")
  665. }
  666. func testThatNilCanBeEncodedByDroppingTheKey() {
  667. // Given
  668. let encoder = URLEncodedFormEncoder(nilEncoding: .dropKey)
  669. let parameters: [String: String?] = ["a": nil]
  670. // When
  671. let result = Result<String, Error> { try encoder.encode(parameters) }
  672. // Then
  673. XCTAssertEqual(result.success, "")
  674. }
  675. func testThatNilCanBeEncodedByDroppingTheValue() {
  676. // Given
  677. let encoder = URLEncodedFormEncoder(nilEncoding: .dropValue)
  678. let parameters: [String: String?] = ["a": nil]
  679. // When
  680. let result = Result<String, Error> { try encoder.encode(parameters) }
  681. // Then
  682. XCTAssertEqual(result.success, "a=")
  683. }
  684. func testThatSpacesCanBeEncodedAsPluses() {
  685. // Given
  686. let encoder = URLEncodedFormEncoder(spaceEncoding: .plusReplaced)
  687. let parameters = ["spaces": "replace with spaces"]
  688. // When
  689. let result = Result<String, Error> { try encoder.encode(parameters) }
  690. // Then
  691. XCTAssertEqual(result.success, "spaces=replace+with+spaces")
  692. }
  693. func testThatEscapedCharactersCanBeCustomized() {
  694. // Given
  695. var allowed = CharacterSet.afURLQueryAllowed
  696. allowed.remove(charactersIn: "?/")
  697. let encoder = URLEncodedFormEncoder(allowedCharacters: allowed)
  698. let parameters = ["allowed": "?/"]
  699. // When
  700. let result = Result<String, Error> { try encoder.encode(parameters) }
  701. // Then
  702. XCTAssertEqual(result.success, "allowed=%3F%2F")
  703. }
  704. func testThatUnreservedCharactersAreNotPercentEscaped() {
  705. // Given
  706. let encoder = URLEncodedFormEncoder()
  707. let parameters = ["lowercase": "abcdefghijklmnopqrstuvwxyz",
  708. "numbers": "0123456789",
  709. "uppercase": "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
  710. // When
  711. let result = Result<String, Error> { try encoder.encode(parameters) }
  712. // Then
  713. let expected = "lowercase=abcdefghijklmnopqrstuvwxyz&numbers=0123456789&uppercase=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  714. XCTAssertEqual(result.success, expected)
  715. }
  716. func testThatReservedCharactersArePercentEscaped() {
  717. // Given
  718. let encoder = URLEncodedFormEncoder()
  719. let generalDelimiters = ":#[]@"
  720. let subDelimiters = "!$&'()*+,;="
  721. let parameters = ["reserved": "\(generalDelimiters)\(subDelimiters)"]
  722. // When
  723. let result = Result<String, Error> { try encoder.encode(parameters) }
  724. // Then
  725. XCTAssertEqual(result.success, "reserved=%3A%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D")
  726. }
  727. func testThatIllegalASCIICharactersArePercentEscaped() {
  728. // Given
  729. let encoder = URLEncodedFormEncoder()
  730. let parameters = ["illegal": " \"#%<>[]\\^`{}|"]
  731. // When
  732. let result = Result<String, Error> { try encoder.encode(parameters) }
  733. // Then
  734. XCTAssertEqual(result.success, "illegal=%20%22%23%25%3C%3E%5B%5D%5C%5E%60%7B%7D%7C")
  735. }
  736. func testThatAmpersandsInKeysAndValuesArePercentEscaped() {
  737. // Given
  738. let encoder = URLEncodedFormEncoder()
  739. let parameters = ["foo&bar": "baz&qux", "foobar": "bazqux"]
  740. // When
  741. let result = Result<String, Error> { try encoder.encode(parameters) }
  742. // Then
  743. XCTAssertEqual(result.success, "foo%26bar=baz%26qux&foobar=bazqux")
  744. }
  745. func testThatQuestionMarksInKeysAndValuesAreNotPercentEscaped() {
  746. // Given
  747. let encoder = URLEncodedFormEncoder()
  748. let parameters = ["?foo?": "?bar?"]
  749. // When
  750. let result = Result<String, Error> { try encoder.encode(parameters) }
  751. // Then
  752. XCTAssertEqual(result.success, "?foo?=?bar?")
  753. }
  754. func testThatSlashesInKeysAndValuesAreNotPercentEscaped() {
  755. // Given
  756. let encoder = URLEncodedFormEncoder()
  757. let parameters = ["foo": "/bar/baz/qux"]
  758. // When
  759. let result = Result<String, Error> { try encoder.encode(parameters) }
  760. // Then
  761. XCTAssertEqual(result.success, "foo=/bar/baz/qux")
  762. }
  763. func testThatSpacesInKeysAndValuesArePercentEscaped() {
  764. // Given
  765. let encoder = URLEncodedFormEncoder()
  766. let parameters = [" foo ": " bar "]
  767. // When
  768. let result = Result<String, Error> { try encoder.encode(parameters) }
  769. // Then
  770. XCTAssertEqual(result.success, "%20foo%20=%20bar%20")
  771. }
  772. func testThatPlusesInKeysAndValuesArePercentEscaped() {
  773. // Given
  774. let encoder = URLEncodedFormEncoder()
  775. let parameters = ["+foo+": "+bar+"]
  776. // When
  777. let result = Result<String, Error> { try encoder.encode(parameters) }
  778. // Then
  779. XCTAssertEqual(result.success, "%2Bfoo%2B=%2Bbar%2B")
  780. }
  781. func testThatPercentsInKeysAndValuesArePercentEscaped() {
  782. // Given
  783. let encoder = URLEncodedFormEncoder()
  784. let parameters = ["percent%": "%25"]
  785. // When
  786. let result = Result<String, Error> { try encoder.encode(parameters) }
  787. // Then
  788. XCTAssertEqual(result.success, "percent%25=%2525")
  789. }
  790. func testThatNonLatinCharactersArePercentEscaped() {
  791. // Given
  792. let encoder = URLEncodedFormEncoder()
  793. let parameters = ["french": "français",
  794. "japanese": "日本語",
  795. "arabic": "العربية",
  796. "emoji": "😃"]
  797. // When
  798. let result = Result<String, Error> { try encoder.encode(parameters) }
  799. // Then
  800. let expectedParameterValues = ["arabic=%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9",
  801. "emoji=%F0%9F%98%83",
  802. "french=fran%C3%A7ais",
  803. "japanese=%E6%97%A5%E6%9C%AC%E8%AA%9E"].joined(separator: "&")
  804. XCTAssertEqual(result.success, expectedParameterValues)
  805. }
  806. func testStringWithThousandsOfChineseCharactersIsPercentEscaped() {
  807. // Given
  808. let encoder = URLEncodedFormEncoder()
  809. let repeatedCount = 2000
  810. let parameters = ["chinese": String(repeating: "一二三四五六七八九十", count: repeatedCount)]
  811. // When
  812. let result = Result<String, Error> { try encoder.encode(parameters) }
  813. // Then
  814. let escaped = String(repeating: "%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",
  815. count: repeatedCount)
  816. let expected = "chinese=\(escaped)"
  817. XCTAssertEqual(result.success, expected)
  818. }
  819. }
  820. final class StaticParameterEncoderInstanceTests: BaseTestCase {
  821. func takeParameterEncoder(_ parameterEncoder: ParameterEncoder) {
  822. _ = parameterEncoder
  823. }
  824. func testThatJSONParameterEncoderCanBeCreatedStaticallyFromProtocol() {
  825. // Given, When, Then
  826. takeParameterEncoder(.json())
  827. }
  828. func testThatURLEncodedFormParameterEncoderCanBeCreatedStaticallyFromProtocol() {
  829. // Given, When, Then
  830. takeParameterEncoder(.urlEncodedForm())
  831. }
  832. }
  833. private struct EncodableStruct: Encodable {
  834. let one = "one"
  835. let two = 2
  836. let three = true
  837. let four = [1, 2, 3]
  838. let five = ["a": "a"]
  839. let six = ["a": ["b": "b"]]
  840. let seven = NestedEncodableStruct()
  841. }
  842. private struct NestedEncodableStruct: Encodable {
  843. let a = "a"
  844. }
  845. private class EncodableSuperclass: Encodable {
  846. let one = "one"
  847. let two = 2
  848. let three = true
  849. }
  850. private final class EncodableSubclass: EncodableSuperclass {
  851. let four = [1, 2, 3]
  852. let five = ["a": "a", "b": "b"]
  853. private enum CodingKeys: String, CodingKey {
  854. case four, five
  855. }
  856. override func encode(to encoder: Encoder) throws {
  857. try super.encode(to: encoder)
  858. var container = encoder.container(keyedBy: CodingKeys.self)
  859. try container.encode(four, forKey: .four)
  860. try container.encode(five, forKey: .five)
  861. }
  862. }
  863. private final class ManuallyEncodableSubclass: EncodableSuperclass {
  864. let four = [1, 2, 3]
  865. let five = ["a": "a", "b": "b"]
  866. private enum CodingKeys: String, CodingKey {
  867. case four, five
  868. }
  869. override func encode(to encoder: Encoder) throws {
  870. var keyedContainer = encoder.container(keyedBy: CodingKeys.self)
  871. try keyedContainer.encode(four, forKey: .four)
  872. try keyedContainer.encode(five, forKey: .five)
  873. let superEncoder = keyedContainer.superEncoder()
  874. var superContainer = superEncoder.container(keyedBy: CodingKeys.self)
  875. try superContainer.encode(one, forKey: .four)
  876. let keyedSuperEncoder = keyedContainer.superEncoder(forKey: .four)
  877. var superKeyedContainer = keyedSuperEncoder.container(keyedBy: CodingKeys.self)
  878. try superKeyedContainer.encode(two, forKey: .five)
  879. var unkeyedContainer = keyedContainer.nestedUnkeyedContainer(forKey: .four)
  880. let unkeyedSuperEncoder = unkeyedContainer.superEncoder()
  881. var keyedUnkeyedSuperContainer = unkeyedSuperEncoder.container(keyedBy: CodingKeys.self)
  882. try keyedUnkeyedSuperContainer.encode(one, forKey: .four)
  883. }
  884. }
  885. private struct ManuallyEncodableStruct: Encodable {
  886. let a = ["string": "string"]
  887. let b = [1, 2, 3]
  888. private enum RootKey: String, CodingKey {
  889. case root
  890. }
  891. private enum TypeKeys: String, CodingKey {
  892. case a, b
  893. }
  894. func encode(to encoder: Encoder) throws {
  895. var container = encoder.container(keyedBy: RootKey.self)
  896. var nestedKeyedContainer = container.nestedContainer(keyedBy: TypeKeys.self, forKey: .root)
  897. try nestedKeyedContainer.encode(a, forKey: .a)
  898. var nestedUnkeyedContainer = container.nestedUnkeyedContainer(forKey: .root)
  899. try nestedUnkeyedContainer.encode(b)
  900. var nestedUnkeyedKeyedContainer = nestedUnkeyedContainer.nestedContainer(keyedBy: TypeKeys.self)
  901. try nestedUnkeyedKeyedContainer.encode(a, forKey: .a)
  902. var nestedUnkeyedUnkeyedContainer = nestedUnkeyedContainer.nestedUnkeyedContainer()
  903. try nestedUnkeyedUnkeyedContainer.encode(b)
  904. }
  905. }
  906. private struct FailingOptionalStruct: Encodable {
  907. enum TestedContainer {
  908. case keyed, unkeyed
  909. }
  910. enum CodingKeys: String, CodingKey { case a }
  911. let testedContainer: TestedContainer
  912. func encode(to encoder: Encoder) throws {
  913. var container = encoder.container(keyedBy: CodingKeys.self)
  914. switch testedContainer {
  915. case .keyed:
  916. var nested = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .a)
  917. try nested.encodeNil(forKey: .a)
  918. case .unkeyed:
  919. var nested = container.nestedUnkeyedContainer(forKey: .a)
  920. try nested.encodeNil()
  921. }
  922. }
  923. }