From 9440777796e9d068511ec1feecfd9cd98b623a70 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Mon, 1 Dec 2025 10:06:38 -0800 Subject: [PATCH 1/9] JmespathRuntime adaptors for Document and SerializableShape --- gradle/libs.versions.toml | 2 +- .../jmespath/DocumentJmespathRuntime.java | 142 +++++++++++++++ .../java/jmespath/JMESPathDocumentUtils.java | 19 ++ .../SerializableStructJmespathRuntime.java | 163 ++++++++++++++++++ 4 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java create mode 100644 jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 87d81d66c..c2322ebc6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] junit5 = "6.0.1" hamcrest = "3.0" -smithy = "1.64.0" +smithy = "1.65.0" jmh = "0.7.3" test-logger-plugin = "4.0.0" spotbugs = "6.0.22" diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java new file mode 100644 index 000000000..05c2fbf70 --- /dev/null +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java @@ -0,0 +1,142 @@ +package software.amazon.smithy.java.jmespath; + +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.jmespath.RuntimeType; +import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; +import software.amazon.smithy.jmespath.evaluation.JmespathRuntime; +import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; +import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; +import software.amazon.smithy.jmespath.evaluation.NumberType; +import software.amazon.smithy.jmespath.evaluation.WrappingIterable; +import software.amazon.smithy.model.shapes.ShapeType; + +import java.math.BigDecimal; +import java.math.BigInteger; + +public class DocumentJmespathRuntime implements JmespathRuntime { + @Override + public RuntimeType typeOf(Document document) { + if (document == null) { + return RuntimeType.NULL; + } + return switch (document.type()) { + case BOOLEAN -> + RuntimeType.BOOLEAN; + case BLOB, ENUM, STRING -> + RuntimeType.STRING; + case BYTE, SHORT, INTEGER, INT_ENUM, LONG, FLOAT, DOUBLE, BIG_DECIMAL, BIG_INTEGER, TIMESTAMP -> + RuntimeType.NUMBER; + case LIST, SET -> + RuntimeType.ARRAY; + case MAP, STRUCTURE, UNION -> + RuntimeType.OBJECT; + default -> throw new IllegalArgumentException("Unknown runtime type: " + document.type()); + }; + } + + @Override + public Document createNull() { + return null; + } + + @Override + public Document createBoolean(boolean b) { + return Document.of(b); + } + + @Override + public boolean toBoolean(Document document) { + return document.asBoolean(); + } + + @Override + public Document createString(String s) { + return Document.of(s); + } + + @Override + public String toString(Document document) { + if (document.isType(ShapeType.BLOB)) { + return JMESPathDocumentUtils.asString(document.asBlob()); + } else { + return document.asString(); + } + } + + @Override + public Document createNumber(Number number) { + return switch (EvaluationUtils.numberType(number)) { + case BYTE -> Document.of(number.byteValue()); + case SHORT -> Document.of(number.shortValue()); + case INTEGER -> Document.of(number.intValue()); + case LONG -> Document.of(number.longValue()); + case FLOAT -> Document.of(number.floatValue()); + case DOUBLE -> Document.of(number.doubleValue()); + case BIG_INTEGER -> Document.of((BigInteger)number); + case BIG_DECIMAL -> Document.of((BigDecimal)number); + }; + } + + @Override + public NumberType numberType(Document document) { + return switch (document.type()) { + case BYTE -> NumberType.BYTE; + case SHORT -> NumberType.SHORT; + case INTEGER, INT_ENUM -> NumberType.INTEGER; + case LONG -> NumberType.LONG; + case FLOAT -> NumberType.FLOAT; + case DOUBLE -> NumberType.DOUBLE; + case BIG_DECIMAL, TIMESTAMP -> NumberType.BIG_DECIMAL; + case BIG_INTEGER -> NumberType.BIG_INTEGER; + default -> throw new IllegalArgumentException("Not a number: " + document); + }; + } + + @Override + public Number toNumber(Document document) { + if (document.isType(ShapeType.TIMESTAMP)) { + return JMESPathDocumentUtils.asBigDecimal(document.asTimestamp()); + } else { + return document.asNumber(); + } + } + + @Override + public Number length(Document document) { + if (is(document, RuntimeType.STRING)) { + return EvaluationUtils.codePointCount(document.asString()); + } else { + // This handles objects and arrays + return document.size(); + } + } + + @Override + public Document element(Document document, Document index) { + return document.asList().get(toNumber(index).intValue()); + } + + @Override + public Iterable toIterable(Document document) { + return switch (typeOf(document)) { + case ARRAY -> document.asList(); + case OBJECT -> new WrappingIterable<>(Document::of, document.asStringMap().keySet()); + default -> throw new IllegalArgumentException("Not iterable: " + document); + }; + } + + @Override + public JmespathRuntime.ArrayBuilder arrayBuilder() { + return new ListArrayBuilder<>(this, Document::of); + } + + @Override + public Document value(Document document, Document key) { + return document.getMember(key.asString()); + } + + @Override + public JmespathRuntime.ObjectBuilder objectBuilder() { + return new MapObjectBuilder<>(this, Document::of); + } +} diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentUtils.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentUtils.java index be0102402..17b84a970 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentUtils.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentUtils.java @@ -5,6 +5,10 @@ package software.amazon.smithy.java.jmespath; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.time.Instant; +import java.util.Base64; import java.util.EnumSet; import software.amazon.smithy.java.core.serde.document.Document; import software.amazon.smithy.model.shapes.ShapeType; @@ -27,6 +31,7 @@ static boolean isTruthy(Document document) { } return switch (document.type()) { // TODO: Should structures be included here? + // TODO-RS: YES, this is a bug case LIST, MAP -> document.size() != 0; case STRING -> !document.asString().isEmpty(); case BOOLEAN -> document.asBoolean(); @@ -43,5 +48,19 @@ static boolean isNumeric(Document document) { return document != null && NUMERIC_TYPES.contains(document.type()); } + static BigDecimal asBigDecimal(Instant instant) { + // TODO: Faster way? Unlikely to be used in practice, + // mainly just need to compare timestamps which doesn't use this. + BigDecimal secondsPart = BigDecimal.valueOf(instant.getEpochSecond()); + BigDecimal nanosPart = BigDecimal.valueOf(instant.getNano()).movePointLeft(9); + return secondsPart.add(nanosPart); + } + + static String asString(ByteBuffer byteBuffer) { + byte[] bytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(bytes); + return Base64.getEncoder().encodeToString(bytes); + } + private JMESPathDocumentUtils() {} } diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java new file mode 100644 index 000000000..95d75991c --- /dev/null +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java @@ -0,0 +1,163 @@ +package software.amazon.smithy.java.jmespath; + +import software.amazon.smithy.java.core.schema.Schema; +import software.amazon.smithy.java.core.schema.SerializableStruct; +import software.amazon.smithy.java.core.serde.SerializationException; +import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.jmespath.RuntimeType; +import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; +import software.amazon.smithy.jmespath.evaluation.JmespathRuntime; +import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; +import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; +import software.amazon.smithy.jmespath.evaluation.NumberType; +import software.amazon.smithy.jmespath.evaluation.WrappingIterable; +import software.amazon.smithy.model.shapes.ShapeType; + +import java.lang.invoke.SerializedLambda; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +// TODO: still need to handle enums/intenum. +// Requires tracking schema values from containers since the generated types +// have no common supertype/or interface. +public class SerializableStructJmespathRuntime implements JmespathRuntime { + + // Exact class matches for faster typeOf matching + private static final Map, RuntimeType> typeForClass = new HashMap<>(); + static { + typeForClass.put(Boolean.class, RuntimeType.BOOLEAN); + typeForClass.put(String.class, RuntimeType.STRING); + for (Class klass : EvaluationUtils.numberTypeForClass.keySet()) { + typeForClass.put(klass, RuntimeType.NUMBER); + } + typeForClass.put(Instant.class, RuntimeType.NUMBER); + } + + @Override + public RuntimeType typeOf(Object value) { + if (value == null) { + return RuntimeType.NULL; + } + + // Fast path: known exact class + RuntimeType runtimeType = typeForClass.get(value.getClass()); + if (runtimeType != null) { + return runtimeType; + } + + // Slower instanceof checks + // These could be cached and/or precalculated as well + if (value instanceof List) { + return RuntimeType.ARRAY; + } else if (value instanceof Map || value instanceof SerializableStruct) { + return RuntimeType.OBJECT; + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public Document createNull() { + return null; + } + + @Override + public Object createBoolean(boolean b) { + return b; + } + + @Override + public boolean toBoolean(Object value) { + return (Boolean)value; + } + + @Override + public Object createString(String s) { + return s; + } + + @Override + public String toString(Object value) { + return (String)value; + } + + @Override + public Object createNumber(Number number) { + return number; + } + + @Override + public NumberType numberType(Object object) { + return EvaluationUtils.numberType((Number)object); + } + + @Override + public Number toNumber(Object value) { + if (value instanceof Number number) { + return number; + } else if (value instanceof Instant instant) { + return JMESPathDocumentUtils.asBigDecimal(instant); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public Number length(Object value) { + if (value instanceof String s) { + return EvaluationUtils.codePointCount(s); + } else if (value instanceof Collection c) { + return c.size(); + } else if (value instanceof SerializableStruct struct) { + return struct.schema().members().size(); + } else { + throw new IllegalArgumentException("Unknown runtime type: " + value); + } + } + + @Override + public Object element(Object value, Object index) { + return ((List)value).get(toNumber(index).intValue()); + } + + @Override + public Iterable toIterable(Object value) { + if (value instanceof List list) { + return list; + } else if (value instanceof Map map) { + return map.keySet(); + } else if (value instanceof SerializableStruct struct) { + return new WrappingIterable<>(Schema::memberName, struct.schema().members()); + } else { + throw new IllegalArgumentException("Unknown runtime type: " + value); + } + } + + @Override + public ArrayBuilder arrayBuilder() { + return new ListArrayBuilder<>(this, x -> x); + } + + @Override + public Object value(Object object, Object key) { + if (object instanceof SerializableStruct struct) { + // TODO: Check what happens on invalid member name + return struct.getMemberValue(struct.schema().member((String)key)); + } else if (object instanceof Map map) { + return map.get(key); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public ObjectBuilder objectBuilder() { + return new MapObjectBuilder<>(this, x -> x); + } +} From 6588570af0e8959df2b0b8460996bc12628fb7d6 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Mon, 1 Dec 2025 12:01:09 -0800 Subject: [PATCH 2/9] Add Smithy[Int]Enum --- .../codegen/generators/EnumGenerator.java | 5 +++- .../test-cases/enums/expected/EnumType.java | 3 ++- .../enums/expected/IntEnumType.java | 3 ++- .../smithy/java/core/schema/SmithyEnum.java | 6 +++++ .../java/core/schema/SmithyIntEnum.java | 6 +++++ ...java => GeneratedTypeJmespathRuntime.java} | 25 +++++++++++-------- 6 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java create mode 100644 core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java rename jmespath/src/main/java/software/amazon/smithy/java/jmespath/{SerializableStructJmespathRuntime.java => GeneratedTypeJmespathRuntime.java} (88%) diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java index a2f3e230a..04fe09a8d 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java @@ -19,6 +19,8 @@ import software.amazon.smithy.java.codegen.sections.ClassSection; import software.amazon.smithy.java.codegen.sections.EnumVariantSection; import software.amazon.smithy.java.codegen.writer.JavaWriter; +import software.amazon.smithy.java.core.schema.SmithyEnum; +import software.amazon.smithy.java.core.schema.SmithyIntEnum; import software.amazon.smithy.java.core.schema.SerializableShape; import software.amazon.smithy.java.core.serde.ShapeDeserializer; import software.amazon.smithy.java.core.serde.ShapeSerializer; @@ -44,7 +46,7 @@ public void accept(T directive) { directive.context().writerDelegator().useShapeWriter(shape, writer -> { writer.pushState(new ClassSection(shape)); var template = """ - public sealed interface ${shape:T} extends ${serializableShape:T} { + public sealed interface ${shape:T} extends ${enum:T}, ${serializableShape:T} { ${staticImpls:C|} ${schema:C|} @@ -68,6 +70,7 @@ default void serialize(${shapeSerializer:T} serializer) { var shapeSymbol = directive.symbolProvider().toSymbol(shape); writer.putContext("shape", shapeSymbol); writer.putContext("serializableShape", SerializableShape.class); + writer.putContext("enum", shape.isEnumShape() ? SmithyEnum.class : SmithyIntEnum.class); writer.putContext("shapeSerializer", ShapeSerializer.class); var valueSymbol = shapeSymbol.expectProperty(SymbolProperties.ENUM_VALUE_TYPE); writer.putContext("value", valueSymbol); diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/EnumType.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/EnumType.java index 7acc24266..808d7125a 100644 --- a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/EnumType.java +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/EnumType.java @@ -7,6 +7,7 @@ import software.amazon.smithy.java.core.schema.Schema; import software.amazon.smithy.java.core.schema.SerializableShape; import software.amazon.smithy.java.core.schema.ShapeBuilder; +import software.amazon.smithy.java.core.schema.SmithyEnum; import software.amazon.smithy.java.core.serde.ShapeDeserializer; import software.amazon.smithy.java.core.serde.ShapeSerializer; import software.amazon.smithy.java.core.serde.ToStringSerializer; @@ -14,7 +15,7 @@ import software.amazon.smithy.utils.SmithyGenerated; @SmithyGenerated -public sealed interface EnumType extends SerializableShape { +public sealed interface EnumType extends SmithyEnum, SerializableShape { EnumType OPTION_ONE = new OptionOneType(); EnumType OPTION_TWO = new OptionTwoType(); List $TYPES = List.of(OPTION_ONE, OPTION_TWO); diff --git a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/IntEnumType.java b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/IntEnumType.java index df7a09550..3305fff02 100644 --- a/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/IntEnumType.java +++ b/codegen/plugins/types-codegen/src/test/resources/software/amazon/smithy/java/codegen/types/test-cases/enums/expected/IntEnumType.java @@ -6,6 +6,7 @@ import software.amazon.smithy.java.core.schema.Schema; import software.amazon.smithy.java.core.schema.SerializableShape; import software.amazon.smithy.java.core.schema.ShapeBuilder; +import software.amazon.smithy.java.core.schema.SmithyIntEnum; import software.amazon.smithy.java.core.serde.ShapeDeserializer; import software.amazon.smithy.java.core.serde.ShapeSerializer; import software.amazon.smithy.java.core.serde.ToStringSerializer; @@ -13,7 +14,7 @@ import software.amazon.smithy.utils.SmithyGenerated; @SmithyGenerated -public sealed interface IntEnumType extends SerializableShape { +public sealed interface IntEnumType extends SmithyIntEnum, SerializableShape { IntEnumType FIRST = new FirstType(); IntEnumType SECOND = new SecondType(); IntEnumType FIFTH = new FifthType(); diff --git a/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java new file mode 100644 index 000000000..770be619a --- /dev/null +++ b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java @@ -0,0 +1,6 @@ +package software.amazon.smithy.java.core.schema; + +public interface SmithyEnum { + + String getValue(); +} diff --git a/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java new file mode 100644 index 000000000..fd33f881e --- /dev/null +++ b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java @@ -0,0 +1,6 @@ +package software.amazon.smithy.java.core.schema; + +public interface SmithyIntEnum { + + int getValue(); +} diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java similarity index 88% rename from jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java rename to jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java index 95d75991c..6975e433f 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/SerializableStructJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java @@ -1,8 +1,9 @@ package software.amazon.smithy.java.jmespath; +import software.amazon.smithy.java.core.schema.SmithyEnum; +import software.amazon.smithy.java.core.schema.SmithyIntEnum; import software.amazon.smithy.java.core.schema.Schema; import software.amazon.smithy.java.core.schema.SerializableStruct; -import software.amazon.smithy.java.core.serde.SerializationException; import software.amazon.smithy.java.core.serde.document.Document; import software.amazon.smithy.jmespath.RuntimeType; import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; @@ -11,22 +12,14 @@ import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; import software.amazon.smithy.jmespath.evaluation.NumberType; import software.amazon.smithy.jmespath.evaluation.WrappingIterable; -import software.amazon.smithy.model.shapes.ShapeType; -import java.lang.invoke.SerializedLambda; -import java.math.BigDecimal; -import java.math.BigInteger; import java.time.Instant; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; -// TODO: still need to handle enums/intenum. -// Requires tracking schema values from containers since the generated types -// have no common supertype/or interface. -public class SerializableStructJmespathRuntime implements JmespathRuntime { +public class GeneratedTypeJmespathRuntime implements JmespathRuntime { // Exact class matches for faster typeOf matching private static final Map, RuntimeType> typeForClass = new HashMap<>(); @@ -57,6 +50,10 @@ public RuntimeType typeOf(Object value) { return RuntimeType.ARRAY; } else if (value instanceof Map || value instanceof SerializableStruct) { return RuntimeType.OBJECT; + } else if (value instanceof SmithyEnum) { + return RuntimeType.STRING; + } else if (value instanceof SmithyIntEnum) { + return RuntimeType.NUMBER; } else { throw new IllegalArgumentException(); } @@ -84,7 +81,11 @@ public Object createString(String s) { @Override public String toString(Object value) { - return (String)value; + if (value instanceof SmithyEnum enumValue) { + return enumValue.getValue(); + } else { + return (String) value; + } } @Override @@ -103,6 +104,8 @@ public Number toNumber(Object value) { return number; } else if (value instanceof Instant instant) { return JMESPathDocumentUtils.asBigDecimal(instant); + } else if (value instanceof SmithyIntEnum) { + return ((SmithyIntEnum)value).getValue(); } else { throw new IllegalArgumentException(); } From 13a469179c55864c887ba4502eb9767a642a6405 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Wed, 3 Dec 2025 16:00:09 -0800 Subject: [PATCH 3/9] Used shared test runner --- gradle/libs.versions.toml | 1 + jmespath/build.gradle.kts | 1 + .../jmespath/DocumentJmespathRuntime.java | 18 +++-- .../GeneratedTypeJmespathRuntime.java | 74 +++++++++++-------- ...cumentJmespathRuntimeComplianceTests.java} | 5 +- 5 files changed, 62 insertions(+), 37 deletions(-) rename jmespath/src/test/java/software/amazon/smithy/java/jmespath/{JMESPathComplianceTests.java => DocumentJmespathRuntimeComplianceTests.java} (78%) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c2322ebc6..18e15bb1f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,6 +31,7 @@ smithy-aws-protocol-tests = { module = "software.amazon.smithy:smithy-aws-protoc smithy-protocol-tests = { module = "software.amazon.smithy:smithy-protocol-tests", version.ref = "smithy" } smithy-validation-model = { module = "software.amazon.smithy:smithy-validation-model", version.ref = "smithy" } smithy-jmespath = { module = "software.amazon.smithy:smithy-jmespath", version.ref = "smithy" } +smithy-jmespath-tests = { module = "software.amazon.smithy:smithy-jmespath-tests", version.ref = "smithy" } smithy-waiters = { module = "software.amazon.smithy:smithy-waiters", version.ref = "smithy" } smithy-utils = { module = "software.amazon.smithy:smithy-utils", version.ref = "smithy" } smithy-traitcodegen = { module = "software.amazon.smithy:smithy-trait-codegen", version.ref = "smithy" } diff --git a/jmespath/build.gradle.kts b/jmespath/build.gradle.kts index 0b542f7df..a9a1f56e8 100644 --- a/jmespath/build.gradle.kts +++ b/jmespath/build.gradle.kts @@ -10,4 +10,5 @@ extra["moduleName"] = "software.amazon.smithy.java.jmespath" dependencies { api(project(":core")) api(libs.smithy.jmespath) + testImplementation(libs.smithy.jmespath.tests) } diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java index 05c2fbf70..00b02004d 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java @@ -13,7 +13,11 @@ import java.math.BigDecimal; import java.math.BigInteger; +// TODO: default equal isn't correct, need to normalize number types public class DocumentJmespathRuntime implements JmespathRuntime { + + public static final DocumentJmespathRuntime INSTANCE = new DocumentJmespathRuntime(); + @Override public RuntimeType typeOf(Document document) { if (document == null) { @@ -45,7 +49,7 @@ public Document createBoolean(boolean b) { } @Override - public boolean toBoolean(Document document) { + public boolean asBoolean(Document document) { return document.asBoolean(); } @@ -55,7 +59,7 @@ public Document createString(String s) { } @Override - public String toString(Document document) { + public String asString(Document document) { if (document.isType(ShapeType.BLOB)) { return JMESPathDocumentUtils.asString(document.asBlob()); } else { @@ -93,7 +97,7 @@ public NumberType numberType(Document document) { } @Override - public Number toNumber(Document document) { + public Number asNumber(Document document) { if (document.isType(ShapeType.TIMESTAMP)) { return JMESPathDocumentUtils.asBigDecimal(document.asTimestamp()); } else { @@ -113,7 +117,7 @@ public Number length(Document document) { @Override public Document element(Document document, Document index) { - return document.asList().get(toNumber(index).intValue()); + return document.asList().get(asNumber(index).intValue()); } @Override @@ -132,7 +136,11 @@ public JmespathRuntime.ArrayBuilder arrayBuilder() { @Override public Document value(Document document, Document key) { - return document.getMember(key.asString()); + if (typeOf(document) == RuntimeType.OBJECT) { + return document.getMember(key.asString()); + } else { + return createNull(); + } } @Override diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java index 6975e433f..c6f6d11ad 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java @@ -7,12 +7,15 @@ import software.amazon.smithy.java.core.serde.document.Document; import software.amazon.smithy.jmespath.RuntimeType; import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; +import software.amazon.smithy.jmespath.evaluation.InheritingClassMap; import software.amazon.smithy.jmespath.evaluation.JmespathRuntime; import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; import software.amazon.smithy.jmespath.evaluation.NumberType; import software.amazon.smithy.jmespath.evaluation.WrappingIterable; +import java.math.BigDecimal; +import java.math.BigInteger; import java.time.Instant; import java.util.Collection; import java.util.HashMap; @@ -21,16 +24,35 @@ public class GeneratedTypeJmespathRuntime implements JmespathRuntime { - // Exact class matches for faster typeOf matching - private static final Map, RuntimeType> typeForClass = new HashMap<>(); - static { - typeForClass.put(Boolean.class, RuntimeType.BOOLEAN); - typeForClass.put(String.class, RuntimeType.STRING); - for (Class klass : EvaluationUtils.numberTypeForClass.keySet()) { - typeForClass.put(klass, RuntimeType.NUMBER); - } - typeForClass.put(Instant.class, RuntimeType.NUMBER); - } + private static final InheritingClassMap typeForClass = InheritingClassMap.builder() + .put(String.class, RuntimeType.STRING) + .put(Boolean.class, RuntimeType.BOOLEAN) + .put(Byte.class, RuntimeType.NUMBER) + .put(Short.class, RuntimeType.NUMBER) + .put(Integer.class, RuntimeType.NUMBER) + .put(Long.class, RuntimeType.NUMBER) + .put(Float.class, RuntimeType.NUMBER) + .put(Double.class, RuntimeType.NUMBER) + .put(BigInteger.class, RuntimeType.NUMBER) + .put(BigDecimal.class, RuntimeType.NUMBER) + .put(Instant.class, RuntimeType.NUMBER) + .put(SerializableStruct.class, RuntimeType.OBJECT) + .put(SmithyEnum.class, RuntimeType.STRING) + .put(SmithyIntEnum.class, RuntimeType.NUMBER) + .build(); + + private static final InheritingClassMap numberTypeForClass = InheritingClassMap.builder() + .put(Byte.class, NumberType.BYTE) + .put(Short.class, NumberType.SHORT) + .put(Integer.class, NumberType.INTEGER) + .put(Long.class, NumberType.LONG) + .put(Float.class, NumberType.FLOAT) + .put(Double.class, NumberType.DOUBLE) + .put(BigInteger.class, NumberType.BIG_INTEGER) + .put(BigDecimal.class, NumberType.BIG_DECIMAL) + .put(Instant.class, NumberType.BIG_DECIMAL) + .put(SmithyIntEnum.class, NumberType.INTEGER) + .build(); @Override public RuntimeType typeOf(Object value) { @@ -38,25 +60,12 @@ public RuntimeType typeOf(Object value) { return RuntimeType.NULL; } - // Fast path: known exact class RuntimeType runtimeType = typeForClass.get(value.getClass()); if (runtimeType != null) { return runtimeType; } - // Slower instanceof checks - // These could be cached and/or precalculated as well - if (value instanceof List) { - return RuntimeType.ARRAY; - } else if (value instanceof Map || value instanceof SerializableStruct) { - return RuntimeType.OBJECT; - } else if (value instanceof SmithyEnum) { - return RuntimeType.STRING; - } else if (value instanceof SmithyIntEnum) { - return RuntimeType.NUMBER; - } else { - throw new IllegalArgumentException(); - } + throw new IllegalArgumentException(); } @Override @@ -70,7 +79,7 @@ public Object createBoolean(boolean b) { } @Override - public boolean toBoolean(Object value) { + public boolean asBoolean(Object value) { return (Boolean)value; } @@ -80,7 +89,7 @@ public Object createString(String s) { } @Override - public String toString(Object value) { + public String asString(Object value) { if (value instanceof SmithyEnum enumValue) { return enumValue.getValue(); } else { @@ -94,12 +103,16 @@ public Object createNumber(Number number) { } @Override - public NumberType numberType(Object object) { - return EvaluationUtils.numberType((Number)object); + public NumberType numberType(Object value) { + NumberType numberType = numberTypeForClass.get(value.getClass()); + if (numberType != null) { + return numberType; + } + throw new IllegalArgumentException(); } @Override - public Number toNumber(Object value) { + public Number asNumber(Object value) { if (value instanceof Number number) { return number; } else if (value instanceof Instant instant) { @@ -126,7 +139,7 @@ public Number length(Object value) { @Override public Object element(Object value, Object index) { - return ((List)value).get(toNumber(index).intValue()); + return ((List)value).get(asNumber(index).intValue()); } @Override @@ -136,6 +149,7 @@ public Iterable toIterable(Object value) { } else if (value instanceof Map map) { return map.keySet(); } else if (value instanceof SerializableStruct struct) { + // TODO: Should this be only present members? return new WrappingIterable<>(Schema::memberName, struct.schema().members()); } else { throw new IllegalArgumentException("Unknown runtime type: " + value); diff --git a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/JMESPathComplianceTests.java b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntimeComplianceTests.java similarity index 78% rename from jmespath/src/test/java/software/amazon/smithy/java/jmespath/JMESPathComplianceTests.java rename to jmespath/src/test/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntimeComplianceTests.java index e83b4b886..50a34c66c 100644 --- a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/JMESPathComplianceTests.java +++ b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntimeComplianceTests.java @@ -8,8 +8,9 @@ import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.jmespath.tests.ComplianceTestRunner; -public class JMESPathComplianceTests { +public class DocumentJmespathRuntimeComplianceTests { @ParameterizedTest(name = "{0}") @MethodSource("source") public void testRunner(String filename, Runnable callable) throws Exception { @@ -17,6 +18,6 @@ public void testRunner(String filename, Runnable callable) throws Exception { } public static Stream source() { - return ComplianceTestRunner.defaultParameterizedTestSource(JMESPathComplianceTests.class); + return ComplianceTestRunner.defaultParameterizedTestSource(DocumentJmespathRuntime.INSTANCE); } } From 3a6707ab62846122a532f0a6e770460a53ed5cc6 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Fri, 5 Dec 2025 15:41:16 -0800 Subject: [PATCH 4/9] Use shared evaluator instead --- .../jmespath/DocumentJmespathRuntime.java | 15 +- .../java/jmespath/JMESPathDocumentQuery.java | 263 +-------- .../java/jmespath/JMESPathFunction.java | 511 ------------------ 3 files changed, 15 insertions(+), 774 deletions(-) delete mode 100644 jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathFunction.java diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java index 00b02004d..94527cf85 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java @@ -1,6 +1,9 @@ package software.amazon.smithy.java.jmespath; +import software.amazon.smithy.java.core.serde.SerializationException; import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.jmespath.JmespathException; +import software.amazon.smithy.jmespath.JmespathExceptionType; import software.amazon.smithy.jmespath.RuntimeType; import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; import software.amazon.smithy.jmespath.evaluation.JmespathRuntime; @@ -63,7 +66,11 @@ public String asString(Document document) { if (document.isType(ShapeType.BLOB)) { return JMESPathDocumentUtils.asString(document.asBlob()); } else { - return document.asString(); + try { + return document.asString(); + } catch (SerializationException e) { + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Not a string: " + document, e); + } } } @@ -101,7 +108,11 @@ public Number asNumber(Document document) { if (document.isType(ShapeType.TIMESTAMP)) { return JMESPathDocumentUtils.asBigDecimal(document.asTimestamp()); } else { - return document.asNumber(); + try { + return document.asNumber(); + } catch (SerializationException e) { + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Not a number: " + document, e); + } } } diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java index 773f16cb9..f8f5cddb1 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java @@ -32,6 +32,7 @@ import software.amazon.smithy.jmespath.ast.ProjectionExpression; import software.amazon.smithy.jmespath.ast.SliceExpression; import software.amazon.smithy.jmespath.ast.Subexpression; +import software.amazon.smithy.jmespath.evaluation.Evaluator; import software.amazon.smithy.model.shapes.ShapeType; /** @@ -60,266 +61,6 @@ public static Document query(String expression, Document document) { * @return result of query */ public static Document query(JmespathExpression expression, Document document) { - return new Visitor(document).visit(expression); - } - - private record Visitor(Document document) implements ExpressionVisitor { - private static final EnumSet OBJECT_TYPES = EnumSet.of( - ShapeType.MAP, - ShapeType.STRUCTURE, - ShapeType.UNION); - - private Document visit(JmespathExpression expression) { - if (document == null) { - return null; - } - return expression.accept(this); - } - - @Override - public Document visitComparator(ComparatorExpression comparatorExpression) { - var left = visit(comparatorExpression.getLeft()); - var right = visit(comparatorExpression.getRight()); - Boolean value = switch (comparatorExpression.getComparator()) { - case EQUAL -> Objects.equals(left, right); - case NOT_EQUAL -> !Objects.equals(left, right); - // NOTE: Ordering operators >, >=, <, <= are only valid for numbers. All invalid - // comparisons return null. - case LESS_THAN -> - JMESPathDocumentUtils.isNumericComparison(left, right) ? Document.compare(left, right) < 0 : null; - case LESS_THAN_EQUAL -> - JMESPathDocumentUtils.isNumericComparison(left, right) ? Document.compare(left, right) <= 0 : null; - case GREATER_THAN -> - JMESPathDocumentUtils.isNumericComparison(left, right) ? Document.compare(left, right) > 0 : null; - case GREATER_THAN_EQUAL -> - JMESPathDocumentUtils.isNumericComparison(left, right) ? Document.compare(left, right) >= 0 : null; - }; - return value == null ? null : Document.of(value); - } - - @Override - public Document visitCurrentNode(CurrentExpression currentExpression) { - return document; - } - - @Override - public Document visitExpressionType(ExpressionTypeExpression expressionTypeExpression) { - return visit(expressionTypeExpression.getExpression()); - } - - @Override - public Document visitFlatten(FlattenExpression flattenExpression) { - var value = visit(flattenExpression.getExpression()); - - // Only lists can be flattened. - if (value == null || !value.type().equals(ShapeType.LIST)) { - return null; - } - List flattened = new ArrayList<>(); - for (var val : value.asList()) { - if (val.type().equals(ShapeType.LIST)) { - flattened.addAll(val.asList()); - continue; - } - flattened.add(val); - } - return Document.of(flattened); - } - - @Override - public Document visitFunction(FunctionExpression functionExpression) { - var function = JMESPathFunction.from(functionExpression); - List arguments = new ArrayList<>(); - ExpressionTypeExpression functionReference = null; - for (var expr : functionExpression.getArguments()) { - // Store up to one function reference for passing to jmespath functions - if (expr instanceof ExpressionTypeExpression exprType) { - if (functionReference != null) { - throw new IllegalArgumentException( - "JMESPath functions only support a single function reference"); - } - functionReference = exprType; - continue; - } - arguments.add(visit(expr)); - } - return function.apply(arguments, functionReference); - } - - @Override - public Document visitField(FieldExpression fieldExpression) { - return switch (document.type()) { - case MAP, STRUCTURE, UNION -> document.getMember(fieldExpression.getName()); - default -> null; - }; - } - - @Override - public Document visitIndex(IndexExpression indexExpression) { - var index = indexExpression.getIndex(); - if (!document.type().equals(ShapeType.LIST)) { - return null; - } - // Negative indices indicate reverse indexing in JMESPath - if (index < 0) { - index = document.size() + index; - } - if (document.size() <= index || index < 0) { - return null; - } - return document.asList().get(index); - } - - @Override - public Document visitLiteral(LiteralExpression literalExpression) { - if (literalExpression.isNumberValue()) { - // TODO: Remove this check by correcting behavior in smithy-jmespath to correctly - // handle int vs double - var value = literalExpression.expectNumberValue(); - if (value.doubleValue() == Math.floor(value.doubleValue())) { - return Document.ofNumber(value.longValue()); - } - } else if (literalExpression.isArrayValue()) { - List result = new ArrayList<>(); - for (var item : literalExpression.expectArrayValue()) { - result.add(visit(LiteralExpression.from(item))); - } - return Document.of(result); - } else if (literalExpression.isObjectValue()) { - var value = literalExpression.expectObjectValue(); - Map result = new HashMap<>(); - for (var entry : value.entrySet()) { - result.put(entry.getKey(), visit(LiteralExpression.from(entry.getValue()))); - } - return Document.of(result); - } - return literalExpression.isNullValue() ? null : Document.ofObject(literalExpression.getValue()); - } - - @Override - public Document visitMultiSelectList(MultiSelectListExpression multiSelectListExpression) { - List output = new ArrayList<>(); - for (var exp : multiSelectListExpression.getExpressions()) { - output.add(visit(exp)); - } - return output.isEmpty() ? null : Document.of(output); - } - - @Override - public Document visitMultiSelectHash(MultiSelectHashExpression multiSelectHashExpression) { - Map output = new HashMap<>(); - for (var expEntry : multiSelectHashExpression.getExpressions().entrySet()) { - output.put(expEntry.getKey(), visit(expEntry.getValue())); - } - return output.isEmpty() ? null : Document.of(output); - } - - @Override - public Document visitAnd(AndExpression andExpression) { - var left = visit(andExpression.getLeft()); - return JMESPathDocumentUtils.isTruthy(left) ? visit(andExpression.getRight()) : left; - } - - @Override - public Document visitOr(OrExpression orExpression) { - var left = visit(orExpression.getLeft()); - if (JMESPathDocumentUtils.isTruthy(left)) { - return left; - } - return orExpression.getRight().accept(this); - } - - @Override - public Document visitNot(NotExpression notExpression) { - var output = visit(notExpression.getExpression()); - return Document.of(!JMESPathDocumentUtils.isTruthy(output)); - } - - @Override - public Document visitProjection(ProjectionExpression projectionExpression) { - var resultList = visit(projectionExpression.getLeft()); - if (resultList == null || !resultList.type().equals(ShapeType.LIST)) { - return null; - } - List projectedResults = new ArrayList<>(); - for (var result : resultList.asList()) { - var projected = new Visitor(result).visit(projectionExpression.getRight()); - if (projected != null) { - projectedResults.add(projected); - } - } - return Document.of(projectedResults); - } - - @Override - public Document visitFilterProjection(FilterProjectionExpression filterProjectionExpression) { - var left = visit(filterProjectionExpression.getLeft()); - if (left == null || !left.type().equals(ShapeType.LIST)) { - return null; - } - List results = new ArrayList<>(); - for (var val : left.asList()) { - var output = new Visitor(val).visit(filterProjectionExpression.getComparison()); - if (JMESPathDocumentUtils.isTruthy(output)) { - var result = new Visitor(val).visit(filterProjectionExpression.getRight()); - if (result != null) { - results.add(result); - } - } - } - return Document.of(results); - } - - @Override - public Document visitObjectProjection(ObjectProjectionExpression objectProjectionExpression) { - var resultObject = visit(objectProjectionExpression.getLeft()); - if (resultObject == null || !OBJECT_TYPES.contains(resultObject.type())) { - return null; - } - List projectedResults = new ArrayList<>(); - for (var member : resultObject.getMemberNames()) { - var memberValue = resultObject.getMember(member); - if (memberValue != null) { - var projectedResult = new Visitor(memberValue).visit(objectProjectionExpression.getRight()); - if (projectedResult != null) { - projectedResults.add(projectedResult); - } - } - } - return Document.of(projectedResults); - } - - @Override - public Document visitSlice(SliceExpression sliceExpression) { - List output = new ArrayList<>(); - int step = sliceExpression.getStep(); - int start = sliceExpression.getStart().orElseGet(() -> step > 0 ? 0 : document.size()); - if (start < 0) { - start = document.size() + start; - } - int stop = sliceExpression.getStop().orElseGet(() -> step > 0 ? document.size() : 0); - if (stop < 0) { - stop = document.size() + stop; - } - - var docList = document.asList(); - if (start < stop) { - for (int idx = start; idx < stop; idx += step) { - output.add(docList.get(idx)); - } - } else { - // List is iterating in reverse - for (int idx = start; idx > stop; idx += step) { - output.add(docList.get(idx - 1)); - } - } - return Document.of(output); - } - - @Override - public Document visitSubexpression(Subexpression subexpression) { - var left = visit(subexpression.getLeft()); - return new Visitor(left).visit(subexpression.getRight()); - } + return new Evaluator<>(document, DocumentJmespathRuntime.INSTANCE).visit(expression); } } diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathFunction.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathFunction.java deleted file mode 100644 index 831b4acdc..000000000 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathFunction.java +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.java.jmespath; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import software.amazon.smithy.java.core.serde.document.Document; -import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression; -import software.amazon.smithy.jmespath.ast.FunctionExpression; -import software.amazon.smithy.model.shapes.ShapeType; - -/** - * Built-in JMESPath functions. - * - * @see JMESPath built-in functions - */ -// TODO: Complete support for all built-in functions -enum JMESPathFunction { - ABS("abs", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var arg = arguments.get(0); - return switch (arg.type()) { - case BYTE -> Document.of(Math.abs(arg.asByte())); - case INTEGER, INT_ENUM -> Document.of(Math.abs(arg.asInteger())); - case LONG -> Document.of(Math.abs(arg.asLong())); - case BIG_DECIMAL -> Document.of(arg.asBigDecimal().abs()); - case BIG_INTEGER -> Document.of(arg.asBigInteger().abs()); - case SHORT -> Document.of(Math.abs(arg.asShort())); - case DOUBLE -> Document.of(Math.abs(arg.asDouble())); - case FLOAT -> Document.of(Math.abs(arg.asFloat())); - default -> throw new IllegalArgumentException("`abs` only supports numeric arguments"); - }; - } - }, - AVG("avg", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var list = arguments.get(0); - if (!list.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`avg` only supports array arguments"); - } - if (list.size() == 0) { - return null; - } - var firstItem = list.asList().get(0); - return switch (firstItem.type()) { - case INTEGER, INT_ENUM, LONG, SHORT, BYTE -> { - long sum = 0; - for (var item : list.asList()) { - sum += item.asLong(); - } - yield Document.of((double) sum / (double) list.size()); - } - case FLOAT, DOUBLE -> { - double sum = 0; - for (var item : list.asList()) { - sum += item.asDouble(); - } - yield Document.of(sum / (double) list.size()); - } - case BIG_DECIMAL -> { - var sum = BigDecimal.valueOf(0); - for (var item : list.asList()) { - sum = sum.add(item.asBigDecimal()); - } - yield Document.of(sum.divide(BigDecimal.valueOf(list.size()), RoundingMode.HALF_UP)); - } - case BIG_INTEGER -> { - var sum = BigInteger.valueOf(0); - for (var item : list.asList()) { - sum = sum.add(item.asBigInteger()); - } - yield Document.of(sum.divide(BigInteger.valueOf(list.size()))); - } - default -> null; - }; - } - }, - CONTAINS("contains", 2) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression ignored) { - var subject = arguments.get(0); - var search = arguments.get(1); - return switch (subject.type()) { - case STRING -> { - var searchString = search.asString(); - yield Document.of(subject.asString().contains(searchString)); - } - case LIST -> { - var subjectList = subject.asList(); - for (var item : subjectList) { - if (item.equals(search)) { - yield Document.of(true); - } - } - yield Document.of(false); - } - default -> throw new IllegalArgumentException("`contains` only supports lists or strings as subject"); - }; - } - }, - CEIL("ceil", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var arg = arguments.get(0); - return switch (arg.type()) { - case BYTE, INTEGER, INT_ENUM, BIG_INTEGER, LONG, SHORT -> arg; - case BIG_DECIMAL -> Document.of(arg.asBigDecimal().setScale(0, RoundingMode.CEILING)); - case DOUBLE -> Document.of((long) Math.ceil(arg.asDouble())); - case FLOAT -> Document.of((long) Math.ceil(arg.asFloat())); - // Non numeric searches return null per spec - default -> null; - }; - } - }, - ENDS_WITH("ends_with", 2) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - var search = arguments.get(1); - if (!subject.type().equals(ShapeType.STRING) || !search.type().equals(ShapeType.STRING)) { - throw new IllegalArgumentException("`ends_with` only supports string arguments."); - } - return Document.of(subject.asString().endsWith(search.asString())); - } - }, - FLOOR("floor", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var arg = arguments.get(0); - return switch (arg.type()) { - case BYTE, INTEGER, INT_ENUM, BIG_INTEGER, LONG, SHORT -> arg; - case BIG_DECIMAL -> Document.of(arg.asBigDecimal().setScale(0, RoundingMode.FLOOR)); - case DOUBLE -> Document.ofNumber((long) Math.floor(arg.asDouble())); - case FLOAT -> Document.ofNumber((long) Math.floor(arg.asFloat())); - // Non numeric searches return null per specification - default -> null; - }; - } - }, - JOIN("join", 2) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var delimiter = arguments.get(0); - if (!delimiter.type().equals(ShapeType.STRING)) { - throw new IllegalArgumentException("`join` delimiter must be a string."); - } - var list = arguments.get(1); - if (!list.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`join` only supports array joining."); - } - var builder = new StringBuilder(); - var iter = list.asList().iterator(); - while (iter.hasNext()) { - builder.append(iter.next().asString()); - if (iter.hasNext()) { - builder.append(delimiter.asString()); - } - } - return Document.of(builder.toString()); - } - }, - KEYS("keys", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var arg = arguments.get(0); - return switch (arg.type()) { - case MAP, STRUCTURE -> { - List keys = arg.getMemberNames().stream().map(Document::of).toList(); - yield Document.of(keys); - } - default -> throw new IllegalArgumentException("`keys` only supports object arguments"); - }; - } - }, - LENGTH("length", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var arg = arguments.get(0); - return switch (arg.type()) { - case STRING -> Document.of((long) arg.asString().length()); - case MAP, STRUCTURE, LIST -> Document.of((long) arg.size()); - default -> throw new IllegalArgumentException("Type: " + arg.type() + " not supported by `length`"); - }; - } - }, - MAP("map", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - return null; - } - }, - MAX_BY("max_by", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - if (!subject.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`max_by` only supports arrays"); - } - if (subject.size() == 0) { - return null; - } - Document max = null; - Document maxValue = null; - for (var item : subject.asList()) { - var value = JMESPathDocumentQuery.query(fnRef, item); - if (max == null || Document.compare(maxValue, value) < 0) { - max = item; - maxValue = value; - } - } - return max; - } - }, - MAX("max", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - if (!subject.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`max` only supports array arguments"); - } - return subject.size() == 0 ? null : Collections.max(subject.asList(), Document::compare); - } - }, - MERGE("merge", 0) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - return null; - } - }, - MIN("min", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - if (!subject.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`max` only supports array arguments"); - } - return subject.size() == 0 ? null : Collections.min(subject.asList(), Document::compare); - } - }, - MIN_BY("min_by", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - if (!subject.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`min_by` only supports arrays"); - } - if (subject.size() == 0) { - return null; - } - Document min = null; - Document minValue = null; - for (var item : subject.asList()) { - var value = JMESPathDocumentQuery.query(fnRef, item); - if (min == null || Document.compare(minValue, value) > 0) { - min = item; - minValue = value; - } - } - return min; - } - }, - NOT_NULL("not_null", 0) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - for (var arg : arguments) { - if (arg != null) { - return arg; - } - } - return null; - } - }, - REVERSE("reverse", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - return switch (subject.type()) { - case STRING -> Document.of(new StringBuffer(subject.asString()).reverse().toString()); - case LIST -> { - var copy = new ArrayList<>(subject.asList()); - Collections.reverse(copy); - yield Document.of(copy); - } - default -> throw new IllegalArgumentException("`reverse` only supports array or string arguments"); - }; - } - }, - SORT("sort", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - if (!subject.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`sort` only supports array arguments"); - } - return Document.of(subject.asList().stream().sorted(Document::compare).toList()); - } - }, - SORT_BY("sort_by", 1, true) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - if (!subject.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`sort_by` only supports arrays"); - } - return Document.of(subject.asList() - .stream() - .sorted((l, r) -> Document.compare(JMESPathDocumentQuery.query(fnRef, l), - JMESPathDocumentQuery.query(fnRef, r))) - .toList()); - } - }, - STARTS_WITH("starts_with", 2) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var subject = arguments.get(0); - var search = arguments.get(1); - if (!subject.type().equals(ShapeType.STRING) || !search.type().equals(ShapeType.STRING)) { - throw new IllegalArgumentException("`starts_with` only supports string arguments."); - } - return Document.of(subject.asString().startsWith(search.asString())); - } - }, - SUM("sum", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var list = arguments.get(0); - if (!list.type().equals(ShapeType.LIST)) { - throw new IllegalArgumentException("`avg` only supports array arguments"); - } - if (list.size() == 0) { - return Document.of(0L); - } - var firstItem = list.asList().get(0); - return switch (firstItem.type()) { - case BYTE -> { - byte sum = 0; - for (var item : list.asList()) { - sum += item.asByte(); - } - yield Document.of(sum); - } - case SHORT -> { - short sum = 0; - for (var item : list.asList()) { - sum += item.asShort(); - } - yield Document.of(sum); - } - case INTEGER, INT_ENUM -> { - int sum = 0; - for (var item : list.asList()) { - sum += item.asInteger(); - } - yield Document.of(sum); - } - case LONG -> { - long sum = 0; - for (var item : list.asList()) { - sum += item.asLong(); - } - yield Document.of(sum); - } - case FLOAT -> { - float sum = 0; - for (var item : list.asList()) { - sum += item.asFloat(); - } - yield Document.of(sum); - } - case DOUBLE -> { - double sum = 0; - for (var item : list.asList()) { - sum += item.asDouble(); - } - yield Document.of(sum); - } - case BIG_DECIMAL -> { - var sum = BigDecimal.valueOf(0); - for (var item : list.asList()) { - sum = sum.add(item.asBigDecimal()); - } - yield Document.of(sum); - } - case BIG_INTEGER -> { - var sum = BigInteger.valueOf(0); - for (var item : list.asList()) { - sum = sum.add(item.asBigInteger()); - } - yield Document.of(sum); - } - default -> null; - }; - } - }, - TO_ARRAY("to_array", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - throw new UnsupportedOperationException("To Array function is not supported"); - } - }, - TO_STRING("to_string", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - throw new UnsupportedOperationException("to_string function is not supported"); - } - }, - TO_NUMBER("to_number", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var argument = arguments.get(0); - if (argument == null) { - return null; - } - return switch (argument.type()) { - case STRING -> { - try { - yield Document.ofNumber(new BigDecimal(argument.asString())); - } catch (NumberFormatException e) { - yield null; - } - } - case SHORT, BYTE, INTEGER, INT_ENUM, LONG, FLOAT, DOUBLE, BIG_DECIMAL, BIG_INTEGER -> - Document.ofNumber(argument.asNumber()); - default -> null; - }; - } - }, - TYPE("type", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var argument = arguments.get(0); - if (argument == null) { - return Document.of("null"); - } - String typeStr = switch (argument.type()) { - case DOUBLE, INTEGER, INT_ENUM, LONG, SHORT, BYTE, BIG_DECIMAL, BIG_INTEGER, FLOAT -> "number"; - case STRING, ENUM -> "string"; - case MAP, STRUCTURE, UNION -> "object"; - case BOOLEAN -> "boolean"; - case LIST -> "array"; - default -> throw new IllegalArgumentException("unsupported smithy type: " + argument.type()); - }; - return Document.of(typeStr); - } - }, - VALUES("values", 1) { - @Override - protected Document applyImpl(List arguments, ExpressionTypeExpression fnRef) { - var arg = arguments.get(0); - return switch (arg.type()) { - case MAP, STRUCTURE -> { - List values = arg.asStringMap().values().stream().map(Document::of).toList(); - yield Document.of(values); - } - default -> throw new IllegalArgumentException("`values` only supports object arguments"); - }; - } - }; - - private final String name; - private final int argumentCount; - private final boolean expectsFnRef; - - JMESPathFunction(String name, int argumentCount) { - this(name, argumentCount, false); - } - - JMESPathFunction(String name, int argumentCount, boolean expectsFnRef) { - this.name = name; - this.argumentCount = argumentCount; - this.expectsFnRef = expectsFnRef; - } - - static JMESPathFunction from(FunctionExpression expression) { - var name = expression.getName(); - for (JMESPathFunction val : JMESPathFunction.values()) { - if (val.name.equalsIgnoreCase(name)) { - return val; - } - } - throw new UnsupportedOperationException("Could not find function implementation for " + name); - } - - /** - * Apply the JMESPath function to a set of arguments. - * @param arguments arguments - * @param fnRef function reference if supported by function, or null. - * @return result of function - */ - public Document apply(List arguments, ExpressionTypeExpression fnRef) { - if (argumentCount > 0 && argumentCount != arguments.size()) { - throw new IllegalArgumentException("Unexpected number of arguments. Expected " + argumentCount - + " but found " + arguments.size()); - } - if (expectsFnRef && fnRef == null) { - throw new IllegalArgumentException("Expected a function reference for `" + name + "`, but found null."); - } - return applyImpl(arguments, fnRef); - } - - protected abstract Document applyImpl(List arguments, ExpressionTypeExpression fnRef); -} From c144559b39e332ac2019aaf6db19ff57a518bd61 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Fri, 5 Dec 2025 18:03:28 -0800 Subject: [PATCH 5/9] Renames --- gradle/libs.versions.toml | 2 +- .../smithy/java/jmespath/DocumentJmespathRuntime.java | 6 +++--- .../smithy/java/jmespath/GeneratedTypeJmespathRuntime.java | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 18e15bb1f..858620318 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] junit5 = "6.0.1" hamcrest = "3.0" -smithy = "1.65.0" +smithy = "1.64.0" jmh = "0.7.3" test-logger-plugin = "4.0.0" spotbugs = "6.0.22" diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java index 94527cf85..7ea93ecee 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java @@ -10,7 +10,7 @@ import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; import software.amazon.smithy.jmespath.evaluation.NumberType; -import software.amazon.smithy.jmespath.evaluation.WrappingIterable; +import software.amazon.smithy.jmespath.evaluation.MappingIterable; import software.amazon.smithy.model.shapes.ShapeType; import java.math.BigDecimal; @@ -132,10 +132,10 @@ public Document element(Document document, Document index) { } @Override - public Iterable toIterable(Document document) { + public Iterable asIterable(Document document) { return switch (typeOf(document)) { case ARRAY -> document.asList(); - case OBJECT -> new WrappingIterable<>(Document::of, document.asStringMap().keySet()); + case OBJECT -> new MappingIterable<>(Document::of, document.asStringMap().keySet()); default -> throw new IllegalArgumentException("Not iterable: " + document); }; } diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java index c6f6d11ad..e7b748689 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java @@ -12,7 +12,7 @@ import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; import software.amazon.smithy.jmespath.evaluation.NumberType; -import software.amazon.smithy.jmespath.evaluation.WrappingIterable; +import software.amazon.smithy.jmespath.evaluation.MappingIterable; import java.math.BigDecimal; import java.math.BigInteger; @@ -143,14 +143,13 @@ public Object element(Object value, Object index) { } @Override - public Iterable toIterable(Object value) { + public Iterable asIterable(Object value) { if (value instanceof List list) { return list; } else if (value instanceof Map map) { return map.keySet(); } else if (value instanceof SerializableStruct struct) { - // TODO: Should this be only present members? - return new WrappingIterable<>(Schema::memberName, struct.schema().members()); + return new MappingIterable<>(Schema::memberName, struct.schema().members()); } else { throw new IllegalArgumentException("Unknown runtime type: " + value); } From 79248fd83e1d298e94323abd089455ce6937db5e Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Fri, 5 Dec 2025 20:27:52 -0800 Subject: [PATCH 6/9] CI Hack --- .github/workflows/ci.yml | 10 + .../java/jmespath/ComplianceTestRunner.java | 231 ------------------ 2 files changed, 10 insertions(+), 231 deletions(-) delete mode 100644 jmespath/src/test/java/software/amazon/smithy/java/jmespath/ComplianceTestRunner.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7daf6c1c5..a5033c6ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,16 @@ jobs: os: [macos-latest, ubuntu-latest] steps: + # HACK TEMPORARY WORKAROUND UNTIL https://github.com/smithy-lang/smithy/pull/2878 IS RELEASED + - uses: actions/checkout@v6 + with: + repository: 'robin-aws/smithy' + path: 'smithy' + ref: 'smithy-jmespath-evaluator' + - working-directory: smithy + run: ./gradlew publishToMavenLocal + # END HACK + - uses: actions/checkout@v6 - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@v5 diff --git a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/ComplianceTestRunner.java b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/ComplianceTestRunner.java deleted file mode 100644 index b12abf555..000000000 --- a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/ComplianceTestRunner.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.java.jmespath; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.math.BigDecimal; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; -import software.amazon.smithy.java.core.serde.document.Document; -import software.amazon.smithy.model.node.ArrayNode; -import software.amazon.smithy.model.node.BooleanNode; -import software.amazon.smithy.model.node.Node; -import software.amazon.smithy.model.node.NodeVisitor; -import software.amazon.smithy.model.node.NullNode; -import software.amazon.smithy.model.node.NumberNode; -import software.amazon.smithy.model.node.ObjectNode; -import software.amazon.smithy.model.node.StringNode; -import software.amazon.smithy.model.shapes.ShapeType; - -class ComplianceTestRunner { - private static final String DEFAULT_TEST_CASE_LOCATION = "compliance"; - private static final String SUBJECT_MEMBER = "given"; - private static final String CASES_MEMBER = "cases"; - private static final String EXPRESSION_MEMBER = "expression"; - private static final String RESULT_MEMBER = "result"; - private static final NodeToDocumentConverter CONVERTER = new NodeToDocumentConverter(); - // TODO: Remove these suppressions as remaining functions are supported - private static final List UNSUPPORTED_FUNCTIONS = List.of( - "to_string", - "to_array", - "merge", - "map"); - private final List testCases = new ArrayList<>(); - - private ComplianceTestRunner() {} - - static ComplianceTestRunner runner() { - return new ComplianceTestRunner(); - } - - public static Stream defaultParameterizedTestSource(Class contextClass) { - return ComplianceTestRunner.runner() - .addTestCasesFromUrl(Objects.requireNonNull(contextClass.getResource(DEFAULT_TEST_CASE_LOCATION))) - .parameterizedTestSource(); - } - - public ComplianceTestRunner addTestCasesFromUrl(URL url) { - if (!url.getProtocol().equals("file")) { - throw new IllegalArgumentException("Only file URLs are supported by the test runner: " + url); - } - - try { - return addTestCasesFromDirectory(Paths.get(url.toURI())); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - public Stream parameterizedTestSource() { - return testCases.stream().map(testCase -> new Object[] {testCase.name(), testCase}); - } - - public ComplianceTestRunner addTestCasesFromDirectory(Path directory) { - for (var file : Objects.requireNonNull(directory.toFile().listFiles())) { - if (file.isFile() && file.getName().endsWith(".json")) { - testCases.addAll(TestCase.from(file)); - } - } - return this; - } - - private record TestCase(String testSuite, Node givenNode, Document given, String expression, Document expected) - implements Runnable { - public static List from(File file) { - var testSuiteName = file.getName().substring(0, file.getName().lastIndexOf('.')); - var testCases = new ArrayList(); - try (var is = new FileInputStream(file)) { - var tests = Node.parse(is).expectArrayNode().getElementsAs(ObjectNode.class); - - for (var test : tests) { - var givenNode = test.expectMember(SUBJECT_MEMBER); - var given = CONVERTER.convert(givenNode); - for (var testCase : test.expectArrayMember(CASES_MEMBER).getElementsAs(ObjectNode.class)) { - var expression = testCase.expectStringMember(EXPRESSION_MEMBER).getValue(); - // Filters out unsupported functions - // TODO: Remove once all built-in functions are supported - if (testSuiteName.equals("functions") - && UNSUPPORTED_FUNCTIONS.stream().anyMatch(expression::contains)) { - continue; - } - // Skip error cases as those are handled by smithy jmespath library - var resultOptional = testCase.getMember(RESULT_MEMBER); - if (resultOptional.isEmpty()) { - continue; - } - var expected = CONVERTER.convert(resultOptional.get()); - testCases.add(new TestCase(testSuiteName, givenNode, given, expression, expected)); - } - } - return testCases; - } catch (FileNotFoundException e) { - throw new RuntimeException("Could not find test file.", e); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private String name() { - return testSuite + " (" + Node.printJson(givenNode) + ")[" + expression + "]"; - } - - @Override - public void run() { - var result = JMESPathDocumentQuery.query(expression, given); - if (expected == null && result == null) { - return; - } - if (!isEqual(expected, result)) { - throw new AssertionError("Expected does not match actual. \n" - + "Expected: " + expected + "\n" - + "Actual: " + result + "\n" - + "For query: " + expression + "\n"); - } - } - } - - /** - * Compare documents element by element so we can assert null values are equal - */ - private static boolean isEqual(Document expected, Document actual) { - if (expected == null || actual == null) { - return expected == null && actual == null; - } else if (expected.type().equals(ShapeType.MAP) && actual.type().equals(ShapeType.MAP)) { - for (var member : expected.getMemberNames()) { - var expectedMember = expected.getMember(member); - var actualMember = actual.getMember(member); - if (!isEqual(expectedMember, actualMember)) { - return false; - } - } - return true; - } else if (expected.type().equals(ShapeType.LIST) && actual.type().equals(ShapeType.LIST)) { - if (expected.size() != actual.size()) { - return false; - } else { - for (int i = 0; i < expected.size(); i++) { - if (!isEqual(expected.asList().get(i), actual.asList().get(i))) { - return false; - } - } - return true; - } - } else if (isNumeric(expected) && isNumeric(actual)) { - // Normalize all numbers to BigDecimal to make comparisons work. - return new BigDecimal(expected.asNumber().toString()) - .compareTo(new BigDecimal(actual.asNumber().toString())) == 0; - } - return Objects.equals(expected, actual); - } - - private static boolean isNumeric(Document doc) { - var type = doc.type(); - return type == ShapeType.BYTE || type == ShapeType.SHORT - || type == ShapeType.INTEGER - || type == ShapeType.LONG - || type == ShapeType.BIG_INTEGER - || type == ShapeType.BIG_DECIMAL - || type == ShapeType.FLOAT - || type == ShapeType.DOUBLE - || type == ShapeType.INT_ENUM; - } - - private static final class NodeToDocumentConverter implements NodeVisitor { - private Document convert(Node node) { - return node.accept(this); - } - - @Override - public Document arrayNode(ArrayNode node) { - List result = new ArrayList<>(); - for (var item : node.getElements()) { - result.add(item.accept(this)); - } - return Document.of(result); - } - - @Override - public Document booleanNode(BooleanNode node) { - return Document.of(node.getValue()); - } - - @Override - public Document nullNode(NullNode node) { - return null; - } - - @Override - public Document numberNode(NumberNode node) { - return Document.ofNumber(node.getValue()); - } - - @Override - public Document objectNode(ObjectNode node) { - Map result = new HashMap<>(); - for (var entry : node.getMembers().entrySet()) { - result.put(entry.getKey().getValue(), entry.getValue().accept(this)); - } - return Document.of(result); - } - - @Override - public Document stringNode(StringNode node) { - return Document.of(node.getValue()); - } - } -} From ba8ba3ecab991be6a738049ac37b05aff856cc7d Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Fri, 5 Dec 2025 21:11:13 -0800 Subject: [PATCH 7/9] spotless --- .../codegen/generators/EnumGenerator.java | 2 +- .../smithy/java/core/schema/SmithyEnum.java | 5 +++ .../java/core/schema/SmithyIntEnum.java | 5 +++ .../jmespath/DocumentJmespathRuntime.java | 16 +++++---- .../GeneratedTypeJmespathRuntime.java | 33 ++++++++++--------- .../java/jmespath/JMESPathDocumentQuery.java | 26 --------------- 6 files changed, 39 insertions(+), 48 deletions(-) diff --git a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java index 04fe09a8d..591a26a17 100644 --- a/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java +++ b/codegen/codegen-core/src/main/java/software/amazon/smithy/java/codegen/generators/EnumGenerator.java @@ -19,9 +19,9 @@ import software.amazon.smithy.java.codegen.sections.ClassSection; import software.amazon.smithy.java.codegen.sections.EnumVariantSection; import software.amazon.smithy.java.codegen.writer.JavaWriter; +import software.amazon.smithy.java.core.schema.SerializableShape; import software.amazon.smithy.java.core.schema.SmithyEnum; import software.amazon.smithy.java.core.schema.SmithyIntEnum; -import software.amazon.smithy.java.core.schema.SerializableShape; import software.amazon.smithy.java.core.serde.ShapeDeserializer; import software.amazon.smithy.java.core.serde.ShapeSerializer; import software.amazon.smithy.model.Model; diff --git a/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java index 770be619a..2d6628438 100644 --- a/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java +++ b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyEnum.java @@ -1,3 +1,8 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + package software.amazon.smithy.java.core.schema; public interface SmithyEnum { diff --git a/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java index fd33f881e..cb25618e5 100644 --- a/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java +++ b/core/src/main/java/software/amazon/smithy/java/core/schema/SmithyIntEnum.java @@ -1,3 +1,8 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + package software.amazon.smithy.java.core.schema; public interface SmithyIntEnum { diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java index 7ea93ecee..8763b3c9e 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/DocumentJmespathRuntime.java @@ -1,5 +1,12 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + package software.amazon.smithy.java.jmespath; +import java.math.BigDecimal; +import java.math.BigInteger; import software.amazon.smithy.java.core.serde.SerializationException; import software.amazon.smithy.java.core.serde.document.Document; import software.amazon.smithy.jmespath.JmespathException; @@ -9,13 +16,10 @@ import software.amazon.smithy.jmespath.evaluation.JmespathRuntime; import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; -import software.amazon.smithy.jmespath.evaluation.NumberType; import software.amazon.smithy.jmespath.evaluation.MappingIterable; +import software.amazon.smithy.jmespath.evaluation.NumberType; import software.amazon.smithy.model.shapes.ShapeType; -import java.math.BigDecimal; -import java.math.BigInteger; - // TODO: default equal isn't correct, need to normalize number types public class DocumentJmespathRuntime implements JmespathRuntime { @@ -83,8 +87,8 @@ public Document createNumber(Number number) { case LONG -> Document.of(number.longValue()); case FLOAT -> Document.of(number.floatValue()); case DOUBLE -> Document.of(number.doubleValue()); - case BIG_INTEGER -> Document.of((BigInteger)number); - case BIG_DECIMAL -> Document.of((BigDecimal)number); + case BIG_INTEGER -> Document.of((BigInteger) number); + case BIG_DECIMAL -> Document.of((BigDecimal) number); }; } diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java index e7b748689..7b1818d61 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java @@ -1,9 +1,20 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + package software.amazon.smithy.java.jmespath; -import software.amazon.smithy.java.core.schema.SmithyEnum; -import software.amazon.smithy.java.core.schema.SmithyIntEnum; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.util.Collection; +import java.util.List; +import java.util.Map; import software.amazon.smithy.java.core.schema.Schema; import software.amazon.smithy.java.core.schema.SerializableStruct; +import software.amazon.smithy.java.core.schema.SmithyEnum; +import software.amazon.smithy.java.core.schema.SmithyIntEnum; import software.amazon.smithy.java.core.serde.document.Document; import software.amazon.smithy.jmespath.RuntimeType; import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; @@ -11,16 +22,8 @@ import software.amazon.smithy.jmespath.evaluation.JmespathRuntime; import software.amazon.smithy.jmespath.evaluation.ListArrayBuilder; import software.amazon.smithy.jmespath.evaluation.MapObjectBuilder; -import software.amazon.smithy.jmespath.evaluation.NumberType; import software.amazon.smithy.jmespath.evaluation.MappingIterable; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.Instant; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import software.amazon.smithy.jmespath.evaluation.NumberType; public class GeneratedTypeJmespathRuntime implements JmespathRuntime { @@ -80,7 +83,7 @@ public Object createBoolean(boolean b) { @Override public boolean asBoolean(Object value) { - return (Boolean)value; + return (Boolean) value; } @Override @@ -118,7 +121,7 @@ public Number asNumber(Object value) { } else if (value instanceof Instant instant) { return JMESPathDocumentUtils.asBigDecimal(instant); } else if (value instanceof SmithyIntEnum) { - return ((SmithyIntEnum)value).getValue(); + return ((SmithyIntEnum) value).getValue(); } else { throw new IllegalArgumentException(); } @@ -139,7 +142,7 @@ public Number length(Object value) { @Override public Object element(Object value, Object index) { - return ((List)value).get(asNumber(index).intValue()); + return ((List) value).get(asNumber(index).intValue()); } @Override @@ -164,7 +167,7 @@ public ArrayBuilder arrayBuilder() { public Object value(Object object, Object key) { if (object instanceof SerializableStruct struct) { // TODO: Check what happens on invalid member name - return struct.getMemberValue(struct.schema().member((String)key)); + return struct.getMemberValue(struct.schema().member((String) key)); } else if (object instanceof Map map) { return map.get(key); } else { diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java index f8f5cddb1..a26c668d1 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/JMESPathDocumentQuery.java @@ -5,35 +5,9 @@ package software.amazon.smithy.java.jmespath; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; import software.amazon.smithy.java.core.serde.document.Document; -import software.amazon.smithy.jmespath.ExpressionVisitor; import software.amazon.smithy.jmespath.JmespathExpression; -import software.amazon.smithy.jmespath.ast.AndExpression; -import software.amazon.smithy.jmespath.ast.ComparatorExpression; -import software.amazon.smithy.jmespath.ast.CurrentExpression; -import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression; -import software.amazon.smithy.jmespath.ast.FieldExpression; -import software.amazon.smithy.jmespath.ast.FilterProjectionExpression; -import software.amazon.smithy.jmespath.ast.FlattenExpression; -import software.amazon.smithy.jmespath.ast.FunctionExpression; -import software.amazon.smithy.jmespath.ast.IndexExpression; -import software.amazon.smithy.jmespath.ast.LiteralExpression; -import software.amazon.smithy.jmespath.ast.MultiSelectHashExpression; -import software.amazon.smithy.jmespath.ast.MultiSelectListExpression; -import software.amazon.smithy.jmespath.ast.NotExpression; -import software.amazon.smithy.jmespath.ast.ObjectProjectionExpression; -import software.amazon.smithy.jmespath.ast.OrExpression; -import software.amazon.smithy.jmespath.ast.ProjectionExpression; -import software.amazon.smithy.jmespath.ast.SliceExpression; -import software.amazon.smithy.jmespath.ast.Subexpression; import software.amazon.smithy.jmespath.evaluation.Evaluator; -import software.amazon.smithy.model.shapes.ShapeType; /** * Performs a query on a document given a JMESPath expression. From d8cb631f290a7d0c603307c4676c890b5785cb49 Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Sat, 6 Dec 2025 10:00:41 -0800 Subject: [PATCH 8/9] Test (and fix) GeneratedTypeJmespathRuntime --- .../GeneratedTypeJmespathRuntime.java | 43 +- ...tedTypeJmespathRuntimeComplianceTests.java | 24 + .../jmespath/TestJMESPathDocumentQuery.java | 11 +- .../java/jmespath/compliance/basic.json | 96 -- .../java/jmespath/compliance/boolean.json | 288 ---- .../java/jmespath/compliance/current.json | 25 - .../java/jmespath/compliance/escape.json | 46 - .../java/jmespath/compliance/filters.json | 594 ------- .../java/jmespath/compliance/functions.json | 841 ---------- .../java/jmespath/compliance/identifiers.json | 1377 ----------------- .../java/jmespath/compliance/indices.json | 346 ----- .../java/jmespath/compliance/literals.json | 195 --- .../java/jmespath/compliance/multiselect.json | 398 ----- .../java/jmespath/compliance/slice.json | 398 ----- .../java/jmespath/compliance/unicode.json | 38 - .../java/jmespath/compliance/wildcard.json | 460 ------ 16 files changed, 56 insertions(+), 5124 deletions(-) create mode 100644 jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/basic.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/boolean.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/current.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/escape.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/filters.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/functions.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/identifiers.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/indices.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/literals.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/multiselect.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/slice.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/unicode.json delete mode 100644 jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/wildcard.json diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java index 7b1818d61..2aef54224 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java @@ -16,6 +16,8 @@ import software.amazon.smithy.java.core.schema.SmithyEnum; import software.amazon.smithy.java.core.schema.SmithyIntEnum; import software.amazon.smithy.java.core.serde.document.Document; +import software.amazon.smithy.jmespath.JmespathException; +import software.amazon.smithy.jmespath.JmespathExceptionType; import software.amazon.smithy.jmespath.RuntimeType; import software.amazon.smithy.jmespath.evaluation.EvaluationUtils; import software.amazon.smithy.jmespath.evaluation.InheritingClassMap; @@ -27,8 +29,11 @@ public class GeneratedTypeJmespathRuntime implements JmespathRuntime { + public static final GeneratedTypeJmespathRuntime INSTANCE = new GeneratedTypeJmespathRuntime(); + private static final InheritingClassMap typeForClass = InheritingClassMap.builder() .put(String.class, RuntimeType.STRING) + .put(SmithyEnum.class, RuntimeType.STRING) .put(Boolean.class, RuntimeType.BOOLEAN) .put(Byte.class, RuntimeType.NUMBER) .put(Short.class, RuntimeType.NUMBER) @@ -39,9 +44,10 @@ public class GeneratedTypeJmespathRuntime implements JmespathRuntime { .put(BigInteger.class, RuntimeType.NUMBER) .put(BigDecimal.class, RuntimeType.NUMBER) .put(Instant.class, RuntimeType.NUMBER) - .put(SerializableStruct.class, RuntimeType.OBJECT) - .put(SmithyEnum.class, RuntimeType.STRING) .put(SmithyIntEnum.class, RuntimeType.NUMBER) + .put(List.class, RuntimeType.ARRAY) + .put(SerializableStruct.class, RuntimeType.OBJECT) + .put(Map.class, RuntimeType.OBJECT) .build(); private static final InheritingClassMap numberTypeForClass = InheritingClassMap.builder() @@ -95,8 +101,10 @@ public Object createString(String s) { public String asString(Object value) { if (value instanceof SmithyEnum enumValue) { return enumValue.getValue(); + } else if (value instanceof String s){ + return s; } else { - return (String) value; + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); } } @@ -111,7 +119,7 @@ public NumberType numberType(Object value) { if (numberType != null) { return numberType; } - throw new IllegalArgumentException(); + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); } @Override @@ -123,21 +131,24 @@ public Number asNumber(Object value) { } else if (value instanceof SmithyIntEnum) { return ((SmithyIntEnum) value).getValue(); } else { - throw new IllegalArgumentException(); + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); } } @Override public Number length(Object value) { - if (value instanceof String s) { - return EvaluationUtils.codePointCount(s); - } else if (value instanceof Collection c) { - return c.size(); - } else if (value instanceof SerializableStruct struct) { - return struct.schema().members().size(); - } else { - throw new IllegalArgumentException("Unknown runtime type: " + value); - } + return switch (typeOf(value)) { + case STRING -> EvaluationUtils.codePointCount((String) value); + case ARRAY -> ((List) value).size(); + case OBJECT -> { + if (value instanceof Map) { + yield ((Map) value).size(); + } else { + yield ((SerializableStruct) value).schema().members().size(); + } + } + default -> throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); + }; } @Override @@ -154,7 +165,7 @@ public Iterable asIterable(Object value) { } else if (value instanceof SerializableStruct struct) { return new MappingIterable<>(Schema::memberName, struct.schema().members()); } else { - throw new IllegalArgumentException("Unknown runtime type: " + value); + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); } } @@ -171,7 +182,7 @@ public Object value(Object object, Object key) { } else if (object instanceof Map map) { return map.get(key); } else { - throw new IllegalArgumentException(); + return null; } } diff --git a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java new file mode 100644 index 000000000..7dac68a21 --- /dev/null +++ b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java @@ -0,0 +1,24 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.java.jmespath; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import software.amazon.smithy.jmespath.tests.ComplianceTestRunner; + +import java.util.stream.Stream; + +public class GeneratedTypeJmespathRuntimeComplianceTests { + @ParameterizedTest(name = "{0}") + @MethodSource("source") + public void testRunner(String filename, Runnable callable) throws Exception { + callable.run(); + } + + public static Stream source() { + return ComplianceTestRunner.defaultParameterizedTestSource(GeneratedTypeJmespathRuntime.INSTANCE); + } +} diff --git a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/TestJMESPathDocumentQuery.java b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/TestJMESPathDocumentQuery.java index 0eda45e20..790a58018 100644 --- a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/TestJMESPathDocumentQuery.java +++ b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/TestJMESPathDocumentQuery.java @@ -297,16 +297,15 @@ static List functionSource() { Arguments.of("contains(foo, 'b')", Document.of(true)), Arguments.of("contains(foo, 'n')", Document.of(false)), Arguments.of("contains(str, 'my')", Document.of(true)), - Arguments.of("ceil(`1.001`)", Document.of(2L)), - Arguments.of("ceil(`1.9`)", Document.of(2L)), + Arguments.of("ceil(`1.001`)", Document.of(2D)), + Arguments.of("ceil(`1.9`)", Document.of(2D)), Arguments.of("ceil(`1`)", Document.of(1L)), - Arguments.of("ceil(`\"abc\"`)", null), Arguments.of("ends_with(str, 'Str')", Document.of(true)), Arguments.of("ends_with(str, 'bar')", Document.of(false)), Arguments.of("starts_with(str, 'my')", Document.of(true)), Arguments.of("starts_with(str, 'bar')", Document.of(false)), - Arguments.of("floor(`1.001`)", Document.of(1L)), - Arguments.of("floor(`1.9`)", Document.of(1L)), + Arguments.of("floor(`1.001`)", Document.of(1D)), + Arguments.of("floor(`1.9`)", Document.of(1D)), Arguments.of("floor(`1`)", Document.of(1L)), Arguments.of("keys(@)", Document.of(List @@ -315,7 +314,7 @@ static List functionSource() { Document.of("foo"), Document.of("nums"), Document.of("vals")))), - Arguments.of("length(nums)", Document.of(3L)), + Arguments.of("length(nums)", Document.of(3)), Arguments.of("max(nums)", Document.of(3)), Arguments.of("min(nums)", Document.of(1)), Arguments.of("not_null(no, not, this, str)", Document.of("myStr")), diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/basic.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/basic.json deleted file mode 100644 index c9082c922..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/basic.json +++ /dev/null @@ -1,96 +0,0 @@ -[{ - "given": - {"foo": {"bar": {"baz": "correct"}}}, - "cases": [ - { - "expression": "foo", - "result": {"bar": {"baz": "correct"}} - }, - { - "expression": "foo.bar", - "result": {"baz": "correct"} - }, - { - "expression": "foo.bar.baz", - "result": "correct" - }, - { - "expression": "foo\n.\nbar\n.baz", - "result": "correct" - }, - { - "expression": "foo.bar.baz.bad", - "result": null - }, - { - "expression": "foo.bar.bad", - "result": null - }, - { - "expression": "foo.bad", - "result": null - }, - { - "expression": "bad", - "result": null - }, - { - "expression": "bad.morebad.morebad", - "result": null - } - ] -}, - { - "given": - {"foo": {"bar": ["one", "two", "three"]}}, - "cases": [ - { - "expression": "foo", - "result": {"bar": ["one", "two", "three"]} - }, - { - "expression": "foo.bar", - "result": ["one", "two", "three"] - } - ] - }, - { - "given": ["one", "two", "three"], - "cases": [ - { - "expression": "one", - "result": null - }, - { - "expression": "two", - "result": null - }, - { - "expression": "three", - "result": null - }, - { - "expression": "one.two", - "result": null - } - ] - }, - { - "given": - {"foo": {"1": ["one", "two", "three"], "-1": "bar"}}, - "cases": [ - { - "expression": "foo.\"1\"", - "result": ["one", "two", "three"] - }, - { - "expression": "foo.\"1\"[0]", - "result": "one" - }, - { - "expression": "foo.\"-1\"", - "result": "bar" - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/boolean.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/boolean.json deleted file mode 100644 index dd7ee5882..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/boolean.json +++ /dev/null @@ -1,288 +0,0 @@ -[ - { - "given": { - "outer": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - } - }, - "cases": [ - { - "expression": "outer.foo || outer.bar", - "result": "foo" - }, - { - "expression": "outer.foo||outer.bar", - "result": "foo" - }, - { - "expression": "outer.bar || outer.baz", - "result": "bar" - }, - { - "expression": "outer.bar||outer.baz", - "result": "bar" - }, - { - "expression": "outer.bad || outer.foo", - "result": "foo" - }, - { - "expression": "outer.bad||outer.foo", - "result": "foo" - }, - { - "expression": "outer.foo || outer.bad", - "result": "foo" - }, - { - "expression": "outer.foo||outer.bad", - "result": "foo" - }, - { - "expression": "outer.bad || outer.alsobad", - "result": null - }, - { - "expression": "outer.bad||outer.alsobad", - "result": null - } - ] - }, - { - "given": { - "outer": { - "foo": "foo", - "bool": false, - "empty_list": [], - "empty_string": "" - } - }, - "cases": [ - { - "expression": "outer.empty_string || outer.foo", - "result": "foo" - }, - { - "expression": "outer.nokey || outer.bool || outer.empty_list || outer.empty_string || outer.foo", - "result": "foo" - } - ] - }, - { - "given": { - "True": true, - "False": false, - "Number": 5, - "EmptyList": [], - "Zero": 0, - "ZeroFloat": 0.0 - }, - "cases": [ - { - "expression": "True && False", - "result": false - }, - { - "expression": "False && True", - "result": false - }, - { - "expression": "True && True", - "result": true - }, - { - "expression": "False && False", - "result": false - }, - { - "expression": "True && Number", - "result": 5 - }, - { - "expression": "Number && True", - "result": true - }, - { - "expression": "Number && False", - "result": false - }, - { - "expression": "Number && EmptyList", - "result": [] - }, - { - "expression": "Number && True", - "result": true - }, - { - "expression": "EmptyList && True", - "result": [] - }, - { - "expression": "EmptyList && False", - "result": [] - }, - { - "expression": "True || False", - "result": true - }, - { - "expression": "True || True", - "result": true - }, - { - "expression": "False || True", - "result": true - }, - { - "expression": "False || False", - "result": false - }, - { - "expression": "Number || EmptyList", - "result": 5 - }, - { - "expression": "Number || True", - "result": 5 - }, - { - "expression": "Number || True && False", - "result": 5 - }, - { - "expression": "(Number || True) && False", - "result": false - }, - { - "expression": "Number || (True && False)", - "result": 5 - }, - { - "expression": "!True", - "result": false - }, - { - "expression": "!False", - "result": true - }, - { - "expression": "!Number", - "result": false - }, - { - "expression": "!EmptyList", - "result": true - }, - { - "expression": "True && !False", - "result": true - }, - { - "expression": "True && !EmptyList", - "result": true - }, - { - "expression": "!False && !EmptyList", - "result": true - }, - { - "expression": "!True && False", - "result": false - }, - { - "expression": "!(True && False)", - "result": true - }, - { - "expression": "!Zero", - "result": false - }, - { - "expression": "!!Zero", - "result": true - }, - { - "expression": "Zero || Number", - "result": 0 - }, - { - "expression": "ZeroFloat || Number", - "result": 0.0 - } - ] - }, - { - "given": { - "one": 1, - "two": 2, - "three": 3, - "emptylist": [], - "boolvalue": false - }, - "cases": [ - { - "expression": "one < two", - "result": true - }, - { - "expression": "one <= two", - "result": true - }, - { - "expression": "one == one", - "result": true - }, - { - "expression": "one == two", - "result": false - }, - { - "expression": "one > two", - "result": false - }, - { - "expression": "one >= two", - "result": false - }, - { - "expression": "one != two", - "result": true - }, - { - "expression": "emptylist < one", - "result": null - }, - { - "expression": "emptylist < nullvalue", - "result": null - }, - { - "expression": "emptylist < boolvalue", - "result": null - }, - { - "expression": "one < boolvalue", - "result": null - }, - { - "expression": "one < two && three > one", - "result": true - }, - { - "expression": "one < two || three > one", - "result": true - }, - { - "expression": "one < two || three < one", - "result": true - }, - { - "expression": "two < one || three < one", - "result": false - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/current.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/current.json deleted file mode 100644 index 4fa64fbf0..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/current.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "given": { - "foo": [{"name": "a"}, {"name": "b"}], - "bar": {"baz": "qux"} - }, - "cases": [ - { - "expression": "@", - "result": { - "foo": [{"name": "a"}, {"name": "b"}], - "bar": {"baz": "qux"} - } - }, - { - "expression": "@.bar", - "result": {"baz": "qux"} - }, - { - "expression": "@.foo[0]", - "result": {"name": "a"} - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/escape.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/escape.json deleted file mode 100644 index 652da353b..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/escape.json +++ /dev/null @@ -1,46 +0,0 @@ -[{ - "given": { - "foo.bar": "dot", - "foo bar": "space", - "foo\nbar": "newline", - "foo\"bar": "doublequote", - "c:\\\\windows\\path": "windows", - "/unix/path": "unix", - "\"\"\"": "threequotes", - "bar": {"baz": "qux"} - }, - "cases": [ - { - "expression": "\"foo.bar\"", - "result": "dot" - }, - { - "expression": "\"foo bar\"", - "result": "space" - }, - { - "expression": "\"foo\\nbar\"", - "result": "newline" - }, - { - "expression": "\"foo\\\"bar\"", - "result": "doublequote" - }, - { - "expression": "\"c:\\\\\\\\windows\\\\path\"", - "result": "windows" - }, - { - "expression": "\"/unix/path\"", - "result": "unix" - }, - { - "expression": "\"\\\"\\\"\\\"\"", - "result": "threequotes" - }, - { - "expression": "\"bar\".\"baz\"", - "result": "qux" - } - ] -}] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/filters.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/filters.json deleted file mode 100644 index 6c7c959ea..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/filters.json +++ /dev/null @@ -1,594 +0,0 @@ -[ - { - "given": {"foo": [{"name": "a"}, {"name": "b"}]}, - "cases": [ - { - "comment": "Matching a literal", - "expression": "foo[?name == 'a']", - "result": [{"name": "a"}] - } - ] - }, - { - "given": {"foo": [0, 1], "bar": [2, 3]}, - "cases": [ - { - "comment": "Matching a literal", - "expression": "*[?[0] == `0`]", - "result": [[], []] - } - ] - }, - { - "given": {"foo": [{"first": "foo", "last": "bar"}, - {"first": "foo", "last": "foo"}, - {"first": "foo", "last": "baz"}]}, - "cases": [ - { - "comment": "Matching an expression", - "expression": "foo[?first == last]", - "result": [{"first": "foo", "last": "foo"}] - }, - { - "comment": "Verify projection created from filter", - "expression": "foo[?first == last].first", - "result": ["foo"] - } - ] - }, - { - "given": {"foo": [{"age": 20}, - {"age": 25}, - {"age": 30}]}, - "cases": [ - { - "comment": "Greater than with a number", - "expression": "foo[?age > `25`]", - "result": [{"age": 30}] - }, - { - "expression": "foo[?age >= `25`]", - "result": [{"age": 25}, {"age": 30}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age > `30`]", - "result": [] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age < `25`]", - "result": [{"age": 20}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age <= `25`]", - "result": [{"age": 20}, {"age": 25}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?age < `20`]", - "result": [] - }, - { - "expression": "foo[?age == `20`]", - "result": [{"age": 20}] - }, - { - "expression": "foo[?age != `20`]", - "result": [{"age": 25}, {"age": 30}] - } - ] - }, - { - "given": {"foo": [{"weight": 33.3}, - {"weight": 44.4}, - {"weight": 55.5}]}, - "cases": [ - { - "comment": "Greater than with a number", - "expression": "foo[?weight > `44.4`]", - "result": [{"weight": 55.5}] - }, - { - "expression": "foo[?weight >= `44.4`]", - "result": [{"weight": 44.4}, {"weight": 55.5}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?weight > `55.5`]", - "result": [] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?weight < `44.4`]", - "result": [{"weight": 33.3}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?weight <= `44.4`]", - "result": [{"weight": 33.3}, {"weight": 44.4}] - }, - { - "comment": "Greater than with a number", - "expression": "foo[?weight < `33.3`]", - "result": [] - }, - { - "expression": "foo[?weight == `33.3`]", - "result": [{"weight": 33.3}] - }, - { - "expression": "foo[?weight != `33.3`]", - "result": [{"weight": 44.4}, {"weight": 55.5}] - } - ] - }, - { - "given": {"foo": [{"top": {"name": "a"}}, - {"top": {"name": "b"}}]}, - "cases": [ - { - "comment": "Filter with subexpression", - "expression": "foo[?top.name == 'a']", - "result": [{"top": {"name": "a"}}] - } - ] - }, - { - "given": {"foo": [{"top": {"first": "foo", "last": "bar"}}, - {"top": {"first": "foo", "last": "foo"}}, - {"top": {"first": "foo", "last": "baz"}}]}, - "cases": [ - { - "comment": "Matching an expression", - "expression": "foo[?top.first == top.last]", - "result": [{"top": {"first": "foo", "last": "foo"}}] - }, - { - "comment": "Matching a JSON array", - "expression": "foo[?top == `{\"first\": \"foo\", \"last\": \"bar\"}`]", - "result": [{"top": {"first": "foo", "last": "bar"}}] - } - ] - }, - { - "given": {"foo": [ - {"key": true}, - {"key": false}, - {"key": 0}, - {"key": 1}, - {"key": [0]}, - {"key": {"bar": [0]}}, - {"key": null}, - {"key": [1]}, - {"key": {"a":2}} - ]}, - "cases": [ - { - "expression": "foo[?key == `true`]", - "result": [{"key": true}] - }, - { - "expression": "foo[?key == `false`]", - "result": [{"key": false}] - }, - { - "expression": "foo[?key == `0`]", - "result": [{"key": 0}] - }, - { - "expression": "foo[?key == `1`]", - "result": [{"key": 1}] - }, - { - "expression": "foo[?key == `[0]`]", - "result": [{"key": [0]}] - }, - { - "expression": "foo[?key == `{\"bar\": [0]}`]", - "result": [{"key": {"bar": [0]}}] - }, - { - "expression": "foo[?key == `null`]", - "result": [{"key": null}] - }, - { - "expression": "foo[?key == `[1]`]", - "result": [{"key": [1]}] - }, - { - "expression": "foo[?key == `{\"a\":2}`]", - "result": [{"key": {"a":2}}] - }, - { - "expression": "foo[?`true` == key]", - "result": [{"key": true}] - }, - { - "expression": "foo[?`false` == key]", - "result": [{"key": false}] - }, - { - "expression": "foo[?`0` == key]", - "result": [{"key": 0}] - }, - { - "expression": "foo[?`1` == key]", - "result": [{"key": 1}] - }, - { - "expression": "foo[?`[0]` == key]", - "result": [{"key": [0]}] - }, - { - "expression": "foo[?`{\"bar\": [0]}` == key]", - "result": [{"key": {"bar": [0]}}] - }, - { - "expression": "foo[?`null` == key]", - "result": [{"key": null}] - }, - { - "expression": "foo[?`[1]` == key]", - "result": [{"key": [1]}] - }, - { - "expression": "foo[?`{\"a\":2}` == key]", - "result": [{"key": {"a":2}}] - }, - { - "expression": "foo[?key != `true`]", - "result": [{"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `false`]", - "result": [{"key": true}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `0`]", - "result": [{"key": true}, {"key": false}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `1`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `null`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `[1]`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": {"a":2}}] - }, - { - "expression": "foo[?key != `{\"a\":2}`]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}] - }, - { - "expression": "foo[?`true` != key]", - "result": [{"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`false` != key]", - "result": [{"key": true}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`0` != key]", - "result": [{"key": true}, {"key": false}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`1` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`null` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": [1]}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`[1]` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": {"a":2}}] - }, - { - "expression": "foo[?`{\"a\":2}` != key]", - "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, - {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}] - } - ] - }, - { - "given": {"foo": [ - {"key": true}, - {"key": false}, - {"key": 0}, - {"key": 0.0}, - {"key": 1}, - {"key": 1.0}, - {"key": [0]}, - {"key": null}, - {"key": [1]}, - {"key": []}, - {"key": {}}, - {"key": {"a":2}} - ]}, - "cases": [ - { - "expression": "foo[?key == `true`]", - "result": [{"key": true}] - }, - { - "expression": "foo[?key == `false`]", - "result": [{"key": false}] - }, - { - "expression": "foo[?key]", - "result": [ - {"key": true}, - {"key": 0}, - {"key": 0.0}, - {"key": 1}, - {"key": 1.0}, - {"key": [0]}, - {"key": [1]}, - {"key": {"a": 2}} - ] - }, - { - "expression": "foo[? !key]", - "result": [ - {"key": false}, - {"key": null}, - {"key": []}, - {"key": {}} - ] - }, - { - "expression": "foo[? !!key]", - "result": [ - {"key": true}, - {"key": 0}, - {"key": 0.0}, - {"key": 1}, - {"key": 1.0}, - {"key": [0]}, - {"key": [1]}, - {"key": {"a": 2}} - ] - }, - { - "expression": "foo[? `true`]", - "result": [ - {"key": true}, - {"key": false}, - {"key": 0}, - {"key": 0.0}, - {"key": 1}, - {"key": 1.0}, - {"key": [0]}, - {"key": null}, - {"key": [1]}, - {"key": []}, - {"key": {}}, - {"key": {"a":2}} - ] - }, - { - "expression": "foo[? `false`]", - "result": [] - } - ] - }, - { - "given": {"reservations": [ - {"instances": [ - {"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, - {"foo": 1, "bar": 2}, {"foo": 2, "bar": 1}]}]}, - "cases": [ - { - "expression": "reservations[].instances[?bar==`1`]", - "result": [[{"foo": 2, "bar": 1}]] - }, - { - "expression": "reservations[*].instances[?bar==`1`]", - "result": [[{"foo": 2, "bar": 1}]] - }, - { - "expression": "reservations[].instances[?bar==`1`][]", - "result": [{"foo": 2, "bar": 1}] - } - ] - }, - { - "given": { - "baz": "other", - "foo": [ - {"bar": 1}, {"bar": 2}, {"bar": 3}, {"bar": 4}, {"bar": 1, "baz": 2} - ] - }, - "cases": [ - { - "expression": "foo[?bar==`1`].bar[0]", - "result": [] - } - ] - }, - { - "given": { - "foo": [ - {"a": 1, "b": {"c": "x"}}, - {"a": 1, "b": {"c": "y"}}, - {"a": 1, "b": {"c": "z"}}, - {"a": 2, "b": {"c": "z"}}, - {"a": 1, "baz": 2} - ] - }, - "cases": [ - { - "expression": "foo[?a==`1`].b.c", - "result": ["x", "y", "z"] - } - ] - }, - { - "given": {"foo": [{"name": "a"}, {"name": "b"}, {"name": "c"}]}, - "cases": [ - { - "comment": "Filter with or expression", - "expression": "foo[?name == 'a' || name == 'b']", - "result": [{"name": "a"}, {"name": "b"}] - }, - { - "expression": "foo[?name == 'a' || name == 'e']", - "result": [{"name": "a"}] - }, - { - "expression": "foo[?name == 'a' || name == 'b' || name == 'c']", - "result": [{"name": "a"}, {"name": "b"}, {"name": "c"}] - } - ] - }, - { - "given": {"foo": [{"a": 1, "b": 2}, {"a": 1, "b": 3}]}, - "cases": [ - { - "comment": "Filter with and expression", - "expression": "foo[?a == `1` && b == `2`]", - "result": [{"a": 1, "b": 2}] - }, - { - "expression": "foo[?a == `1` && b == `4`]", - "result": [] - } - ] - }, - { - "given": {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}, - "cases": [ - { - "comment": "Filter with Or and And expressions", - "expression": "foo[?c == `3` || a == `1` && b == `4`]", - "result": [{"a": 1, "b": 2, "c": 3}] - }, - { - "expression": "foo[?b == `2` || a == `3` && b == `4`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?a == `3` && b == `4` || b == `2`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?(a == `3` && b == `4`) || b == `2`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?((a == `3` && b == `4`)) || b == `2`]", - "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] - }, - { - "expression": "foo[?a == `3` && (b == `4` || b == `2`)]", - "result": [{"a": 3, "b": 4}] - }, - { - "expression": "foo[?a == `3` && ((b == `4` || b == `2`))]", - "result": [{"a": 3, "b": 4}] - } - ] - }, - { - "given": {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}, - "cases": [ - { - "comment": "Verify precedence of or/and expressions", - "expression": "foo[?a == `1` || b ==`2` && c == `5`]", - "result": [{"a": 1, "b": 2, "c": 3}] - }, - { - "comment": "Parentheses can alter precedence", - "expression": "foo[?(a == `1` || b ==`2`) && c == `5`]", - "result": [] - }, - { - "comment": "Not expressions combined with and/or", - "expression": "foo[?!(a == `1` || b ==`2`)]", - "result": [{"a": 3, "b": 4}] - } - ] - }, - { - "given": { - "foo": [ - {"key": true}, - {"key": false}, - {"key": []}, - {"key": {}}, - {"key": [0]}, - {"key": {"a": "b"}}, - {"key": 0}, - {"key": 1}, - {"key": null}, - {"notkey": true} - ] - }, - "cases": [ - { - "comment": "Unary filter expression", - "expression": "foo[?key]", - "result": [ - {"key": true}, {"key": [0]}, {"key": {"a": "b"}}, - {"key": 0}, {"key": 1} - ] - }, - { - "comment": "Unary not filter expression", - "expression": "foo[?!key]", - "result": [ - {"key": false}, {"key": []}, {"key": {}}, - {"key": null}, {"notkey": true} - ] - }, - { - "comment": "Equality with null RHS", - "expression": "foo[?key == `null`]", - "result": [ - {"key": null}, {"notkey": true} - ] - } - ] - }, - { - "given": { - "foo": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, - "cases": [ - { - "comment": "Using @ in a filter expression", - "expression": "foo[?@ < `5`]", - "result": [0, 1, 2, 3, 4] - }, - { - "comment": "Using @ in a filter expression", - "expression": "foo[?`5` > @]", - "result": [0, 1, 2, 3, 4] - }, - { - "comment": "Using @ in a filter expression", - "expression": "foo[?@ == @]", - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/functions.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/functions.json deleted file mode 100644 index 0b585f632..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/functions.json +++ /dev/null @@ -1,841 +0,0 @@ -[{ - "given": - { - "foo": -1, - "zero": 0, - "numbers": [-1, 3, 4, 5], - "array": [-1, 3, 4, 5, "a", "100"], - "strings": ["a", "b", "c"], - "decimals": [1.01, 1.2, -1.5], - "str": "Str", - "false": false, - "empty_list": [], - "empty_hash": {}, - "objects": {"foo": "bar", "bar": "baz"}, - "null_key": null - }, - "cases": [ - { - "expression": "abs(foo)", - "result": 1 - }, - { - "expression": "abs(foo)", - "result": 1 - }, - { - "expression": "abs(str)", - "error": "invalid-type" - }, - { - "expression": "abs(array[1])", - "result": 3 - }, - { - "expression": "abs(array[1])", - "result": 3 - }, - { - "expression": "abs(`false`)", - "error": "invalid-type" - }, - { - "expression": "abs(`-24`)", - "result": 24 - }, - { - "expression": "abs(`-24`)", - "result": 24 - }, - { - "expression": "abs(`1`, `2`)", - "error": "invalid-arity" - }, - { - "expression": "abs()", - "error": "invalid-arity" - }, - { - "expression": "unknown_function(`1`, `2`)", - "error": "unknown-function" - }, - { - "expression": "avg(numbers)", - "result": 2.75 - }, - { - "expression": "avg(array)", - "error": "invalid-type" - }, - { - "expression": "avg('abc')", - "error": "invalid-type" - }, - { - "expression": "avg(foo)", - "error": "invalid-type" - }, - { - "expression": "avg(@)", - "error": "invalid-type" - }, - { - "expression": "avg(strings)", - "error": "invalid-type" - }, - { - "expression": "avg(empty_list)", - "result": null - }, - { - "expression": "ceil(`1.2`)", - "result": 2 - }, - { - "expression": "ceil(decimals[0])", - "result": 2 - }, - { - "expression": "ceil(decimals[1])", - "result": 2 - }, - { - "expression": "ceil(decimals[2])", - "result": -1 - }, - { - "expression": "ceil('string')", - "error": "invalid-type" - }, - { - "expression": "contains('abc', 'a')", - "result": true - }, - { - "expression": "contains('abc', 'd')", - "result": false - }, - { - "expression": "contains(`false`, 'd')", - "error": "invalid-type" - }, - { - "expression": "contains(strings, 'a')", - "result": true - }, - { - "expression": "contains(decimals, `1.2`)", - "result": true - }, - { - "expression": "contains(decimals, `false`)", - "result": false - }, - { - "expression": "ends_with(str, 'r')", - "result": true - }, - { - "expression": "ends_with(str, 'tr')", - "result": true - }, - { - "expression": "ends_with(str, 'Str')", - "result": true - }, - { - "expression": "ends_with(str, 'SStr')", - "result": false - }, - { - "expression": "ends_with(str, 'foo')", - "result": false - }, - { - "expression": "ends_with(str, `0`)", - "error": "invalid-type" - }, - { - "expression": "floor(`1.2`)", - "result": 1 - }, - { - "expression": "floor('string')", - "error": "invalid-type" - }, - { - "expression": "floor(decimals[0])", - "result": 1 - }, - { - "expression": "floor(foo)", - "result": -1 - }, - { - "expression": "floor(str)", - "error": "invalid-type" - }, - { - "expression": "length('abc')", - "result": 3 - }, - { - "expression": "length('✓foo')", - "result": 4 - }, - { - "expression": "length('')", - "result": 0 - }, - { - "expression": "length(@)", - "result": 12 - }, - { - "expression": "length(strings[0])", - "result": 1 - }, - { - "expression": "length(str)", - "result": 3 - }, - { - "expression": "length(array)", - "result": 6 - }, - { - "expression": "length(objects)", - "result": 2 - }, - { - "expression": "length(`false`)", - "error": "invalid-type" - }, - { - "expression": "length(foo)", - "error": "invalid-type" - }, - { - "expression": "length(strings[0])", - "result": 1 - }, - { - "expression": "max(numbers)", - "result": 5 - }, - { - "expression": "max(decimals)", - "result": 1.2 - }, - { - "expression": "max(strings)", - "result": "c" - }, - { - "expression": "max(abc)", - "error": "invalid-type" - }, - { - "expression": "max(array)", - "error": "invalid-type" - }, - { - "expression": "max(decimals)", - "result": 1.2 - }, - { - "expression": "max(empty_list)", - "result": null - }, - { - "expression": "merge(`{}`)", - "result": {} - }, - { - "expression": "merge(`{}`, `{}`)", - "result": {} - }, - { - "expression": "merge(`{\"a\": 1}`, `{\"b\": 2}`)", - "result": {"a": 1, "b": 2} - }, - { - "expression": "merge(`{\"a\": 1}`, `{\"a\": 2}`)", - "result": {"a": 2} - }, - { - "expression": "merge(`{\"a\": 1, \"b\": 2}`, `{\"a\": 2, \"c\": 3}`, `{\"d\": 4}`)", - "result": {"a": 2, "b": 2, "c": 3, "d": 4} - }, - { - "expression": "min(numbers)", - "result": -1 - }, - { - "expression": "min(decimals)", - "result": -1.5 - }, - { - "expression": "min(abc)", - "error": "invalid-type" - }, - { - "expression": "min(array)", - "error": "invalid-type" - }, - { - "expression": "min(empty_list)", - "result": null - }, - { - "expression": "min(decimals)", - "result": -1.5 - }, - { - "expression": "min(strings)", - "result": "a" - }, - { - "expression": "type('abc')", - "result": "string" - }, - { - "expression": "type(`1.0`)", - "result": "number" - }, - { - "expression": "type(`2`)", - "result": "number" - }, - { - "expression": "type(`true`)", - "result": "boolean" - }, - { - "expression": "type(`false`)", - "result": "boolean" - }, - { - "expression": "type(`null`)", - "result": "null" - }, - { - "expression": "type(`[0]`)", - "result": "array" - }, - { - "expression": "type(`{\"a\": \"b\"}`)", - "result": "object" - }, - { - "expression": "type(@)", - "result": "object" - }, - { - "expression": "sort(keys(objects))", - "result": ["bar", "foo"] - }, - { - "expression": "keys(foo)", - "error": "invalid-type" - }, - { - "expression": "keys(strings)", - "error": "invalid-type" - }, - { - "expression": "keys(`false`)", - "error": "invalid-type" - }, - { - "expression": "sort(values(objects))", - "result": ["bar", "baz"] - }, - { - "expression": "keys(empty_hash)", - "result": [] - }, - { - "expression": "values(foo)", - "error": "invalid-type" - }, - { - "expression": "join(', ', strings)", - "result": "a, b, c" - }, - { - "expression": "join(', ', strings)", - "result": "a, b, c" - }, - { - "expression": "join(',', `[\"a\", \"b\"]`)", - "result": "a,b" - }, - { - "expression": "join(',', `[\"a\", 0]`)", - "error": "invalid-type" - }, - { - "expression": "join(', ', str)", - "error": "invalid-type" - }, - { - "expression": "join('|', strings)", - "result": "a|b|c" - }, - { - "expression": "join(`2`, strings)", - "error": "invalid-type" - }, - { - "expression": "join('|', decimals)", - "error": "invalid-type" - }, - { - "expression": "join('|', decimals[].to_string(@))", - "result": "1.01|1.2|-1.5" - }, - { - "expression": "join('|', empty_list)", - "result": "" - }, - { - "expression": "reverse(numbers)", - "result": [5, 4, 3, -1] - }, - { - "expression": "reverse(array)", - "result": ["100", "a", 5, 4, 3, -1] - }, - { - "expression": "reverse(`[]`)", - "result": [] - }, - { - "expression": "reverse('')", - "result": "" - }, - { - "expression": "reverse('hello world')", - "result": "dlrow olleh" - }, - { - "expression": "starts_with(str, 'S')", - "result": true - }, - { - "expression": "starts_with(str, 'St')", - "result": true - }, - { - "expression": "starts_with(str, 'Str')", - "result": true - }, - { - "expression": "starts_with(str, 'String')", - "result": false - }, - { - "expression": "starts_with(str, `0`)", - "error": "invalid-type" - }, - { - "expression": "sum(numbers)", - "result": 11 - }, - { - "expression": "sum(decimals)", - "result": 0.71 - }, - { - "expression": "sum(array)", - "error": "invalid-type" - }, - { - "expression": "sum(array[].to_number(@))", - "result": 111 - }, - { - "expression": "sum(`[]`)", - "result": 0 - }, - { - "expression": "to_array('foo')", - "result": ["foo"] - }, - { - "expression": "to_array(`0`)", - "result": [0] - }, - { - "expression": "to_array(objects)", - "result": [{"foo": "bar", "bar": "baz"}] - }, - { - "expression": "to_array(`[1, 2, 3]`)", - "result": [1, 2, 3] - }, - { - "expression": "to_array(false)", - "result": [false] - }, - { - "expression": "to_string('foo')", - "result": "foo" - }, - { - "expression": "to_string(`1.2`)", - "result": "1.2" - }, - { - "expression": "to_string(`[0, 1]`)", - "result": "[0,1]" - }, - { - "expression": "to_number('1.0')", - "result": 1.0 - }, - { - "expression": "to_number('1e21')", - "result": 1e21 - }, - { - "expression": "to_number('1.1')", - "result": 1.1 - }, - { - "expression": "to_number('4')", - "result": 4 - }, - { - "expression": "to_number('notanumber')", - "result": null - }, - { - "expression": "to_number(`false`)", - "result": null - }, - { - "expression": "to_number(`null`)", - "result": null - }, - { - "expression": "to_number(`[0]`)", - "result": null - }, - { - "expression": "to_number(`{\"foo\": 0}`)", - "result": null - }, - { - "expression": "\"to_string\"(`1.0`)", - "error": "syntax" - }, - { - "expression": "sort(numbers)", - "result": [-1, 3, 4, 5] - }, - { - "expression": "sort(strings)", - "result": ["a", "b", "c"] - }, - { - "expression": "sort(decimals)", - "result": [-1.5, 1.01, 1.2] - }, - { - "expression": "sort(array)", - "error": "invalid-type" - }, - { - "expression": "sort(abc)", - "error": "invalid-type" - }, - { - "expression": "sort(empty_list)", - "result": [] - }, - { - "expression": "sort(@)", - "error": "invalid-type" - }, - { - "expression": "not_null(unknown_key, str)", - "result": "Str" - }, - { - "expression": "not_null(unknown_key, foo.bar, empty_list, str)", - "result": [] - }, - { - "expression": "not_null(unknown_key, null_key, empty_list, str)", - "result": [] - }, - { - "expression": "not_null(all, expressions, are_null)", - "result": null - }, - { - "expression": "not_null()", - "error": "invalid-arity" - }, - { - "comment": "function projection on single arg function", - "expression": "numbers[].to_string(@)", - "result": ["-1", "3", "4", "5"] - }, - { - "comment": "function projection on single arg function", - "expression": "array[].to_number(@)", - "result": [-1, 3, 4, 5, 100] - } - ] -}, { - "given": - { - "foo": [ - {"b": "b", "a": "a"}, - {"c": "c", "b": "b"}, - {"d": "d", "c": "c"}, - {"e": "e", "d": "d"}, - {"f": "f", "e": "e"} - ] - }, - "cases": [ - { - "comment": "function projection on variadic function", - "expression": "foo[].not_null(f, e, d, c, b, a)", - "result": ["b", "c", "d", "e", "f"] - } - ] -}, { - "given": - { - "people": [ - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"}, - {"age": 10, "age_str": "10", "bool": true, "name": 3} - ] - }, - "cases": [ - { - "comment": "sort by field expression", - "expression": "sort_by(people, &age)", - "result": [ - {"age": 10, "age_str": "10", "bool": true, "name": 3}, - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"} - ] - }, - { - "expression": "sort_by(people, &age_str)", - "result": [ - {"age": 10, "age_str": "10", "bool": true, "name": 3}, - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"} - ] - }, - { - "comment": "sort by function expression", - "expression": "sort_by(people, &to_number(age_str))", - "result": [ - {"age": 10, "age_str": "10", "bool": true, "name": 3}, - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"} - ] - }, - { - "comment": "function projection on sort_by function", - "expression": "sort_by(people, &age)[].name", - "result": [3, "a", "c", "b", "d"] - }, - { - "expression": "sort_by(people, &extra)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, &bool)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, &name)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, name)", - "error": "invalid-type" - }, - { - "expression": "sort_by(people, &age)[].extra", - "result": ["foo", "bar"] - }, - { - "expression": "sort_by(`[]`, &age)", - "result": [] - }, - { - "expression": "max_by(people, &age)", - "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} - }, - { - "expression": "max_by(people, &age_str)", - "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} - }, - { - "expression": "max_by(people, &bool)", - "error": "invalid-type" - }, - { - "expression": "max_by(people, &extra)", - "error": "invalid-type" - }, - { - "expression": "max_by(people, &to_number(age_str))", - "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} - }, - { - "expression": "max_by(`[]`, &age)", - "result": null - }, - { - "expression": "min_by(people, &age)", - "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} - }, - { - "expression": "min_by(people, &age_str)", - "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} - }, - { - "expression": "min_by(people, &bool)", - "error": "invalid-type" - }, - { - "expression": "min_by(people, &extra)", - "error": "invalid-type" - }, - { - "expression": "min_by(people, &to_number(age_str))", - "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} - }, - { - "expression": "min_by(`[]`, &age)", - "result": null - } - ] -}, { - "given": - { - "people": [ - {"age": 10, "order": "1"}, - {"age": 10, "order": "2"}, - {"age": 10, "order": "3"}, - {"age": 10, "order": "4"}, - {"age": 10, "order": "5"}, - {"age": 10, "order": "6"}, - {"age": 10, "order": "7"}, - {"age": 10, "order": "8"}, - {"age": 10, "order": "9"}, - {"age": 10, "order": "10"}, - {"age": 10, "order": "11"} - ] - }, - "cases": [ - { - "comment": "stable sort order", - "expression": "sort_by(people, &age)", - "result": [ - {"age": 10, "order": "1"}, - {"age": 10, "order": "2"}, - {"age": 10, "order": "3"}, - {"age": 10, "order": "4"}, - {"age": 10, "order": "5"}, - {"age": 10, "order": "6"}, - {"age": 10, "order": "7"}, - {"age": 10, "order": "8"}, - {"age": 10, "order": "9"}, - {"age": 10, "order": "10"}, - {"age": 10, "order": "11"} - ] - } - ] -}, { - "given": - { - "people": [ - {"a": 10, "b": 1, "c": "z"}, - {"a": 10, "b": 2, "c": null}, - {"a": 10, "b": 3}, - {"a": 10, "b": 4, "c": "z"}, - {"a": 10, "b": 5, "c": null}, - {"a": 10, "b": 6}, - {"a": 10, "b": 7, "c": "z"}, - {"a": 10, "b": 8, "c": null}, - {"a": 10, "b": 9} - ], - "empty": [] - }, - "cases": [ - { - "expression": "map(&a, people)", - "result": [10, 10, 10, 10, 10, 10, 10, 10, 10] - }, - { - "expression": "map(&c, people)", - "result": ["z", null, null, "z", null, null, "z", null, null] - }, - { - "expression": "map(&a, badkey)", - "error": "invalid-type" - }, - { - "expression": "map(&foo, empty)", - "result": [] - } - ] -}, { - "given": { - "array": [ - { - "foo": {"bar": "yes1"} - }, - { - "foo": {"bar": "yes2"} - }, - { - "foo1": {"bar": "no"} - } - ]}, - "cases": [ - { - "expression": "map(&foo.bar, array)", - "result": ["yes1", "yes2", null] - }, - { - "expression": "map(&foo1.bar, array)", - "result": [null, null, "no"] - }, - { - "expression": "map(&foo.bar.baz, array)", - "result": [null, null, null] - } - ] -}, { - "given": { - "array": [[1, 2, 3, [4]], [5, 6, 7, [8, 9]]] - }, - "cases": [ - { - "expression": "map(&[], array)", - "result": [[1, 2, 3, 4], [5, 6, 7, 8, 9]] - } - ] -} -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/identifiers.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/identifiers.json deleted file mode 100644 index 6896668b9..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/identifiers.json +++ /dev/null @@ -1,1377 +0,0 @@ -[ - { - "given": { - "__L": true - }, - "cases": [ - { - "expression": "__L", - "result": true - } - ] - }, - { - "given": { - "!\r": true - }, - "cases": [ - { - "expression": "\"!\\r\"", - "result": true - } - ] - }, - { - "given": { - "Y_1623": true - }, - "cases": [ - { - "expression": "Y_1623", - "result": true - } - ] - }, - { - "given": { - "x": true - }, - "cases": [ - { - "expression": "x", - "result": true - } - ] - }, - { - "given": { - "\tF\uCebb": true - }, - "cases": [ - { - "expression": "\"\\tF\\uCebb\"", - "result": true - } - ] - }, - { - "given": { - " \t": true - }, - "cases": [ - { - "expression": "\" \\t\"", - "result": true - } - ] - }, - { - "given": { - " ": true - }, - "cases": [ - { - "expression": "\" \"", - "result": true - } - ] - }, - { - "given": { - "v2": true - }, - "cases": [ - { - "expression": "v2", - "result": true - } - ] - }, - { - "given": { - "\t": true - }, - "cases": [ - { - "expression": "\"\\t\"", - "result": true - } - ] - }, - { - "given": { - "_X": true - }, - "cases": [ - { - "expression": "_X", - "result": true - } - ] - }, - { - "given": { - "\t4\ud9da\udd15": true - }, - "cases": [ - { - "expression": "\"\\t4\\ud9da\\udd15\"", - "result": true - } - ] - }, - { - "given": { - "v24_W": true - }, - "cases": [ - { - "expression": "v24_W", - "result": true - } - ] - }, - { - "given": { - "H": true - }, - "cases": [ - { - "expression": "\"H\"", - "result": true - } - ] - }, - { - "given": { - "\f": true - }, - "cases": [ - { - "expression": "\"\\f\"", - "result": true - } - ] - }, - { - "given": { - "E4": true - }, - "cases": [ - { - "expression": "\"E4\"", - "result": true - } - ] - }, - { - "given": { - "!": true - }, - "cases": [ - { - "expression": "\"!\"", - "result": true - } - ] - }, - { - "given": { - "tM": true - }, - "cases": [ - { - "expression": "tM", - "result": true - } - ] - }, - { - "given": { - " [": true - }, - "cases": [ - { - "expression": "\" [\"", - "result": true - } - ] - }, - { - "given": { - "R!": true - }, - "cases": [ - { - "expression": "\"R!\"", - "result": true - } - ] - }, - { - "given": { - "_6W": true - }, - "cases": [ - { - "expression": "_6W", - "result": true - } - ] - }, - { - "given": { - "\uaBA1\r": true - }, - "cases": [ - { - "expression": "\"\\uaBA1\\r\"", - "result": true - } - ] - }, - { - "given": { - "tL7": true - }, - "cases": [ - { - "expression": "tL7", - "result": true - } - ] - }, - { - "given": { - "<": true - }, - "cases": [ - { - "expression": "\">\"", - "result": true - } - ] - }, - { - "given": { - "hvu": true - }, - "cases": [ - { - "expression": "hvu", - "result": true - } - ] - }, - { - "given": { - "; !": true - }, - "cases": [ - { - "expression": "\"; !\"", - "result": true - } - ] - }, - { - "given": { - "hU": true - }, - "cases": [ - { - "expression": "hU", - "result": true - } - ] - }, - { - "given": { - "!I\n\/": true - }, - "cases": [ - { - "expression": "\"!I\\n\\/\"", - "result": true - } - ] - }, - { - "given": { - "\uEEbF": true - }, - "cases": [ - { - "expression": "\"\\uEEbF\"", - "result": true - } - ] - }, - { - "given": { - "U)\t": true - }, - "cases": [ - { - "expression": "\"U)\\t\"", - "result": true - } - ] - }, - { - "given": { - "fa0_9": true - }, - "cases": [ - { - "expression": "fa0_9", - "result": true - } - ] - }, - { - "given": { - "/": true - }, - "cases": [ - { - "expression": "\"/\"", - "result": true - } - ] - }, - { - "given": { - "Gy": true - }, - "cases": [ - { - "expression": "Gy", - "result": true - } - ] - }, - { - "given": { - "\b": true - }, - "cases": [ - { - "expression": "\"\\b\"", - "result": true - } - ] - }, - { - "given": { - "<": true - }, - "cases": [ - { - "expression": "\"<\"", - "result": true - } - ] - }, - { - "given": { - "\t": true - }, - "cases": [ - { - "expression": "\"\\t\"", - "result": true - } - ] - }, - { - "given": { - "\t&\\\r": true - }, - "cases": [ - { - "expression": "\"\\t&\\\\\\r\"", - "result": true - } - ] - }, - { - "given": { - "#": true - }, - "cases": [ - { - "expression": "\"#\"", - "result": true - } - ] - }, - { - "given": { - "B__": true - }, - "cases": [ - { - "expression": "B__", - "result": true - } - ] - }, - { - "given": { - "\nS \n": true - }, - "cases": [ - { - "expression": "\"\\nS \\n\"", - "result": true - } - ] - }, - { - "given": { - "Bp": true - }, - "cases": [ - { - "expression": "Bp", - "result": true - } - ] - }, - { - "given": { - ",\t;": true - }, - "cases": [ - { - "expression": "\",\\t;\"", - "result": true - } - ] - }, - { - "given": { - "B_q": true - }, - "cases": [ - { - "expression": "B_q", - "result": true - } - ] - }, - { - "given": { - "\/+\t\n\b!Z": true - }, - "cases": [ - { - "expression": "\"\\/+\\t\\n\\b!Z\"", - "result": true - } - ] - }, - { - "given": { - "\udadd\udfc7\\ueFAc": true - }, - "cases": [ - { - "expression": "\"\udadd\udfc7\\\\ueFAc\"", - "result": true - } - ] - }, - { - "given": { - ":\f": true - }, - "cases": [ - { - "expression": "\":\\f\"", - "result": true - } - ] - }, - { - "given": { - "\/": true - }, - "cases": [ - { - "expression": "\"\\/\"", - "result": true - } - ] - }, - { - "given": { - "_BW_6Hg_Gl": true - }, - "cases": [ - { - "expression": "_BW_6Hg_Gl", - "result": true - } - ] - }, - { - "given": { - "\udbcf\udc02": true - }, - "cases": [ - { - "expression": "\"\udbcf\udc02\"", - "result": true - } - ] - }, - { - "given": { - "zs1DC": true - }, - "cases": [ - { - "expression": "zs1DC", - "result": true - } - ] - }, - { - "given": { - "__434": true - }, - "cases": [ - { - "expression": "__434", - "result": true - } - ] - }, - { - "given": { - "\udb94\udd41": true - }, - "cases": [ - { - "expression": "\"\udb94\udd41\"", - "result": true - } - ] - }, - { - "given": { - "Z_5": true - }, - "cases": [ - { - "expression": "Z_5", - "result": true - } - ] - }, - { - "given": { - "z_M_": true - }, - "cases": [ - { - "expression": "z_M_", - "result": true - } - ] - }, - { - "given": { - "YU_2": true - }, - "cases": [ - { - "expression": "YU_2", - "result": true - } - ] - }, - { - "given": { - "_0": true - }, - "cases": [ - { - "expression": "_0", - "result": true - } - ] - }, - { - "given": { - "\b+": true - }, - "cases": [ - { - "expression": "\"\\b+\"", - "result": true - } - ] - }, - { - "given": { - "\"": true - }, - "cases": [ - { - "expression": "\"\\\"\"", - "result": true - } - ] - }, - { - "given": { - "D7": true - }, - "cases": [ - { - "expression": "D7", - "result": true - } - ] - }, - { - "given": { - "_62L": true - }, - "cases": [ - { - "expression": "_62L", - "result": true - } - ] - }, - { - "given": { - "\tK\t": true - }, - "cases": [ - { - "expression": "\"\\tK\\t\"", - "result": true - } - ] - }, - { - "given": { - "\n\\\f": true - }, - "cases": [ - { - "expression": "\"\\n\\\\\\f\"", - "result": true - } - ] - }, - { - "given": { - "I_": true - }, - "cases": [ - { - "expression": "I_", - "result": true - } - ] - }, - { - "given": { - "W_a0_": true - }, - "cases": [ - { - "expression": "W_a0_", - "result": true - } - ] - }, - { - "given": { - "BQ": true - }, - "cases": [ - { - "expression": "BQ", - "result": true - } - ] - }, - { - "given": { - "\tX$\uABBb": true - }, - "cases": [ - { - "expression": "\"\\tX$\\uABBb\"", - "result": true - } - ] - }, - { - "given": { - "Z9": true - }, - "cases": [ - { - "expression": "Z9", - "result": true - } - ] - }, - { - "given": { - "\b%\"\uda38\udd0f": true - }, - "cases": [ - { - "expression": "\"\\b%\\\"\uda38\udd0f\"", - "result": true - } - ] - }, - { - "given": { - "_F": true - }, - "cases": [ - { - "expression": "_F", - "result": true - } - ] - }, - { - "given": { - "!,": true - }, - "cases": [ - { - "expression": "\"!,\"", - "result": true - } - ] - }, - { - "given": { - "\"!": true - }, - "cases": [ - { - "expression": "\"\\\"!\"", - "result": true - } - ] - }, - { - "given": { - "Hh": true - }, - "cases": [ - { - "expression": "Hh", - "result": true - } - ] - }, - { - "given": { - "&": true - }, - "cases": [ - { - "expression": "\"&\"", - "result": true - } - ] - }, - { - "given": { - "9\r\\R": true - }, - "cases": [ - { - "expression": "\"9\\r\\\\R\"", - "result": true - } - ] - }, - { - "given": { - "M_k": true - }, - "cases": [ - { - "expression": "M_k", - "result": true - } - ] - }, - { - "given": { - "!\b\n\udb06\ude52\"\"": true - }, - "cases": [ - { - "expression": "\"!\\b\\n\udb06\ude52\\\"\\\"\"", - "result": true - } - ] - }, - { - "given": { - "6": true - }, - "cases": [ - { - "expression": "\"6\"", - "result": true - } - ] - }, - { - "given": { - "_7": true - }, - "cases": [ - { - "expression": "_7", - "result": true - } - ] - }, - { - "given": { - "0": true - }, - "cases": [ - { - "expression": "\"0\"", - "result": true - } - ] - }, - { - "given": { - "\\8\\": true - }, - "cases": [ - { - "expression": "\"\\\\8\\\\\"", - "result": true - } - ] - }, - { - "given": { - "b7eo": true - }, - "cases": [ - { - "expression": "b7eo", - "result": true - } - ] - }, - { - "given": { - "xIUo9": true - }, - "cases": [ - { - "expression": "xIUo9", - "result": true - } - ] - }, - { - "given": { - "5": true - }, - "cases": [ - { - "expression": "\"5\"", - "result": true - } - ] - }, - { - "given": { - "?": true - }, - "cases": [ - { - "expression": "\"?\"", - "result": true - } - ] - }, - { - "given": { - "sU": true - }, - "cases": [ - { - "expression": "sU", - "result": true - } - ] - }, - { - "given": { - "VH2&H\\\/": true - }, - "cases": [ - { - "expression": "\"VH2&H\\\\\\/\"", - "result": true - } - ] - }, - { - "given": { - "_C": true - }, - "cases": [ - { - "expression": "_C", - "result": true - } - ] - }, - { - "given": { - "_": true - }, - "cases": [ - { - "expression": "_", - "result": true - } - ] - }, - { - "given": { - "<\t": true - }, - "cases": [ - { - "expression": "\"<\\t\"", - "result": true - } - ] - }, - { - "given": { - "\uD834\uDD1E": true - }, - "cases": [ - { - "expression": "\"\\uD834\\uDD1E\"", - "result": true - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/indices.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/indices.json deleted file mode 100644 index ef1b75c72..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/indices.json +++ /dev/null @@ -1,346 +0,0 @@ -[{ - "given": - {"foo": {"bar": ["zero", "one", "two"]}}, - "cases": [ - { - "expression": "foo.bar[0]", - "result": "zero" - }, - { - "expression": "foo.bar[1]", - "result": "one" - }, - { - "expression": "foo.bar[2]", - "result": "two" - }, - { - "expression": "foo.bar[3]", - "result": null - }, - { - "expression": "foo.bar[-1]", - "result": "two" - }, - { - "expression": "foo.bar[-2]", - "result": "one" - }, - { - "expression": "foo.bar[-3]", - "result": "zero" - }, - { - "expression": "foo.bar[-4]", - "result": null - } - ] -}, - { - "given": - {"foo": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}]}, - "cases": [ - { - "expression": "foo.bar", - "result": null - }, - { - "expression": "foo[0].bar", - "result": "one" - }, - { - "expression": "foo[1].bar", - "result": "two" - }, - { - "expression": "foo[2].bar", - "result": "three" - }, - { - "expression": "foo[3].notbar", - "result": "four" - }, - { - "expression": "foo[3].bar", - "result": null - }, - { - "expression": "foo[0]", - "result": {"bar": "one"} - }, - { - "expression": "foo[1]", - "result": {"bar": "two"} - }, - { - "expression": "foo[2]", - "result": {"bar": "three"} - }, - { - "expression": "foo[3]", - "result": {"notbar": "four"} - }, - { - "expression": "foo[4]", - "result": null - } - ] - }, - { - "given": [ - "one", "two", "three" - ], - "cases": [ - { - "expression": "[0]", - "result": "one" - }, - { - "expression": "[1]", - "result": "two" - }, - { - "expression": "[2]", - "result": "three" - }, - { - "expression": "[-1]", - "result": "three" - }, - { - "expression": "[-2]", - "result": "two" - }, - { - "expression": "[-3]", - "result": "one" - } - ] - }, - { - "given": {"reservations": [ - {"instances": [{"foo": 1}, {"foo": 2}]} - ]}, - "cases": [ - { - "expression": "reservations[].instances[].foo", - "result": [1, 2] - }, - { - "expression": "reservations[].instances[].bar", - "result": [] - }, - { - "expression": "reservations[].notinstances[].foo", - "result": [] - }, - { - "expression": "reservations[].notinstances[].foo", - "result": [] - } - ] - }, - { - "given": {"reservations": [{ - "instances": [ - {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]}, - {"foo": [{"bar": 5}, {"bar": 6}, {"notbar": [7]}, {"bar": 8}]}, - {"foo": "bar"}, - {"notfoo": [{"bar": 20}, {"bar": 21}, {"notbar": [7]}, {"bar": 22}]}, - {"bar": [{"baz": [1]}, {"baz": [2]}, {"baz": [3]}, {"baz": [4]}]}, - {"baz": [{"baz": [1, 2]}, {"baz": []}, {"baz": []}, {"baz": [3, 4]}]}, - {"qux": [{"baz": []}, {"baz": [1, 2, 3]}, {"baz": [4]}, {"baz": []}]} - ], - "otherkey": {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]} - }, { - "instances": [ - {"a": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]}, - {"b": [{"bar": 5}, {"bar": 6}, {"notbar": [7]}, {"bar": 8}]}, - {"c": "bar"}, - {"notfoo": [{"bar": 23}, {"bar": 24}, {"notbar": [7]}, {"bar": 25}]}, - {"qux": [{"baz": []}, {"baz": [1, 2, 3]}, {"baz": [4]}, {"baz": []}]} - ], - "otherkey": {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]} - } - ]}, - "cases": [ - { - "expression": "reservations[].instances[].foo[].bar", - "result": [1, 2, 4, 5, 6, 8] - }, - { - "expression": "reservations[].instances[].foo[].baz", - "result": [] - }, - { - "expression": "reservations[].instances[].notfoo[].bar", - "result": [20, 21, 22, 23, 24, 25] - }, - { - "expression": "reservations[].instances[].notfoo[].notbar", - "result": [[7], [7]] - }, - { - "expression": "reservations[].notinstances[].foo", - "result": [] - }, - { - "expression": "reservations[].instances[].foo[].notbar", - "result": [3, [7]] - }, - { - "expression": "reservations[].instances[].bar[].baz", - "result": [[1], [2], [3], [4]] - }, - { - "expression": "reservations[].instances[].baz[].baz", - "result": [[1, 2], [], [], [3, 4]] - }, - { - "expression": "reservations[].instances[].qux[].baz", - "result": [[], [1, 2, 3], [4], [], [], [1, 2, 3], [4], []] - }, - { - "expression": "reservations[].instances[].qux[].baz[]", - "result": [1, 2, 3, 4, 1, 2, 3, 4] - } - ] - }, - { - "given": { - "foo": [ - [["one", "two"], ["three", "four"]], - [["five", "six"], ["seven", "eight"]], - [["nine"], ["ten"]] - ] - }, - "cases": [ - { - "expression": "foo[]", - "result": [["one", "two"], ["three", "four"], ["five", "six"], - ["seven", "eight"], ["nine"], ["ten"]] - }, - { - "expression": "foo[][0]", - "result": ["one", "three", "five", "seven", "nine", "ten"] - }, - { - "expression": "foo[][1]", - "result": ["two", "four", "six", "eight"] - }, - { - "expression": "foo[][0][0]", - "result": [] - }, - { - "expression": "foo[][2][2]", - "result": [] - }, - { - "expression": "foo[][0][0][100]", - "result": [] - } - ] - }, - { - "given": { - "foo": [{ - "bar": [ - { - "qux": 2, - "baz": 1 - }, - { - "qux": 4, - "baz": 3 - } - ] - }, - { - "bar": [ - { - "qux": 6, - "baz": 5 - }, - { - "qux": 8, - "baz": 7 - } - ] - } - ] - }, - "cases": [ - { - "expression": "foo", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[]", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[].bar", - "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], - [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] - }, - { - "expression": "foo[].bar[]", - "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, - {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] - }, - { - "expression": "foo[].bar[].baz", - "result": [1, 3, 5, 7] - } - ] - }, - { - "given": { - "string": "string", - "hash": {"foo": "bar", "bar": "baz"}, - "number": 23, - "nullvalue": null - }, - "cases": [ - { - "expression": "string[]", - "result": null - }, - { - "expression": "hash[]", - "result": null - }, - { - "expression": "number[]", - "result": null - }, - { - "expression": "nullvalue[]", - "result": null - }, - { - "expression": "string[].foo", - "result": null - }, - { - "expression": "hash[].foo", - "result": null - }, - { - "expression": "number[].foo", - "result": null - }, - { - "expression": "nullvalue[].foo", - "result": null - }, - { - "expression": "nullvalue[].foo[].bar", - "result": null - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/literals.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/literals.json deleted file mode 100644 index 47ecf771e..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/literals.json +++ /dev/null @@ -1,195 +0,0 @@ -[ - { - "given": { - "foo": [{"name": "a"}, {"name": "b"}], - "bar": {"baz": "qux"} - }, - "cases": [ - { - "expression": "`\"foo\"`", - "result": "foo" - }, - { - "comment": "Interpret escaped unicode.", - "expression": "`\"\\u03a6\"`", - "result": "Φ" - }, - { - "expression": "`\"✓\"`", - "result": "✓" - }, - { - "expression": "`[1, 2, 3]`", - "result": [1, 2, 3] - }, - { - "expression": "`{\"a\": \"b\"}`", - "result": {"a": "b"} - }, - { - "expression": "`true`", - "result": true - }, - { - "expression": "`false`", - "result": false - }, - { - "expression": "`null`", - "result": null - }, - { - "expression": "`0`", - "result": 0 - }, - { - "expression": "`1`", - "result": 1 - }, - { - "expression": "`2`", - "result": 2 - }, - { - "expression": "`3`", - "result": 3 - }, - { - "expression": "`4`", - "result": 4 - }, - { - "expression": "`5`", - "result": 5 - }, - { - "expression": "`6`", - "result": 6 - }, - { - "expression": "`7`", - "result": 7 - }, - { - "expression": "`8`", - "result": 8 - }, - { - "expression": "`9`", - "result": 9 - }, - { - "comment": "Escaping a backtick in quotes", - "expression": "`\"foo\\`bar\"`", - "result": "foo`bar" - }, - { - "comment": "Double quote in literal", - "expression": "`\"foo\\\"bar\"`", - "result": "foo\"bar" - }, - { - "expression": "`\"1\\`\"`", - "result": "1`" - }, - { - "comment": "Multiple literal expressions with escapes", - "expression": "`\"\\\\\"`.{a:`\"b\"`}", - "result": {"a": "b"} - }, - { - "comment": "literal . identifier", - "expression": "`{\"a\": \"b\"}`.a", - "result": "b" - }, - { - "comment": "literal . identifier . identifier", - "expression": "`{\"a\": {\"b\": \"c\"}}`.a.b", - "result": "c" - }, - { - "comment": "literal . identifier bracket-expr", - "expression": "`[0, 1, 2]`[1]", - "result": 1 - } - ] - }, - { - "comment": "Literals", - "given": {"type": "object"}, - "cases": [ - { - "comment": "Literal with leading whitespace", - "expression": "` {\"foo\": true}`", - "result": {"foo": true} - }, - { - "comment": "Literal with trailing whitespace", - "expression": "`{\"foo\": true} `", - "result": {"foo": true} - }, - { - "comment": "Literal on RHS of subexpr not allowed", - "expression": "foo.`\"bar\"`", - "error": "syntax" - } - ] - }, - { - "comment": "Raw String Literals", - "given": {}, - "cases": [ - { - "expression": "'foo'", - "result": "foo" - }, - { - "expression": "' foo '", - "result": " foo " - }, - { - "expression": "'0'", - "result": "0" - }, - { - "expression": "'newline\n'", - "result": "newline\n" - }, - { - "expression": "'\n'", - "result": "\n" - }, - { - "expression": "'✓'", - "result": "✓" - }, - { - "expression": "'𝄞'", - "result": "𝄞" - }, - { - "expression": "' [foo] '", - "result": " [foo] " - }, - { - "expression": "'[foo]'", - "result": "[foo]" - }, - { - "comment": "Do not interpret escaped unicode.", - "expression": "'\\u03a6'", - "result": "\\u03a6" - }, - { - "comment": "Can escape the single quote", - "expression": "'foo\\'bar'", - "result": "foo'bar" - }, - { - "comment": "Backslash not followed by single quote is treated as any other character", - "expression": "'\\z'", - "result": "\\z" - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/multiselect.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/multiselect.json deleted file mode 100644 index 0f19b5105..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/multiselect.json +++ /dev/null @@ -1,398 +0,0 @@ -[{ - "given": { - "foo": { - "bar": "bar", - "baz": "baz", - "qux": "qux", - "nested": { - "one": { - "a": "first", - "b": "second", - "c": "third" - }, - "two": { - "a": "first", - "b": "second", - "c": "third" - }, - "three": { - "a": "first", - "b": "second", - "c": {"inner": "third"} - } - } - }, - "bar": 1, - "baz": 2, - "qux\"": 3 - }, - "cases": [ - { - "expression": "foo.{bar: bar}", - "result": {"bar": "bar"} - }, - { - "expression": "foo.{\"bar\": bar}", - "result": {"bar": "bar"} - }, - { - "expression": "foo.{\"foo.bar\": bar}", - "result": {"foo.bar": "bar"} - }, - { - "expression": "foo.{bar: bar, baz: baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "foo.{\"bar\": bar, \"baz\": baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "{\"baz\": baz, \"qux\\\"\": \"qux\\\"\"}", - "result": {"baz": 2, "qux\"": 3} - }, - { - "expression": "foo.{bar:bar,baz:baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "foo.{bar: bar,qux: qux}", - "result": {"bar": "bar", "qux": "qux"} - }, - { - "expression": "foo.{bar: bar, noexist: noexist}", - "result": {"bar": "bar", "noexist": null} - }, - { - "expression": "foo.{noexist: noexist, alsonoexist: alsonoexist}", - "result": {"noexist": null, "alsonoexist": null} - }, - { - "expression": "foo.badkey.{nokey: nokey, alsonokey: alsonokey}", - "result": null - }, - { - "expression": "foo.nested.*.{a: a,b: b}", - "result": [{"a": "first", "b": "second"}, - {"a": "first", "b": "second"}, - {"a": "first", "b": "second"}] - }, - { - "expression": "foo.nested.three.{a: a, cinner: c.inner}", - "result": {"a": "first", "cinner": "third"} - }, - { - "expression": "foo.nested.three.{a: a, c: c.inner.bad.key}", - "result": {"a": "first", "c": null} - }, - { - "expression": "foo.{a: nested.one.a, b: nested.two.b}", - "result": {"a": "first", "b": "second"} - }, - { - "expression": "{bar: bar, baz: baz}", - "result": {"bar": 1, "baz": 2} - }, - { - "expression": "{bar: bar}", - "result": {"bar": 1} - }, - { - "expression": "{otherkey: bar}", - "result": {"otherkey": 1} - }, - { - "expression": "{no: no, exist: exist}", - "result": {"no": null, "exist": null} - }, - { - "expression": "foo.[bar]", - "result": ["bar"] - }, - { - "expression": "foo.[bar,baz]", - "result": ["bar", "baz"] - }, - { - "expression": "foo.[bar,qux]", - "result": ["bar", "qux"] - }, - { - "expression": "foo.[bar,noexist]", - "result": ["bar", null] - }, - { - "expression": "foo.[noexist,alsonoexist]", - "result": [null, null] - } - ] -}, { - "given": { - "foo": {"bar": 1, "baz": [2, 3, 4]} - }, - "cases": [ - { - "expression": "foo.{bar:bar,baz:baz}", - "result": {"bar": 1, "baz": [2, 3, 4]} - }, - { - "expression": "foo.[bar,baz[0]]", - "result": [1, 2] - }, - { - "expression": "foo.[bar,baz[1]]", - "result": [1, 3] - }, - { - "expression": "foo.[bar,baz[2]]", - "result": [1, 4] - }, - { - "expression": "foo.[bar,baz[3]]", - "result": [1, null] - }, - { - "expression": "foo.[bar[0],baz[3]]", - "result": [null, null] - } - ] -}, { - "given": { - "foo": {"bar": 1, "baz": 2} - }, - "cases": [ - { - "expression": "foo.{bar: bar, baz: baz}", - "result": {"bar": 1, "baz": 2} - }, - { - "expression": "foo.[bar,baz]", - "result": [1, 2] - } - ] -}, { - "given": { - "foo": { - "bar": {"baz": [{"common": "first", "one": 1}, - {"common": "second", "two": 2}]}, - "ignoreme": 1, - "includeme": true - } - }, - "cases": [ - { - "expression": "foo.{bar: bar.baz[1],includeme: includeme}", - "result": {"bar": {"common": "second", "two": 2}, "includeme": true} - }, - { - "expression": "foo.{\"bar.baz.two\": bar.baz[1].two, includeme: includeme}", - "result": {"bar.baz.two": 2, "includeme": true} - }, - { - "expression": "foo.[includeme, bar.baz[*].common]", - "result": [true, ["first", "second"]] - }, - { - "expression": "foo.[includeme, bar.baz[*].none]", - "result": [true, []] - }, - { - "expression": "foo.[includeme, bar.baz[].common]", - "result": [true, ["first", "second"]] - } - ] -}, { - "given": { - "reservations": [{ - "instances": [ - {"id": "id1", - "name": "first"}, - {"id": "id2", - "name": "second"} - ]}, { - "instances": [ - {"id": "id3", - "name": "third"}, - {"id": "id4", - "name": "fourth"} - ]} - ]}, - "cases": [ - { - "expression": "reservations[*].instances[*].{id: id, name: name}", - "result": [[{"id": "id1", "name": "first"}, {"id": "id2", "name": "second"}], - [{"id": "id3", "name": "third"}, {"id": "id4", "name": "fourth"}]] - }, - { - "expression": "reservations[].instances[].{id: id, name: name}", - "result": [{"id": "id1", "name": "first"}, - {"id": "id2", "name": "second"}, - {"id": "id3", "name": "third"}, - {"id": "id4", "name": "fourth"}] - }, - { - "expression": "reservations[].instances[].[id, name]", - "result": [["id1", "first"], - ["id2", "second"], - ["id3", "third"], - ["id4", "fourth"]] - } - ] -}, - { - "given": { - "foo": [{ - "bar": [ - { - "qux": 2, - "baz": 1 - }, - { - "qux": 4, - "baz": 3 - } - ] - }, - { - "bar": [ - { - "qux": 6, - "baz": 5 - }, - { - "qux": 8, - "baz": 7 - } - ] - } - ] - }, - "cases": [ - { - "expression": "foo", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[]", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[].bar", - "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], - [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] - }, - { - "expression": "foo[].bar[]", - "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, - {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] - }, - { - "expression": "foo[].bar[].[baz, qux]", - "result": [[1, 2], [3, 4], [5, 6], [7, 8]] - }, - { - "expression": "foo[].bar[].[baz]", - "result": [[1], [3], [5], [7]] - }, - { - "expression": "foo[].bar[].[baz, qux][]", - "result": [1, 2, 3, 4, 5, 6, 7, 8] - } - ] - }, - { - "given": { - "foo": { - "baz": [ - { - "bar": "abc" - }, { - "bar": "def" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].bar, qux[0]]", - "result": [["abc", "def"], "zero"] - } - ] - }, - { - "given": { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].[bar, boo], qux[0]]", - "result": [[["a", "c" ], ["d", "f" ]], "zero"] - } - ] - }, - { - "given": { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].not_there || baz[*].bar, qux[0]]", - "result": [["a", "d"], "zero"] - } - ] - }, - { - "given": {"type": "object"}, - "cases": [ - { - "comment": "Nested multiselect", - "expression": "[[*],*]", - "result": [null, ["object"]] - } - ] - }, - { - "given": [], - "cases": [ - { - "comment": "Nested multiselect", - "expression": "[[*]]", - "result": [[]] - }, - { - "comment": "Select on null", - "expression": "missing.{foo: bar}", - "result": null - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/slice.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/slice.json deleted file mode 100644 index 0f19b5105..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/slice.json +++ /dev/null @@ -1,398 +0,0 @@ -[{ - "given": { - "foo": { - "bar": "bar", - "baz": "baz", - "qux": "qux", - "nested": { - "one": { - "a": "first", - "b": "second", - "c": "third" - }, - "two": { - "a": "first", - "b": "second", - "c": "third" - }, - "three": { - "a": "first", - "b": "second", - "c": {"inner": "third"} - } - } - }, - "bar": 1, - "baz": 2, - "qux\"": 3 - }, - "cases": [ - { - "expression": "foo.{bar: bar}", - "result": {"bar": "bar"} - }, - { - "expression": "foo.{\"bar\": bar}", - "result": {"bar": "bar"} - }, - { - "expression": "foo.{\"foo.bar\": bar}", - "result": {"foo.bar": "bar"} - }, - { - "expression": "foo.{bar: bar, baz: baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "foo.{\"bar\": bar, \"baz\": baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "{\"baz\": baz, \"qux\\\"\": \"qux\\\"\"}", - "result": {"baz": 2, "qux\"": 3} - }, - { - "expression": "foo.{bar:bar,baz:baz}", - "result": {"bar": "bar", "baz": "baz"} - }, - { - "expression": "foo.{bar: bar,qux: qux}", - "result": {"bar": "bar", "qux": "qux"} - }, - { - "expression": "foo.{bar: bar, noexist: noexist}", - "result": {"bar": "bar", "noexist": null} - }, - { - "expression": "foo.{noexist: noexist, alsonoexist: alsonoexist}", - "result": {"noexist": null, "alsonoexist": null} - }, - { - "expression": "foo.badkey.{nokey: nokey, alsonokey: alsonokey}", - "result": null - }, - { - "expression": "foo.nested.*.{a: a,b: b}", - "result": [{"a": "first", "b": "second"}, - {"a": "first", "b": "second"}, - {"a": "first", "b": "second"}] - }, - { - "expression": "foo.nested.three.{a: a, cinner: c.inner}", - "result": {"a": "first", "cinner": "third"} - }, - { - "expression": "foo.nested.three.{a: a, c: c.inner.bad.key}", - "result": {"a": "first", "c": null} - }, - { - "expression": "foo.{a: nested.one.a, b: nested.two.b}", - "result": {"a": "first", "b": "second"} - }, - { - "expression": "{bar: bar, baz: baz}", - "result": {"bar": 1, "baz": 2} - }, - { - "expression": "{bar: bar}", - "result": {"bar": 1} - }, - { - "expression": "{otherkey: bar}", - "result": {"otherkey": 1} - }, - { - "expression": "{no: no, exist: exist}", - "result": {"no": null, "exist": null} - }, - { - "expression": "foo.[bar]", - "result": ["bar"] - }, - { - "expression": "foo.[bar,baz]", - "result": ["bar", "baz"] - }, - { - "expression": "foo.[bar,qux]", - "result": ["bar", "qux"] - }, - { - "expression": "foo.[bar,noexist]", - "result": ["bar", null] - }, - { - "expression": "foo.[noexist,alsonoexist]", - "result": [null, null] - } - ] -}, { - "given": { - "foo": {"bar": 1, "baz": [2, 3, 4]} - }, - "cases": [ - { - "expression": "foo.{bar:bar,baz:baz}", - "result": {"bar": 1, "baz": [2, 3, 4]} - }, - { - "expression": "foo.[bar,baz[0]]", - "result": [1, 2] - }, - { - "expression": "foo.[bar,baz[1]]", - "result": [1, 3] - }, - { - "expression": "foo.[bar,baz[2]]", - "result": [1, 4] - }, - { - "expression": "foo.[bar,baz[3]]", - "result": [1, null] - }, - { - "expression": "foo.[bar[0],baz[3]]", - "result": [null, null] - } - ] -}, { - "given": { - "foo": {"bar": 1, "baz": 2} - }, - "cases": [ - { - "expression": "foo.{bar: bar, baz: baz}", - "result": {"bar": 1, "baz": 2} - }, - { - "expression": "foo.[bar,baz]", - "result": [1, 2] - } - ] -}, { - "given": { - "foo": { - "bar": {"baz": [{"common": "first", "one": 1}, - {"common": "second", "two": 2}]}, - "ignoreme": 1, - "includeme": true - } - }, - "cases": [ - { - "expression": "foo.{bar: bar.baz[1],includeme: includeme}", - "result": {"bar": {"common": "second", "two": 2}, "includeme": true} - }, - { - "expression": "foo.{\"bar.baz.two\": bar.baz[1].two, includeme: includeme}", - "result": {"bar.baz.two": 2, "includeme": true} - }, - { - "expression": "foo.[includeme, bar.baz[*].common]", - "result": [true, ["first", "second"]] - }, - { - "expression": "foo.[includeme, bar.baz[*].none]", - "result": [true, []] - }, - { - "expression": "foo.[includeme, bar.baz[].common]", - "result": [true, ["first", "second"]] - } - ] -}, { - "given": { - "reservations": [{ - "instances": [ - {"id": "id1", - "name": "first"}, - {"id": "id2", - "name": "second"} - ]}, { - "instances": [ - {"id": "id3", - "name": "third"}, - {"id": "id4", - "name": "fourth"} - ]} - ]}, - "cases": [ - { - "expression": "reservations[*].instances[*].{id: id, name: name}", - "result": [[{"id": "id1", "name": "first"}, {"id": "id2", "name": "second"}], - [{"id": "id3", "name": "third"}, {"id": "id4", "name": "fourth"}]] - }, - { - "expression": "reservations[].instances[].{id: id, name: name}", - "result": [{"id": "id1", "name": "first"}, - {"id": "id2", "name": "second"}, - {"id": "id3", "name": "third"}, - {"id": "id4", "name": "fourth"}] - }, - { - "expression": "reservations[].instances[].[id, name]", - "result": [["id1", "first"], - ["id2", "second"], - ["id3", "third"], - ["id4", "fourth"]] - } - ] -}, - { - "given": { - "foo": [{ - "bar": [ - { - "qux": 2, - "baz": 1 - }, - { - "qux": 4, - "baz": 3 - } - ] - }, - { - "bar": [ - { - "qux": 6, - "baz": 5 - }, - { - "qux": 8, - "baz": 7 - } - ] - } - ] - }, - "cases": [ - { - "expression": "foo", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[]", - "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, - {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] - }, - { - "expression": "foo[].bar", - "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], - [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] - }, - { - "expression": "foo[].bar[]", - "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, - {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] - }, - { - "expression": "foo[].bar[].[baz, qux]", - "result": [[1, 2], [3, 4], [5, 6], [7, 8]] - }, - { - "expression": "foo[].bar[].[baz]", - "result": [[1], [3], [5], [7]] - }, - { - "expression": "foo[].bar[].[baz, qux][]", - "result": [1, 2, 3, 4, 5, 6, 7, 8] - } - ] - }, - { - "given": { - "foo": { - "baz": [ - { - "bar": "abc" - }, { - "bar": "def" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].bar, qux[0]]", - "result": [["abc", "def"], "zero"] - } - ] - }, - { - "given": { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].[bar, boo], qux[0]]", - "result": [[["a", "c" ], ["d", "f" ]], "zero"] - } - ] - }, - { - "given": { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - }, - "cases": [ - { - "expression": "foo.[baz[*].not_there || baz[*].bar, qux[0]]", - "result": [["a", "d"], "zero"] - } - ] - }, - { - "given": {"type": "object"}, - "cases": [ - { - "comment": "Nested multiselect", - "expression": "[[*],*]", - "result": [null, ["object"]] - } - ] - }, - { - "given": [], - "cases": [ - { - "comment": "Nested multiselect", - "expression": "[[*]]", - "result": [[]] - }, - { - "comment": "Select on null", - "expression": "missing.{foo: bar}", - "result": null - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/unicode.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/unicode.json deleted file mode 100644 index 8a72e40fd..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/unicode.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "given": {"foo": [{"✓": "✓"}, {"✓": "✗"}]}, - "cases": [ - { - "expression": "foo[].\"✓\"", - "result": ["✓", "✗"] - } - ] - }, - { - "given": {"☯": true}, - "cases": [ - { - "expression": "\"☯\"", - "result": true - } - ] - }, - { - "given": {"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪": true}, - "cases": [ - { - "expression": "\"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪\"", - "result": true - } - ] - }, - { - "given": {"☃": true}, - "cases": [ - { - "expression": "\"☃\"", - "result": true - } - ] - } -] diff --git a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/wildcard.json b/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/wildcard.json deleted file mode 100644 index 87b77bf67..000000000 --- a/jmespath/src/test/resources/software/amazon/smithy/java/jmespath/compliance/wildcard.json +++ /dev/null @@ -1,460 +0,0 @@ -[{ - "given": { - "foo": { - "bar": { - "baz": "val" - }, - "other": { - "baz": "val" - }, - "other2": { - "baz": "val" - }, - "other3": { - "notbaz": ["a", "b", "c"] - }, - "other4": { - "notbaz": ["a", "b", "c"] - }, - "other5": { - "other": { - "a": 1, - "b": 1, - "c": 1 - } - } - } - }, - "cases": [ - { - "expression": "foo.*.baz", - "result": ["val", "val", "val"] - }, - { - "expression": "foo.bar.*", - "result": ["val"] - }, - { - "expression": "foo.*.notbaz", - "result": [["a", "b", "c"], ["a", "b", "c"]] - }, - { - "expression": "foo.*.notbaz[0]", - "result": ["a", "a"] - }, - { - "expression": "foo.*.notbaz[-1]", - "result": ["c", "c"] - } - ] -}, { - "given": { - "foo": { - "first-1": { - "second-1": "val" - }, - "first-2": { - "second-1": "val" - }, - "first-3": { - "second-1": "val" - } - } - }, - "cases": [ - { - "expression": "foo.*", - "result": [{"second-1": "val"}, {"second-1": "val"}, - {"second-1": "val"}] - }, - { - "expression": "foo.*.*", - "result": [["val"], ["val"], ["val"]] - }, - { - "expression": "foo.*.*.*", - "result": [[], [], []] - }, - { - "expression": "foo.*.*.*.*", - "result": [[], [], []] - } - ] -}, { - "given": { - "foo": { - "bar": "one" - }, - "other": { - "bar": "one" - }, - "nomatch": { - "notbar": "three" - } - }, - "cases": [ - { - "expression": "*.bar", - "result": ["one", "one"] - } - ] -}, { - "given": { - "top1": { - "sub1": {"foo": "one"} - }, - "top2": { - "sub1": {"foo": "one"} - } - }, - "cases": [ - { - "expression": "*", - "result": [{"sub1": {"foo": "one"}}, - {"sub1": {"foo": "one"}}] - }, - { - "expression": "*.sub1", - "result": [{"foo": "one"}, - {"foo": "one"}] - }, - { - "expression": "*.*", - "result": [[{"foo": "one"}], - [{"foo": "one"}]] - }, - { - "expression": "*.*.foo[]", - "result": ["one", "one"] - }, - { - "expression": "*.sub1.foo", - "result": ["one", "one"] - } - ] -}, - { - "given": - {"foo": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}]}, - "cases": [ - { - "expression": "foo[*].bar", - "result": ["one", "two", "three"] - }, - { - "expression": "foo[*].notbar", - "result": ["four"] - } - ] - }, - { - "given": - [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}], - "cases": [ - { - "expression": "[*]", - "result": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}] - }, - { - "expression": "[*].bar", - "result": ["one", "two", "three"] - }, - { - "expression": "[*].notbar", - "result": ["four"] - } - ] - }, - { - "given": { - "foo": { - "bar": [ - {"baz": ["one", "two", "three"]}, - {"baz": ["four", "five", "six"]}, - {"baz": ["seven", "eight", "nine"]} - ] - } - }, - "cases": [ - { - "expression": "foo.bar[*].baz", - "result": [["one", "two", "three"], ["four", "five", "six"], ["seven", "eight", "nine"]] - }, - { - "expression": "foo.bar[*].baz[0]", - "result": ["one", "four", "seven"] - }, - { - "expression": "foo.bar[*].baz[1]", - "result": ["two", "five", "eight"] - }, - { - "expression": "foo.bar[*].baz[2]", - "result": ["three", "six", "nine"] - }, - { - "expression": "foo.bar[*].baz[3]", - "result": [] - } - ] - }, - { - "given": { - "foo": { - "bar": [["one", "two"], ["three", "four"]] - } - }, - "cases": [ - { - "expression": "foo.bar[*]", - "result": [["one", "two"], ["three", "four"]] - }, - { - "expression": "foo.bar[0]", - "result": ["one", "two"] - }, - { - "expression": "foo.bar[0][0]", - "result": "one" - }, - { - "expression": "foo.bar[0][0][0]", - "result": null - }, - { - "expression": "foo.bar[0][0][0][0]", - "result": null - }, - { - "expression": "foo[0][0]", - "result": null - } - ] - }, - { - "given": { - "foo": [ - {"bar": [{"kind": "basic"}, {"kind": "intermediate"}]}, - {"bar": [{"kind": "advanced"}, {"kind": "expert"}]}, - {"bar": "string"} - ] - - }, - "cases": [ - { - "expression": "foo[*].bar[*].kind", - "result": [["basic", "intermediate"], ["advanced", "expert"]] - }, - { - "expression": "foo[*].bar[0].kind", - "result": ["basic", "advanced"] - } - ] - }, - { - "given": { - "foo": [ - {"bar": {"kind": "basic"}}, - {"bar": {"kind": "intermediate"}}, - {"bar": {"kind": "advanced"}}, - {"bar": {"kind": "expert"}}, - {"bar": "string"} - ] - }, - "cases": [ - { - "expression": "foo[*].bar.kind", - "result": ["basic", "intermediate", "advanced", "expert"] - } - ] - }, - { - "given": { - "foo": [{"bar": ["one", "two"]}, {"bar": ["three", "four"]}, {"bar": ["five"]}] - }, - "cases": [ - { - "expression": "foo[*].bar[0]", - "result": ["one", "three", "five"] - }, - { - "expression": "foo[*].bar[1]", - "result": ["two", "four"] - }, - { - "expression": "foo[*].bar[2]", - "result": [] - } - ] - }, - { - "given": { - "foo": [{"bar": []}, {"bar": []}, {"bar": []}] - }, - "cases": [ - { - "expression": "foo[*].bar[0]", - "result": [] - } - ] - }, - { - "given": { - "foo": [["one", "two"], ["three", "four"], ["five"]] - }, - "cases": [ - { - "expression": "foo[*][0]", - "result": ["one", "three", "five"] - }, - { - "expression": "foo[*][1]", - "result": ["two", "four"] - } - ] - }, - { - "given": { - "foo": [ - [ - ["one", "two"], ["three", "four"] - ], [ - ["five", "six"], ["seven", "eight"] - ], [ - ["nine"], ["ten"] - ] - ] - }, - "cases": [ - { - "expression": "foo[*][0]", - "result": [["one", "two"], ["five", "six"], ["nine"]] - }, - { - "expression": "foo[*][1]", - "result": [["three", "four"], ["seven", "eight"], ["ten"]] - }, - { - "expression": "foo[*][0][0]", - "result": ["one", "five", "nine"] - }, - { - "expression": "foo[*][1][0]", - "result": ["three", "seven", "ten"] - }, - { - "expression": "foo[*][0][1]", - "result": ["two", "six"] - }, - { - "expression": "foo[*][1][1]", - "result": ["four", "eight"] - }, - { - "expression": "foo[*][2]", - "result": [] - }, - { - "expression": "foo[*][2][2]", - "result": [] - }, - { - "expression": "bar[*]", - "result": null - }, - { - "expression": "bar[*].baz[*]", - "result": null - } - ] - }, - { - "given": { - "string": "string", - "hash": {"foo": "bar", "bar": "baz"}, - "number": 23, - "nullvalue": null - }, - "cases": [ - { - "expression": "string[*]", - "result": null - }, - { - "expression": "hash[*]", - "result": null - }, - { - "expression": "number[*]", - "result": null - }, - { - "expression": "nullvalue[*]", - "result": null - }, - { - "expression": "string[*].foo", - "result": null - }, - { - "expression": "hash[*].foo", - "result": null - }, - { - "expression": "number[*].foo", - "result": null - }, - { - "expression": "nullvalue[*].foo", - "result": null - }, - { - "expression": "nullvalue[*].foo[*].bar", - "result": null - } - ] - }, - { - "given": { - "string": "string", - "hash": {"foo": "val", "bar": "val"}, - "number": 23, - "array": [1, 2, 3], - "nullvalue": null - }, - "cases": [ - { - "expression": "string.*", - "result": null - }, - { - "expression": "hash.*", - "result": ["val", "val"] - }, - { - "expression": "number.*", - "result": null - }, - { - "expression": "array.*", - "result": null - }, - { - "expression": "nullvalue.*", - "result": null - } - ] - }, - { - "given": { - "a": [0, 1, 2], - "b": [0, 1, 2] - }, - "cases": [ - { - "expression": "*[0]", - "result": [0, 0] - } - ] - } -] From 56631084a138fe50775404225263c5a2bb8f5f3c Mon Sep 17 00:00:00 2001 From: Robin Salkeld Date: Sat, 6 Dec 2025 11:04:17 -0800 Subject: [PATCH 9/9] spotless --- .../smithy/java/jmespath/GeneratedTypeJmespathRuntime.java | 6 +++--- .../GeneratedTypeJmespathRuntimeComplianceTests.java | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java index 2aef54224..12200c602 100644 --- a/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java +++ b/jmespath/src/main/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntime.java @@ -8,7 +8,6 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.time.Instant; -import java.util.Collection; import java.util.List; import java.util.Map; import software.amazon.smithy.java.core.schema.Schema; @@ -101,7 +100,7 @@ public Object createString(String s) { public String asString(Object value) { if (value instanceof SmithyEnum enumValue) { return enumValue.getValue(); - } else if (value instanceof String s){ + } else if (value instanceof String s) { return s; } else { throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); @@ -147,7 +146,8 @@ public Number length(Object value) { yield ((SerializableStruct) value).schema().members().size(); } } - default -> throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); + default -> + throw new JmespathException(JmespathExceptionType.INVALID_TYPE, "Incorrect runtime type: " + value); }; } diff --git a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java index 7dac68a21..536334ad9 100644 --- a/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java +++ b/jmespath/src/test/java/software/amazon/smithy/java/jmespath/GeneratedTypeJmespathRuntimeComplianceTests.java @@ -5,12 +5,11 @@ package software.amazon.smithy.java.jmespath; +import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import software.amazon.smithy.jmespath.tests.ComplianceTestRunner; -import java.util.stream.Stream; - public class GeneratedTypeJmespathRuntimeComplianceTests { @ParameterizedTest(name = "{0}") @MethodSource("source")