[api-upload-refactor] Add iOS15 upload progress overload; toObjetct throws
- upload(..., onProgress: @Sendable (Double) -> Void) @available(iOS 15.0, *) via URLSession.upload(for:fromFile:delegate:) + UploadProgressDelegate; emits 1.0 on completion. Base upload stays iOS 13+ - move all upload code to LCEssentials+API+Upload.swift (buildUploadRequest / finishUpload / performUpload shared); API file 400 lines. Shared request helpers private -> internal - Dictionary.toObjetct: try! -> throws - APIUploadTests: +progress contract test (final 1.0, monotonic, decodes)
This commit is contained in:
@@ -5,6 +5,14 @@ private struct UploadEcho: Decodable, Sendable, Equatable {
|
||||
let ok: Bool
|
||||
}
|
||||
|
||||
/// Thread-safe sink for progress callbacks (invoked on an arbitrary queue).
|
||||
private final class ProgressBox: @unchecked Sendable {
|
||||
private let lock = NSLock()
|
||||
private var storage: [Double] = []
|
||||
func record(_ value: Double) { lock.lock(); storage.append(value); lock.unlock() }
|
||||
var values: [Double] { lock.lock(); defer { lock.unlock() }; return storage }
|
||||
}
|
||||
|
||||
final class APIUploadTests: XCTestCase {
|
||||
|
||||
private var api: API!
|
||||
@@ -79,6 +87,27 @@ final class APIUploadTests: XCTestCase {
|
||||
XCTAssertEqual(tempCountInDir(dir), before)
|
||||
}
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
func testProgressOverloadDeliversFinalCompletionAndDecodes() async throws {
|
||||
StubURLProtocol.setStub(.init(statusCode: 200, body: Data(#"{"ok":true}"#.utf8)))
|
||||
|
||||
var form = MultipartForm()
|
||||
form.file("f", data: Data(repeating: 0x41, count: 4096), filename: "a.bin")
|
||||
|
||||
let progressBox = ProgressBox()
|
||||
let result: UploadEcho = try await api.upload(
|
||||
url: "https://api.example.com/x",
|
||||
form: form,
|
||||
onProgress: { progressBox.record($0) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(result, UploadEcho(ok: true))
|
||||
let values = progressBox.values
|
||||
XCTAssertEqual(values.last, 1.0, "final progress must be 1.0")
|
||||
XCTAssertTrue(values.allSatisfy { $0 >= 0 && $0 <= 1 })
|
||||
XCTAssertEqual(values, values.sorted(), "progress must be monotonic non-decreasing")
|
||||
}
|
||||
|
||||
func testUploadServerErrorThrowsWithStatus() async {
|
||||
StubURLProtocol.setStub(.init(statusCode: 413, body: Data(#"{"error":"too big"}"#.utf8)))
|
||||
var form = MultipartForm()
|
||||
|
||||
Reference in New Issue
Block a user