DownloadTests.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. //
  2. // DownloadTests.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 Foundation
  26. import XCTest
  27. class DownloadInitializationTestCase: BaseTestCase {
  28. func testDownloadClassMethodWithMethodURLAndDestination() {
  29. // Given
  30. let urlString = "https://httpbin.org/"
  31. // When
  32. let request = Alamofire.download(urlString)
  33. // Then
  34. XCTAssertNotNil(request.request)
  35. XCTAssertEqual(request.request?.httpMethod, "GET")
  36. XCTAssertEqual(request.request?.url?.absoluteString, urlString)
  37. XCTAssertNil(request.response)
  38. }
  39. func testDownloadClassMethodWithMethodURLHeadersAndDestination() {
  40. // Given
  41. let urlString = "https://httpbin.org/"
  42. let headers = ["Authorization": "123456"]
  43. // When
  44. let request = Alamofire.download(urlString, headers: headers)
  45. // Then
  46. XCTAssertNotNil(request.request)
  47. XCTAssertEqual(request.request?.httpMethod, "GET")
  48. XCTAssertEqual(request.request?.url?.absoluteString, urlString)
  49. XCTAssertEqual(request.request?.value(forHTTPHeaderField: "Authorization"), "123456")
  50. XCTAssertNil(request.response)
  51. }
  52. }
  53. // MARK: -
  54. class DownloadResponseTestCase: BaseTestCase {
  55. private var randomCachesFileURL: URL {
  56. return testDirectoryURL.appendingPathComponent("\(UUID().uuidString).json")
  57. }
  58. func testDownloadRequest() {
  59. // Given
  60. let fileURL = randomCachesFileURL
  61. let numberOfLines = 100
  62. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  63. let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
  64. let expectation = self.expectation(description: "Download request should download data to file: \(urlString)")
  65. var response: DefaultDownloadResponse?
  66. // When
  67. Alamofire.download(urlString, to: destination)
  68. .response { resp in
  69. response = resp
  70. expectation.fulfill()
  71. }
  72. waitForExpectations(timeout: timeout, handler: nil)
  73. // Then
  74. XCTAssertNotNil(response?.request)
  75. XCTAssertNotNil(response?.response)
  76. XCTAssertNotNil(response?.destinationURL)
  77. XCTAssertNil(response?.resumeData)
  78. XCTAssertNil(response?.error)
  79. if let destinationURL = response?.destinationURL {
  80. XCTAssertTrue(FileManager.default.fileExists(atPath: destinationURL.path))
  81. if let data = try? Data(contentsOf: destinationURL) {
  82. XCTAssertGreaterThan(data.count, 0)
  83. } else {
  84. XCTFail("data should exist for contents of destinationURL")
  85. }
  86. }
  87. }
  88. func testCancelledDownloadRequest() {
  89. // Given
  90. let fileURL = randomCachesFileURL
  91. let numberOfLines = 100
  92. let urlString = "https://httpbin.org/stream/\(numberOfLines)"
  93. let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
  94. let expectation = self.expectation(description: "Cancelled download request should not download data to file")
  95. var response: DefaultDownloadResponse?
  96. // When
  97. Alamofire.download(urlString, to: destination)
  98. .response { resp in
  99. response = resp
  100. expectation.fulfill()
  101. }
  102. .cancel()
  103. waitForExpectations(timeout: timeout, handler: nil)
  104. // Then
  105. XCTAssertNotNil(response?.request)
  106. XCTAssertNil(response?.response)
  107. XCTAssertNil(response?.destinationURL)
  108. XCTAssertNotNil(response?.error)
  109. }
  110. func testDownloadRequestWithProgress() {
  111. // Given
  112. let randomBytes = 4 * 1024 * 1024
  113. let urlString = "https://httpbin.org/bytes/\(randomBytes)"
  114. let expectation = self.expectation(description: "Bytes download progress should be reported: \(urlString)")
  115. var progressValues: [Double] = []
  116. var response: DefaultDownloadResponse?
  117. // When
  118. Alamofire.download(urlString)
  119. .downloadProgress { progress in
  120. progressValues.append(progress.fractionCompleted)
  121. }
  122. .response { resp in
  123. response = resp
  124. expectation.fulfill()
  125. }
  126. waitForExpectations(timeout: timeout, handler: nil)
  127. // Then
  128. XCTAssertNotNil(response?.request)
  129. XCTAssertNotNil(response?.response)
  130. XCTAssertNotNil(response?.temporaryURL)
  131. XCTAssertNil(response?.destinationURL)
  132. XCTAssertNil(response?.resumeData)
  133. XCTAssertNil(response?.error)
  134. var previousProgress: Double = progressValues.first ?? 0.0
  135. for progress in progressValues {
  136. XCTAssertGreaterThanOrEqual(progress, previousProgress)
  137. previousProgress = progress
  138. }
  139. if let lastProgressValue = progressValues.last {
  140. XCTAssertEqual(lastProgressValue, 1.0)
  141. } else {
  142. XCTFail("last item in progressValues should not be nil")
  143. }
  144. }
  145. func testDownloadRequestWithParameters() {
  146. // Given
  147. let urlString = "https://httpbin.org/get"
  148. let parameters = ["foo": "bar"]
  149. let expectation = self.expectation(description: "Download request should download data to file")
  150. var response: DefaultDownloadResponse?
  151. // When
  152. Alamofire.download(urlString, parameters: parameters)
  153. .response { resp in
  154. response = resp
  155. expectation.fulfill()
  156. }
  157. waitForExpectations(timeout: timeout, handler: nil)
  158. // Then
  159. XCTAssertNotNil(response?.request)
  160. XCTAssertNotNil(response?.response)
  161. XCTAssertNotNil(response?.temporaryURL)
  162. XCTAssertNil(response?.destinationURL)
  163. XCTAssertNil(response?.resumeData)
  164. XCTAssertNil(response?.error)
  165. if
  166. let temporaryURL = response?.temporaryURL,
  167. let data = try? Data(contentsOf: temporaryURL),
  168. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: 0)),
  169. let json = jsonObject as? [String: Any],
  170. let args = json["args"] as? [String: String]
  171. {
  172. XCTAssertEqual(args["foo"], "bar")
  173. } else {
  174. XCTFail("args parameter in JSON should not be nil")
  175. }
  176. }
  177. func testDownloadRequestWithHeaders() {
  178. // Given
  179. let fileURL = randomCachesFileURL
  180. let urlString = "https://httpbin.org/get"
  181. let headers = ["Authorization": "123456"]
  182. let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
  183. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  184. var response: DefaultDownloadResponse?
  185. // When
  186. Alamofire.download(urlString, headers: headers, to: destination)
  187. .response { resp in
  188. response = resp
  189. expectation.fulfill()
  190. }
  191. waitForExpectations(timeout: timeout, handler: nil)
  192. // Then
  193. XCTAssertNotNil(response?.request)
  194. XCTAssertNotNil(response?.response)
  195. XCTAssertNotNil(response?.destinationURL)
  196. XCTAssertNil(response?.resumeData)
  197. XCTAssertNil(response?.error)
  198. if
  199. let data = try? Data(contentsOf: fileURL),
  200. let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
  201. let json = jsonObject as? [String: Any],
  202. let headers = json["headers"] as? [String: String]
  203. {
  204. XCTAssertEqual(headers["Authorization"], "123456")
  205. } else {
  206. XCTFail("headers parameter in JSON should not be nil")
  207. }
  208. }
  209. func testThatDownloadingFileAndMovingToDirectoryThatDoesNotExistThrowsError() {
  210. // Given
  211. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  212. let expectation = self.expectation(description: "Download request should download data but fail to move file")
  213. var response: DefaultDownloadResponse?
  214. // When
  215. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  216. .response { resp in
  217. response = resp
  218. expectation.fulfill()
  219. }
  220. waitForExpectations(timeout: timeout, handler: nil)
  221. // Then
  222. XCTAssertNotNil(response?.request)
  223. XCTAssertNotNil(response?.response)
  224. XCTAssertNotNil(response?.temporaryURL)
  225. XCTAssertNotNil(response?.destinationURL)
  226. XCTAssertNil(response?.resumeData)
  227. XCTAssertNotNil(response?.error)
  228. if let error = response?.error as? CocoaError {
  229. XCTAssertEqual(error.code, .fileNoSuchFile)
  230. } else {
  231. XCTFail("error should not be nil")
  232. }
  233. }
  234. func testThatDownloadOptionsCanCreateIntermediateDirectoriesPriorToMovingFile() {
  235. // Given
  236. let fileURL = testDirectoryURL.appendingPathComponent("some/random/folder/test_output.json")
  237. let expectation = self.expectation(description: "Download request should download data to file: \(fileURL)")
  238. var response: DefaultDownloadResponse?
  239. // When
  240. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.createIntermediateDirectories])})
  241. .response { resp in
  242. response = resp
  243. expectation.fulfill()
  244. }
  245. waitForExpectations(timeout: timeout, handler: nil)
  246. // Then
  247. XCTAssertNotNil(response?.request)
  248. XCTAssertNotNil(response?.response)
  249. XCTAssertNotNil(response?.temporaryURL)
  250. XCTAssertNotNil(response?.destinationURL)
  251. XCTAssertNil(response?.resumeData)
  252. XCTAssertNil(response?.error)
  253. }
  254. func testThatDownloadingFileAndMovingToDestinationThatIsOccupiedThrowsError() {
  255. do {
  256. // Given
  257. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  258. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  259. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  260. try "random_data".write(to: fileURL, atomically: true, encoding: .utf8)
  261. let expectation = self.expectation(description: "Download should complete but fail to move file")
  262. var response: DefaultDownloadResponse?
  263. // When
  264. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [])})
  265. .response { resp in
  266. response = resp
  267. expectation.fulfill()
  268. }
  269. waitForExpectations(timeout: timeout, handler: nil)
  270. // Then
  271. XCTAssertTrue(directoryCreated)
  272. XCTAssertNotNil(response?.request)
  273. XCTAssertNotNil(response?.response)
  274. XCTAssertNotNil(response?.temporaryURL)
  275. XCTAssertNotNil(response?.destinationURL)
  276. XCTAssertNil(response?.resumeData)
  277. XCTAssertNotNil(response?.error)
  278. if let error = response?.error as? CocoaError {
  279. XCTAssertEqual(error.code, .fileWriteFileExists)
  280. } else {
  281. XCTFail("error should not be nil")
  282. }
  283. } catch {
  284. XCTFail("Test encountered unexpected error: \(error)")
  285. }
  286. }
  287. func testThatDownloadOptionsCanRemovePreviousFilePriorToMovingFile() {
  288. // Given
  289. let directoryURL = testDirectoryURL.appendingPathComponent("some/random/folder")
  290. let directoryCreated = FileManager.createDirectory(at: directoryURL)
  291. let fileURL = directoryURL.appendingPathComponent("test_output.json")
  292. let expectation = self.expectation(description: "Download should complete and move file to URL: \(fileURL)")
  293. var response: DefaultDownloadResponse?
  294. // When
  295. Alamofire.download("https://httpbin.org/get", to: { _, _ in (fileURL, [.removePreviousFile])})
  296. .response { resp in
  297. response = resp
  298. expectation.fulfill()
  299. }
  300. waitForExpectations(timeout: timeout, handler: nil)
  301. // Then
  302. XCTAssertTrue(directoryCreated)
  303. XCTAssertNotNil(response?.request)
  304. XCTAssertNotNil(response?.response)
  305. XCTAssertNotNil(response?.temporaryURL)
  306. XCTAssertNotNil(response?.destinationURL)
  307. XCTAssertNil(response?.resumeData)
  308. XCTAssertNil(response?.error)
  309. }
  310. }
  311. // MARK: -
  312. class DownloadResumeDataTestCase: BaseTestCase {
  313. let urlString = "https://upload.wikimedia.org/wikipedia/commons/6/69/NASA-HS201427a-HubbleUltraDeepField2014-20140603.jpg"
  314. func testThatCancelledDownloadResponseDataMatchesResumeData() {
  315. // Given
  316. let expectation = self.expectation(description: "Download should be cancelled")
  317. var cancelled = false
  318. var response: DefaultDownloadResponse?
  319. // When
  320. let download = Alamofire.download(urlString)
  321. download.downloadProgress { progress in
  322. guard !cancelled else { return }
  323. if progress.fractionCompleted > 0.1 {
  324. download.cancel()
  325. cancelled = true
  326. }
  327. }
  328. download.response { resp in
  329. response = resp
  330. expectation.fulfill()
  331. }
  332. waitForExpectations(timeout: timeout, handler: nil)
  333. // Then
  334. XCTAssertNotNil(response?.request)
  335. XCTAssertNotNil(response?.response)
  336. XCTAssertNil(response?.destinationURL)
  337. XCTAssertNotNil(response?.error)
  338. XCTAssertNotNil(response?.resumeData)
  339. XCTAssertNotNil(download.resumeData)
  340. XCTAssertEqual(response?.resumeData, download.resumeData)
  341. }
  342. func testThatCancelledDownloadResumeDataIsAvailableWithJSONResponseSerializer() {
  343. // Given
  344. let expectation = self.expectation(description: "Download should be cancelled")
  345. var cancelled = false
  346. var response: DownloadResponse<Any>?
  347. // When
  348. let download = Alamofire.download(urlString)
  349. download.downloadProgress { progress in
  350. guard !cancelled else { return }
  351. if progress.fractionCompleted > 0.1 {
  352. download.cancel()
  353. cancelled = true
  354. }
  355. }
  356. download.responseJSON { resp in
  357. response = resp
  358. expectation.fulfill()
  359. }
  360. waitForExpectations(timeout: timeout, handler: nil)
  361. // Then
  362. XCTAssertNotNil(response?.request)
  363. XCTAssertNotNil(response?.response)
  364. XCTAssertNil(response?.destinationURL)
  365. XCTAssertEqual(response?.result.isFailure, true)
  366. XCTAssertNotNil(response?.result.error)
  367. XCTAssertNotNil(response?.resumeData)
  368. XCTAssertNotNil(download.resumeData)
  369. XCTAssertEqual(response?.resumeData, download.resumeData)
  370. }
  371. func testThatCancelledDownloadCanBeResumedWithResumeData() {
  372. // Given
  373. let expectation1 = self.expectation(description: "Download should be cancelled")
  374. var cancelled = false
  375. var response1: DownloadResponse<Data>?
  376. // When
  377. let download = Alamofire.download(urlString)
  378. download.downloadProgress { progress in
  379. guard !cancelled else { return }
  380. if progress.fractionCompleted > 0.4 {
  381. download.cancel()
  382. cancelled = true
  383. }
  384. }
  385. download.responseData { resp in
  386. response1 = resp
  387. expectation1.fulfill()
  388. }
  389. waitForExpectations(timeout: timeout, handler: nil)
  390. guard let resumeData = download.resumeData else {
  391. XCTFail("resumeData should not be nil")
  392. return
  393. }
  394. let expectation2 = self.expectation(description: "Download should complete")
  395. var progressValues: [Double] = []
  396. var response2: DownloadResponse<Data>?
  397. Alamofire.download(resumingWith: resumeData)
  398. .downloadProgress { progress in
  399. progressValues.append(progress.fractionCompleted)
  400. }
  401. .responseData { resp in
  402. response2 = resp
  403. expectation2.fulfill()
  404. }
  405. waitForExpectations(timeout: timeout, handler: nil)
  406. // Then
  407. XCTAssertNotNil(response1?.request)
  408. XCTAssertNotNil(response1?.response)
  409. XCTAssertNil(response1?.destinationURL)
  410. XCTAssertEqual(response1?.result.isFailure, true)
  411. XCTAssertNotNil(response1?.result.error)
  412. XCTAssertNotNil(response2?.response)
  413. XCTAssertNotNil(response2?.temporaryURL)
  414. XCTAssertNil(response2?.destinationURL)
  415. XCTAssertEqual(response2?.result.isSuccess, true)
  416. XCTAssertNil(response2?.result.error)
  417. progressValues.forEach { XCTAssertGreaterThanOrEqual($0, 0.4) }
  418. }
  419. }
  420. // MARK: -
  421. class DownloadResponseMapTestCase: BaseTestCase {
  422. func testThatMapTransformsSuccessValue() {
  423. // Given
  424. let urlString = "https://httpbin.org/get"
  425. let expectation = self.expectation(description: "request should succeed")
  426. var response: DownloadResponse<String>?
  427. // When
  428. Alamofire.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  429. response = resp.map { json in
  430. // json["args"]["foo"] is "bar": use this invariant to test the map function
  431. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  432. }
  433. expectation.fulfill()
  434. }
  435. waitForExpectations(timeout: timeout, handler: nil)
  436. // Then
  437. XCTAssertNotNil(response?.request)
  438. XCTAssertNotNil(response?.response)
  439. XCTAssertNotNil(response?.temporaryURL)
  440. XCTAssertNil(response?.destinationURL)
  441. XCTAssertNil(response?.resumeData)
  442. XCTAssertNil(response?.error)
  443. XCTAssertEqual(response?.result.value, "bar")
  444. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  445. XCTAssertNotNil(response?.metrics)
  446. }
  447. }
  448. func testThatMapPreservesFailureError() {
  449. // Given
  450. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  451. let expectation = self.expectation(description: "request should fail with 404")
  452. var response: DownloadResponse<String>?
  453. // When
  454. Alamofire.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  455. response = resp.map { _ in "ignored" }
  456. expectation.fulfill()
  457. }
  458. waitForExpectations(timeout: timeout, handler: nil)
  459. // Then
  460. XCTAssertNotNil(response?.request)
  461. XCTAssertNil(response?.response)
  462. XCTAssertNil(response?.temporaryURL)
  463. XCTAssertNil(response?.destinationURL)
  464. XCTAssertNil(response?.resumeData)
  465. XCTAssertNotNil(response?.error)
  466. XCTAssertEqual(response?.result.isFailure, true)
  467. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  468. XCTAssertNotNil(response?.metrics)
  469. }
  470. }
  471. }
  472. // MARK: -
  473. class DownloadResponseFlatMapTestCase: BaseTestCase {
  474. func testThatFlatMapTransformsSuccessValue() {
  475. // Given
  476. let urlString = "https://httpbin.org/get"
  477. let expectation = self.expectation(description: "request should succeed")
  478. var response: DownloadResponse<String>?
  479. // When
  480. Alamofire.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  481. response = resp.flatMap { json in
  482. // json["args"]["foo"] is "bar": use this invariant to test the map function
  483. return ((json as? [String: Any])?["args"] as? [String: Any])?["foo"] as? String ?? "invalid"
  484. }
  485. expectation.fulfill()
  486. }
  487. waitForExpectations(timeout: timeout, handler: nil)
  488. // Then
  489. XCTAssertNotNil(response?.request)
  490. XCTAssertNotNil(response?.response)
  491. XCTAssertNotNil(response?.temporaryURL)
  492. XCTAssertNil(response?.destinationURL)
  493. XCTAssertNil(response?.resumeData)
  494. XCTAssertNil(response?.error)
  495. XCTAssertEqual(response?.result.value, "bar")
  496. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  497. XCTAssertNotNil(response?.metrics)
  498. }
  499. }
  500. func testThatFlatMapCatchesTransformationError() {
  501. // Given
  502. struct TransformError: Error {}
  503. let urlString = "https://httpbin.org/get"
  504. let expectation = self.expectation(description: "request should succeed")
  505. var response: DownloadResponse<String>?
  506. // When
  507. Alamofire.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  508. response = resp.flatMap { json in
  509. throw TransformError()
  510. }
  511. expectation.fulfill()
  512. }
  513. waitForExpectations(timeout: timeout, handler: nil)
  514. // Then
  515. XCTAssertNotNil(response?.request)
  516. XCTAssertNotNil(response?.response)
  517. XCTAssertNotNil(response?.temporaryURL)
  518. XCTAssertNil(response?.destinationURL)
  519. XCTAssertNil(response?.resumeData)
  520. if let error = response?.result.error {
  521. XCTAssertTrue(error is TransformError)
  522. } else {
  523. XCTFail("flatMap should catch the transformation error")
  524. }
  525. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  526. XCTAssertNotNil(response?.metrics)
  527. }
  528. }
  529. func testThatFlatMapPreservesFailureError() {
  530. // Given
  531. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  532. let expectation = self.expectation(description: "request should fail with 404")
  533. var response: DownloadResponse<String>?
  534. // When
  535. Alamofire.download(urlString, parameters: ["foo": "bar"]).responseJSON { resp in
  536. response = resp.flatMap { _ in "ignored" }
  537. expectation.fulfill()
  538. }
  539. waitForExpectations(timeout: timeout, handler: nil)
  540. // Then
  541. XCTAssertNotNil(response?.request)
  542. XCTAssertNil(response?.response)
  543. XCTAssertNil(response?.temporaryURL)
  544. XCTAssertNil(response?.destinationURL)
  545. XCTAssertNil(response?.resumeData)
  546. XCTAssertNotNil(response?.error)
  547. XCTAssertEqual(response?.result.isFailure, true)
  548. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  549. XCTAssertNotNil(response?.metrics)
  550. }
  551. }
  552. }
  553. class DownloadResponseMapErrorTestCase: BaseTestCase {
  554. func testThatMapErrorTransformsFailureValue() {
  555. // Given
  556. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  557. let expectation = self.expectation(description: "request should not succeed")
  558. var response: DownloadResponse<Any>?
  559. // When
  560. Alamofire.download(urlString).responseJSON { resp in
  561. response = resp.mapError { error in
  562. return TestError.error(error: error)
  563. }
  564. expectation.fulfill()
  565. }
  566. waitForExpectations(timeout: timeout, handler: nil)
  567. // Then
  568. XCTAssertNotNil(response?.request)
  569. XCTAssertNil(response?.response)
  570. XCTAssertNil(response?.temporaryURL)
  571. XCTAssertNil(response?.destinationURL)
  572. XCTAssertNil(response?.resumeData)
  573. XCTAssertNotNil(response?.error)
  574. XCTAssertEqual(response?.result.isFailure, true)
  575. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  576. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  577. XCTAssertNotNil(response?.metrics)
  578. }
  579. }
  580. func testThatMapErrorPreservesSuccessValue() {
  581. // Given
  582. let urlString = "https://httpbin.org/get"
  583. let expectation = self.expectation(description: "request should succeed")
  584. var response: DownloadResponse<Data>?
  585. // When
  586. Alamofire.download(urlString).responseData { resp in
  587. response = resp.mapError { TestError.error(error: $0) }
  588. expectation.fulfill()
  589. }
  590. waitForExpectations(timeout: timeout, handler: nil)
  591. // Then
  592. XCTAssertNotNil(response?.request)
  593. XCTAssertNotNil(response?.response)
  594. XCTAssertNotNil(response?.temporaryURL)
  595. XCTAssertNil(response?.destinationURL)
  596. XCTAssertNil(response?.resumeData)
  597. XCTAssertEqual(response?.result.isSuccess, true)
  598. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  599. XCTAssertNotNil(response?.metrics)
  600. }
  601. }
  602. }
  603. // MARK: -
  604. class DownloadResponseFlatMapErrorTestCase: BaseTestCase {
  605. func testThatFlatMapErrorPreservesSuccessValue() {
  606. // Given
  607. let urlString = "https://httpbin.org/get"
  608. let expectation = self.expectation(description: "request should succeed")
  609. var response: DownloadResponse<Data>?
  610. // When
  611. Alamofire.download(urlString).responseData { resp in
  612. response = resp.flatMapError { TestError.error(error: $0) }
  613. expectation.fulfill()
  614. }
  615. waitForExpectations(timeout: timeout, handler: nil)
  616. // Then
  617. XCTAssertNotNil(response?.request)
  618. XCTAssertNotNil(response?.response)
  619. XCTAssertNotNil(response?.temporaryURL)
  620. XCTAssertNil(response?.destinationURL)
  621. XCTAssertNil(response?.resumeData)
  622. XCTAssertNil(response?.error)
  623. XCTAssertEqual(response?.result.isSuccess, true)
  624. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  625. XCTAssertNotNil(response?.metrics)
  626. }
  627. }
  628. func testThatFlatMapErrorCatchesTransformationError() {
  629. // Given
  630. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  631. let expectation = self.expectation(description: "request should fail")
  632. var response: DownloadResponse<Data>?
  633. // When
  634. Alamofire.download(urlString).responseData { resp in
  635. response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }
  636. expectation.fulfill()
  637. }
  638. waitForExpectations(timeout: timeout, handler: nil)
  639. // Then
  640. XCTAssertNotNil(response?.request)
  641. XCTAssertNil(response?.response)
  642. XCTAssertNil(response?.temporaryURL)
  643. XCTAssertNil(response?.destinationURL)
  644. XCTAssertNil(response?.resumeData)
  645. XCTAssertNotNil(response?.error)
  646. XCTAssertEqual(response?.result.isFailure, true)
  647. if let error = response?.result.error {
  648. XCTAssertTrue(error is TransformationError)
  649. } else {
  650. XCTFail("flatMapError should catch the transformation error")
  651. }
  652. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  653. XCTAssertNotNil(response?.metrics)
  654. }
  655. }
  656. func testThatFlatMapErrorTransformsError() {
  657. // Given
  658. let urlString = "https://invalid-url-here.org/this/does/not/exist"
  659. let expectation = self.expectation(description: "request should fail")
  660. var response: DownloadResponse<Data>?
  661. // When
  662. Alamofire.download(urlString).responseData { resp in
  663. response = resp.flatMapError { TestError.error(error: $0) }
  664. expectation.fulfill()
  665. }
  666. waitForExpectations(timeout: timeout, handler: nil)
  667. // Then
  668. XCTAssertNotNil(response?.request)
  669. XCTAssertNil(response?.response)
  670. XCTAssertNil(response?.temporaryURL)
  671. XCTAssertNil(response?.destinationURL)
  672. XCTAssertNil(response?.resumeData)
  673. XCTAssertNotNil(response?.error)
  674. XCTAssertEqual(response?.result.isFailure, true)
  675. guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }
  676. if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {
  677. XCTAssertNotNil(response?.metrics)
  678. }
  679. }
  680. }