Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions Sources/NetworkImage/NetworkImageLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<CGImage, Error>] = [:]
Expand Down Expand Up @@ -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
Expand All @@ -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)
}

Expand Down
47 changes: 45 additions & 2 deletions Tests/NetworkImageTests/DefaultNetworkImageLoaderTests.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import XCTest

@testable import NetworkImage
#if canImport(AppKit)
import class AppKit.NSImage
#elseif canImport(UIKit)
import class UIKit.UIImage
#endif

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)
}

Expand All @@ -27,14 +35,17 @@ final class DefaultNetworkImageLoaderTests: XCTestCase {
XCTAssertIdentical(imageCache.image(for: Fixtures.anotherURL), images.1)
}

@MainActor
func testImageCache() async throws {
// given
let imageCache = DefaultNetworkImageCache()
imageCache.setImage(Fixtures.image, for: Fixtures.url)

var loadCount = 0
let imageLoader = DefaultNetworkImageLoader(cache: imageCache) { _ in
loadCount += 1
Task { @MainActor in
loadCount += 1
}
return (Fixtures.imageData, Fixtures.okResponse)
}

Expand Down Expand Up @@ -83,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
}
}