Skip to content

Commit 0a6ed3f

Browse files
author
Gayathri Sairamkrishnan
committed
Confirm RuntimeErrors to HTTPResponseConvertible
1 parent 7177b0c commit 0a6ed3f

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

Sources/OpenAPIRuntime/Errors/RuntimeError.swift

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414
import protocol Foundation.LocalizedError
1515
import struct Foundation.Data
16-
16+
import HTTPTypes
1717
/// Error thrown by generated code.
1818
internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, PrettyStringConvertible {
1919

@@ -141,3 +141,43 @@ internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, Pret
141141
@_spi(Generated) public func throwUnexpectedResponseBody(expectedContent: String, body: any Sendable) throws -> Never {
142142
throw RuntimeError.unexpectedResponseBody(expectedContent: expectedContent, body: body)
143143
}
144+
145+
/// HTTP Response status definition for ``RuntimeError``.
146+
extension RuntimeError: HTTPResponseConvertible {
147+
public var httpStatus: HTTPTypes.HTTPResponse.Status {
148+
switch self {
149+
case .invalidServerURL,
150+
.invalidServerVariableValue:
151+
.notFound
152+
case .invalidExpectedContentType,
153+
.missingCoderForCustomContentType,
154+
.unexpectedContentTypeHeader:
155+
.unsupportedMediaType
156+
case .unexpectedAcceptHeader(_):
157+
.notAcceptable
158+
case .missingOrMalformedContentDispositionName:
159+
.unprocessableContent
160+
case .failedToDecodeStringConvertibleValue,
161+
.invalidAcceptSubstring,
162+
.invalidBase64String,
163+
.invalidHeaderFieldName,
164+
.malformedAcceptHeader,
165+
.missingMultipartBoundaryContentTypeParameter,
166+
.missingRequiredHeaderField,
167+
.missingRequiredMultipartFormDataContentType,
168+
.missingRequiredQueryParameter,
169+
.missingRequiredPathParameter,
170+
.missingRequiredRequestBody,
171+
.pathUnset,
172+
.unsupportedParameterStyle:
173+
.badRequest
174+
case .handlerFailed,
175+
.middlewareFailed,
176+
.missingRequiredResponseBody,
177+
.transportFailed,
178+
.unexpectedResponseStatus,
179+
.unexpectedResponseBody:
180+
.internalServerError
181+
}
182+
}
183+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftOpenAPIGenerator open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the SwiftOpenAPIGenerator project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import HTTPTypes
16+
@_spi(Generated) @testable import OpenAPIRuntime
17+
import XCTest
18+
19+
struct MockRuntimeErrorHandler: Sendable {
20+
var failWithError: (any Error)? = nil
21+
func greet(_ input: String) async throws -> String {
22+
if failWithError != nil { throw failWithError! }
23+
guard input == "hello" else { throw TestError() }
24+
return "bye"
25+
}
26+
27+
static let requestBody: HTTPBody = HTTPBody("hello")
28+
static let responseBody: HTTPBody = HTTPBody("bye")
29+
}
30+
31+
final class Test_RuntimeError: XCTestCase {
32+
33+
func testRuntimeError_withUnderlyingErrorNotConfirming_returns500() async throws {
34+
35+
let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: RuntimeError.transportFailed(TestError())),
36+
middlewares: [ErrorHandlingMiddleware()])
37+
let response = try await server.handle(
38+
request: .init(soar_path: "/", method: .post),
39+
requestBody: MockHandler.requestBody,
40+
metadata: .init(),
41+
forOperation: "op",
42+
using: { MockRuntimeErrorHandler.greet($0) },
43+
deserializer: { request, body, metadata in
44+
let body = try XCTUnwrap(body)
45+
return try await String(collecting: body, upTo: 10)
46+
},
47+
serializer: { output, _ in fatalError() }
48+
)
49+
XCTAssertEqual(response.0.status, .internalServerError)
50+
}
51+
52+
func testRuntimeError_withUnderlyingErrorConfirming_returns500() async throws {
53+
54+
let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: TestErrorConvertible.testError("Test Error")),
55+
middlewares: [ErrorHandlingMiddleware()])
56+
let response = try await server.handle(
57+
request: .init(soar_path: "/", method: .post),
58+
requestBody: MockHandler.requestBody,
59+
metadata: .init(),
60+
forOperation: "op",
61+
using: { MockRuntimeErrorHandler.greet($0) },
62+
deserializer: { request, body, metadata in
63+
let body = try XCTUnwrap(body)
64+
return try await String(collecting: body, upTo: 10)
65+
},
66+
serializer: { output, _ in fatalError() }
67+
)
68+
XCTAssertEqual(response.0.status, .badGateway)
69+
}
70+
}
71+
72+
enum TestErrorConvertible: Error, HTTPResponseConvertible {
73+
case testError(String)
74+
75+
public var httpStatus: HTTPTypes.HTTPResponse.Status {
76+
.badGateway
77+
}
78+
}
79+
80+

0 commit comments

Comments
 (0)