[api-upload-refactor] Add test target, relax decode constraints, add HTTPBody + MultipartForm

- Package: new LCEssentialsTests target (runs on iOS simulator)
- JSONDecoder.decode: T: Codable -> T: Decodable & Sendable (4 overloads);
  remove try! in decode(fromURL:); honour encoding param in decode(_:using:)
- Propagate & Sendable to Data.object, Dictionary.toObjetct, API.request return
- LCEHTTPBody: HTTPBody protocol, JSONBody, FormURLEncodedBody, RawBody, factories
- LCEMultipartForm: multipart builder, OutputStream-streamed serialize(),
  in-memory + on-disk file parts, ported mimeType(for:)
- Tests: StubURLProtocol harness + 15 tests
This commit is contained in:
Daniel Arantes Loverde
2026-08-29 16:59:08 -03:00
parent db696b5a34
commit e89935a69c
14 changed files with 688 additions and 22 deletions

View File

@@ -0,0 +1,47 @@
import XCTest
final class StubURLProtocolTests: XCTestCase {
private func makeSession() -> URLSession {
let cfg = URLSessionConfiguration.ephemeral
cfg.protocolClasses = [StubURLProtocol.self]
return URLSession(configuration: cfg)
}
override func tearDown() {
StubURLProtocol.reset()
super.tearDown()
}
func testReplaysCannedResponseAndCapturesRequest() async throws {
var stub = StubURLProtocol.Stub()
stub.statusCode = 201
stub.body = Data(#"{"ok":true}"#.utf8)
StubURLProtocol.setStub(stub)
var request = URLRequest(url: URL(string: "https://example.com/things")!)
request.httpMethod = "POST"
request.httpBody = Data(#"{"name":"x"}"#.utf8)
let (data, response) = try await makeSession().data(for: request)
XCTAssertEqual((response as? HTTPURLResponse)?.statusCode, 201)
XCTAssertEqual(String(data: data, encoding: .utf8), #"{"ok":true}"#)
XCTAssertEqual(StubURLProtocol.requestCount, 1)
XCTAssertEqual(StubURLProtocol.capturedRequests.first?.httpMethod, "POST")
XCTAssertEqual(StubURLProtocol.lastCapturedBody, Data(#"{"name":"x"}"#.utf8))
}
func testReplaysError() async {
var stub = StubURLProtocol.Stub()
stub.error = URLError(.notConnectedToInternet)
StubURLProtocol.setStub(stub)
do {
_ = try await makeSession().data(for: URLRequest(url: URL(string: "https://example.com")!))
XCTFail("expected throw")
} catch {
XCTAssertEqual((error as? URLError)?.code, .notConnectedToInternet)
}
}
}