Skip to content

Commit

Permalink
Detect if the uniqueItems trait is used (#2001)
Browse files Browse the repository at this point in the history
And act like in the rest of the unsupported constraint traits cases.

I missed this in the implementation of #1342.
  • Loading branch information
david-perez committed Nov 18, 2022
1 parent 0a610ec commit 5eeb5d7
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 20 deletions.
45 changes: 30 additions & 15 deletions codegen-core/common-test-models/constraints.smithy
Expand Up @@ -154,8 +154,10 @@ structure ConstrainedHttpBoundShapesOperationInputOutput {
// @httpHeader("X-Length-MediaType")
// lengthStringHeaderWithMediaType: MediaTypeLengthString,

@httpHeader("X-Length-Set")
lengthStringSetHeader: SetOfLengthString,
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// @httpHeader("X-Length-Set")
// lengthStringSetHeader: SetOfLengthString,

@httpHeader("X-Length-List")
lengthStringListHeader: ListOfLengthString,
Expand All @@ -176,8 +178,10 @@ structure ConstrainedHttpBoundShapesOperationInputOutput {
@httpQuery("lengthStringList")
lengthStringListQuery: ListOfLengthString,

@httpQuery("lengthStringSet")
lengthStringSetQuery: SetOfLengthString,
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// @httpQuery("lengthStringSet")
// lengthStringSetQuery: SetOfLengthString,

@httpQuery("enumStringList")
enumStringListQuery: ListOfEnumString,
Expand Down Expand Up @@ -277,7 +281,9 @@ structure ConA {
conBList: ConBList,
conBList2: ConBList2,

conBSet: ConBSet,
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// conBSet: ConBSet,

conBMap: ConBMap,

Expand All @@ -287,7 +293,9 @@ structure ConA {
enumString: EnumString,

listOfLengthString: ListOfLengthString,
setOfLengthString: SetOfLengthString,
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// setOfLengthString: SetOfLengthString,
mapOfLengthString: MapOfLengthString,

nonStreamingBlob: NonStreamingBlob
Expand Down Expand Up @@ -315,7 +323,10 @@ map MapOfListOfEnumString {

map MapOfSetOfLengthString {
key: LengthString,
value: SetOfLengthString,
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// value: SetOfLengthString,
value: ListOfLengthString
}

@length(min: 2, max: 8)
Expand Down Expand Up @@ -346,7 +357,9 @@ union ConstrainedUnion {

constrainedStructure: ConB,
conBList: ConBList,
conBSet: ConBSet,
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// conBSet: ConBSet,
conBMap: ConBMap,
}

Expand Down Expand Up @@ -420,13 +433,15 @@ list NestedList {
member: ConB
}

set ConBSet {
member: NestedSet
}

set NestedSet {
member: String
}
// TODO(https://github.com/awslabs/smithy-rs/issues/1401): a `set` shape is
// just a `list` shape with `uniqueItems`, which hasn't been implemented yet.
// set ConBSet {
// member: NestedSet
// }
//
// set NestedSet {
// member: String
// }

@length(min: 1, max: 69)
map ConBMap {
Expand Down
3 changes: 2 additions & 1 deletion codegen-core/common-test-models/misc.smithy
Expand Up @@ -255,6 +255,7 @@ list HeaderList {
member: String
}

set HeaderSet {
@uniqueItems
list HeaderSet {
member: String
}
21 changes: 18 additions & 3 deletions codegen-server-test/build.gradle.kts
Expand Up @@ -54,7 +54,12 @@ val allCodegenTests = "../codegen-core/common-test-models".let { commonModels ->
"constraints",
imports = listOf("$commonModels/constraints.smithy"),
),
CodegenTest("aws.protocoltests.restjson#RestJson", "rest_json"),
CodegenTest(
"aws.protocoltests.restjson#RestJson",
"rest_json",
// TODO(https://github.com/awslabs/smithy-rs/issues/1401) `@uniqueItems` is used.
extraConfig = """, "codegen": { "ignoreUnsupportedConstraints": true } """,
),
CodegenTest(
"aws.protocoltests.restjson#RestJsonExtras",
"rest_json_extras",
Expand All @@ -65,8 +70,18 @@ val allCodegenTests = "../codegen-core/common-test-models".let { commonModels ->
extraConfig = """, "codegen": { "ignoreUnsupportedConstraints": true } """,
),
CodegenTest("aws.protocoltests.json10#JsonRpc10", "json_rpc10"),
CodegenTest("aws.protocoltests.json#JsonProtocol", "json_rpc11"),
CodegenTest("aws.protocoltests.misc#MiscService", "misc", imports = listOf("$commonModels/misc.smithy")),
CodegenTest(
"aws.protocoltests.json#JsonProtocol",
"json_rpc11",
extraConfig = """, "codegen": { "ignoreUnsupportedConstraints": true } """,
),
CodegenTest(
"aws.protocoltests.misc#MiscService",
"misc",
imports = listOf("$commonModels/misc.smithy"),
// TODO(https://github.com/awslabs/smithy-rs/issues/1401) `@uniqueItems` is used.
extraConfig = """, "codegen": { "ignoreUnsupportedConstraints": true } """,
),
CodegenTest(
"com.amazonaws.ebs#Ebs", "ebs",
imports = listOf("$commonModels/ebs.json"),
Expand Down
Expand Up @@ -94,6 +94,10 @@ private sealed class UnsupportedConstraintMessageKind {
level,
buildMessageShapeHasUnsupportedConstraintTrait(shape, rangeTrait, constraintTraitsUberIssue),
)
is UnsupportedUniqueItemsTraitOnShape -> LogMessage(
level,
buildMessageShapeHasUnsupportedConstraintTrait(shape, uniqueItemsTrait, constraintTraitsUberIssue),
)
}
}
}
Expand All @@ -104,6 +108,7 @@ private data class UnsupportedLengthTraitOnStreamingBlobShape(val shape: BlobSha
private data class UnsupportedLengthTraitOnCollectionOrOnBlobShape(val shape: Shape, val lengthTrait: LengthTrait) : UnsupportedConstraintMessageKind()
private data class UnsupportedPatternTraitOnStringShape(val shape: Shape, val patternTrait: PatternTrait) : UnsupportedConstraintMessageKind()
private data class UnsupportedRangeTraitOnShape(val shape: Shape, val rangeTrait: RangeTrait) : UnsupportedConstraintMessageKind()
private data class UnsupportedUniqueItemsTraitOnShape(val shape: Shape, val uniqueItemsTrait: UniqueItemsTrait) : UnsupportedConstraintMessageKind()

data class LogMessage(val level: Level, val message: String)
data class ValidationResult(val shouldAbort: Boolean, val messages: List<LogMessage>)
Expand Down Expand Up @@ -228,13 +233,23 @@ fun validateUnsupportedConstraints(model: Model, service: ServiceShape, codegenC
.map { (shape, rangeTrait) -> UnsupportedRangeTraitOnShape(shape, rangeTrait as RangeTrait) }
.toSet()

// 7. UniqueItems trait on any shape is used. It has not been implemented yet.
// TODO(https://github.com/awslabs/smithy-rs/issues/1401)
val unsupportedUniqueItemsTraitOnShapeSet = walker
.walkShapes(service)
.asSequence()
.filterMapShapesToTraits(setOf(UniqueItemsTrait::class.java))
.map { (shape, uniqueItemsTrait) -> UnsupportedUniqueItemsTraitOnShape(shape, uniqueItemsTrait as UniqueItemsTrait) }
.toSet()

val messages =
unsupportedConstraintOnMemberShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } +
unsupportedLengthTraitOnStreamingBlobShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } +
unsupportedConstraintOnShapeReachableViaAnEventStreamSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } +
unsupportedLengthTraitOnCollectionOrOnBlobShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } +
unsupportedPatternTraitOnStringShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } +
unsupportedRangeTraitOnShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) }
unsupportedRangeTraitOnShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } +
unsupportedUniqueItemsTraitOnShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) }

return ValidationResult(shouldAbort = messages.any { it.level == Level.SEVERE }, messages)
}
Expand Down
Expand Up @@ -214,6 +214,27 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest {
validationResult.messages[0].message shouldContain "The integer shape `test#RangeInteger` has the constraint trait `smithy.api#range` attached"
}

@Test
fun `it should detect when the unique items trait is used`() {
val model =
"""
$baseModel
structure TestInputOutput {
uniqueItemsList: UniqueItemsList
}
@uniqueItems
list UniqueItemsList {
member: String
}
""".asSmithyModel()
val validationResult = validateModel(model)

validationResult.messages shouldHaveSize 1
validationResult.messages[0].message shouldContain "The list shape `test#UniqueItemsList` has the constraint trait `smithy.api#uniqueItems` attached"
}

@Test
fun `it should abort when ignoreUnsupportedConstraints is false and unsupported constraints are used`() {
val validationResult = validateModel(constraintTraitOnStreamingBlobShapeModel, ServerCodegenConfig())
Expand Down

0 comments on commit 5eeb5d7

Please sign in to comment.