ValidationTests.swift 28 KB

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