From 373d7247ce9f0033aaba7c43a28837479af68ea0 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 8 Aug 2023 13:13:10 +0200 Subject: [PATCH 1/2] Nullable enums with an empty string fail to get generated --- .../Translator/CommonTranslations/translateSchema.swift | 1 + .../CommonTranslations/translateStringEnum.swift | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift index d34036c7..58b6b049 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift @@ -115,6 +115,7 @@ extension FileTranslator { let enumDecl = try translateStringEnum( typeName: typeName, userDescription: overrides.userDescription ?? coreContext.description, + isNullable: coreContext.nullable, allowedValues: allowedValues ) return [enumDecl] diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift index 5c87f9df..cd0ac7eb 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift @@ -20,15 +20,23 @@ extension FileTranslator { /// - typeName: The name of the type to give to the declared enum. /// - openAPIDescription: A user-specified description from the OpenAPI /// document. + /// - isNullable: Whether the enum schema is nullable. /// - allowedValues: The enumerated allowed values. func translateStringEnum( typeName: TypeName, userDescription: String?, + isNullable: Bool, allowedValues: [AnyCodable] ) throws -> Declaration { let rawValues = try allowedValues.map(\.value) .map { anyValue in + // In nullable enum schemas, empty strings are parsed as Void. + // This is unlikely to be fixed, so handling that case here. + // https://github.com/apple/swift-openapi-generator/issues/118 + if isNullable && anyValue is Void { + return "" + } guard let string = anyValue as? String else { throw GenericError(message: "Disallowed value for a string enum '\(typeName)': \(anyValue)") } From 06c04e651cdc33522b9b04f2775ff966b5d9ad3b Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 8 Aug 2023 13:26:23 +0200 Subject: [PATCH 2/2] Add unit tests --- .../Test_translateStringEnum.swift | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Tests/OpenAPIGeneratorCoreTests/Translator/CommonTranslations/Test_translateStringEnum.swift diff --git a/Tests/OpenAPIGeneratorCoreTests/Translator/CommonTranslations/Test_translateStringEnum.swift b/Tests/OpenAPIGeneratorCoreTests/Translator/CommonTranslations/Test_translateStringEnum.swift new file mode 100644 index 00000000..59a41509 --- /dev/null +++ b/Tests/OpenAPIGeneratorCoreTests/Translator/CommonTranslations/Test_translateStringEnum.swift @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftOpenAPIGenerator open source project +// +// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// +import XCTest +import OpenAPIKit30 +@testable import _OpenAPIGeneratorCore + +final class Test_translateStringEnum: Test_Core { + + func testCaseValues() throws { + let names = try _caseValues( + .string( + allowedValues: "a", + "" + ) + ) + XCTAssertEqual(names, ["a", "_empty", "undocumented"]) + } + + func testCaseValuesForNullableSchema() throws { + let names = try _caseValues( + .string( + nullable: true, + allowedValues: "a", + nil + ) + ) + XCTAssertEqual(names, ["a", "_empty", "undocumented"]) + } + + func _caseValues(_ schema: JSONSchema) throws -> [String] { + self.continueAfterFailure = false + let translator = makeTypesTranslator() + let decls = try translator.translateSchema( + typeName: .init(swiftKeyPath: ["FooEnum"]), + schema: schema, + overrides: .none + ) + XCTAssertEqual(decls.count, 1) + let decl = decls[0] + guard case .enum(let enumDesc) = decl.strippingTopComment else { + throw UnexpectedDeclError(actual: decl.info.kind, expected: .enum) + } + XCTAssertEqual(enumDesc.name, "FooEnum") + let names: [String] = enumDesc.members.compactMap { memberDecl in + guard case .enumCase(let caseDesc) = memberDecl.strippingTopComment else { + return nil + } + return caseDesc.name + } + return names + } +}