-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow nil returns for optional return type (#50)
Added an additional decoding method for endpoints with optional return types. An endpoint with an optional return type will return nil in case the response body is nil or empty.
- Loading branch information
Showing
3 changed files
with
219 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,150 @@ | ||
import XCTest | ||
import Papyrus | ||
@testable import PapyrusCore | ||
|
||
final class APITests: XCTestCase { | ||
func testAPIGeneration() { | ||
func testApiEndpointReturnsNilForOptionalReturnType_forNilBody() async throws { | ||
// Arrange | ||
let sut = _PeopleAPI(provider: .init(baseURL: "", http: _HTTPServiceMock(responseType: .nil))) | ||
|
||
// Act | ||
let person = try await sut.getOptional() | ||
|
||
// Assert | ||
XCTAssertNil(person) | ||
} | ||
|
||
func testApiEndpointThrowsForNonOptionalReturnType_forNilBody() async throws { | ||
// Arrange | ||
let sut = _PeopleAPI(provider: .init(baseURL: "", http: _HTTPServiceMock(responseType: .nil))) | ||
|
||
// Act | ||
let expectation = expectation(description: "The endpoint with the non-optional return type should throw an error for an invalid body.") | ||
do { | ||
let _ = try await sut.get() | ||
} catch { | ||
expectation.fulfill() | ||
} | ||
|
||
// Assert | ||
await fulfillment(of: [expectation], timeout: 1) | ||
} | ||
|
||
func testApiEndpointReturnsNilForOptionalReturnType_forEmptyBody() async throws { | ||
// Arrange | ||
let sut = _PeopleAPI(provider: .init(baseURL: "", http: _HTTPServiceMock(responseType: .empty))) | ||
|
||
// Act | ||
let person = try await sut.getOptional() | ||
|
||
// Assert | ||
XCTAssertNil(person) | ||
} | ||
|
||
func testApiEndpointThrowsForNonOptionalReturnType_forEmptyBody() async throws { | ||
// Arrange | ||
let sut = _PeopleAPI(provider: .init(baseURL: "", http: _HTTPServiceMock(responseType: .empty))) | ||
|
||
// Act | ||
let expectation = expectation(description: "The endpoint with the non-optional return type should throw an error for an invalid body.") | ||
do { | ||
let _ = try await sut.get() | ||
} catch { | ||
expectation.fulfill() | ||
} | ||
|
||
// Assert | ||
await fulfillment(of: [expectation], timeout: 1) | ||
} | ||
|
||
func testApiEndpointReturnsValidObjectForOptionalReturnType() async throws { | ||
// Arrange | ||
let sut = _PeopleAPI(provider: .init(baseURL: "", http: _HTTPServiceMock(responseType: .person))) | ||
|
||
// Act | ||
let person = try await sut.getOptional() | ||
|
||
// Assert | ||
XCTAssertNotNil(person) | ||
XCTAssertEqual(person?.name, "Petru") | ||
} | ||
|
||
func testApiEndpointReturnsValidObjectForNonOptionalReturnType() async throws { | ||
// Arrange | ||
let sut = _PeopleAPI(provider: .init(baseURL: "", http: _HTTPServiceMock(responseType: .person))) | ||
|
||
// Act | ||
let person = try await sut.get() | ||
|
||
// Assert | ||
XCTAssertNotNil(person) | ||
XCTAssertEqual(person.name, "Petru") | ||
} | ||
} | ||
|
||
@API() | ||
fileprivate protocol _People { | ||
|
||
@GET("") | ||
func getOptional() async throws -> _Person? | ||
|
||
@GET("") | ||
func get() async throws -> _Person | ||
} | ||
|
||
fileprivate struct _Person: Decodable { | ||
let name: String | ||
} | ||
|
||
fileprivate class _HTTPServiceMock: HTTPService { | ||
|
||
enum ResponseType { | ||
case `nil` | ||
case empty | ||
case person | ||
|
||
var value: String? { | ||
switch self { | ||
case .nil: | ||
nil | ||
case .empty: | ||
"" | ||
case .person: | ||
"{\"name\": \"Petru\"}" | ||
} | ||
} | ||
} | ||
|
||
private let _responseType: ResponseType | ||
|
||
init(responseType: ResponseType) { | ||
_responseType = responseType | ||
} | ||
|
||
func build(method: String, url: URL, headers: [String : String], body: Data?) -> Request { | ||
_Request(method: "", headers: [:]) | ||
} | ||
|
||
func request(_ req: PapyrusCore.Request) async -> PapyrusCore.Response { | ||
_Response(body: _responseType.value?.data(using: .utf8), statusCode: 200) | ||
} | ||
|
||
func request(_ req: PapyrusCore.Request, completionHandler: @escaping (PapyrusCore.Response) -> Void) { | ||
completionHandler(_Response(body: "".data(using: .utf8))) | ||
} | ||
} | ||
|
||
fileprivate struct _Request: Request { | ||
var url: URL? | ||
var method: String | ||
var headers: [String : String] | ||
var body: Data? | ||
} | ||
|
||
fileprivate struct _Response: Response { | ||
var request: PapyrusCore.Request? | ||
var body: Data? | ||
var headers: [String : String]? | ||
var statusCode: Int? | ||
var error: Error? | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters