ValidationTests.swift 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. //
  2. // ValidationTests.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. @testable import Alamofire
  25. import Foundation
  26. import XCTest
  27. final class StatusCodeValidationTestCase: BaseTestCase {
  28. func testThatValidationForRequestWithAcceptableStatusCodeResponseSucceeds() {
  29. // Given
  30. let endpoint = Endpoint.status(200)
  31. let expectation1 = expectation(description: "request should return 200 status code")
  32. let expectation2 = expectation(description: "download should return 200 status code")
  33. var requestError: AFError?
  34. var downloadError: AFError?
  35. // When
  36. AF.request(endpoint)
  37. .validate(statusCode: 200..<300)
  38. .response { resp in
  39. requestError = resp.error
  40. expectation1.fulfill()
  41. }
  42. AF.download(endpoint)
  43. .validate(statusCode: 200..<300)
  44. .response { resp in
  45. downloadError = resp.error
  46. expectation2.fulfill()
  47. }
  48. waitForExpectations(timeout: timeout)
  49. // Then
  50. XCTAssertNil(requestError)
  51. XCTAssertNil(downloadError)
  52. }
  53. func testThatValidationForRequestWithUnacceptableStatusCodeResponseFails() {
  54. // Given
  55. let endpoint = Endpoint.status(404)
  56. let expectation1 = expectation(description: "request should return 404 status code")
  57. let expectation2 = expectation(description: "download should return 404 status code")
  58. var requestError: AFError?
  59. var downloadError: AFError?
  60. // When
  61. AF.request(endpoint)
  62. .validate(statusCode: [200])
  63. .response { resp in
  64. requestError = resp.error
  65. expectation1.fulfill()
  66. }
  67. AF.download(endpoint)
  68. .validate(statusCode: [200])
  69. .response { resp in
  70. downloadError = resp.error
  71. expectation2.fulfill()
  72. }
  73. waitForExpectations(timeout: timeout)
  74. // Then
  75. XCTAssertNotNil(requestError)
  76. XCTAssertNotNil(downloadError)
  77. for error in [requestError, downloadError] {
  78. XCTAssertEqual(error?.isUnacceptableStatusCode, true)
  79. XCTAssertEqual(error?.responseCode, 404)
  80. }
  81. }
  82. func testThatValidationForRequestWithNoAcceptableStatusCodesFails() {
  83. // Given
  84. let endpoint = Endpoint.status(201)
  85. let expectation1 = expectation(description: "request should return 201 status code")
  86. let expectation2 = expectation(description: "download should return 201 status code")
  87. var requestError: AFError?
  88. var downloadError: AFError?
  89. // When
  90. AF.request(endpoint)
  91. .validate(statusCode: [])
  92. .response { resp in
  93. requestError = resp.error
  94. expectation1.fulfill()
  95. }
  96. AF.download(endpoint)
  97. .validate(statusCode: [])
  98. .response { resp in
  99. downloadError = resp.error
  100. expectation2.fulfill()
  101. }
  102. waitForExpectations(timeout: timeout)
  103. // Then
  104. XCTAssertNotNil(requestError)
  105. XCTAssertNotNil(downloadError)
  106. for error in [requestError, downloadError] {
  107. XCTAssertEqual(error?.isUnacceptableStatusCode, true)
  108. XCTAssertEqual(error?.responseCode, 201)
  109. }
  110. }
  111. }
  112. // MARK: -
  113. final class ContentTypeValidationTestCase: BaseTestCase {
  114. func testThatValidationForRequestWithAcceptableContentTypeResponseSucceeds() {
  115. // Given
  116. let endpoint = Endpoint.ip
  117. let expectation1 = expectation(description: "request should succeed and return ip")
  118. let expectation2 = expectation(description: "download should succeed and return ip")
  119. var requestError: AFError?
  120. var downloadError: AFError?
  121. // When
  122. AF.request(endpoint)
  123. .validate(contentType: ["application/json"])
  124. .validate(contentType: ["application/json; charset=utf-8"])
  125. .validate(contentType: ["application/json; q=0.8; charset=utf-8"])
  126. .response { resp in
  127. requestError = resp.error
  128. expectation1.fulfill()
  129. }
  130. AF.download(endpoint)
  131. .validate(contentType: ["application/json"])
  132. .validate(contentType: ["application/json; charset=utf-8"])
  133. .validate(contentType: ["application/json; q=0.8; charset=utf-8"])
  134. .response { resp in
  135. downloadError = resp.error
  136. expectation2.fulfill()
  137. }
  138. waitForExpectations(timeout: timeout)
  139. // Then
  140. XCTAssertNil(requestError)
  141. XCTAssertNil(downloadError)
  142. }
  143. func testThatValidationForRequestWithAcceptableWildcardContentTypeResponseSucceeds() {
  144. // Given
  145. let endpoint = Endpoint.ip
  146. let expectation1 = expectation(description: "request should succeed and return ip")
  147. let expectation2 = expectation(description: "download should succeed and return ip")
  148. var requestError: AFError?
  149. var downloadError: AFError?
  150. // When
  151. AF.request(endpoint)
  152. .validate(contentType: ["*/*"])
  153. .validate(contentType: ["application/*"])
  154. .validate(contentType: ["*/json"])
  155. .response { resp in
  156. requestError = resp.error
  157. expectation1.fulfill()
  158. }
  159. AF.download(endpoint)
  160. .validate(contentType: ["*/*"])
  161. .validate(contentType: ["application/*"])
  162. .validate(contentType: ["*/json"])
  163. .response { resp in
  164. downloadError = resp.error
  165. expectation2.fulfill()
  166. }
  167. waitForExpectations(timeout: timeout)
  168. // Then
  169. XCTAssertNil(requestError)
  170. XCTAssertNil(downloadError)
  171. }
  172. func testThatValidationForRequestWithUnacceptableContentTypeResponseFails() {
  173. // Given
  174. let endpoint = Endpoint.xml
  175. let expectation1 = expectation(description: "request should succeed and return xml")
  176. let expectation2 = expectation(description: "download should succeed and return xml")
  177. var requestError: AFError?
  178. var downloadError: AFError?
  179. // When
  180. AF.request(endpoint)
  181. .validate(contentType: ["application/octet-stream"])
  182. .response { resp in
  183. requestError = resp.error
  184. expectation1.fulfill()
  185. }
  186. AF.download(endpoint)
  187. .validate(contentType: ["application/octet-stream"])
  188. .response { resp in
  189. downloadError = resp.error
  190. expectation2.fulfill()
  191. }
  192. waitForExpectations(timeout: timeout)
  193. // Then
  194. XCTAssertNotNil(requestError)
  195. XCTAssertNotNil(downloadError)
  196. for error in [requestError, downloadError] {
  197. XCTAssertEqual(error?.isUnacceptableContentType, true)
  198. XCTAssertEqual(error?.responseContentType, "application/xml")
  199. XCTAssertEqual(error?.acceptableContentTypes?.first, "application/octet-stream")
  200. }
  201. }
  202. func testThatContentTypeValidationFailureSortsPossibleContentTypes() {
  203. // Given
  204. let endpoint = Endpoint.xml
  205. let requestDidCompleteExpectation = expectation(description: "request should succeed and return xml")
  206. let downloadDidCompleteExpectation = expectation(description: "download should succeed and return xml")
  207. var requestError: AFError?
  208. var downloadError: AFError?
  209. let acceptableContentTypes = [ // Sorted in a random order, not alphabetically
  210. "application/octet-stream",
  211. "image/gif",
  212. "image/x-xbitmap",
  213. "image/tiff",
  214. "image/jpg",
  215. "image/x-bmp",
  216. "image/jpeg",
  217. "image/x-icon",
  218. "image/jp2",
  219. "image/png",
  220. "image/ico",
  221. "image/bmp",
  222. "image/x-ms-bmp",
  223. "image/x-win-bitmap"
  224. ]
  225. // When
  226. AF.request(endpoint)
  227. .validate(contentType: acceptableContentTypes)
  228. .response { resp in
  229. requestError = resp.error
  230. requestDidCompleteExpectation.fulfill()
  231. }
  232. AF.download(endpoint)
  233. .validate(contentType: acceptableContentTypes)
  234. .response { resp in
  235. downloadError = resp.error
  236. downloadDidCompleteExpectation.fulfill()
  237. }
  238. waitForExpectations(timeout: timeout)
  239. // Then
  240. XCTAssertNotNil(requestError)
  241. XCTAssertNotNil(downloadError)
  242. let expectedAcceptableContentTypes = [ // Sorted in a specific order, alphabetically
  243. "application/octet-stream",
  244. "image/bmp",
  245. "image/gif",
  246. "image/ico",
  247. "image/jp2",
  248. "image/jpeg",
  249. "image/jpg",
  250. "image/png",
  251. "image/tiff",
  252. "image/x-bmp",
  253. "image/x-icon",
  254. "image/x-ms-bmp",
  255. "image/x-win-bitmap",
  256. "image/x-xbitmap"
  257. ]
  258. for error in [requestError, downloadError] {
  259. XCTAssertEqual(error?.isUnacceptableContentType, true)
  260. XCTAssertEqual(error?.responseContentType, "application/xml")
  261. XCTAssertEqual(error?.acceptableContentTypes, expectedAcceptableContentTypes)
  262. }
  263. }
  264. func testThatValidationForRequestWithNoAcceptableContentTypeResponseFails() {
  265. // Given
  266. let endpoint = Endpoint.xml
  267. let expectation1 = expectation(description: "request should succeed and return xml")
  268. let expectation2 = expectation(description: "download should succeed and return xml")
  269. var requestError: AFError?
  270. var downloadError: AFError?
  271. // When
  272. AF.request(endpoint)
  273. .validate(contentType: [])
  274. .response { resp in
  275. requestError = resp.error
  276. expectation1.fulfill()
  277. }
  278. AF.download(endpoint)
  279. .validate(contentType: [])
  280. .response { resp in
  281. downloadError = resp.error
  282. expectation2.fulfill()
  283. }
  284. waitForExpectations(timeout: timeout)
  285. // Then
  286. XCTAssertNotNil(requestError)
  287. XCTAssertNotNil(downloadError)
  288. for error in [requestError, downloadError] {
  289. XCTAssertEqual(error?.isUnacceptableContentType, true)
  290. XCTAssertEqual(error?.responseContentType, "application/xml")
  291. XCTAssertEqual(error?.acceptableContentTypes?.isEmpty, true)
  292. }
  293. }
  294. func testThatValidationForRequestWithNoAcceptableContentTypeResponseSucceedsWhenNoDataIsReturned() {
  295. // Given
  296. let endpoint = Endpoint.status(204)
  297. let expectation1 = expectation(description: "request should succeed and return no data")
  298. let expectation2 = expectation(description: "download should succeed and return no data")
  299. var requestError: AFError?
  300. var downloadError: AFError?
  301. // When
  302. AF.request(endpoint)
  303. .validate(contentType: [])
  304. .response { resp in
  305. requestError = resp.error
  306. expectation1.fulfill()
  307. }
  308. AF.download(endpoint)
  309. .validate(contentType: [])
  310. .response { resp in
  311. downloadError = resp.error
  312. expectation2.fulfill()
  313. }
  314. waitForExpectations(timeout: timeout)
  315. // Then
  316. XCTAssertNil(requestError)
  317. XCTAssertNil(downloadError)
  318. }
  319. }
  320. // MARK: -
  321. final class MultipleValidationTestCase: BaseTestCase {
  322. func testThatValidationForRequestWithAcceptableStatusCodeAndContentTypeResponseSucceeds() {
  323. // Given
  324. let endpoint = Endpoint.ip
  325. let expectation1 = expectation(description: "request should succeed and return ip")
  326. let expectation2 = expectation(description: "request should succeed and return ip")
  327. var requestError: AFError?
  328. var downloadError: AFError?
  329. // When
  330. AF.request(endpoint)
  331. .validate(statusCode: 200..<300)
  332. .validate(contentType: ["application/json"])
  333. .response { resp in
  334. requestError = resp.error
  335. expectation1.fulfill()
  336. }
  337. AF.download(endpoint)
  338. .validate(statusCode: 200..<300)
  339. .validate(contentType: ["application/json"])
  340. .response { resp in
  341. downloadError = resp.error
  342. expectation2.fulfill()
  343. }
  344. waitForExpectations(timeout: timeout)
  345. // Then
  346. XCTAssertNil(requestError)
  347. XCTAssertNil(downloadError)
  348. }
  349. func testThatValidationForRequestWithUnacceptableStatusCodeAndContentTypeResponseFailsWithStatusCodeError() {
  350. // Given
  351. let endpoint = Endpoint.xml
  352. let expectation1 = expectation(description: "request should succeed and return xml")
  353. let expectation2 = expectation(description: "download should succeed and return xml")
  354. var requestError: AFError?
  355. var downloadError: AFError?
  356. // When
  357. AF.request(endpoint)
  358. .validate(statusCode: 400..<600)
  359. .validate(contentType: ["application/octet-stream"])
  360. .response { resp in
  361. requestError = resp.error
  362. expectation1.fulfill()
  363. }
  364. AF.download(endpoint)
  365. .validate(statusCode: 400..<600)
  366. .validate(contentType: ["application/octet-stream"])
  367. .response { resp in
  368. downloadError = resp.error
  369. expectation2.fulfill()
  370. }
  371. waitForExpectations(timeout: timeout)
  372. // Then
  373. XCTAssertNotNil(requestError)
  374. XCTAssertNotNil(downloadError)
  375. for error in [requestError, downloadError] {
  376. XCTAssertEqual(error?.isUnacceptableStatusCode, true)
  377. XCTAssertEqual(error?.responseCode, 200)
  378. }
  379. }
  380. func testThatValidationForRequestWithUnacceptableStatusCodeAndContentTypeResponseFailsWithContentTypeError() {
  381. // Given
  382. let endpoint = Endpoint.xml
  383. let expectation1 = expectation(description: "request should succeed and return xml")
  384. let expectation2 = expectation(description: "download should succeed and return xml")
  385. var requestError: AFError?
  386. var downloadError: AFError?
  387. // When
  388. AF.request(endpoint)
  389. .validate(contentType: ["application/octet-stream"])
  390. .validate(statusCode: 400..<600)
  391. .response { resp in
  392. requestError = resp.error
  393. expectation1.fulfill()
  394. }
  395. AF.download(endpoint)
  396. .validate(contentType: ["application/octet-stream"])
  397. .validate(statusCode: 400..<600)
  398. .response { resp in
  399. downloadError = resp.error
  400. expectation2.fulfill()
  401. }
  402. waitForExpectations(timeout: timeout)
  403. // Then
  404. XCTAssertNotNil(requestError)
  405. XCTAssertNotNil(downloadError)
  406. for error in [requestError, downloadError] {
  407. XCTAssertEqual(error?.isUnacceptableContentType, true)
  408. XCTAssertEqual(error?.responseContentType, "application/xml")
  409. XCTAssertEqual(error?.acceptableContentTypes?.first, "application/octet-stream")
  410. }
  411. }
  412. }
  413. // MARK: -
  414. final class AutomaticValidationTestCase: BaseTestCase {
  415. func testThatValidationForRequestWithAcceptableStatusCodeAndContentTypeResponseSucceeds() {
  416. // Given
  417. let urlRequest = Endpoint.ip.modifying(\.headers, to: [.accept("application/json")])
  418. let expectation1 = expectation(description: "request should succeed and return ip")
  419. let expectation2 = expectation(description: "download should succeed and return ip")
  420. var requestError: AFError?
  421. var downloadError: AFError?
  422. // When
  423. AF.request(urlRequest).validate().response { resp in
  424. requestError = resp.error
  425. expectation1.fulfill()
  426. }
  427. AF.download(urlRequest).validate().response { resp in
  428. downloadError = resp.error
  429. expectation2.fulfill()
  430. }
  431. waitForExpectations(timeout: timeout)
  432. // Then
  433. XCTAssertNil(requestError)
  434. XCTAssertNil(downloadError)
  435. }
  436. func testThatValidationForRequestWithUnacceptableStatusCodeResponseFails() {
  437. // Given
  438. let request = Endpoint.status(404)
  439. let expectation1 = expectation(description: "request should return 404 status code")
  440. let expectation2 = expectation(description: "download should return 404 status code")
  441. var requestError: AFError?
  442. var downloadError: AFError?
  443. // When
  444. AF.request(request)
  445. .validate()
  446. .response { resp in
  447. requestError = resp.error
  448. expectation1.fulfill()
  449. }
  450. AF.download(request)
  451. .validate()
  452. .response { resp in
  453. downloadError = resp.error
  454. expectation2.fulfill()
  455. }
  456. waitForExpectations(timeout: timeout)
  457. // Then
  458. XCTAssertNotNil(requestError)
  459. XCTAssertNotNil(downloadError)
  460. for error in [requestError, downloadError] {
  461. XCTAssertEqual(error?.isUnacceptableStatusCode, true)
  462. XCTAssertEqual(error?.responseCode, 404)
  463. }
  464. }
  465. func testThatValidationForRequestWithAcceptableWildcardContentTypeResponseSucceeds() {
  466. // Given
  467. let urlRequest = Endpoint.ip.modifying(\.headers, to: [.accept("application/*")])
  468. let expectation1 = expectation(description: "request should succeed and return ip")
  469. let expectation2 = expectation(description: "download should succeed and return ip")
  470. var requestError: AFError?
  471. var downloadError: AFError?
  472. // When
  473. AF.request(urlRequest).validate().response { resp in
  474. requestError = resp.error
  475. expectation1.fulfill()
  476. }
  477. AF.download(urlRequest).validate().response { resp in
  478. downloadError = resp.error
  479. expectation2.fulfill()
  480. }
  481. waitForExpectations(timeout: timeout)
  482. // Then
  483. XCTAssertNil(requestError)
  484. XCTAssertNil(downloadError)
  485. }
  486. func testThatValidationForRequestWithAcceptableComplexContentTypeResponseSucceeds() {
  487. // Given
  488. var urlRequest = Endpoint.xml.urlRequest
  489. let headerValue = "text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8,*/*;q=0.5"
  490. urlRequest.headers["Accept"] = headerValue
  491. let expectation1 = expectation(description: "request should succeed and return xml")
  492. let expectation2 = expectation(description: "request should succeed and return xml")
  493. var requestError: AFError?
  494. var downloadError: AFError?
  495. // When
  496. AF.request(urlRequest).validate().response { resp in
  497. requestError = resp.error
  498. expectation1.fulfill()
  499. }
  500. AF.download(urlRequest).validate().response { resp in
  501. downloadError = resp.error
  502. expectation2.fulfill()
  503. }
  504. waitForExpectations(timeout: timeout)
  505. // Then
  506. XCTAssertNil(requestError)
  507. XCTAssertNil(downloadError)
  508. }
  509. func testThatValidationForRequestWithUnacceptableContentTypeResponseFails() {
  510. // Given
  511. let urlRequest = Endpoint.xml.modifying(\.headers, to: [.accept("application/json")])
  512. let expectation1 = expectation(description: "request should succeed and return xml")
  513. let expectation2 = expectation(description: "download should succeed and return xml")
  514. var requestError: AFError?
  515. var downloadError: AFError?
  516. // When
  517. AF.request(urlRequest).validate().response { resp in
  518. requestError = resp.error
  519. expectation1.fulfill()
  520. }
  521. AF.download(urlRequest).validate().response { resp in
  522. downloadError = resp.error
  523. expectation2.fulfill()
  524. }
  525. waitForExpectations(timeout: timeout)
  526. // Then
  527. XCTAssertNotNil(requestError)
  528. XCTAssertNotNil(downloadError)
  529. for error in [requestError, downloadError] {
  530. XCTAssertEqual(error?.isUnacceptableContentType, true)
  531. XCTAssertEqual(error?.responseContentType, "application/xml")
  532. XCTAssertEqual(error?.acceptableContentTypes?.first, "application/json")
  533. }
  534. }
  535. }
  536. // MARK: -
  537. private enum ValidationError: Error {
  538. case missingData, missingFile, fileReadFailed
  539. }
  540. extension DataRequest {
  541. func validateDataExists() -> Self {
  542. validate { _, _, data in
  543. guard data != nil else { return .failure(ValidationError.missingData) }
  544. return .success(())
  545. }
  546. }
  547. func validate(with error: Error) -> Self {
  548. validate { _, _, _ in .failure(error) }
  549. }
  550. }
  551. extension DownloadRequest {
  552. func validateDataExists() -> Self {
  553. validate { [unowned self] _, _, _ in
  554. guard let validFileURL = fileURL else { return .failure(ValidationError.missingFile) }
  555. do {
  556. _ = try Data(contentsOf: validFileURL)
  557. return .success(())
  558. } catch {
  559. return .failure(ValidationError.fileReadFailed)
  560. }
  561. }
  562. }
  563. func validate(with error: Error) -> Self {
  564. validate { _, _, _ in .failure(error) }
  565. }
  566. }
  567. // MARK: -
  568. final class CustomValidationTestCase: BaseTestCase {
  569. func testThatCustomValidationClosureHasAccessToServerResponseData() {
  570. // Given
  571. let endpoint = Endpoint()
  572. let expectation1 = expectation(description: "request should return 200 status code")
  573. let expectation2 = expectation(description: "download should return 200 status code")
  574. var requestError: AFError?
  575. var downloadError: AFError?
  576. // When
  577. AF.request(endpoint)
  578. .validate { _, _, data in
  579. guard data != nil else { return .failure(ValidationError.missingData) }
  580. return .success(())
  581. }
  582. .response { resp in
  583. requestError = resp.error
  584. expectation1.fulfill()
  585. }
  586. AF.download(endpoint)
  587. .validate { _, _, fileURL in
  588. guard let fileURL else { return .failure(ValidationError.missingFile) }
  589. do {
  590. _ = try Data(contentsOf: fileURL)
  591. return .success(())
  592. } catch {
  593. return .failure(ValidationError.fileReadFailed)
  594. }
  595. }
  596. .response { resp in
  597. downloadError = resp.error
  598. expectation2.fulfill()
  599. }
  600. waitForExpectations(timeout: timeout)
  601. // Then
  602. XCTAssertNil(requestError)
  603. XCTAssertNil(downloadError)
  604. }
  605. func testThatCustomValidationCanThrowCustomError() {
  606. // Given
  607. let endpoint = Endpoint()
  608. let expectation1 = expectation(description: "request should return 200 status code")
  609. let expectation2 = expectation(description: "download should return 200 status code")
  610. var requestError: AFError?
  611. var downloadError: AFError?
  612. // When
  613. AF.request(endpoint)
  614. .validate { _, _, _ in .failure(ValidationError.missingData) }
  615. .validate { _, _, _ in .failure(ValidationError.missingFile) } // should be ignored
  616. .response { resp in
  617. requestError = resp.error
  618. expectation1.fulfill()
  619. }
  620. AF.download(endpoint)
  621. .validate { _, _, _ in .failure(ValidationError.missingFile) }
  622. .validate { _, _, _ in .failure(ValidationError.fileReadFailed) } // should be ignored
  623. .response { resp in
  624. downloadError = resp.error
  625. expectation2.fulfill()
  626. }
  627. waitForExpectations(timeout: timeout)
  628. // Then
  629. XCTAssertEqual(requestError?.asAFError?.underlyingError as? ValidationError, .missingData)
  630. XCTAssertEqual(downloadError?.asAFError?.underlyingError as? ValidationError, .missingFile)
  631. }
  632. func testThatValidationExtensionHasAccessToServerResponseData() {
  633. // Given
  634. let endpoint = Endpoint()
  635. let expectation1 = expectation(description: "request should return 200 status code")
  636. let expectation2 = expectation(description: "download should return 200 status code")
  637. var requestError: AFError?
  638. var downloadError: AFError?
  639. // When
  640. AF.request(endpoint)
  641. .validateDataExists()
  642. .response { resp in
  643. requestError = resp.error
  644. expectation1.fulfill()
  645. }
  646. AF.download(endpoint)
  647. .validateDataExists()
  648. .response { resp in
  649. downloadError = resp.error
  650. expectation2.fulfill()
  651. }
  652. waitForExpectations(timeout: timeout)
  653. // Then
  654. XCTAssertNil(requestError)
  655. XCTAssertNil(downloadError)
  656. }
  657. func testThatValidationExtensionCanThrowCustomError() {
  658. // Given
  659. let endpoint = Endpoint()
  660. let expectation1 = expectation(description: "request should return 200 status code")
  661. let expectation2 = expectation(description: "download should return 200 status code")
  662. var requestError: AFError?
  663. var downloadError: AFError?
  664. // When
  665. AF.request(endpoint)
  666. .validate(with: ValidationError.missingData)
  667. .validate(with: ValidationError.missingFile) // should be ignored
  668. .response { resp in
  669. requestError = resp.error
  670. expectation1.fulfill()
  671. }
  672. AF.download(endpoint)
  673. .validate(with: ValidationError.missingFile)
  674. .validate(with: ValidationError.fileReadFailed) // should be ignored
  675. .response { resp in
  676. downloadError = resp.error
  677. expectation2.fulfill()
  678. }
  679. waitForExpectations(timeout: timeout)
  680. // Then
  681. XCTAssertEqual(requestError?.asAFError?.underlyingError as? ValidationError, .missingData)
  682. XCTAssertEqual(downloadError?.asAFError?.underlyingError as? ValidationError, .missingFile)
  683. }
  684. }