Repository: smithy-lang/smithy
Pull request #2357 (2024-07-25 21:30:28)

Add intEnum validation to NodeValidationVisitor
#### Background

Adds a new plugin to validate intEnums in NodeValidationVisitor. Previously you could provide values outside of the allowed set without failing validation. IntEnum Shapes also qualify as Integer Shapes, so they will pass through the same validation as Integer Shapes in [`validateNaturalNumber()`](https://github.com/smithy-lang/smithy/blob/main/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java#L228-L248) to make sure floats aren't provided.

#### Testing

Added test cases:
- two for valid values defined by the intEnum
- one for wrong shape
- one for a number with a floating point, similar to Integer tests

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.




Patch:
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/IntEnumPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/IntEnumPlugin.java
new file mode 100644
index 000000000..e33be0e8c
--- /dev/null
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/IntEnumPlugin.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package software.amazon.smithy.model.validation.node;
+
+import java.util.Collection;
+import software.amazon.smithy.model.node.NumberNode;
+import software.amazon.smithy.model.shapes.IntEnumShape;
+import software.amazon.smithy.model.validation.ValidationUtils;
+
+
+/**
+ * Validates NumberNodes against intEnum shapes' allowed enum values.
+ */
+final class IntEnumPlugin extends FilteredPlugin<IntEnumShape, NumberNode> {
+
+    IntEnumPlugin() {
+        super(IntEnumShape.class, NumberNode.class);
+    }
+
+    @Override
+    protected void check(IntEnumShape shape, NumberNode node, Context context, Emitter emitter) {
+        Collection<Integer> values = shape.getEnumValues().values();
+        if (!values.contains(node.getValue().intValue())) {
+            emitter.accept(node, String.format(
+                    "Integer value provided for `%s` must be one of the following values: %s, but found %s",
+                    shape.getId(), ValidationUtils.tickedList(values), node.getValue()));
+        }
+    }
+}
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/NodeValidatorPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/NodeValidatorPlugin.java
index 5398f3529..2042ece5e 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/NodeValidatorPlugin.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/NodeValidatorPlugin.java
@@ -64,6 +64,7 @@ public interface NodeValidatorPlugin {
                 new PatternTraitPlugin(),
                 new RangeTraitPlugin(),
                 new StringEnumPlugin(),
+                new IntEnumPlugin(),
                 new StringLengthPlugin(),
                 new UniqueItemsPlugin());
     }


Test patch:
diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java
index 779a5f7b3..1712d5103 100644
--- a/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java
+++ b/smithy-model/src/test/java/software/amazon/smithy/model/validation/NodeValidationVisitorTest.java
@@ -132,6 +132,13 @@ public class NodeValidationVisitorTest {
                 {"ns.foo#Integer", "9", new String[] {"Value provided for `ns.foo#Integer` must be greater than or equal to 10, but found 9"}},
                 {"ns.foo#Integer", "10.2", new String[] {"integer shapes must not have floating point values, but found `10.2` provided for `ns.foo#Integer`"}},
 
+                // intEnum
+                {"ns.foo#IntEnum", "1", null},
+                {"ns.foo#IntEnum", "2", null},
+                {"ns.foo#IntEnum", "3", new String[] {"Integer value provided for `ns.foo#IntEnum` must be one of the following values: `1`, `2`, but found 3"}},
+                {"ns.foo#IntEnum", "true", new String[] {"Expected number value for intEnum shape, `ns.foo#IntEnum`; found boolean value, `true`"}},
+                {"ns.foo#IntEnum", "1.1", new String[] {"intEnum shapes must not have floating point values, but found `1.1` provided for `ns.foo#IntEnum`"}},
+
                 // long
                 {"ns.foo#Long", "10", null},
                 {"ns.foo#Long", "true", new String[] {"Expected number value for long shape, `ns.foo#Long`; found boolean value, `true`"}},
diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json b/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json
index 3b3375b42..f4100e4c5 100644
--- a/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json
+++ b/smithy-model/src/test/resources/software/amazon/smithy/model/validation/node-validator.json
@@ -28,6 +28,23 @@
                 }
             }
         },
+        "ns.foo#IntEnum": {
+            "type": "intEnum",
+            "members": {
+                "V1": {
+                    "target": "smithy.api#Unit",
+                    "traits": {
+                        "smithy.api#enumValue": 1
+                    }
+                },
+                "V2": {
+                    "target": "smithy.api#Unit",
+                    "traits": {
+                        "smithy.api#enumValue": 2
+                    }
+                }
+            }
+        },
         "ns.foo#Long": {
             "type": "long",
             "traits": {