ImageViewExtensionTests.swift 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. //
  2. // UIImageViewExtensionTests.swift
  3. // Kingfisher
  4. //
  5. // Created by Wei Wang on 15/4/17.
  6. //
  7. // Copyright (c) 2017 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import XCTest
  27. @testable import Kingfisher
  28. class ImageViewExtensionTests: XCTestCase {
  29. var imageView: ImageView!
  30. override class func setUp() {
  31. super.setUp()
  32. LSNocilla.sharedInstance().start()
  33. }
  34. override class func tearDown() {
  35. super.tearDown()
  36. LSNocilla.sharedInstance().stop()
  37. }
  38. override func setUp() {
  39. super.setUp()
  40. // Put setup code here. This method is called before the invocation of each test method in the class.
  41. imageView = ImageView()
  42. KingfisherManager.shared.downloader = ImageDownloader(name: "testDownloader")
  43. cleanDefaultCache()
  44. }
  45. override func tearDown() {
  46. // Put teardown code here. This method is called after the invocation of each test method in the class.
  47. LSNocilla.sharedInstance().clearStubs()
  48. imageView = nil
  49. cleanDefaultCache()
  50. super.tearDown()
  51. }
  52. func testImageDownloadForImageView() {
  53. let expectation = self.expectation(description: "wait for downloading image")
  54. let URLString = testKeys[0]
  55. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  56. let url = URL(string: URLString)!
  57. var progressBlockIsCalled = false
  58. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  59. progressBlockIsCalled = true
  60. XCTAssertTrue(Thread.isMainThread)
  61. }) { (image, error, cacheType, imageURL) -> () in
  62. expectation.fulfill()
  63. XCTAssert(progressBlockIsCalled, "progressBlock should be called at least once.")
  64. XCTAssert(image != nil, "Downloaded image should exist.")
  65. XCTAssert(image! == testImage, "Downloaded image should be the same as test image.")
  66. XCTAssert(self.imageView.image! == testImage, "Downloaded image should be already set to the image property.")
  67. XCTAssert(self.imageView.kf.webURL == imageURL, "Web URL should equal to the downloaded url.")
  68. XCTAssert(cacheType == .none, "The cache type should be none here. This image was just downloaded.")
  69. XCTAssertTrue(Thread.isMainThread)
  70. }
  71. waitForExpectations(timeout: 5, handler: nil)
  72. }
  73. func testImageDownloadCompletionHandlerRunningOnMainQueue() {
  74. let expectation = self.expectation(description: "wait for downloading image")
  75. let URLString = testKeys[0]
  76. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  77. let url = URL(string: URLString)!
  78. let customQueue = DispatchQueue(label: "com.kingfisher.testQueue")
  79. imageView.kf.setImage(with: url, placeholder: nil, options: [.callbackDispatchQueue(customQueue)], progressBlock: { (receivedSize, totalSize) -> () in
  80. XCTAssertTrue(Thread.isMainThread)
  81. }) { (image, error, cacheType, imageURL) -> () in
  82. XCTAssertTrue(Thread.isMainThread, "The image extension callback should be always in main queue.")
  83. expectation.fulfill()
  84. }
  85. waitForExpectations(timeout: 5, handler: nil)
  86. }
  87. func testImageDownloadWithResourceForImageView() {
  88. let expectation = self.expectation(description: "wait for downloading image")
  89. let URLString = testKeys[0]
  90. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  91. let url = URL(string: URLString)!
  92. let resource = ImageResource(downloadURL: url)
  93. var progressBlockIsCalled = false
  94. cleanDefaultCache()
  95. _ = imageView.kf.setImage(with: resource, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  96. progressBlockIsCalled = true
  97. }) { (image, error, cacheType, imageURL) -> () in
  98. expectation.fulfill()
  99. XCTAssert(progressBlockIsCalled, "progressBlock should be called at least once.")
  100. XCTAssert(image != nil, "Downloaded image should exist.")
  101. XCTAssert(image! == testImage, "Downloaded image should be the same as test image.")
  102. XCTAssert(self.imageView.image! == testImage, "Downloaded image should be already set to the image property.")
  103. XCTAssert(self.imageView.kf.webURL == imageURL, "Web URL should equal to the downloaded url.")
  104. XCTAssert(cacheType == .none, "The cache type should be none here. This image was just downloaded. But now is: \(cacheType)")
  105. }
  106. waitForExpectations(timeout: 5, handler: nil)
  107. }
  108. func testImageDownloadCancelForImageView() {
  109. let expectation = self.expectation(description: "wait for downloading image")
  110. let URLString = testKeys[0]
  111. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  112. let url = URL(string: URLString)!
  113. var progressBlockIsCalled = false
  114. let task = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  115. progressBlockIsCalled = true
  116. }) { (image, error, cacheType, imageURL) -> () in
  117. XCTAssertEqual(error?.code, KingfisherError.downloadCancelledBeforeStarting.rawValue, "The error should be downloadCancelledBeforeStarting")
  118. XCTAssert(progressBlockIsCalled == false, "ProgressBlock should not be called since it is canceled.")
  119. expectation.fulfill()
  120. }
  121. task.cancel()
  122. waitForExpectations(timeout: 5, handler: nil)
  123. }
  124. func testImageDownloadCancelForImageViewAfterRequestStarted() {
  125. let expectation = self.expectation(description: "wait for downloading image")
  126. let URLString = testKeys[0]
  127. let stub = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)?.delay()
  128. let url = URL(string: URLString)!
  129. var progressBlockIsCalled = false
  130. cleanDefaultCache()
  131. let task = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  132. progressBlockIsCalled = true
  133. }) { (image, error, cacheType, imageURL) -> () in
  134. XCTAssertNotNil(error)
  135. XCTAssertEqual(error?.code, NSURLErrorCancelled)
  136. XCTAssert(progressBlockIsCalled == false, "ProgressBlock should not be called since it is canceled.")
  137. expectation.fulfill()
  138. }
  139. delay(0.1) {
  140. task.cancel()
  141. _ = stub!.go()
  142. }
  143. waitForExpectations(timeout: 5, handler: nil)
  144. }
  145. func testImageDownloadCancelPartialTaskBeforeRequest() {
  146. let expectation = self.expectation(description: "wait for downloading image")
  147. let URLString = testKeys[0]
  148. let stub = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)?.delay()
  149. let url = URL(string: URLString)!
  150. let group = DispatchGroup()
  151. group.enter()
  152. let task1 = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  153. }) { (image, error, cacheType, imageURL) -> () in
  154. XCTAssertNil(image)
  155. XCTAssertEqual(error?.code, KingfisherError.downloadCancelledBeforeStarting.rawValue, "The error should be downloadCancelledBeforeStarting")
  156. group.leave()
  157. }
  158. group.enter()
  159. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  160. }) { (image, error, cacheType, imageURL) -> () in
  161. XCTAssertNotNil(image)
  162. group.leave()
  163. }
  164. group.enter()
  165. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  166. }) { (image, error, cacheType, imageURL) -> () in
  167. XCTAssertNotNil(image)
  168. group.leave()
  169. }
  170. task1.cancel()
  171. delay(0.1) { _ = stub!.go() }
  172. group.notify(queue: .main, execute: expectation.fulfill)
  173. waitForExpectations(timeout: 5, handler: nil)
  174. }
  175. func testImageDownloadCancelPartialTaskAfterRequestStarted() {
  176. let expectation = self.expectation(description: "wait for downloading image")
  177. let URLString = testKeys[0]
  178. let stub = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)?.delay()
  179. let url = URL(string: URLString)!
  180. let group = DispatchGroup()
  181. group.enter()
  182. let task1 = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  183. }) { (image, error, cacheType, imageURL) -> () in
  184. XCTAssertNotNil(image)
  185. group.leave()
  186. }
  187. group.enter()
  188. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  189. }) { (image, error, cacheType, imageURL) -> () in
  190. XCTAssertNotNil(image)
  191. group.leave()
  192. }
  193. group.enter()
  194. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  195. }) { (image, error, cacheType, imageURL) -> () in
  196. XCTAssertNotNil(image)
  197. group.leave()
  198. }
  199. delay(0.1) {
  200. task1.cancel()
  201. _ = stub!.go()
  202. }
  203. group.notify(queue: .main, execute: expectation.fulfill)
  204. waitForExpectations(timeout: 5, handler: nil)
  205. }
  206. func testImageDownloadCancelAllTasksAfterRequestStarted() {
  207. let expectation = self.expectation(description: "wait for downloading image")
  208. let URLString = testKeys[0]
  209. let stub = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)?.delay()
  210. let url = URL(string: URLString)!
  211. let group = DispatchGroup()
  212. group.enter()
  213. let task1 = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  214. }) { (image, error, cacheType, imageURL) -> () in
  215. XCTAssertNotNil(error)
  216. XCTAssertEqual(error?.code, NSURLErrorCancelled)
  217. group.leave()
  218. }
  219. group.enter()
  220. let task2 = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  221. }) { (image, error, cacheType, imageURL) -> () in
  222. XCTAssertNotNil(error)
  223. XCTAssertEqual(error?.code, NSURLErrorCancelled)
  224. group.leave()
  225. }
  226. group.enter()
  227. let task3 = imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  228. }) { (image, error, cacheType, imageURL) -> () in
  229. XCTAssertNotNil(error)
  230. XCTAssertEqual(error?.code, NSURLErrorCancelled)
  231. group.leave()
  232. }
  233. delay(0.1) {
  234. task1.cancel()
  235. task2.cancel()
  236. task3.cancel()
  237. _ = stub!.go()
  238. }
  239. group.notify(queue: .main, execute: expectation.fulfill)
  240. waitForExpectations(timeout: 5, handler: nil)
  241. }
  242. func testImageDownloadMultipleCaches() {
  243. let cache1 = ImageCache(name: "cache1")
  244. let cache2 = ImageCache(name: "cache2")
  245. cache1.clearDiskCache()
  246. cache2.clearDiskCache()
  247. let expectation = self.expectation(description: "wait for downloading image")
  248. let URLString = testKeys[0]
  249. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  250. let url = URL(string: URLString)!
  251. imageView.kf.setImage(with: url, placeholder: nil, options: [.targetCache(cache1)], progressBlock: { (receivedSize, totalSize) -> () in
  252. }) { (image, error, cacheType, imageURL) -> () in
  253. XCTAssertTrue(cache1.isImageCached(forKey: URLString).cached, "This image should be cached in cache1.")
  254. XCTAssertFalse(cache2.isImageCached(forKey: URLString).cached, "This image should not be cached in cache2.")
  255. XCTAssertFalse(KingfisherManager.shared.cache.isImageCached(forKey: URLString).cached, "This image should not be cached in default cache.")
  256. self.imageView.kf.setImage(with: url, placeholder: nil, options: [.targetCache(cache2)], progressBlock: { (receivedSize, totalSize) -> () in
  257. }, completionHandler: { (image, error, cacheType, imageURL) -> () in
  258. XCTAssertTrue(cache1.isImageCached(forKey: URLString).cached, "This image should be cached in cache1.")
  259. XCTAssertTrue(cache2.isImageCached(forKey: URLString).cached, "This image should be cached in cache2.")
  260. XCTAssertFalse(KingfisherManager.shared.cache.isImageCached(forKey: URLString).cached, "This image should not be cached in default cache.")
  261. clearCaches([cache1, cache2])
  262. expectation.fulfill()
  263. })
  264. }
  265. waitForExpectations(timeout: 5, handler: { (error) -> Void in
  266. clearCaches([cache1, cache2])
  267. })
  268. }
  269. func testIndicatorViewExisting() {
  270. imageView.kf.indicatorType = .activity
  271. XCTAssertNotNil(imageView.kf.indicator, "The indicator should exist when indicatorType is different than .none")
  272. XCTAssertTrue(imageView.kf.indicator is ActivityIndicator)
  273. imageView.kf.indicatorType = .none
  274. XCTAssertNil(imageView.kf.indicator, "The indicator should be removed when indicatorType is .none")
  275. }
  276. func testActivityIndicatorViewAnimating() {
  277. imageView.kf.indicatorType = .activity
  278. let expectation = self.expectation(description: "wait for downloading image")
  279. let URLString = testKeys[0]
  280. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  281. let url = URL(string: URLString)!
  282. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  283. let indicator = self.imageView.kf.indicator
  284. XCTAssertNotNil(indicator, "The indicator view should exist when showIndicatorWhenLoading is true")
  285. XCTAssertFalse(indicator!.view.isHidden, "The indicator should be shown and animating when loading")
  286. }) { (image, error, cacheType, imageURL) -> () in
  287. let indicator = self.imageView.kf.indicator
  288. XCTAssertTrue(indicator!.view.isHidden, "The indicator should stop and hidden after loading")
  289. expectation.fulfill()
  290. }
  291. waitForExpectations(timeout: 5, handler: nil)
  292. }
  293. func testCanUseImageIndicatorViewAnimating() {
  294. imageView.kf.indicatorType = .image(imageData: testImageData! as Data)
  295. XCTAssertTrue(imageView.kf.indicator is ImageIndicator)
  296. let image = (imageView.kf.indicator?.view as? ImageView)?.image
  297. XCTAssertNotNil(image)
  298. XCTAssertTrue(image!.renderEqual(to: testImage))
  299. let expectation = self.expectation(description: "wait for downloading image")
  300. let URLString = testKeys[0]
  301. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  302. let url = URL(string: URLString)!
  303. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  304. let indicator = self.imageView.kf.indicator
  305. XCTAssertNotNil(indicator, "The indicator view should exist when showIndicatorWhenLoading is true")
  306. XCTAssertFalse(indicator!.view.isHidden, "The indicator should be shown and animating when loading")
  307. }) { (image, error, cacheType, imageURL) -> () in
  308. let indicator = self.imageView.kf.indicator
  309. XCTAssertTrue(indicator!.view.isHidden, "The indicator should stop and hidden after loading")
  310. expectation.fulfill()
  311. }
  312. waitForExpectations(timeout: 5, handler: nil)
  313. }
  314. func testCacnelImageTask() {
  315. let expectation = self.expectation(description: "wait for downloading image")
  316. let URLString = testKeys[0]
  317. let stub = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)?.delay()
  318. let url = URL(string: URLString)!
  319. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  320. XCTFail("Progress block should not be called.")
  321. }) { (image, error, cacheType, imageURL) -> () in
  322. XCTAssertNotNil(error)
  323. XCTAssertEqual(error?.code, NSURLErrorCancelled)
  324. expectation.fulfill()
  325. }
  326. delay(0.1) {
  327. self.imageView.kf.cancelDownloadTask()
  328. _ = stub!.go()
  329. }
  330. waitForExpectations(timeout: 5, handler: nil)
  331. }
  332. func testDownloadForMutipleURLs() {
  333. let expectation = self.expectation(description: "wait for downloading image")
  334. let URLStrings = [testKeys[0], testKeys[1]]
  335. _ = stubRequest("GET", URLStrings[0]).andReturn(200)?.withBody(testImageData)
  336. _ = stubRequest("GET", URLStrings[1]).andReturn(200)?.withBody(testImageData)
  337. let URLs = URLStrings.map{URL(string: $0)!}
  338. let group = DispatchGroup()
  339. group.enter()
  340. imageView.kf.setImage(with: URLs[0], placeholder: nil, options: nil) {
  341. image, error, cacheType, imageURL in
  342. XCTAssertNotNil(image)
  343. XCTAssertEqual(imageURL, URLs[0])
  344. XCTAssertNotEqual(self.imageView.image, image)
  345. group.leave()
  346. }
  347. group.enter()
  348. self.imageView.kf.setImage(with: URLs[1], placeholder: nil, options: nil) {
  349. image, error, cacheType, imageURL in
  350. XCTAssertNotNil(image)
  351. XCTAssertEqual(imageURL, URLs[1])
  352. XCTAssertEqual(self.imageView.image, image)
  353. group.leave()
  354. }
  355. group.notify(queue: .main, execute: expectation.fulfill)
  356. waitForExpectations(timeout: 5, handler: nil)
  357. }
  358. func testSettingNilURL() {
  359. let expectation = self.expectation(description: "wait for downloading image")
  360. let url: URL? = nil
  361. imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedSize, totalSize) -> () in
  362. XCTFail("Progress block should not be called.")
  363. }) { (image, error, cacheType, imageURL) -> () in
  364. XCTAssertNil(image)
  365. XCTAssertNil(error)
  366. XCTAssertEqual(cacheType, CacheType.none)
  367. XCTAssertNil(imageURL)
  368. expectation.fulfill()
  369. }
  370. waitForExpectations(timeout: 5, handler: nil)
  371. }
  372. func testSettingImageWhileKeepingCurrentOne() {
  373. let expectation = self.expectation(description: "wait for downloading image")
  374. let URLString = testKeys[0]
  375. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData)
  376. let url = URL(string: URLString)!
  377. imageView.image = testImage
  378. imageView.kf.setImage(with: url, placeholder: nil, options: nil)
  379. XCTAssertNil(imageView.image)
  380. imageView.image = testImage
  381. imageView.kf.setImage(with: url, placeholder: nil, options: [.keepCurrentImageWhileLoading])
  382. XCTAssertEqual(testImage, imageView.image)
  383. // Wait request finished. Ensure tests timing order.
  384. delay(0.1, block: expectation.fulfill)
  385. waitForExpectations(timeout: 5, handler: nil)
  386. }
  387. func testSetGIFImageOnlyFirstFrameThenFullFrames() {
  388. let expectation = self.expectation(description: "wait for downloading image")
  389. let URLString = testKeys[0]
  390. _ = stubRequest("GET", URLString).andReturn(200)?.withBody(NSData(data: testImageGIFData))
  391. let url = URL(string: URLString)!
  392. func loadFullGIFImage() {
  393. var progressBlockIsCalled = false
  394. ImageCache.default.clearMemoryCache()
  395. imageView.kf.setImage(with: url, placeholder: nil, options: [], progressBlock: { (receivedSize, totalSize) -> () in
  396. progressBlockIsCalled = true
  397. XCTAssertTrue(Thread.isMainThread)
  398. }) { (image, error, cacheType, imageURL) -> () in
  399. XCTAssertFalse(progressBlockIsCalled, "progressBlock should not be called since the image is cached.")
  400. XCTAssertNotNil(image, "Downloaded image should exist.")
  401. XCTAssertNotNil(image!.kf.images, "images should exist since we load full GIF.")
  402. XCTAssertEqual(image!.kf.images?.count, 8, "There are 8 frames in total.")
  403. XCTAssert(cacheType == .disk, "We should find it cached in disk")
  404. XCTAssertTrue(Thread.isMainThread)
  405. expectation.fulfill()
  406. }
  407. }
  408. var progressBlockIsCalled = false
  409. imageView.kf.setImage(with: url, placeholder: nil, options: [.onlyLoadFirstFrame], progressBlock: { (receivedSize, totalSize) -> () in
  410. progressBlockIsCalled = true
  411. XCTAssertTrue(Thread.isMainThread)
  412. }) { (image, error, cacheType, imageURL) -> () in
  413. XCTAssertTrue(progressBlockIsCalled, "progressBlock should be called at least once.")
  414. XCTAssertNotNil(image, "Downloaded image should exist.")
  415. XCTAssertNil(image!.kf.images, "images should not exist since we set only load first frame.")
  416. XCTAssert(cacheType == .none, "The cache type should be none here. This image was just downloaded.")
  417. XCTAssertTrue(Thread.isMainThread)
  418. loadFullGIFImage()
  419. }
  420. waitForExpectations(timeout: 5, handler: nil)
  421. }
  422. // https://github.com/onevcat/Kingfisher/issues/665
  423. // The completion handler should be called even when the image view loading url gets changed.
  424. func testIssue665() {
  425. let expectation = self.expectation(description: "wait for downloading image")
  426. let URLString1 = testKeys[0]
  427. let URLString2 = testKeys[1]
  428. _ = stubRequest("GET", URLString1).andReturn(200)?.withBody(testImageData)
  429. _ = stubRequest("GET", URLString2).andReturn(200)?.withBody(testImageData)
  430. let url1 = URL(string: URLString1)!
  431. let url2 = URL(string: URLString2)!
  432. let group = DispatchGroup()
  433. group.enter()
  434. imageView.kf.setImage(with: url1) { (image, _, cacheType, url) in
  435. group.leave()
  436. }
  437. group.enter()
  438. imageView.kf.setImage(with: url2) { (image, _, cacheType, url) in
  439. group.leave()
  440. }
  441. group.notify(queue: .main, execute: expectation.fulfill)
  442. waitForExpectations(timeout: 1, handler: nil)
  443. }
  444. }