Osiris/Tests/OsirisTests/HTTPResponseTests.swift

240 lines
11 KiB
Swift

//
// HTTPResponseTests.swift
// OsirisTests
//
// Created by Sami Samhuri on 2025-06-15.
//
@testable import Osiris
import XCTest
class HTTPResponseTests: XCTestCase {
func testSuccessResponse() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: ["Content-Type": "application/json"])!
let data = Data("{}".utf8)
let response = HTTPResponse(response: httpResponse, data: data, error: nil)
if case let .success(urlResponse, responseData) = response {
XCTAssertEqual(urlResponse.statusCode, 200)
XCTAssertEqual(responseData, data)
} else {
XCTFail("Expected success response")
}
}
func testFailureResponseWithError() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let error = NSError(domain: "test", code: 1, userInfo: nil)
let response = HTTPResponse(response: httpResponse, data: nil, error: error)
if case let .failure(responseError, urlResponse, responseData) = response {
XCTAssertEqual((responseError as NSError).domain, "test")
XCTAssertEqual(urlResponse?.statusCode, 200)
XCTAssertNil(responseData)
} else {
XCTFail("Expected failure response")
}
}
func testFailureResponseWithHTTPError() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 404, httpVersion: nil, headerFields: nil)!
let data = Data("Not Found".utf8)
let response = HTTPResponse(response: httpResponse, data: data, error: nil)
if case let .failure(error, urlResponse, responseData) = response {
XCTAssertTrue(error is HTTPRequestError)
XCTAssertEqual(urlResponse?.statusCode, 404)
XCTAssertEqual(responseData, data)
} else {
XCTFail("Expected failure response")
}
}
func testResponseWithoutHTTPURLResponse() {
let response = HTTPResponse(response: nil, data: nil, error: nil)
if case let .failure(error, _, _) = response {
XCTAssertTrue(error is HTTPRequestError)
} else {
XCTFail("Expected failure response")
}
}
func testDataProperty() {
let data = Data("test".utf8)
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let successResponse = HTTPResponse(response: httpResponse, data: data, error: nil)
XCTAssertEqual(successResponse.data, data)
let httpErrorResponse = HTTPURLResponse(url: url, statusCode: 400, httpVersion: nil, headerFields: nil)!
let failureResponse = HTTPResponse(response: httpErrorResponse, data: data, error: nil)
XCTAssertEqual(failureResponse.data, data)
}
func testStatusProperty() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 201, httpVersion: nil, headerFields: nil)!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
XCTAssertEqual(response.status, 201)
}
func testHeadersProperty() {
let url = URL(string: "https://api.example.net")!
let headers = ["Content-Type": "application/json", "X-Custom": "value"]
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: headers)!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
XCTAssertEqual(response.headers["Content-Type"] as? String, "application/json")
XCTAssertEqual(response.headers["X-Custom"] as? String, "value")
}
func testBodyStringProperty() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let data = Data("Hello, World!".utf8)
let response = HTTPResponse(response: httpResponse, data: data, error: nil)
XCTAssertEqual(response.bodyString, "Hello, World!")
}
func testBodyStringPropertyWithNoData() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
XCTAssertEqual(response.bodyString, "")
}
func testDictionaryFromJSONProperty() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let json = ["name": "John", "age": 30] as [String: any Sendable]
let data = try! JSONSerialization.data(withJSONObject: json)
let response = HTTPResponse(response: httpResponse, data: data, error: nil)
let dictionary = response.dictionaryFromJSON
XCTAssertEqual(dictionary["name"] as? String, "John")
XCTAssertEqual(dictionary["age"] as? Int, 30)
}
func testDictionaryFromJSONPropertyWithInvalidJSON() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let data = Data("invalid json".utf8)
let response = HTTPResponse(response: httpResponse, data: data, error: nil)
let dictionary = response.dictionaryFromJSON
XCTAssertTrue(dictionary.isEmpty)
}
func testDictionaryFromJSONPropertyWithNoData() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
XCTAssertEqual(response.bodyString, "")
}
func testDictionaryFromJSONPropertyWithNonDictionaryJSON() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let arrayJSON = try! JSONSerialization.data(withJSONObject: ["item1", "item2", "item3"])
let response = HTTPResponse(response: httpResponse, data: arrayJSON, error: nil)
let dictionary = response.dictionaryFromJSON
XCTAssertTrue(dictionary.isEmpty)
}
func testUnderlyingResponseProperty() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 201, httpVersion: "HTTP/1.1", headerFields: ["Server": "nginx"])!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
if case let .success(underlyingResponse, _) = response {
XCTAssertEqual(underlyingResponse.statusCode, 201)
XCTAssertEqual(underlyingResponse.allHeaderFields["Server"] as? String, "nginx")
} else {
XCTFail("Expected success response")
}
}
func testResponseStringDescription() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let data = Data("test response".utf8)
let successResponse = HTTPResponse(response: httpResponse, data: data, error: nil)
let description = String(describing: successResponse)
XCTAssertTrue(description.contains("success"))
let failureResponse = HTTPResponse(response: httpResponse, data: data, error: HTTPRequestError.http)
let failureDescription = String(describing: failureResponse)
XCTAssertTrue(failureDescription.contains("failure"))
}
func testResponseWithDifferentStatusCodes() {
let url = URL(string: "https://api.example.net")!
// Test various 2xx success codes
for statusCode in [200, 201, 202, 204, 206] {
let httpResponse = HTTPURLResponse(url: url, statusCode: statusCode, httpVersion: nil, headerFields: nil)!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
if case .success = response {
// Expected
} else {
XCTFail("Status code \(statusCode) should be success")
}
}
// Test various error status codes
for statusCode in [300, 400, 401, 404, 500, 503] {
let httpResponse = HTTPURLResponse(url: url, statusCode: statusCode, httpVersion: nil, headerFields: nil)!
let response = HTTPResponse(response: httpResponse, data: nil, error: nil)
if case .failure = response {
// Expected
} else {
XCTFail("Status code \(statusCode) should be failure")
}
}
}
func testResponseWithBinaryData() {
let url = URL(string: "https://api.example.net")!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let binaryData = Data([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]) // PNG header
let response = HTTPResponse(response: httpResponse, data: binaryData, error: nil)
XCTAssertEqual(response.data, binaryData)
// bodyString should handle binary data gracefully - it will be empty since this isn't valid UTF-8
let bodyString = response.bodyString
XCTAssertTrue(bodyString.isEmpty) // Binary data that isn't valid UTF-8 returns empty string
}
func testResponseStatusPropertyEdgeCases() {
// Test with no HTTP response - creates dummy HTTPURLResponse with status 0
let responseNoHTTP = HTTPResponse(response: nil, data: nil, error: nil)
XCTAssertEqual(responseNoHTTP.status, 0)
// Test with URLResponse that's not HTTPURLResponse - creates dummy HTTPURLResponse with status 0
let url = URL(string: "file:///test.txt")!
let fileResponse = URLResponse(url: url, mimeType: "text/plain", expectedContentLength: 10, textEncodingName: nil)
let responseNonHTTP = HTTPResponse(response: fileResponse, data: nil, error: nil)
XCTAssertEqual(responseNonHTTP.status, 0)
}
}