From 7464222196c5f41bd214ce0b249491eb1d3180a1 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 11 Oct 2025 16:13:56 +0200 Subject: [PATCH 1/4] don't fail when loading images from the local file system --- Sources/NetworkImage/NetworkImageLoader.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Sources/NetworkImage/NetworkImageLoader.swift b/Sources/NetworkImage/NetworkImageLoader.swift index a491e6e..7953bdc 100644 --- a/Sources/NetworkImage/NetworkImageLoader.swift +++ b/Sources/NetworkImage/NetworkImageLoader.swift @@ -70,9 +70,7 @@ extension DefaultNetworkImageLoader: NetworkImageLoader { // remove ongoing task self.ongoingTasks.removeValue(forKey: url) - guard let statusCode = (response as? HTTPURLResponse)?.statusCode, - 200..<300 ~= statusCode - else { + if let response = response as? HTTPURLResponse, !(200..<300).contains(response.statusCode) { throw URLError(.badServerResponse) } From f03601f8d3f230e6a37fa003c65ee45810fd8503 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 11 Oct 2025 16:41:29 +0200 Subject: [PATCH 2/4] fix tests not compiling --- Sources/NetworkImage/NetworkImageLoader.swift | 4 ++-- .../DefaultNetworkImageLoaderTests.swift | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Sources/NetworkImage/NetworkImageLoader.swift b/Sources/NetworkImage/NetworkImageLoader.swift index 7953bdc..b07971b 100644 --- a/Sources/NetworkImage/NetworkImageLoader.swift +++ b/Sources/NetworkImage/NetworkImageLoader.swift @@ -18,7 +18,7 @@ public actor DefaultNetworkImageLoader { static let timeoutInterval: TimeInterval = 15 } - private let data: (URL) async throws -> (Data, URLResponse) + private let data: @Sendable (URL) async throws -> (Data, URLResponse) private let cache: NetworkImageCache private var ongoingTasks: [URL: Task] = [:] @@ -47,7 +47,7 @@ public actor DefaultNetworkImageLoader { init( cache: NetworkImageCache, - data: @escaping (URL) async throws -> (Data, URLResponse) + data: @escaping @Sendable (URL) async throws -> (Data, URLResponse) ) { self.data = data self.cache = cache diff --git a/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift b/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift index d07858f..a82304b 100644 --- a/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift +++ b/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift @@ -3,13 +3,16 @@ import XCTest @testable import NetworkImage final class DefaultNetworkImageLoaderTests: XCTestCase { + @MainActor func testImageLoad() async throws { // given let imageCache = DefaultNetworkImageCache() var loadCount = 0 let imageLoader = DefaultNetworkImageLoader(cache: imageCache) { _ in - loadCount += 1 + Task { @MainActor in + loadCount += 1 + } return (Fixtures.imageData, Fixtures.okResponse) } @@ -27,6 +30,7 @@ final class DefaultNetworkImageLoaderTests: XCTestCase { XCTAssertIdentical(imageCache.image(for: Fixtures.anotherURL), images.1) } + @MainActor func testImageCache() async throws { // given let imageCache = DefaultNetworkImageCache() @@ -34,7 +38,9 @@ final class DefaultNetworkImageLoaderTests: XCTestCase { var loadCount = 0 let imageLoader = DefaultNetworkImageLoader(cache: imageCache) { _ in - loadCount += 1 + Task { @MainActor in + loadCount += 1 + } return (Fixtures.imageData, Fixtures.okResponse) } From af45122d29be33fefe52ad52d1d7242c173e3d16 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 11 Oct 2025 16:41:39 +0200 Subject: [PATCH 3/4] add a test for local image loading --- .../DefaultNetworkImageLoaderTests.swift | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift b/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift index a82304b..c7e2fb0 100644 --- a/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift +++ b/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift @@ -1,5 +1,10 @@ import XCTest +#if canImport(AppKit) +import class AppKit.NSImage +#elseif canImport(UIKit) +import class UIKit.UIImage +#endif @testable import NetworkImage final class DefaultNetworkImageLoaderTests: XCTestCase { @@ -89,4 +94,36 @@ final class DefaultNetworkImageLoaderTests: XCTestCase { // then XCTAssertEqual(capturedError, URLError(.cannotDecodeContentData)) } + + func testLocalImageLoading() async throws { + // given + let fileManager = FileManager.default + let tmpDir = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString) + try fileManager.createDirectory(at: tmpDir, withIntermediateDirectories: true) + defer { + try? fileManager.removeItem(at: tmpDir) + } + let localImageUrl = tmpDir.appendingPathComponent("image", conformingTo: .png) + try Fixtures.imageData.write(to: localImageUrl) + let imageLoader = DefaultNetworkImageLoader.shared + + // when + let image = try await imageLoader.image(from: localImageUrl) + + // then + try XCTAssertEqual(XCTUnwrap(image.pngData), XCTUnwrap(Fixtures.image.pngData)) + } +} + + +// MARK: Utils + +extension CGImage { + var pngData: Data? { + #if canImport(AppKit) + NSBitmapImageRep(cgImage: self).representation(using: .png, properties: [:]) + #elseif canImport(UIKit) + UIImage(cgImage: self).pngData() + #endif + } } From 8e1fd76ad799c3ae94565c8460555cd5c32b6d91 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 11 Oct 2025 16:43:07 +0200 Subject: [PATCH 4/4] x --- .../DefaultNetworkImageLoaderTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift b/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift index c7e2fb0..6fae8a2 100644 --- a/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift +++ b/Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift @@ -1,11 +1,11 @@ import XCTest +@testable import NetworkImage #if canImport(AppKit) import class AppKit.NSImage #elseif canImport(UIKit) import class UIKit.UIImage #endif -@testable import NetworkImage final class DefaultNetworkImageLoaderTests: XCTestCase { @MainActor @@ -120,10 +120,10 @@ final class DefaultNetworkImageLoaderTests: XCTestCase { extension CGImage { var pngData: Data? { - #if canImport(AppKit) + #if canImport(AppKit) NSBitmapImageRep(cgImage: self).representation(using: .png, properties: [:]) - #elseif canImport(UIKit) + #elseif canImport(UIKit) UIImage(cgImage: self).pngData() - #endif + #endif } }