Skip to content

Commit

Permalink
Merge branch 'fix/add-error-info-generation' of github.com:awslabs/sm…
Browse files Browse the repository at this point in the history
…ithy-swift into fix/add-error-info-generation
  • Loading branch information
Sichan Yoo committed Aug 14, 2023
2 parents 9998fdd + 6c04868 commit 958caf2
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 6 deletions.
8 changes: 8 additions & 0 deletions Sources/ClientRuntime/Waiters/WaiterOutcome.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ public struct WaiterOutcome<Output> {

/// The result (output object or error) that caused an `Acceptor` to match.
public let result: Result<Output, Error>

/// Creates an instance of WaiterOutcome
/// - Parameter attempts: The number of operation attempts that were required for the wait to succeed.
/// - Parameter result: The result (output object or error) that caused an `Acceptor` to match.
public init(attempts: Int, result: Result<Output, Error>) {
self.attempts = attempts
self.result = result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,9 @@ class ServiceGenerator(
writer.writeSingleLineDocs { write("- Throws: `${op.toUpperCamelCase() + "Error"}` : Place-holder wrapper object for possible exceptions listed below.") }
writeEmptyLine()
writer.writeSingleLineDocs { write("__Possible Exceptions:__") }
}

for (error in op.getErrors(service)) {
writer.writeDocs("\\- \\`${error.name}\\` : ${retrieveMemberShapeDoc(error.toShapeId(), model)}")
op.getErrors(service).forEach { error ->
writer.writeDocs("\\- \\`${error.name}\\` : ${retrieveMemberShapeDoc(error.toShapeId(), model)}")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import software.amazon.smithy.model.shapes.MemberShape
import software.amazon.smithy.model.shapes.SetShape
import software.amazon.smithy.model.shapes.Shape
import software.amazon.smithy.model.shapes.TimestampShape
import software.amazon.smithy.model.traits.DefaultTrait
import software.amazon.smithy.model.traits.SparseTrait
import software.amazon.smithy.model.traits.StreamingTrait
import software.amazon.smithy.model.traits.TimestampFormatTrait
Expand All @@ -22,12 +23,14 @@ import software.amazon.smithy.swift.codegen.ClientRuntimeTypes
import software.amazon.smithy.swift.codegen.SwiftTypes
import software.amazon.smithy.swift.codegen.SwiftWriter
import software.amazon.smithy.swift.codegen.customtraits.SwiftBoxTrait
import software.amazon.smithy.swift.codegen.getOrNull
import software.amazon.smithy.swift.codegen.integration.ProtocolGenerator
import software.amazon.smithy.swift.codegen.integration.serde.MemberShapeDecodeGeneratable
import software.amazon.smithy.swift.codegen.integration.serde.TimestampDecodeGenerator
import software.amazon.smithy.swift.codegen.integration.serde.TimestampHelpers
import software.amazon.smithy.swift.codegen.integration.serde.xml.collection.CollectionMemberCodingKey
import software.amazon.smithy.swift.codegen.integration.serde.xml.collection.MapKeyValue
import software.amazon.smithy.swift.codegen.model.getTrait
import software.amazon.smithy.swift.codegen.model.hasTrait
import software.amazon.smithy.swift.codegen.model.isBoxed
import software.amazon.smithy.swift.codegen.model.recursiveSymbol
Expand Down Expand Up @@ -296,12 +299,22 @@ abstract class MemberShapeDecodeXMLGenerator(
if (member.hasTrait(SwiftBoxTrait::class.java)) {
memberTargetSymbol = memberTargetSymbol.recursiveSymbol()
}
val decodeVerb = if (memberTargetSymbol.isBoxed() && !isUnion) "decodeIfPresent" else "decode"
val decodeVerb = if (memberTargetSymbol.isBoxed() && !isUnion || (member.hasTrait<DefaultTrait>())) "decodeIfPresent" else "decode"
val decodedMemberName = "${memberNameUnquoted}Decoded"

val defaultValNilCoalescing = member.getTrait(DefaultTrait::class.java).getOrNull()?.let { trait ->
val defaultVal = trait.toNode()
when {
defaultVal.isStringNode() -> "?? \"$defaultVal\""
defaultVal.isNullNode() -> "?? nil"
else -> "?? $defaultVal"
}
} ?: ""

if (unkeyed) {
writer.write("let $decodedMemberName = try $containerName.$decodeVerb(\$N.self)", memberTargetSymbol)
} else {
writer.write("let $decodedMemberName = try $containerName.$decodeVerb(\$N.self, forKey: .$memberNameUnquoted)", memberTargetSymbol)
writer.write("let $decodedMemberName = try $containerName.$decodeVerb(\$N.self, forKey: .$memberNameUnquoted) $defaultValNilCoalescing", memberTargetSymbol)
}
renderAssigningDecodedMember(memberName, decodedMemberName, member.hasTrait(SwiftBoxTrait::class.java))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package serde.xml

import MockHttpRestXMLProtocolGenerator
import TestContext
import defaultSettings
import getFileContents
import io.kotest.matchers.string.shouldContainOnlyOnce
import org.junit.jupiter.api.Test

class MemberShapeDecodeXMLGeneratorTests {

@Test
fun `001 set default value for a missing value of a scalar member`() {
val context = setupTests("Isolated/Restxml/xml-scalarmember-default-value.smithy", "aws.protocoltests.restxml#RestXml")
val contents = getFileContents(context.manifest, "/RestXml/models/SimpleScalarPropertiesOutputResponseBody+Decodable.swift")
val expectedContents =
"""
extension SimpleScalarPropertiesOutputResponseBody: Swift.Decodable {
enum CodingKeys: Swift.String, Swift.CodingKey {
case byteValue
case doubleValue = "DoubleDribble"
case falseBooleanValue
case floatValue
case integerValue
case longValue
case `protocol` = "protocol"
case shortValue
case stringValue
case trueBooleanValue
}
public init(from decoder: Swift.Decoder) throws {
let containerValues = try decoder.container(keyedBy: CodingKeys.self)
let stringValueDecoded = try containerValues.decodeIfPresent(Swift.String.self, forKey: .stringValue) ?? "test"
stringValue = stringValueDecoded
let trueBooleanValueDecoded = try containerValues.decodeIfPresent(Swift.Bool.self, forKey: .trueBooleanValue) ?? false
trueBooleanValue = trueBooleanValueDecoded
let falseBooleanValueDecoded = try containerValues.decodeIfPresent(Swift.Bool.self, forKey: .falseBooleanValue)
falseBooleanValue = falseBooleanValueDecoded
let byteValueDecoded = try containerValues.decodeIfPresent(Swift.Int8.self, forKey: .byteValue)
byteValue = byteValueDecoded
let shortValueDecoded = try containerValues.decodeIfPresent(Swift.Int16.self, forKey: .shortValue)
shortValue = shortValueDecoded
let integerValueDecoded = try containerValues.decodeIfPresent(Swift.Int.self, forKey: .integerValue) ?? 5
integerValue = integerValueDecoded
let longValueDecoded = try containerValues.decodeIfPresent(Swift.Int.self, forKey: .longValue)
longValue = longValueDecoded
let floatValueDecoded = try containerValues.decodeIfPresent(Swift.Float.self, forKey: .floatValue) ?? 2.4
floatValue = floatValueDecoded
let protocolDecoded = try containerValues.decodeIfPresent(Swift.String.self, forKey: .protocol)
`protocol` = protocolDecoded
let doubleValueDecoded = try containerValues.decodeIfPresent(Swift.Double.self, forKey: .doubleValue)
doubleValue = doubleValueDecoded
}
}
""".trimIndent()
contents.shouldContainOnlyOnce(expectedContents)
}
private fun setupTests(smithyFile: String, serviceShapeId: String): TestContext {
val context = TestContext.initContextFrom(smithyFile, serviceShapeId, MockHttpRestXMLProtocolGenerator()) { model ->
model.defaultSettings(serviceShapeId, "RestXml", "2023-08-08", "Rest Xml Protocol")
}
context.generator.generateDeserializers(context.generationCtx)
context.generationCtx.delegator.flushWriters()
return context
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
$version: "2.0"

namespace aws.protocoltests.restxml

use aws.api#service
use aws.protocols#restXml
use smithy.test#httpRequestTests
use smithy.test#httpResponseTests

@service(sdkId: "Rest Xml List")
@restXml
service RestXml {
version: "2023-08-08",
operations: [
SimpleScalarProperties
]
}


@idempotent
@http(uri: "/SimpleScalarProperties", method: "PUT")
operation SimpleScalarProperties {
input: SimpleScalarPropertiesInputOutput,
output: SimpleScalarPropertiesInputOutput
}


structure SimpleScalarPropertiesInputOutput {
@httpHeader("X-Foo")
foo: String,

@default("test")
stringValue: String,
@default(false)
trueBooleanValue: Boolean,
falseBooleanValue: Boolean,
byteValue: Byte,
shortValue: Short,
@default(5)
integerValue: Integer,
longValue: Long,
@default(2.4)
floatValue: Float,
protocol: String,

@xmlName("DoubleDribble")
doubleValue: Double,
}

0 comments on commit 958caf2

Please sign in to comment.