Bläddra i källkod

Minor refactoring and more tests

onevcat 1 år sedan
förälder
incheckning
253226efdf

+ 15 - 12
Sources/General/KingfisherManager+LivePhoto.swift

@@ -90,11 +90,7 @@ extension KingfisherManager {
         
         let targetCache = checkedOptions.targetCache ?? cache
         let fileURLs = source.resources.map {
-            targetCache.possibleCacheFileURLIfOnDisk(
-                forKey: $0.cacheKey,
-                processorIdentifier: checkedOptions.processor.identifier,
-                referenceFileType: $0.referenceFileType
-            )
+            targetCache.possibleCacheFileURLIfOnDisk(resource: $0, options: checkedOptions)
         }
         if fileURLs.contains(nil) {
             // not all file done. throw error
@@ -116,13 +112,8 @@ extension KingfisherManager {
         } else {
             let targetCache = options.targetCache ?? cache
             missingResources = source.resources.reduce([], { r, resource in
-                let cacheKey = resource.cacheKey
-                let existingCachedFileURL = targetCache.possibleCacheFileURLIfOnDisk(
-                    forKey: cacheKey,
-                    processorIdentifier: options.processor.identifier,
-                    referenceFileType: resource.referenceFileType
-                )
-                if existingCachedFileURL == nil {
+                let cachedFileURL = targetCache.possibleCacheFileURLIfOnDisk(resource: resource, options: options)
+                if cachedFileURL == nil {
                     return r + [resource]
                 } else {
                     return r
@@ -171,6 +162,18 @@ extension KingfisherManager {
 }
 
 extension ImageCache {
+    
+    func possibleCacheFileURLIfOnDisk(
+        resource: LivePhotoResource,
+        options: KingfisherParsedOptionsInfo
+    ) -> URL? {
+        possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: options.processor.identifier,
+            referenceFileType: resource.referenceFileType
+        )
+    }
+    
     func possibleCacheFileURLIfOnDisk(
         forKey key: String,
         processorIdentifier identifier: String,

+ 114 - 0
Tests/KingfisherTests/ImageCacheTests.swift

@@ -780,6 +780,120 @@ class ImageCacheTests: XCTestCase {
         XCTAssertEqual(cache.imageCachedType(forKey: key, forcedExtension: "jpg"), .disk)
     }
     
+    func testPossibleCacheFileURLIfOnDiskNotCached() {
+        let url = URL(string: "https://example.com/photo")!
+        let resource = LivePhotoResource(downloadURL: url)
+        
+        let fileURL = cache.possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            referenceFileType: .heic
+        )
+            
+        // Not cached
+        XCTAssertNil(fileURL)
+    }
+    
+    func testPossibleCacheFileURLIfOnDiskCachedWithWrongFileType() async throws {
+        let url = URL(string: "https://example.com/photo")!
+        let resource = LivePhotoResource(downloadURL: url, fileType: .heic)
+        
+        // Cache without a file type extension
+        try await cache.storeToDisk(
+            testImageData,
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier
+        )
+        
+        let fileURL = cache.possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            referenceFileType: .heic
+        )
+            
+        // Not cached
+        XCTAssertNil(fileURL)
+    }
+    
+    func testPossibleCacheFileURLIfOnDiskCachedWithExplicitFileType() async throws {
+        let url = URL(string: "https://example.com/photo")!
+        let resource = LivePhotoResource(downloadURL: url, fileType: .heic)
+        
+        // Cache without a file type extension
+        try await cache.storeToDisk(
+            testImageData,
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            forcedExtension: "heic"
+        )
+        
+        let fileURL = cache.possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            referenceFileType: .heic
+        )
+
+        let result = try XCTUnwrap(fileURL)
+        XCTAssertTrue(result.absoluteString.hasSuffix(".heic"))
+    }
+    
+    func testPossibleCacheFileURLIfOnDiskCachedGuessingFileTypeNotHit() async throws {
+        let url = URL(string: "https://example.com/photo")!
+        let resource = LivePhotoResource(downloadURL: url, fileType: .heic)
+
+        let fileURL = cache.possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            referenceFileType: .other("")
+        )
+
+        XCTAssertNil(fileURL)
+    }
+    
+    func testPossibleCacheFileURLIfOnDiskCachedGuessingFileType() async throws {
+        let url = URL(string: "https://example.com/photo")!
+        let resource = LivePhotoResource(downloadURL: url, fileType: .heic)
+        
+        // Cache without a file type extension
+        try await cache.storeToDisk(
+            testImageData,
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            forcedExtension: "heic"
+        )
+        
+        let fileURL = cache.possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            referenceFileType: .other("")
+        )
+
+        let result = try XCTUnwrap(fileURL)
+        XCTAssertTrue(result.absoluteString.hasSuffix(".heic"))
+    }
+    
+    func testPossibleCacheFileURLIfOnDiskCachedArbitraryFileType() async throws {
+        let url = URL(string: "https://example.com/photo")!
+        let resource = LivePhotoResource(downloadURL: url, fileType: .heic)
+        
+        // Cache without a file type extension
+        try await cache.storeToDisk(
+            testImageData,
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            forcedExtension: "myExt"
+        )
+        
+        let fileURL = cache.possibleCacheFileURLIfOnDisk(
+            forKey: resource.cacheKey,
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            referenceFileType: .other("myExt")
+        )
+
+        let result = try XCTUnwrap(fileURL)
+        XCTAssertTrue(result.absoluteString.hasSuffix(".myExt"))
+    }
+    
     // MARK: - Helper
     private func storeMultipleImages(_ completionHandler: @escaping () -> Void) {
         let group = DispatchGroup()

+ 101 - 2
Tests/KingfisherTests/KingfisherManagerTests.swift

@@ -1390,6 +1390,23 @@ class KingfisherManagerTests: XCTestCase {
         XCTAssertEqual(missing[0].downloadURL, resource2.downloadURL)
     }
     
+    func testMissingResourceOfLivePhotoForceRefresh() async throws {
+        let resource1 = KF.ImageResource(downloadURL: LivePhotoURL.heic)
+        let resource2 = KF.ImageResource(downloadURL: LivePhotoURL.mov)
+        
+        try await manager.cache.storeToDisk(
+            testImageData,
+            forKey: resource1.cacheKey,
+            forcedExtension: resource1.downloadURL.pathExtension
+        )
+        
+        let source = LivePhotoSource(resources: [resource1, resource2])
+        let missing = manager.missingResources(source, options: .init([.forceRefresh]))
+        XCTAssertEqual(missing.count, 2)
+        XCTAssertEqual(missing[0].downloadURL, resource1.downloadURL)
+        XCTAssertEqual(missing[1].downloadURL, resource2.downloadURL)
+    }
+    
     func testDownloadAndCacheLivePhotoResourcesAll() async throws {
         let resource1 = KF.ImageResource(downloadURL: LivePhotoURL.mov)
         let resource2 = KF.ImageResource(downloadURL: LivePhotoURL.heic)
@@ -1540,11 +1557,13 @@ class KingfisherManagerTests: XCTestCase {
         
         let resource1Cached = manager.cache.isCached(
             forKey: resource1.cacheKey,
-            processorIdentifier: LivePhotoImageProcessor.default.identifier
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            forcedExtension: resource1.downloadURL.pathExtension
         )
         let resource2Cached = manager.cache.isCached(
             forKey: resource2.cacheKey,
-            processorIdentifier: LivePhotoImageProcessor.default.identifier
+            processorIdentifier: LivePhotoImageProcessor.default.identifier,
+            forcedExtension: resource2.downloadURL.pathExtension
         )
         XCTAssertFalse(resource1Cached)
         XCTAssertFalse(resource2Cached)
@@ -1565,6 +1584,86 @@ class KingfisherManagerTests: XCTestCase {
         XCTAssertEqual(localResult.fileURLs.count, 2)
         XCTAssertEqual(localResult.cacheType, .disk)
     }
+    
+    func testDownloadAndCacheLivePhotoWithEmptyResources() async throws {
+        let result = try await manager.downloadAndCache(resources: [], options: .init([]))
+        XCTAssertTrue(result.isEmpty)
+    }
+    
+    func testDownloadAndCacheLivePhotoWithSingleResource() async throws {
+        let resource = LivePhotoResource(downloadURL: LivePhotoURL.heic)
+        stub(resource.downloadURL, data: testImageData)
+        
+        let result = try await manager.downloadAndCache(resources: [resource], options: .init([]))
+        XCTAssertEqual(result.count, 1)
+        
+        let t = manager.cache.imageCachedType(forKey: resource.cacheKey, forcedExtension: "heic")
+        XCTAssertEqual(t, .disk)
+    }
+    
+    func testDownloadAndCacheLivePhotoWithSingleResourceGuessingUnsupportedExtension() async throws {
+        let resource = LivePhotoResource(downloadURL: URL(string: "https://example.com")!)
+        stub(resource.downloadURL, data: testImageData)
+        
+        XCTAssertEqual(resource.referenceFileType, .other(""))
+        
+        let result = try await manager.downloadAndCache(resources: [resource], options: .init([]))
+        XCTAssertEqual(result.count, 1)
+        
+        var cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey, forcedExtension: "heic")
+        XCTAssertEqual(cacheType, .none)
+        
+        cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey)
+        XCTAssertEqual(cacheType, .disk)
+    }
+    
+    func testDownloadAndCacheLivePhotoWithSingleResourceExplicitSetExtension() async throws {
+        let resource = LivePhotoResource(downloadURL: URL(string: "https://example.com")!, fileType: .heic)
+        stub(resource.downloadURL, data: testImageData)
+        
+        XCTAssertEqual(resource.referenceFileType, .heic)
+        
+        let result = try await manager.downloadAndCache(resources: [resource], options: .init([]))
+        XCTAssertEqual(result.count, 1)
+        
+        var cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey, forcedExtension: "heic")
+        XCTAssertEqual(cacheType, .disk)
+        
+        cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey)
+        XCTAssertEqual(cacheType, .none)
+    }
+    
+    func testDownloadAndCacheLivePhotoWithSingleResourceGuessingHEICExtension() async throws {
+        let resource = LivePhotoResource(downloadURL: URL(string: "https://example.com")!)
+        stub(resource.downloadURL, data: partitalHEICData)
+        
+        XCTAssertEqual(resource.referenceFileType, .other(""))
+        
+        let result = try await manager.downloadAndCache(resources: [resource], options: .init([]))
+        XCTAssertEqual(result.count, 1)
+        
+        var cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey, forcedExtension: "heic")
+        XCTAssertEqual(cacheType, .disk)
+        
+        cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey)
+        XCTAssertEqual(cacheType, .none)
+    }
+    
+    func testDownloadAndCacheLivePhotoWithSingleResourceGuessingMOVExtension() async throws {
+        let resource = LivePhotoResource(downloadURL: URL(string: "https://example.com")!)
+        stub(resource.downloadURL, data: partitalMOVData)
+        
+        XCTAssertEqual(resource.referenceFileType, .other(""))
+        
+        let result = try await manager.downloadAndCache(resources: [resource], options: .init([]))
+        XCTAssertEqual(result.count, 1)
+        
+        var cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey, forcedExtension: "mov")
+        XCTAssertEqual(cacheType, .disk)
+        
+        cacheType = manager.cache.imageCachedType(forKey: resource.cacheKey)
+        XCTAssertEqual(cacheType, .none)
+    }
 }
 
 private var imageCreatingOptionsKey: Void?

+ 3 - 0
Tests/KingfisherTests/KingfisherTestHelper.swift

@@ -72,6 +72,9 @@ let testImageString =
 var testImage = KFCrossPlatformImage(data: testImageData)!
 let testImageData = Data(base64Encoded: testImageString)!
 
+let partitalHEICData = Data(base64Encoded: "AAAALGZ0eXBoZWljAAAAAG1pZjFNaUhCTWlIRU1pUHI=")!
+let partitalMOVData = Data(base64Encoded: "AAAAFGZ0eXBxdCAgAAAAAHF0ICAAAAAId2lkZQAgJto=")!
+
 let testImagePNGData = testImage.kf.pngRepresentation()!
 let testImageJEPGData = testImage.kf.jpegRepresentation(compressionQuality: 1.0)!
 let testImageGIFData = Data(fileName: "dancing-banana.gif")