mirror of
https://github.com/samsonjs/Osiris.git
synced 2026-03-26 09:05:48 +00:00
273 lines
No EOL
9.4 KiB
Swift
273 lines
No EOL
9.4 KiB
Swift
//
|
|
// CodableTests.swift
|
|
// OsirisTests
|
|
//
|
|
// Created by Sami Samhuri on 2025-06-15.
|
|
//
|
|
|
|
@testable import Osiris
|
|
import XCTest
|
|
|
|
class CodableTests: XCTestCase {
|
|
let baseURL = URL(string: "https://api.example.net")!
|
|
|
|
// Test models
|
|
struct Person: Codable, Sendable, Equatable {
|
|
let name: String
|
|
let email: String
|
|
let age: Int?
|
|
}
|
|
|
|
struct APIResponse: Codable, Sendable, Equatable {
|
|
let success: Bool
|
|
let data: Person?
|
|
let message: String?
|
|
}
|
|
|
|
// MARK: - HTTPRequest Codable Body Tests
|
|
|
|
func testHTTPRequestWithCodableBody() throws {
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let request = HTTPRequest(method: .post, url: baseURL, body: person)
|
|
|
|
XCTAssertEqual(request.method, .post)
|
|
XCTAssertEqual(request.url, baseURL)
|
|
XCTAssertNotNil(request.body)
|
|
XCTAssertNil(request.parameters)
|
|
}
|
|
|
|
func testPostJSONConvenience() throws {
|
|
let person = Person(name: "John Doe", email: "john@example.net", age: 25)
|
|
let request = HTTPRequest.postJSON(baseURL, body: person)
|
|
|
|
XCTAssertEqual(request.method, .post)
|
|
XCTAssertEqual(request.url, baseURL)
|
|
XCTAssertEqual(request.contentType, .json)
|
|
XCTAssertNotNil(request.body)
|
|
XCTAssertNil(request.parameters)
|
|
}
|
|
|
|
func testPutJSONConvenience() throws {
|
|
let person = Person(name: "John Doe", email: "john@example.net", age: 26)
|
|
let request = HTTPRequest.putJSON(baseURL, body: person)
|
|
|
|
XCTAssertEqual(request.method, .put)
|
|
XCTAssertEqual(request.url, baseURL)
|
|
XCTAssertEqual(request.contentType, .json)
|
|
XCTAssertNotNil(request.body)
|
|
XCTAssertNil(request.parameters)
|
|
}
|
|
|
|
// MARK: - RequestBuilder Codable Encoding Tests
|
|
|
|
func testRequestBuilderWithCodableBody() throws {
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let httpRequest = HTTPRequest.postJSON(baseURL, body: person)
|
|
|
|
let urlRequest = try RequestBuilder.build(request: httpRequest)
|
|
|
|
XCTAssertEqual(urlRequest.url, baseURL)
|
|
XCTAssertEqual(urlRequest.httpMethod, "POST")
|
|
XCTAssertEqual(urlRequest.value(forHTTPHeaderField: "Content-Type"), "application/json")
|
|
XCTAssertNotNil(urlRequest.httpBody)
|
|
|
|
// Verify the JSON was encoded correctly
|
|
let decodedPerson = try JSONDecoder().decode(Person.self, from: urlRequest.httpBody!)
|
|
XCTAssertEqual(decodedPerson, person)
|
|
}
|
|
|
|
func testRequestBuilderPrefersCodableOverParameters() throws {
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let params = ["name": "Different Name", "email": "different@example.net"]
|
|
|
|
let httpRequest = HTTPRequest(
|
|
method: .post,
|
|
url: baseURL,
|
|
contentType: .json,
|
|
parameters: params,
|
|
body: person
|
|
)
|
|
|
|
let urlRequest = try RequestBuilder.build(request: httpRequest)
|
|
|
|
// Should use the Codable body, not the parameters
|
|
let decodedPerson = try JSONDecoder().decode(Person.self, from: urlRequest.httpBody!)
|
|
XCTAssertEqual(decodedPerson, person)
|
|
XCTAssertEqual(decodedPerson.name, "Jane Doe") // Not "Different Name"
|
|
}
|
|
|
|
// MARK: - HTTPResponse Decoding Tests
|
|
|
|
func testHTTPResponseDecodeSuccess() throws {
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let jsonData = try JSONEncoder().encode(person)
|
|
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, jsonData)
|
|
|
|
let decodedPerson = try response.decode(Person.self)
|
|
XCTAssertEqual(decodedPerson, person)
|
|
}
|
|
|
|
func testHTTPResponseDecodeFailureCase() throws {
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let jsonData = try JSONEncoder().encode(person)
|
|
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 400,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let response = HTTPResponse.failure(HTTPRequestError.http, httpURLResponse, jsonData)
|
|
|
|
// Should still be able to decode data from failure responses
|
|
let decodedPerson = try response.decode(Person.self)
|
|
XCTAssertEqual(decodedPerson, person)
|
|
}
|
|
|
|
func testHTTPResponseDecodeNoData() throws {
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: nil
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, nil)
|
|
|
|
XCTAssertThrowsError(try response.decode(Person.self)) { error in
|
|
XCTAssertTrue(error is DecodingError)
|
|
if case DecodingError.dataCorrupted(let context) = error {
|
|
XCTAssertEqual(context.debugDescription, "No data found in response")
|
|
} else {
|
|
XCTFail("Expected DecodingError.dataCorrupted")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testHTTPResponseDecodeInvalidJSON() throws {
|
|
let invalidJSON = "{ invalid json }".data(using: .utf8)!
|
|
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, invalidJSON)
|
|
|
|
XCTAssertThrowsError(try response.decode(Person.self)) { error in
|
|
XCTAssertTrue(error is DecodingError)
|
|
}
|
|
}
|
|
|
|
func testHTTPResponseTryDecodeSuccess() throws {
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let jsonData = try JSONEncoder().encode(person)
|
|
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, jsonData)
|
|
|
|
let decodedPerson = response.tryDecode(Person.self)
|
|
XCTAssertNotNil(decodedPerson)
|
|
XCTAssertEqual(decodedPerson, person)
|
|
}
|
|
|
|
func testHTTPResponseTryDecodeFailure() throws {
|
|
let invalidJSON = "{ invalid json }".data(using: .utf8)!
|
|
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, invalidJSON)
|
|
|
|
let decodedPerson = response.tryDecode(Person.self)
|
|
XCTAssertNil(decodedPerson)
|
|
}
|
|
|
|
func testHTTPResponseTryDecodeNoData() throws {
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: nil
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, nil)
|
|
|
|
let decodedPerson = response.tryDecode(Person.self)
|
|
XCTAssertNil(decodedPerson)
|
|
}
|
|
|
|
// MARK: - Custom JSONDecoder Tests
|
|
|
|
func testHTTPResponseDecodeWithCustomDecoder() throws {
|
|
// Create a Person with an ISO8601 date as a string (for testing custom decoder)
|
|
let apiResponse = APIResponse(
|
|
success: true,
|
|
data: Person(name: "Jane Doe", email: "jane@example.net", age: 30),
|
|
message: "Success"
|
|
)
|
|
|
|
let jsonData = try JSONEncoder().encode(apiResponse)
|
|
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 200,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let response = HTTPResponse.success(httpURLResponse, jsonData)
|
|
|
|
// Test with custom decoder (just using default for this test)
|
|
let customDecoder = JSONDecoder()
|
|
let decodedResponse = try response.decode(APIResponse.self, using: customDecoder)
|
|
XCTAssertEqual(decodedResponse, apiResponse)
|
|
}
|
|
|
|
// MARK: - Integration Tests
|
|
|
|
func testEndToEndCodableFlow() throws {
|
|
// Create request with Codable body
|
|
let person = Person(name: "Jane Doe", email: "jane@example.net", age: 30)
|
|
let httpRequest = HTTPRequest.postJSON(baseURL, body: person)
|
|
|
|
// Build URLRequest
|
|
let urlRequest = try RequestBuilder.build(request: httpRequest)
|
|
|
|
// Simulate successful response with the same data
|
|
let responseData = urlRequest.httpBody!
|
|
let httpURLResponse = HTTPURLResponse(
|
|
url: baseURL,
|
|
statusCode: 201,
|
|
httpVersion: nil,
|
|
headerFields: ["Content-Type": "application/json"]
|
|
)!
|
|
|
|
let httpResponse = HTTPResponse.success(httpURLResponse, responseData)
|
|
|
|
// Decode response
|
|
let decodedPerson = try httpResponse.decode(Person.self)
|
|
XCTAssertEqual(decodedPerson, person)
|
|
}
|
|
} |