ParameterEncoderTests.swift 37 KB

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