Skip to content

Commit

Permalink
Merge pull request #708 from khlopko/issue-693
Browse files Browse the repository at this point in the history
#693: DataPublisher created from async function should start lazily
  • Loading branch information
kean authored Jun 23, 2023
2 parents bf95178 + 0655d2b commit a84b6ce
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Nuke.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@
0CF5456B25B39A0E00B45F1E /* left-orientation.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 0CF5456A25B39A0E00B45F1E /* left-orientation.jpeg */; };
0CF58FF726DAAC3800D2650D /* ImageDownsampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF58FF626DAAC3800D2650D /* ImageDownsampleTests.swift */; };
2DFD93B0233A6AB300D84DB9 /* ImagePipelineProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DFD93AF233A6AB300D84DB9 /* ImagePipelineProcessorTests.swift */; };
4480674C2A448C9F00DE7CF8 /* DataPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4480674B2A448C9F00DE7CF8 /* DataPublisherTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -537,6 +538,7 @@
0CF5456A25B39A0E00B45F1E /* left-orientation.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "left-orientation.jpeg"; sourceTree = "<group>"; };
0CF58FF626DAAC3800D2650D /* ImageDownsampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDownsampleTests.swift; sourceTree = "<group>"; };
2DFD93AF233A6AB300D84DB9 /* ImagePipelineProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePipelineProcessorTests.swift; sourceTree = "<group>"; };
4480674B2A448C9F00DE7CF8 /* DataPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataPublisherTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -709,6 +711,7 @@
isa = PBXGroup;
children = (
0C1E620A1D6F817700AD5CF5 /* ImageRequestTests.swift */,
4480674B2A448C9F00DE7CF8 /* DataPublisherTests.swift */,
0C7C06871BCA888800089D7F /* ImageCacheTests.swift */,
0C70D9772089017500A49DAC /* ImageDecoderTests.swift */,
0C68F608208A1F40007DC696 /* ImageDecoderRegistryTests.swift */,
Expand Down Expand Up @@ -1617,6 +1620,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4480674C2A448C9F00DE7CF8 /* DataPublisherTests.swift in Sources */,
0CD37C9A25BA36D5006C2C36 /* ImagePipelineLoadDataTests.swift in Sources */,
0C75279F1D473AEF00EC6222 /* MockImageProcessor.swift in Sources */,
0C69FA4E1D4E222D00DA9982 /* ImagePrefetcherTests.swift in Sources */,
Expand Down
21 changes: 11 additions & 10 deletions Sources/Nuke/Internal/DataPublisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,18 @@ final class DataPublisher {
}

private func publisher(from closure: @Sendable @escaping () async throws -> Data) -> AnyPublisher<Data, Error> {
let subject = PassthroughSubject<Data, Error>()
Task {
do {
let data = try await closure()
subject.send(data)
subject.send(completion: .finished)
} catch {
subject.send(completion: .failure(error))
Deferred {
Future { promise in
Task {
do {
let data = try await closure()
promise(.success(data))
} catch {
promise(.failure(error))
}
}
}
}
return subject.eraseToAnyPublisher()
}.eraseToAnyPublisher()
}

enum PublisherCompletion {
Expand Down
38 changes: 38 additions & 0 deletions Tests/NukeTests/DataPublisherTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// DataPublisherTests.swift
//

import XCTest
import Combine
@testable import Nuke

internal final class DataPublisherTests: XCTestCase {

private var cancellable: (any Nuke.Cancellable)?

func testInitNotStartsExecutionRightAway() {
let operation = MockOperation()
let publisher = DataPublisher(id: UUID().uuidString, { await operation.execute() })

XCTAssertEqual(0, operation.executeCalls)

let expOp = expectation(description: "Waits for MockOperation to complete execution")
cancellable = publisher.sink { completion in expOp.fulfill() } receiveValue: { _ in }
waitForExpectations(timeout: 0.1)

XCTAssertEqual(1, operation.executeCalls)
}

private final class MockOperation: @unchecked Sendable {

private(set) var executeCalls = 0

func execute() async -> Data {
executeCalls += 1
await Task.yield()
return Data()
}

}

}

0 comments on commit a84b6ce

Please sign in to comment.