diff --git a/common/src/main/java/dev/cel/common/values/BUILD.bazel b/common/src/main/java/dev/cel/common/values/BUILD.bazel
index 53ffdda3d..0d1d5431f 100644
--- a/common/src/main/java/dev/cel/common/values/BUILD.bazel
+++ b/common/src/main/java/dev/cel/common/values/BUILD.bazel
@@ -118,6 +118,38 @@ java_library(
],
)
+java_library(
+ name = "mutable_map_value",
+ srcs = ["MutableMapValue.java"],
+ tags = [
+ ],
+ deps = [
+ "//common/annotations",
+ "//common/exceptions:attribute_not_found",
+ "//common/types",
+ "//common/types:type_providers",
+ "//common/values",
+ "//common/values:cel_value",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
+cel_android_library(
+ name = "mutable_map_value_android",
+ srcs = ["MutableMapValue.java"],
+ tags = [
+ ],
+ deps = [
+ ":cel_value_android",
+ "//common/annotations",
+ "//common/exceptions:attribute_not_found",
+ "//common/types:type_providers_android",
+ "//common/types:types_android",
+ "//common/values:values_android",
+ "@maven//:com_google_errorprone_error_prone_annotations",
+ ],
+)
+
cel_android_library(
name = "values_android",
srcs = CEL_VALUES_SOURCES,
diff --git a/common/src/main/java/dev/cel/common/values/MutableMapValue.java b/common/src/main/java/dev/cel/common/values/MutableMapValue.java
new file mode 100644
index 000000000..706436b2e
--- /dev/null
+++ b/common/src/main/java/dev/cel/common/values/MutableMapValue.java
@@ -0,0 +1,146 @@
+// Copyright 2026 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dev.cel.common.values;
+
+import com.google.errorprone.annotations.Immutable;
+import dev.cel.common.annotations.Internal;
+import dev.cel.common.exceptions.CelAttributeNotFoundException;
+import dev.cel.common.types.CelType;
+import dev.cel.common.types.MapType;
+import dev.cel.common.types.SimpleType;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A custom CelValue implementation that allows O(1) insertions for maps during comprehension.
+ *
+ *
CEL Library Internals. Do Not Use.
+ */
+@Internal
+@Immutable
+@SuppressWarnings("Immutable") // Intentionally mutable for performance reasons
+public final class MutableMapValue extends CelValue
+ implements SelectableValue, Map {
+ private final Map internalMap;
+ private final CelType celType;
+
+ public static MutableMapValue create(Map, ?> map) {
+ return new MutableMapValue(map);
+ }
+
+ @Override
+ public int size() {
+ return internalMap.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return internalMap.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return internalMap.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return internalMap.containsValue(value);
+ }
+
+ @Override
+ public Object get(Object key) {
+ return internalMap.get(key);
+ }
+
+ @Override
+ public Object put(Object key, Object value) {
+ return internalMap.put(key, value);
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return internalMap.remove(key);
+ }
+
+ @Override
+ public void putAll(Map, ?> m) {
+ internalMap.putAll(m);
+ }
+
+ @Override
+ public void clear() {
+ internalMap.clear();
+ }
+
+ @Override
+ public Set keySet() {
+ return internalMap.keySet();
+ }
+
+ @Override
+ public Collection values() {
+ return internalMap.values();
+ }
+
+ @Override
+ public Set> entrySet() {
+ return internalMap.entrySet();
+ }
+
+ @Override
+ public Object select(Object field) {
+ Object val = internalMap.get(field);
+ if (val != null) {
+ return val;
+ }
+ if (!internalMap.containsKey(field)) {
+ throw CelAttributeNotFoundException.forMissingMapKey(field.toString());
+ }
+ throw CelAttributeNotFoundException.of(
+ String.format("Map value cannot be null for key: %s", field));
+ }
+
+ @Override
+ public Optional> find(Object field) {
+ if (internalMap.containsKey(field)) {
+ return Optional.ofNullable(internalMap.get(field));
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Object value() {
+ return this;
+ }
+
+ @Override
+ public boolean isZeroValue() {
+ return internalMap.isEmpty();
+ }
+
+ @Override
+ public CelType celType() {
+ return celType;
+ }
+
+ private MutableMapValue(Map, ?> map) {
+ this.internalMap = new LinkedHashMap<>(map);
+ this.celType = MapType.create(SimpleType.DYN, SimpleType.DYN);
+ }
+}
diff --git a/common/values/BUILD.bazel b/common/values/BUILD.bazel
index f1fa107b6..74bfa9e0f 100644
--- a/common/values/BUILD.bazel
+++ b/common/values/BUILD.bazel
@@ -47,6 +47,18 @@ cel_android_library(
exports = ["//common/src/main/java/dev/cel/common/values:values_android"],
)
+java_library(
+ name = "mutable_map_value",
+ visibility = ["//:internal"],
+ exports = ["//common/src/main/java/dev/cel/common/values:mutable_map_value"],
+)
+
+cel_android_library(
+ name = "mutable_map_value_android",
+ visibility = ["//:internal"],
+ exports = ["//common/src/main/java/dev/cel/common/values:mutable_map_value_android"],
+)
+
java_library(
name = "base_proto_cel_value_converter",
exports = ["//common/src/main/java/dev/cel/common/values:base_proto_cel_value_converter"],
diff --git a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel
index 77663f2fa..f8e4bfc8c 100644
--- a/extensions/src/main/java/dev/cel/extensions/BUILD.bazel
+++ b/extensions/src/main/java/dev/cel/extensions/BUILD.bazel
@@ -42,6 +42,7 @@ java_library(
":strings",
"//common:options",
"//extensions:extension_library",
+ "@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
],
)
@@ -121,7 +122,6 @@ java_library(
":extension_library",
"//checker:checker_builder",
"//common:compiler_common",
- "//common:options",
"//common/ast",
"//common/exceptions:numeric_overflow",
"//common/internal:comparison_functions",
@@ -307,6 +307,7 @@ java_library(
"//common:options",
"//common/ast",
"//common/types",
+ "//common/values:mutable_map_value",
"//compiler:compiler_builder",
"//extensions:extension_library",
"//parser:macro",
diff --git a/extensions/src/main/java/dev/cel/extensions/CelComprehensionsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelComprehensionsExtensions.java
index 7c298a773..3bf47c4a6 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelComprehensionsExtensions.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelComprehensionsExtensions.java
@@ -29,6 +29,7 @@
import dev.cel.common.ast.CelExpr;
import dev.cel.common.types.MapType;
import dev.cel.common.types.TypeParamType;
+import dev.cel.common.values.MutableMapValue;
import dev.cel.compiler.CelCompilerLibrary;
import dev.cel.parser.CelMacro;
import dev.cel.parser.CelMacroExprFactory;
@@ -171,38 +172,46 @@ public void setParserOptions(CelParserBuilder parserBuilder) {
parserBuilder.addMacros(macros());
}
- // TODO: Implement a more efficient map insertion based on mutability once mutable
- // maps are supported in Java stack.
- private static ImmutableMap mapInsertMap(
+ private static Map mapInsertMap(
Map, ?> targetMap, Map, ?> mapToMerge, RuntimeEquality equality) {
- ImmutableMap.Builder resultBuilder =
- ImmutableMap.builderWithExpectedSize(targetMap.size() + mapToMerge.size());
-
- for (Map.Entry, ?> entry : mapToMerge.entrySet()) {
- if (equality.findInMap(targetMap, entry.getKey()).isPresent()) {
+ for (Object key : mapToMerge.keySet()) {
+ if (equality.findInMap(targetMap, key).isPresent()) {
throw new IllegalArgumentException(
- String.format("insert failed: key '%s' already exists", entry.getKey()));
- } else {
- resultBuilder.put(entry.getKey(), entry.getValue());
+ String.format("insert failed: key '%s' already exists", key));
}
}
- return resultBuilder.putAll(targetMap).buildOrThrow();
+
+ if (targetMap instanceof MutableMapValue) {
+ MutableMapValue wrapper = (MutableMapValue) targetMap;
+ wrapper.putAll(mapToMerge);
+ return wrapper;
+ }
+
+ return ImmutableMap.builderWithExpectedSize(targetMap.size() + mapToMerge.size())
+ .putAll(targetMap)
+ .putAll(mapToMerge)
+ .buildOrThrow();
}
- private static ImmutableMap mapInsertKeyValue(
- Object[] args, RuntimeEquality equality) {
- Map, ?> map = (Map, ?>) args[0];
+ private static Map mapInsertKeyValue(Object[] args, RuntimeEquality equality) {
+ Map, ?> mapArg = (Map, ?>) args[0];
Object key = args[1];
Object value = args[2];
- if (equality.findInMap(map, key).isPresent()) {
+ if (equality.findInMap(mapArg, key).isPresent()) {
throw new IllegalArgumentException(
String.format("insert failed: key '%s' already exists", key));
}
+ if (mapArg instanceof MutableMapValue) {
+ MutableMapValue mutableMap = (MutableMapValue) mapArg;
+ mutableMap.put(key, value);
+ return mutableMap;
+ }
+
ImmutableMap.Builder builder =
- ImmutableMap.builderWithExpectedSize(map.size() + 1);
- return builder.put(key, value).putAll(map).buildOrThrow();
+ ImmutableMap.builderWithExpectedSize(mapArg.size() + 1);
+ return builder.put(key, value).putAll(mapArg).buildOrThrow();
}
private static Optional expandAllMacro(
diff --git a/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java
index a98f9db41..498b8555e 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelEncoderExtensions.java
@@ -135,9 +135,13 @@ public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) {
functions.forEach(
function -> {
if (celOptions.evaluateCanonicalTypesToNativeValues()) {
- runtimeBuilder.addFunctionBindings(function.nativeBytesFunctionBinding);
+ runtimeBuilder.addFunctionBindings(
+ CelFunctionBinding.fromOverloads(
+ function.getFunction(), function.nativeBytesFunctionBinding));
} else {
- runtimeBuilder.addFunctionBindings(function.protoBytesFunctionBinding);
+ runtimeBuilder.addFunctionBindings(
+ CelFunctionBinding.fromOverloads(
+ function.getFunction(), function.protoBytesFunctionBinding));
}
});
}
diff --git a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java
index 2d14ed118..bc4455d7a 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelExtensions.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelExtensions.java
@@ -19,7 +19,9 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
+import com.google.errorprone.annotations.InlineMe;
import dev.cel.common.CelOptions;
+import dev.cel.extensions.CelMathExtensions.Function;
import java.util.Set;
/**
@@ -121,12 +123,9 @@ public static CelProtoExtensions protos() {
* This will include all functions denoted in {@link CelMathExtensions.Function}, including any
* future additions. To expose only a subset of these, use {@link #math(CelOptions,
* CelMathExtensions.Function...)} or {@link #math(CelOptions,int)} instead.
- *
- * @param celOptions CelOptions to configure CelMathExtension with. This should be the same
- * options object used to configure the compilation/runtime environments.
*/
- public static CelMathExtensions math(CelOptions celOptions) {
- return CelMathExtensions.library(celOptions).latest();
+ public static CelMathExtensions math() {
+ return CelMathExtensions.library().latest();
}
/**
@@ -134,8 +133,8 @@ public static CelMathExtensions math(CelOptions celOptions) {
*
*
Refer to README.md for functions available in each version.
*/
- public static CelMathExtensions math(CelOptions celOptions, int version) {
- return CelMathExtensions.library(celOptions).version(version);
+ public static CelMathExtensions math(int version) {
+ return CelMathExtensions.library().version(version);
}
/**
@@ -150,13 +149,9 @@ public static CelMathExtensions math(CelOptions celOptions, int version) {
* collision.
*
*
This will include only the specific functions denoted by {@link CelMathExtensions.Function}.
- *
- * @param celOptions CelOptions to configure CelMathExtension with. This should be the same
- * options object used to configure the compilation/runtime environments.
*/
- public static CelMathExtensions math(
- CelOptions celOptions, CelMathExtensions.Function... functions) {
- return math(celOptions, ImmutableSet.copyOf(functions));
+ public static CelMathExtensions math(CelMathExtensions.Function... functions) {
+ return math(ImmutableSet.copyOf(functions));
}
/**
@@ -171,13 +166,47 @@ public static CelMathExtensions math(
* collision.
*
*
This will include only the specific functions denoted by {@link CelMathExtensions.Function}.
- *
- * @param celOptions CelOptions to configure CelMathExtension with. This should be the same
- * options object used to configure the compilation/runtime environments.
*/
+ public static CelMathExtensions math(Set functions) {
+ return new CelMathExtensions(functions);
+ }
+
+ /**
+ * @deprecated Use {@link #math()} instead.
+ */
+ @Deprecated
+ @InlineMe(replacement = "CelExtensions.math()", imports = "dev.cel.extensions.CelExtensions")
+ public static CelMathExtensions math(CelOptions unused) {
+ return math();
+ }
+
+ /**
+ * @deprecated Use {@link #math(int)} instead.
+ */
+ @Deprecated
+ @InlineMe(
+ replacement = "CelExtensions.math(version)",
+ imports = "dev.cel.extensions.CelExtensions")
+ public static CelMathExtensions math(CelOptions unused, int version) {
+ return math(version);
+ }
+
+ /**
+ * @deprecated Use {@link #math(Function...)} instead.
+ */
+ @Deprecated
+ public static CelMathExtensions math(CelOptions unused, CelMathExtensions.Function... functions) {
+ return math(ImmutableSet.copyOf(functions));
+ }
+
+ /**
+ * @deprecated Use {@link #math(Set)} instead.
+ */
+ @Deprecated
+ @InlineMe(replacement = "CelExtensions.math(functions)", imports = "dev.cel.extensions.CelExtensions")
public static CelMathExtensions math(
- CelOptions celOptions, Set functions) {
- return new CelMathExtensions(celOptions, functions);
+ CelOptions unused, Set functions) {
+ return math(functions);
}
/**
@@ -354,7 +383,7 @@ public static CelExtensionLibrary extends CelExtensionLibrary.FeatureSet> getE
case "lists":
return CelListsExtensions.library();
case "math":
- return CelMathExtensions.library(options);
+ return CelMathExtensions.library();
case "optional":
return CelOptionalLibrary.library();
case "protos":
diff --git a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java
index 22336eb22..16a1b282a 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelMathExtensions.java
@@ -27,7 +27,6 @@
import dev.cel.checker.CelCheckerBuilder;
import dev.cel.common.CelFunctionDecl;
import dev.cel.common.CelIssue;
-import dev.cel.common.CelOptions;
import dev.cel.common.CelOverloadDecl;
import dev.cel.common.ast.CelConstant;
import dev.cel.common.ast.CelExpr;
@@ -136,7 +135,8 @@ public final class CelMathExtensions
return builder.buildOrThrow();
}
- enum Function {
+ /** Enumeration of functions for Math extension. */
+ public enum Function {
MAX(
CelFunctionDecl.newFunctionDeclaration(
MATH_MAX_FUNCTION,
@@ -206,51 +206,21 @@ enum Function {
MATH_MAX_OVERLOAD_DOC,
SimpleType.DYN,
ListType.create(SimpleType.DYN))),
- ImmutableSet.of(
- CelFunctionBinding.from("math_@max_double", Double.class, x -> x),
- CelFunctionBinding.from("math_@max_int", Long.class, x -> x),
- CelFunctionBinding.from(
- "math_@max_double_double", Double.class, Double.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_int_int", Long.class, Long.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_int_double", Long.class, Double.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_double_int", Double.class, Long.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from("math_@max_list_dyn", List.class, CelMathExtensions::maxList)),
- ImmutableSet.of(
- CelFunctionBinding.from("math_@max_uint", Long.class, x -> x),
- CelFunctionBinding.from(
- "math_@max_uint_uint", Long.class, Long.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_double_uint", Double.class, Long.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_uint_int", Long.class, Long.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_uint_double", Long.class, Double.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_int_uint", Long.class, Long.class, CelMathExtensions::maxPair)),
- ImmutableSet.of(
- CelFunctionBinding.from("math_@max_uint", UnsignedLong.class, x -> x),
- CelFunctionBinding.from(
- "math_@max_uint_uint",
- UnsignedLong.class,
- UnsignedLong.class,
- CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_double_uint",
- Double.class,
- UnsignedLong.class,
- CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_uint_int", UnsignedLong.class, Long.class, CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_uint_double",
- UnsignedLong.class,
- Double.class,
- CelMathExtensions::maxPair),
- CelFunctionBinding.from(
- "math_@max_int_uint", Long.class, UnsignedLong.class, CelMathExtensions::maxPair))),
+ ImmutableSet.builder()
+ .add(CelFunctionBinding.from("math_@max_double", Double.class, x -> x))
+ .add(CelFunctionBinding.from("math_@max_int", Long.class, x -> x))
+ .add(CelFunctionBinding.from("math_@max_double_double", Double.class, Double.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_int_int", Long.class, Long.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_int_double", Long.class, Double.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_double_int", Double.class, Long.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_list_dyn", List.class, CelMathExtensions::maxList))
+ .add(CelFunctionBinding.from("math_@max_uint", UnsignedLong.class, x -> x))
+ .add(CelFunctionBinding.from("math_@max_uint_uint", UnsignedLong.class, UnsignedLong.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_double_uint", Double.class, UnsignedLong.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_uint_int", UnsignedLong.class, Long.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_uint_double", UnsignedLong.class, Double.class, CelMathExtensions::maxPair))
+ .add(CelFunctionBinding.from("math_@max_int_uint", Long.class, UnsignedLong.class, CelMathExtensions::maxPair))
+ .build()),
MIN(
CelFunctionDecl.newFunctionDeclaration(
MATH_MIN_FUNCTION,
@@ -320,51 +290,21 @@ enum Function {
MATH_MIN_OVERLOAD_DOC,
SimpleType.DYN,
ListType.create(SimpleType.DYN))),
- ImmutableSet.of(
- CelFunctionBinding.from("math_@min_double", Double.class, x -> x),
- CelFunctionBinding.from("math_@min_int", Long.class, x -> x),
- CelFunctionBinding.from(
- "math_@min_double_double", Double.class, Double.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_int_int", Long.class, Long.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_int_double", Long.class, Double.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_double_int", Double.class, Long.class, CelMathExtensions::minPair),
- CelFunctionBinding.from("math_@min_list_dyn", List.class, CelMathExtensions::minList)),
- ImmutableSet.of(
- CelFunctionBinding.from("math_@min_uint", Long.class, x -> x),
- CelFunctionBinding.from(
- "math_@min_uint_uint", Long.class, Long.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_double_uint", Double.class, Long.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_uint_int", Long.class, Long.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_uint_double", Long.class, Double.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_int_uint", Long.class, Long.class, CelMathExtensions::minPair)),
- ImmutableSet.of(
- CelFunctionBinding.from("math_@min_uint", UnsignedLong.class, x -> x),
- CelFunctionBinding.from(
- "math_@min_uint_uint",
- UnsignedLong.class,
- UnsignedLong.class,
- CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_double_uint",
- Double.class,
- UnsignedLong.class,
- CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_uint_int", UnsignedLong.class, Long.class, CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_uint_double",
- UnsignedLong.class,
- Double.class,
- CelMathExtensions::minPair),
- CelFunctionBinding.from(
- "math_@min_int_uint", Long.class, UnsignedLong.class, CelMathExtensions::minPair))),
+ ImmutableSet.builder()
+ .add(CelFunctionBinding.from("math_@min_double", Double.class, x -> x))
+ .add(CelFunctionBinding.from("math_@min_int", Long.class, x -> x))
+ .add(CelFunctionBinding.from("math_@min_double_double", Double.class, Double.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_int_int", Long.class, Long.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_int_double", Long.class, Double.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_double_int", Double.class, Long.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_list_dyn", List.class, CelMathExtensions::minList))
+ .add(CelFunctionBinding.from("math_@min_uint", UnsignedLong.class, x -> x))
+ .add(CelFunctionBinding.from("math_@min_uint_uint", UnsignedLong.class, UnsignedLong.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_double_uint", Double.class, UnsignedLong.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_uint_int", UnsignedLong.class, Long.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_uint_double", UnsignedLong.class, Double.class, CelMathExtensions::minPair))
+ .add(CelFunctionBinding.from("math_@min_int_uint", Long.class, UnsignedLong.class, CelMathExtensions::minPair))
+ .build()),
CEIL(
CelFunctionDecl.newFunctionDeclaration(
MATH_CEIL_FUNCTION,
@@ -646,36 +586,14 @@ enum Function {
private final CelFunctionDecl functionDecl;
private final ImmutableSet functionBindings;
- private final ImmutableSet functionBindingsULongSigned;
- private final ImmutableSet functionBindingsULongUnsigned;
String getFunction() {
return functionDecl.name();
}
Function(CelFunctionDecl functionDecl, ImmutableSet bindings) {
- this(functionDecl, bindings, ImmutableSet.of(), ImmutableSet.of());
- }
-
- Function(
- CelFunctionDecl functionDecl,
- ImmutableSet functionBindings,
- ImmutableSet functionBindingsULongSigned,
- ImmutableSet functionBindingsULongUnsigned) {
this.functionDecl = functionDecl;
- this.functionBindings =
- functionBindings.isEmpty()
- ? ImmutableSet.of()
- : CelFunctionBinding.fromOverloads(functionDecl.name(), functionBindings);
- this.functionBindingsULongSigned =
- functionBindingsULongSigned.isEmpty()
- ? ImmutableSet.of()
- : CelFunctionBinding.fromOverloads(functionDecl.name(), functionBindingsULongSigned);
- this.functionBindingsULongUnsigned =
- functionBindingsULongUnsigned.isEmpty()
- ? ImmutableSet.of()
- : CelFunctionBinding.fromOverloads(
- functionDecl.name(), functionBindingsULongUnsigned);
+ this.functionBindings = bindings;
}
}
@@ -684,10 +602,8 @@ private static final class Library implements CelExtensionLibrarybuilder()
.addAll(version1.functions)
.add(Function.SQRT)
- .build(),
- enableUnsignedLongs);
+ .build());
}
@Override
@@ -734,25 +648,20 @@ public ImmutableSet versions() {
}
}
- private static final Library LIBRARY_UNSIGNED_LONGS_ENABLED = new Library(true);
- private static final Library LIBRARY_UNSIGNED_LONGS_DISABLED = new Library(false);
+ private static final Library LIBRARY = new Library();
- static CelExtensionLibrary library(CelOptions celOptions) {
- return celOptions.enableUnsignedLongs()
- ? LIBRARY_UNSIGNED_LONGS_ENABLED
- : LIBRARY_UNSIGNED_LONGS_DISABLED;
+ static CelExtensionLibrary library() {
+ return LIBRARY;
}
- private final boolean enableUnsignedLongs;
private final ImmutableSet functions;
private final int version;
- CelMathExtensions(CelOptions celOptions, Set functions) {
- this(-1, functions, celOptions.enableUnsignedLongs());
+ CelMathExtensions(Set functions) {
+ this(-1, functions);
}
- private CelMathExtensions(int version, Set functions, boolean enableUnsignedLongs) {
- this.enableUnsignedLongs = enableUnsignedLongs;
+ private CelMathExtensions(int version, Set functions) {
this.version = version;
this.functions = ImmutableSet.copyOf(functions);
}
@@ -788,11 +697,11 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) {
public void setRuntimeOptions(CelRuntimeBuilder runtimeBuilder) {
functions.forEach(
function -> {
- runtimeBuilder.addFunctionBindings(function.functionBindings);
- runtimeBuilder.addFunctionBindings(
- enableUnsignedLongs
- ? function.functionBindingsULongUnsigned
- : function.functionBindingsULongSigned);
+ ImmutableSet combined = function.functionBindings;
+ if (!combined.isEmpty()) {
+ runtimeBuilder.addFunctionBindings(
+ CelFunctionBinding.fromOverloads(function.functionDecl.name(), combined));
+ }
});
}
diff --git a/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java
index 37c8270cc..2bb477b82 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelStringExtensions.java
@@ -23,7 +23,6 @@
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
import com.google.errorprone.annotations.Immutable;
import dev.cel.checker.CelCheckerBuilder;
import dev.cel.common.CelFunctionDecl;
@@ -37,7 +36,6 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntimeBuilder;
import dev.cel.runtime.CelRuntimeLibrary;
-import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -475,7 +473,7 @@ private static String quote(String s) {
sb.append('"');
for (int i = 0; i < s.length(); ) {
int codePoint = s.codePointAt(i);
- if (isMalformedUtf16(s, i, codePoint)) {
+ if (isMalformedUtf16(s, i)) {
sb.append('\uFFFD');
i++;
continue;
@@ -518,7 +516,7 @@ private static String quote(String s) {
return sb.toString();
}
- private static boolean isMalformedUtf16(String s, int index, int codePoint) {
+ private static boolean isMalformedUtf16(String s, int index) {
char currentChar = s.charAt(index);
if (Character.isLowSurrogate(currentChar)) {
return true;
@@ -587,14 +585,14 @@ private static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}
- private static List split(String str, String separator) {
+ private static ImmutableList split(String str, String separator) {
return split(str, separator, Integer.MAX_VALUE);
}
/**
* @param args Object array with indices of: [0: string], [1: separator], [2: limit]
*/
- private static List split(Object[] args) throws CelEvaluationException {
+ private static ImmutableList split(Object[] args) throws CelEvaluationException {
long limitInLong = (Long) args[2];
int limit;
try {
@@ -609,16 +607,14 @@ private static List split(Object[] args) throws CelEvaluationException {
return split((String) args[0], (String) args[1], limit);
}
- /** Returns a **mutable** list of strings split on the separator */
- private static List split(String str, String separator, int limit) {
+ /** Returns an immutable list of strings split on the separator */
+ private static ImmutableList split(String str, String separator, int limit) {
if (limit == 0) {
- return new ArrayList<>();
+ return ImmutableList.of();
}
if (limit == 1) {
- List singleElementList = new ArrayList<>();
- singleElementList.add(str);
- return singleElementList;
+ return ImmutableList.of(str);
}
if (limit < 0) {
@@ -630,7 +626,7 @@ private static List split(String str, String separator, int limit) {
}
Iterable splitString = Splitter.on(separator).limit(limit).split(str);
- return Lists.newArrayList(splitString);
+ return ImmutableList.copyOf(splitString);
}
/**
@@ -643,8 +639,8 @@ private static List split(String str, String separator, int limit) {
* This exists because neither the built-in String.split nor Guava's splitter is able to deal
* with separating single printable characters.
*/
- private static List explode(String str, int limit) {
- List exploded = new ArrayList<>();
+ private static ImmutableList explode(String str, int limit) {
+ ImmutableList.Builder exploded = ImmutableList.builder();
CelCodePointArray codePointArray = CelCodePointArray.fromString(str);
if (limit > 0) {
limit -= 1;
@@ -656,7 +652,7 @@ private static List explode(String str, int limit) {
if (codePointArray.length() > limit) {
exploded.add(codePointArray.slice(limit, codePointArray.length()).toString());
}
- return exploded;
+ return exploded.build();
}
private static Object substring(String s, long i) throws CelEvaluationException {
diff --git a/extensions/src/main/java/dev/cel/extensions/README.md b/extensions/src/main/java/dev/cel/extensions/README.md
index c3fbf8c54..b1d3611b4 100644
--- a/extensions/src/main/java/dev/cel/extensions/README.md
+++ b/extensions/src/main/java/dev/cel/extensions/README.md
@@ -522,7 +522,7 @@ Examples:
### Split
-Returns a mutable list of strings split from the input by the given separator. The
+Returns a list of strings split from the input by the given separator. The
function accepts an optional argument specifying a limit on the number of
substrings produced by the split.
@@ -1069,4 +1069,4 @@ Examples:
{valueVar: indexVar}) // returns {1:0, 2:1, 3:2}
{'greeting': 'aloha', 'farewell': 'aloha'}
- .transformMapEntry(k, v, {v: k}) // error, duplicate key
\ No newline at end of file
+ .transformMapEntry(k, v, {v: k}) // error, duplicate key
diff --git a/extensions/src/main/java/dev/cel/extensions/SetsExtensionsRuntimeImpl.java b/extensions/src/main/java/dev/cel/extensions/SetsExtensionsRuntimeImpl.java
index a42fba189..a02fdba8a 100644
--- a/extensions/src/main/java/dev/cel/extensions/SetsExtensionsRuntimeImpl.java
+++ b/extensions/src/main/java/dev/cel/extensions/SetsExtensionsRuntimeImpl.java
@@ -45,28 +45,34 @@ ImmutableSet newFunctionBindings() {
for (SetsFunction function : functions) {
switch (function) {
case CONTAINS:
- bindingBuilder.add(
- CelFunctionBinding.from(
- "list_sets_contains_list",
- Collection.class,
- Collection.class,
- this::containsAll));
+ bindingBuilder.addAll(
+ CelFunctionBinding.fromOverloads(
+ function.getFunction(),
+ CelFunctionBinding.from(
+ "list_sets_contains_list",
+ Collection.class,
+ Collection.class,
+ this::containsAll)));
break;
case EQUIVALENT:
- bindingBuilder.add(
- CelFunctionBinding.from(
- "list_sets_equivalent_list",
- Collection.class,
- Collection.class,
- (listA, listB) -> containsAll(listA, listB) && containsAll(listB, listA)));
+ bindingBuilder.addAll(
+ CelFunctionBinding.fromOverloads(
+ function.getFunction(),
+ CelFunctionBinding.from(
+ "list_sets_equivalent_list",
+ Collection.class,
+ Collection.class,
+ (listA, listB) -> containsAll(listA, listB) && containsAll(listB, listA))));
break;
case INTERSECTS:
- bindingBuilder.add(
- CelFunctionBinding.from(
- "list_sets_intersects_list",
- Collection.class,
- Collection.class,
- this::setIntersects));
+ bindingBuilder.addAll(
+ CelFunctionBinding.fromOverloads(
+ function.getFunction(),
+ CelFunctionBinding.from(
+ "list_sets_intersects_list",
+ Collection.class,
+ Collection.class,
+ this::setIntersects)));
break;
}
}
diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel
index 0b6502410..19fd3657e 100644
--- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel
+++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel
@@ -15,6 +15,7 @@ java_library(
"//common:compiler_common",
"//common:container",
"//common:options",
+ "//common/exceptions:attribute_not_found",
"//common/exceptions:divide_by_zero",
"//common/exceptions:index_out_of_bounds",
"//common/types",
diff --git a/extensions/src/test/java/dev/cel/extensions/CelComprehensionsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelComprehensionsExtensionsTest.java
index fbe160cd3..6927841e5 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelComprehensionsExtensionsTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelComprehensionsExtensionsTest.java
@@ -28,6 +28,8 @@
import dev.cel.common.CelFunctionDecl;
import dev.cel.common.CelOptions;
import dev.cel.common.CelValidationException;
+import dev.cel.common.CelValidationResult;
+import dev.cel.common.exceptions.CelAttributeNotFoundException;
import dev.cel.common.exceptions.CelDivideByZeroException;
import dev.cel.common.exceptions.CelIndexOutOfBoundsException;
import dev.cel.common.types.SimpleType;
@@ -222,6 +224,7 @@ public void transformMapEntryMacro_twoVarComprehension_success(
+ " 'key2': 'value2'}",
// map.transformMapEntry()
"{'hello': 'world', 'greetings': 'tacocat'}.transformMapEntry(k, v, {}) == {}",
+ "{'a': 1, 'b': 2}.transformMapEntry(k, v, {k: v}) == {'a': 1, 'b': 2}",
"{'a': 1, 'b': 2}.transformMapEntry(k, v, {k + '_new': v * 2}) == {'a_new': 2,"
+ " 'b_new': 4}",
"{'a': 1, 'b': 2, 'c': 3}.transformMapEntry(k, v, v % 2 == 1, {k: v * 10}) == {'a': 10,"
@@ -310,8 +313,9 @@ public void unparseAST_twoVarComprehension(
+ " err: 'no matching overload'}")
public void twoVarComprehension_compilerErrors(String expr, String err) throws Exception {
Assume.assumeFalse(isParseOnly);
+ CelValidationResult result = cel.compile(expr);
CelValidationException e =
- assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> result.getAst());
assertThat(e).hasMessageThat().contains(err);
}
@@ -364,6 +368,15 @@ public void twoVarComprehension_outOfBounds_runtimeError() throws Exception {
assertThat(e).hasCauseThat().hasMessageThat().contains("Index out of bounds: 1");
}
+ @Test
+ public void mutableMapValue_select_missingKeyException() throws Exception {
+ CelEvaluationException e =
+ assertThrows(
+ CelEvaluationException.class, () -> eval("cel.bind(my_map, {'a': 1}, my_map.b)"));
+ assertThat(e).hasCauseThat().isInstanceOf(CelAttributeNotFoundException.class);
+ assertThat(e).hasCauseThat().hasMessageThat().contains("key 'b' is not present in map.");
+ }
+
private Object eval(String expression) throws Exception {
return eval(this.cel, expression, ImmutableMap.of());
}
diff --git a/extensions/src/test/java/dev/cel/extensions/CelEncoderExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelEncoderExtensionsTest.java
index 7eed3dd5a..b0a501ddb 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelEncoderExtensionsTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelEncoderExtensionsTest.java
@@ -19,36 +19,45 @@
import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableMap;
+import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+import dev.cel.bundle.Cel;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelFunctionDecl;
import dev.cel.common.CelOptions;
import dev.cel.common.CelValidationException;
import dev.cel.common.types.SimpleType;
import dev.cel.common.values.CelByteString;
-import dev.cel.compiler.CelCompiler;
-import dev.cel.compiler.CelCompilerFactory;
import dev.cel.runtime.CelEvaluationException;
-import dev.cel.runtime.CelRuntime;
-import dev.cel.runtime.CelRuntimeFactory;
+import dev.cel.testing.CelRuntimeFlavor;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TestParameterInjector.class)
public class CelEncoderExtensionsTest {
private static final CelOptions CEL_OPTIONS =
- CelOptions.current().build();
-
- private static final CelCompiler CEL_COMPILER =
- CelCompilerFactory.standardCelCompilerBuilder()
- .addVar("stringVar", SimpleType.STRING)
- .addLibraries(CelExtensions.encoders(CEL_OPTIONS))
- .build();
- private static final CelRuntime CEL_RUNTIME =
- CelRuntimeFactory.standardCelRuntimeBuilder()
- .setOptions(CEL_OPTIONS)
- .addLibraries(CelExtensions.encoders(CEL_OPTIONS))
- .build();
+ CelOptions.current().enableHeterogeneousNumericComparisons(true).build();
+
+ @TestParameter public CelRuntimeFlavor runtimeFlavor;
+ @TestParameter public boolean isParseOnly;
+
+ private Cel cel;
+
+ @Before
+ public void setUp() {
+ // Legacy runtime does not support parsed-only evaluation mode.
+ Assume.assumeFalse(runtimeFlavor.equals(CelRuntimeFlavor.LEGACY) && isParseOnly);
+ this.cel =
+ runtimeFlavor
+ .builder()
+ .setOptions(CEL_OPTIONS)
+ .addCompilerLibraries(CelExtensions.encoders(CEL_OPTIONS))
+ .addRuntimeLibraries(CelExtensions.encoders(CEL_OPTIONS))
+ .addVar("stringVar", SimpleType.STRING)
+ .build();
+ }
@Test
public void library() {
@@ -63,22 +72,14 @@ public void library() {
@Test
public void encode_success() throws Exception {
- String encodedBytes =
- (String)
- CEL_RUNTIME
- .createProgram(CEL_COMPILER.compile("base64.encode(b'hello')").getAst())
- .eval();
+ String encodedBytes = (String) eval("base64.encode(b'hello')");
assertThat(encodedBytes).isEqualTo("aGVsbG8=");
}
@Test
public void decode_success() throws Exception {
- CelByteString decodedBytes =
- (CelByteString)
- CEL_RUNTIME
- .createProgram(CEL_COMPILER.compile("base64.decode('aGVsbG8=')").getAst())
- .eval();
+ CelByteString decodedBytes = (CelByteString) eval("base64.decode('aGVsbG8=')");
assertThat(decodedBytes.size()).isEqualTo(5);
assertThat(new String(decodedBytes.toByteArray(), ISO_8859_1)).isEqualTo("hello");
@@ -86,12 +87,7 @@ public void decode_success() throws Exception {
@Test
public void decode_withoutPadding_success() throws Exception {
- CelByteString decodedBytes =
- (CelByteString)
- CEL_RUNTIME
- // RFC2045 6.8, padding can be ignored.
- .createProgram(CEL_COMPILER.compile("base64.decode('aGVsbG8')").getAst())
- .eval();
+ CelByteString decodedBytes = (CelByteString) eval("base64.decode('aGVsbG8')");
assertThat(decodedBytes.size()).isEqualTo(5);
assertThat(new String(decodedBytes.toByteArray(), ISO_8859_1)).isEqualTo("hello");
@@ -99,50 +95,49 @@ public void decode_withoutPadding_success() throws Exception {
@Test
public void roundTrip_success() throws Exception {
- String encodedString =
- (String)
- CEL_RUNTIME
- .createProgram(CEL_COMPILER.compile("base64.encode(b'Hello World!')").getAst())
- .eval();
+ String encodedString = (String) eval("base64.encode(b'Hello World!')");
CelByteString decodedBytes =
(CelByteString)
- CEL_RUNTIME
- .createProgram(CEL_COMPILER.compile("base64.decode(stringVar)").getAst())
- .eval(ImmutableMap.of("stringVar", encodedString));
+ eval("base64.decode(stringVar)", ImmutableMap.of("stringVar", encodedString));
assertThat(new String(decodedBytes.toByteArray(), ISO_8859_1)).isEqualTo("Hello World!");
}
@Test
public void encode_invalidParam_throwsCompilationException() {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
assertThrows(
- CelValidationException.class,
- () -> CEL_COMPILER.compile("base64.encode('hello')").getAst());
+ CelValidationException.class, () -> cel.compile("base64.encode('hello')").getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'base64.encode'");
}
@Test
public void decode_invalidParam_throwsCompilationException() {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
assertThrows(
- CelValidationException.class,
- () -> CEL_COMPILER.compile("base64.decode(b'aGVsbG8=')").getAst());
+ CelValidationException.class, () -> cel.compile("base64.decode(b'aGVsbG8=')").getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'base64.decode'");
}
@Test
public void decode_malformedBase64Char_throwsEvaluationException() throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile("base64.decode('z!')").getAst();
-
CelEvaluationException e =
- assertThrows(CelEvaluationException.class, () -> CEL_RUNTIME.createProgram(ast).eval());
+ assertThrows(CelEvaluationException.class, () -> eval("base64.decode('z!')"));
- assertThat(e)
- .hasMessageThat()
- .contains("Function 'base64_decode_string' failed with arg(s) 'z!'");
+ assertThat(e).hasMessageThat().contains("failed with arg(s) 'z!'");
assertThat(e).hasCauseThat().hasMessageThat().contains("Illegal base64 character");
}
+
+ private Object eval(String expr) throws Exception {
+ return eval(expr, ImmutableMap.of());
+ }
+
+ private Object eval(String expr, ImmutableMap vars) throws Exception {
+ CelAbstractSyntaxTree ast = isParseOnly ? cel.parse(expr).getAst() : cel.compile(expr).getAst();
+ return cel.createProgram(ast).eval(vars);
+ }
}
diff --git a/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java
index b36e0e92e..7a5e7598e 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelListsExtensionsTest.java
@@ -27,6 +27,7 @@
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelContainer;
import dev.cel.common.CelValidationException;
+import dev.cel.common.CelValidationResult;
import dev.cel.common.types.SimpleType;
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
@@ -300,10 +301,11 @@ public void sortBy_success(String expression, String expected) throws Exception
+ "expectedError: 'variable name must be a simple identifier'}")
public void sortBy_throws_validationException(String expression, String expectedError)
throws Exception {
+ CelValidationResult result = cel.compile(expression);
assertThat(
assertThrows(
CelValidationException.class,
- () -> cel.createProgram(cel.compile(expression).getAst()).eval()))
+ () -> result.getAst()))
.hasMessageThat()
.contains(expectedError);
}
diff --git a/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java
index bcdfb0a21..383e50aa2 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java
@@ -20,8 +20,10 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.UnsignedLong;
+import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import com.google.testing.junit.testparameterinjector.TestParameters;
+import dev.cel.bundle.Cel;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelFunctionDecl;
import dev.cel.common.CelOptions;
@@ -35,34 +37,36 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.CelRuntimeFactory;
+import dev.cel.testing.CelRuntimeFlavor;
+import java.util.Map;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TestParameterInjector.class)
public class CelMathExtensionsTest {
- private static final CelOptions CEL_OPTIONS =
- CelOptions.current().enableUnsignedLongs(false).build();
- private static final CelCompiler CEL_COMPILER =
- CelCompilerFactory.standardCelCompilerBuilder()
- .setOptions(CEL_OPTIONS)
- .addLibraries(CelExtensions.math(CEL_OPTIONS))
- .build();
- private static final CelRuntime CEL_RUNTIME =
- CelRuntimeFactory.standardCelRuntimeBuilder()
- .setOptions(CEL_OPTIONS)
- .addLibraries(CelExtensions.math(CEL_OPTIONS))
- .build();
- private static final CelOptions CEL_UNSIGNED_OPTIONS = CelOptions.current().build();
- private static final CelCompiler CEL_UNSIGNED_COMPILER =
- CelCompilerFactory.standardCelCompilerBuilder()
- .setOptions(CEL_UNSIGNED_OPTIONS)
- .addLibraries(CelExtensions.math(CEL_UNSIGNED_OPTIONS))
- .build();
- private static final CelRuntime CEL_UNSIGNED_RUNTIME =
- CelRuntimeFactory.standardCelRuntimeBuilder()
- .setOptions(CEL_UNSIGNED_OPTIONS)
- .addLibraries(CelExtensions.math(CEL_UNSIGNED_OPTIONS))
- .build();
+ @TestParameter public CelRuntimeFlavor runtimeFlavor;
+ @TestParameter public boolean isParseOnly;
+
+ private Cel cel;
+
+ @Before
+ public void setUp() {
+ // Legacy runtime does not support parsed-only evaluation mode.
+ Assume.assumeFalse(runtimeFlavor.equals(CelRuntimeFlavor.LEGACY) && isParseOnly);
+ this.cel =
+ runtimeFlavor
+ .builder()
+ .setOptions(
+ CelOptions.current()
+ .enableHeterogeneousNumericComparisons(
+ runtimeFlavor.equals(CelRuntimeFlavor.PLANNER))
+ .build())
+ .addCompilerLibraries(CelExtensions.math())
+ .addRuntimeLibraries(CelExtensions.math())
+ .build();
+ }
@Test
@TestParameters("{expr: 'math.greatest(-5)', expectedResult: -5}")
@@ -97,9 +101,7 @@ public class CelMathExtensionsTest {
"{expr: 'math.greatest([dyn(5.4), dyn(10), dyn(3u), dyn(-5.0), dyn(3.5)])', expectedResult:"
+ " 10}")
public void greatest_intResult_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = eval(expr);
assertThat(result).isEqualTo(expectedResult);
}
@@ -136,9 +138,7 @@ public void greatest_intResult_success(String expr, long expectedResult) throws
"{expr: 'math.greatest([dyn(5.4), dyn(10.0), dyn(3u), dyn(-5.0), dyn(3.5)])', expectedResult:"
+ " 10.0}")
public void greatest_doubleResult_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = eval(expr);
assertThat(result).isEqualTo(expectedResult);
}
@@ -163,16 +163,16 @@ public void greatest_doubleResult_success(String expr, double expectedResult) th
+ " '10.0'}")
public void greatest_doubleResult_withUnsignedLongsEnabled_success(
String expr, double expectedResult) throws Exception {
- CelOptions celOptions = CelOptions.current().enableUnsignedLongs(true).build();
+ CelOptions celOptions = CelOptions.DEFAULT;
CelCompiler celCompiler =
CelCompilerFactory.standardCelCompilerBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelRuntime celRuntime =
CelRuntimeFactory.standardCelRuntimeBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
@@ -182,44 +182,7 @@ public void greatest_doubleResult_withUnsignedLongsEnabled_success(
}
@Test
- @TestParameters("{expr: 'math.greatest(5u)', expectedResult: 5}")
- @TestParameters("{expr: 'math.greatest(1u, 1.0)', expectedResult: 1}")
- @TestParameters("{expr: 'math.greatest(1u, 1)', expectedResult: 1}")
- @TestParameters("{expr: 'math.greatest(1u, 1u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.greatest(3u, 3.0)', expectedResult: 3}")
- @TestParameters("{expr: 'math.greatest(9u, 10u)', expectedResult: 10}")
- @TestParameters("{expr: 'math.greatest(15u, 14u)', expectedResult: 15}")
- @TestParameters(
- "{expr: 'math.greatest(1, 9223372036854775807u)', expectedResult: 9223372036854775807}")
- @TestParameters(
- "{expr: 'math.greatest(9223372036854775807u, 1)', expectedResult: 9223372036854775807}")
- @TestParameters("{expr: 'math.greatest(1u, 1, 1)', expectedResult: 1}")
- @TestParameters("{expr: 'math.greatest(3u, 1u, 10u)', expectedResult: 10}")
- @TestParameters("{expr: 'math.greatest(1u, 5u, 2u)', expectedResult: 5}")
- @TestParameters("{expr: 'math.greatest(-1, 1u, 0u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.greatest(dyn(1u), 1, 1.0)', expectedResult: 1}")
- @TestParameters("{expr: 'math.greatest(5u, 1.0, 3u)', expectedResult: 5}")
- @TestParameters("{expr: 'math.greatest(5.4, 10u, 3u, -5.0, 3.5)', expectedResult: 10}")
- @TestParameters(
- "{expr: 'math.greatest(5.4, 10, 3u, -5.0, 9223372036854775807)', expectedResult:"
- + " 9223372036854775807}")
- @TestParameters(
- "{expr: 'math.greatest(9223372036854775807, 10, 3u, -5.0, 0)', expectedResult:"
- + " 9223372036854775807}")
- @TestParameters("{expr: 'math.greatest([5.4, 10, 3u, -5.0, 3.5])', expectedResult: 10}")
- @TestParameters(
- "{expr: 'math.greatest([dyn(5.4), dyn(10), dyn(3u), dyn(-5.0), dyn(3.5)])', expectedResult:"
- + " 10}")
- public void greatest_unsignedLongResult_withSignedLongType_success(
- String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- Object result = CEL_RUNTIME.createProgram(ast).eval();
-
- assertThat(result).isEqualTo(expectedResult);
- }
-
- @Test
+ @TestParameters("{expr: 'math.greatest(5u)', expectedResult: '5'}")
@TestParameters(
"{expr: 'math.greatest(18446744073709551615u)', expectedResult: '18446744073709551615'}")
@TestParameters("{expr: 'math.greatest(1u, 1.0)', expectedResult: '1'}")
@@ -251,16 +214,16 @@ public void greatest_unsignedLongResult_withSignedLongType_success(
+ " '10'}")
public void greatest_unsignedLongResult_withUnsignedLongType_success(
String expr, String expectedResult) throws Exception {
- CelOptions celOptions = CelOptions.current().enableUnsignedLongs(true).build();
+ CelOptions celOptions = CelOptions.DEFAULT;
CelCompiler celCompiler =
CelCompilerFactory.standardCelCompilerBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelRuntime celRuntime =
CelRuntimeFactory.standardCelRuntimeBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
@@ -271,9 +234,9 @@ public void greatest_unsignedLongResult_withUnsignedLongType_success(
@Test
public void greatest_noArgs_throwsCompilationException() {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
- assertThrows(
- CelValidationException.class, () -> CEL_COMPILER.compile("math.greatest()").getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile("math.greatest()").getAst());
assertThat(e).hasMessageThat().contains("math.greatest() requires at least one argument");
}
@@ -283,8 +246,9 @@ public void greatest_noArgs_throwsCompilationException() {
@TestParameters("{expr: 'math.greatest({})'}")
@TestParameters("{expr: 'math.greatest([])'}")
public void greatest_invalidSingleArg_throwsCompilationException(String expr) {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("math.greatest() invalid single argument value");
}
@@ -297,8 +261,9 @@ public void greatest_invalidSingleArg_throwsCompilationException(String expr) {
@TestParameters("{expr: 'math.greatest([1, {}, 2])'}")
@TestParameters("{expr: 'math.greatest([1, [], 2])'}")
public void greatest_invalidArgs_throwsCompilationException(String expr) {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e)
.hasMessageThat()
@@ -312,19 +277,16 @@ public void greatest_invalidArgs_throwsCompilationException(String expr) {
@TestParameters("{expr: 'math.greatest([1, dyn({}), 2])'}")
@TestParameters("{expr: 'math.greatest([1, dyn([]), 2])'}")
public void greatest_invalidDynArgs_throwsRuntimeException(String expr) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- CelEvaluationException e =
- assertThrows(CelEvaluationException.class, () -> CEL_RUNTIME.createProgram(ast).eval());
+ CelEvaluationException e = assertThrows(CelEvaluationException.class, () -> eval(expr));
- assertThat(e).hasMessageThat().contains("Function 'math_@max_list_dyn' failed with arg(s)");
+ assertThat(e).hasMessageThat().contains("failed with arg(s)");
}
@Test
public void greatest_listVariableIsEmpty_throwsRuntimeException() throws Exception {
CelCompiler celCompiler =
CelCompilerFactory.standardCelCompilerBuilder()
- .addLibraries(CelExtensions.math(CEL_OPTIONS))
+ .addLibraries(CelExtensions.math())
.addVar("listVar", ListType.create(SimpleType.INT))
.build();
CelAbstractSyntaxTree ast = celCompiler.compile("math.greatest(listVar)").getAst();
@@ -332,12 +294,9 @@ public void greatest_listVariableIsEmpty_throwsRuntimeException() throws Excepti
CelEvaluationException e =
assertThrows(
CelEvaluationException.class,
- () ->
- CEL_RUNTIME
- .createProgram(ast)
- .eval(ImmutableMap.of("listVar", ImmutableList.of())));
+ () -> cel.createProgram(ast).eval(ImmutableMap.of("listVar", ImmutableList.of())));
- assertThat(e).hasMessageThat().contains("Function 'math_@max_list_dyn' failed with arg(s)");
+ assertThat(e).hasMessageThat().contains("failed with arg(s)");
assertThat(e)
.hasCauseThat()
.hasMessageThat()
@@ -347,25 +306,25 @@ public void greatest_listVariableIsEmpty_throwsRuntimeException() throws Excepti
@Test
@TestParameters("{expr: '100.greatest(1) == 1'}")
@TestParameters("{expr: 'dyn(100).greatest(1) == 1'}")
- public void greatest_nonProtoNamespace_success(String expr) throws Exception {
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder()
- .addLibraries(CelExtensions.math(CEL_OPTIONS))
+ public void greatest_nonMathNamespace_success(String expr) throws Exception {
+ Cel cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(CelExtensions.math())
+ .addRuntimeLibraries(CelExtensions.math())
.addFunctionDeclarations(
CelFunctionDecl.newFunctionDeclaration(
"greatest",
CelOverloadDecl.newMemberOverload(
"int_greatest_int", SimpleType.INT, SimpleType.INT, SimpleType.INT)))
- .build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder()
.addFunctionBindings(
- CelFunctionBinding.from(
- "int_greatest_int", Long.class, Long.class, (arg1, arg2) -> arg2))
+ CelFunctionBinding.fromOverloads(
+ "greatest",
+ CelFunctionBinding.from(
+ "int_greatest_int", Long.class, Long.class, (arg1, arg2) -> arg2)))
.build();
- CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
- boolean result = (boolean) celRuntime.createProgram(ast).eval();
+ boolean result = (boolean) eval(cel, expr);
assertThat(result).isTrue();
}
@@ -400,13 +359,14 @@ public void greatest_nonProtoNamespace_success(String expr) throws Exception {
"{expr: 'math.least(-9223372036854775808, 10, 3u, -5.0, 0)', expectedResult:"
+ " -9223372036854775808}")
@TestParameters("{expr: 'math.least([5.4, -10, 3u, -5.0, 3.5])', expectedResult: -10}")
+ @TestParameters("{expr: 'math.least(1, 9223372036854775807u)', expectedResult: 1}")
+ @TestParameters("{expr: 'math.least(9223372036854775807u, 1)', expectedResult: 1}")
+ @TestParameters("{expr: 'math.least(9223372036854775807, 10, 3u, 5.0, 0)', expectedResult: 0}")
@TestParameters(
"{expr: 'math.least([dyn(5.4), dyn(-10), dyn(3u), dyn(-5.0), dyn(3.5)])', expectedResult:"
+ " -10}")
public void least_intResult_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = eval(expr);
assertThat(result).isEqualTo(expectedResult);
}
@@ -443,9 +403,7 @@ public void least_intResult_success(String expr, long expectedResult) throws Exc
"{expr: 'math.least([dyn(5.4), dyn(10.0), dyn(3u), dyn(-5.0), dyn(3.5)])', expectedResult:"
+ " -5.0}")
public void least_doubleResult_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = eval(expr);
assertThat(result).isEqualTo(expectedResult);
}
@@ -474,12 +432,12 @@ public void least_doubleResult_withUnsignedLongsEnabled_success(
CelCompiler celCompiler =
CelCompilerFactory.standardCelCompilerBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelRuntime celRuntime =
CelRuntimeFactory.standardCelRuntimeBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
@@ -489,37 +447,15 @@ public void least_doubleResult_withUnsignedLongsEnabled_success(
}
@Test
- @TestParameters("{expr: 'math.least(5u)', expectedResult: 5}")
- @TestParameters("{expr: 'math.least(1u, 1.0)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(1u, 1)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(1u, 1u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(3u, 3.0)', expectedResult: 3}")
- @TestParameters("{expr: 'math.least(9u, 10u)', expectedResult: 9}")
- @TestParameters("{expr: 'math.least(15u, 14u)', expectedResult: 14}")
- @TestParameters("{expr: 'math.least(1, 9223372036854775807u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(9223372036854775807u, 1)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(1u, 1, 1)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(3u, 1u, 10u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(1u, 5u, 2u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(9, 1u, 0u)', expectedResult: 0}")
- @TestParameters("{expr: 'math.least(dyn(1u), 1, 1.0)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(5.0, 1u, 3u)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(5.4, 1u, 3u, 9, 3.5)', expectedResult: 1}")
- @TestParameters("{expr: 'math.least(5.4, 10, 3u, 5.0, 9223372036854775807)', expectedResult: 3}")
- @TestParameters("{expr: 'math.least(9223372036854775807, 10, 3u, 5.0, 0)', expectedResult: 0}")
- @TestParameters("{expr: 'math.least([5.4, 10, 3u, 5.0, 3.5])', expectedResult: 3}")
+ @TestParameters("{expr: 'math.least(9, 1u, 0u)', expectedResult: '0'}")
+ @TestParameters("{expr: 'math.least(dyn(1u), 1, 1.0)', expectedResult: '1'}")
+ @TestParameters("{expr: 'math.least(5.0, 1u, 3u)', expectedResult: '1'}")
+ @TestParameters("{expr: 'math.least(5.4, 1u, 3u, 9, 3.5)', expectedResult: '1'}")
@TestParameters(
- "{expr: 'math.least([dyn(5.4), dyn(10), dyn(3u), dyn(5.0), dyn(3.5)])', expectedResult: 3}")
- public void least_unsignedLongResult_withSignedLongType_success(String expr, long expectedResult)
- throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- Object result = CEL_RUNTIME.createProgram(ast).eval();
-
- assertThat(result).isEqualTo(expectedResult);
- }
-
- @Test
+ "{expr: 'math.least(5.4, 10, 3u, 5.0, 9223372036854775807)', expectedResult: '3'}")
+ @TestParameters("{expr: 'math.least([5.4, 10, 3u, 5.0, 3.5])', expectedResult: '3'}")
+ @TestParameters(
+ "{expr: 'math.least([dyn(5.4), dyn(10), dyn(3u), dyn(5.0), dyn(3.5)])', expectedResult: '3'}")
@TestParameters(
"{expr: 'math.least(18446744073709551615u)', expectedResult: '18446744073709551615'}")
@TestParameters("{expr: 'math.least(1u, 1.0)', expectedResult: '1'}")
@@ -553,12 +489,12 @@ public void least_unsignedLongResult_withUnsignedLongType_success(
CelCompiler celCompiler =
CelCompilerFactory.standardCelCompilerBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelRuntime celRuntime =
CelRuntimeFactory.standardCelRuntimeBuilder()
.setOptions(celOptions)
- .addLibraries(CelExtensions.math(celOptions))
+ .addLibraries(CelExtensions.math())
.build();
CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
@@ -569,9 +505,9 @@ public void least_unsignedLongResult_withUnsignedLongType_success(
@Test
public void least_noArgs_throwsCompilationException() {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
- assertThrows(
- CelValidationException.class, () -> CEL_COMPILER.compile("math.least()").getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile("math.least()").getAst());
assertThat(e).hasMessageThat().contains("math.least() requires at least one argument");
}
@@ -581,8 +517,9 @@ public void least_noArgs_throwsCompilationException() {
@TestParameters("{expr: 'math.least({})'}")
@TestParameters("{expr: 'math.least([])'}")
public void least_invalidSingleArg_throwsCompilationException(String expr) {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("math.least() invalid single argument value");
}
@@ -595,8 +532,9 @@ public void least_invalidSingleArg_throwsCompilationException(String expr) {
@TestParameters("{expr: 'math.least([1, {}, 2])'}")
@TestParameters("{expr: 'math.least([1, [], 2])'}")
public void least_invalidArgs_throwsCompilationException(String expr) {
+ Assume.assumeFalse(isParseOnly);
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e)
.hasMessageThat()
@@ -610,19 +548,16 @@ public void least_invalidArgs_throwsCompilationException(String expr) {
@TestParameters("{expr: 'math.least([1, dyn({}), 2])'}")
@TestParameters("{expr: 'math.least([1, dyn([]), 2])'}")
public void least_invalidDynArgs_throwsRuntimeException(String expr) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- CelEvaluationException e =
- assertThrows(CelEvaluationException.class, () -> CEL_RUNTIME.createProgram(ast).eval());
+ CelEvaluationException e = assertThrows(CelEvaluationException.class, () -> eval(expr));
- assertThat(e).hasMessageThat().contains("Function 'math_@min_list_dyn' failed with arg(s)");
+ assertThat(e).hasMessageThat().contains("failed with arg(s)");
}
@Test
public void least_listVariableIsEmpty_throwsRuntimeException() throws Exception {
CelCompiler celCompiler =
CelCompilerFactory.standardCelCompilerBuilder()
- .addLibraries(CelExtensions.math(CEL_OPTIONS))
+ .addLibraries(CelExtensions.math())
.addVar("listVar", ListType.create(SimpleType.INT))
.build();
CelAbstractSyntaxTree ast = celCompiler.compile("math.least(listVar)").getAst();
@@ -630,12 +565,9 @@ public void least_listVariableIsEmpty_throwsRuntimeException() throws Exception
CelEvaluationException e =
assertThrows(
CelEvaluationException.class,
- () ->
- CEL_RUNTIME
- .createProgram(ast)
- .eval(ImmutableMap.of("listVar", ImmutableList.of())));
+ () -> cel.createProgram(ast).eval(ImmutableMap.of("listVar", ImmutableList.of())));
- assertThat(e).hasMessageThat().contains("Function 'math_@min_list_dyn' failed with arg(s)");
+ assertThat(e).hasMessageThat().contains("failed with arg(s)");
assertThat(e)
.hasCauseThat()
.hasMessageThat()
@@ -645,24 +577,25 @@ public void least_listVariableIsEmpty_throwsRuntimeException() throws Exception
@Test
@TestParameters("{expr: '100.least(1) == 1'}")
@TestParameters("{expr: 'dyn(100).least(1) == 1'}")
- public void least_nonProtoNamespace_success(String expr) throws Exception {
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder()
- .addLibraries(CelExtensions.math(CEL_OPTIONS))
+ public void least_nonMathNamespace_success(String expr) throws Exception {
+ Cel cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(CelExtensions.math())
+ .addRuntimeLibraries(CelExtensions.math())
.addFunctionDeclarations(
CelFunctionDecl.newFunctionDeclaration(
"least",
CelOverloadDecl.newMemberOverload(
"int_least", SimpleType.INT, SimpleType.INT, SimpleType.INT)))
- .build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder()
.addFunctionBindings(
- CelFunctionBinding.from("int_least", Long.class, Long.class, (arg1, arg2) -> arg2))
+ CelFunctionBinding.fromOverloads(
+ "least",
+ CelFunctionBinding.from(
+ "int_least", Long.class, Long.class, (arg1, arg2) -> arg2)))
.build();
- CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
- boolean result = (boolean) celRuntime.createProgram(ast).eval();
+ boolean result = (boolean) eval(cel, expr);
assertThat(result).isTrue();
}
@@ -676,9 +609,9 @@ public void least_nonProtoNamespace_success(String expr) throws Exception {
@TestParameters("{expr: 'math.isNaN(math.sign(0.0/0.0))', expectedResult: true}")
@TestParameters("{expr: 'math.isNaN(math.sqrt(-4))', expectedResult: true}")
public void isNaN_success(String expr, boolean expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -690,7 +623,7 @@ public void isNaN_success(String expr, boolean expectedResult) throws Exception
@TestParameters("{expr: 'math.isNaN(1u)'}")
public void isNaN_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.isNaN'");
}
@@ -701,9 +634,9 @@ public void isNaN_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.isFinite(1.0/0.0)', expectedResult: false}")
@TestParameters("{expr: 'math.isFinite(0.0/0.0)', expectedResult: false}")
public void isFinite_success(String expr, boolean expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -715,7 +648,7 @@ public void isFinite_success(String expr, boolean expectedResult) throws Excepti
@TestParameters("{expr: 'math.isFinite(1u)'}")
public void isFinite_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.isFinite'");
}
@@ -726,9 +659,9 @@ public void isFinite_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.isInf(0.0/0.0)', expectedResult: false}")
@TestParameters("{expr: 'math.isInf(10.0)', expectedResult: false}")
public void isInf_success(String expr, boolean expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -740,7 +673,7 @@ public void isInf_success(String expr, boolean expectedResult) throws Exception
@TestParameters("{expr: 'math.isInf(1u)'}")
public void isInf_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.isInf'");
}
@@ -752,9 +685,9 @@ public void isInf_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.ceil(20.0)' , expectedResult: 20.0}")
@TestParameters("{expr: 'math.ceil(0.0/0.0)' , expectedResult: NaN}")
public void ceil_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -766,7 +699,7 @@ public void ceil_success(String expr, double expectedResult) throws Exception {
@TestParameters("{expr: 'math.ceil(1u)'}")
public void ceil_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.ceil'");
}
@@ -777,9 +710,9 @@ public void ceil_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.floor(0.0/0.0)' , expectedResult: NaN}")
@TestParameters("{expr: 'math.floor(50.0)' , expectedResult: 50.0}")
public void floor_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -791,7 +724,7 @@ public void floor_success(String expr, double expectedResult) throws Exception {
@TestParameters("{expr: 'math.floor(1u)'}")
public void floor_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.floor'");
}
@@ -806,9 +739,9 @@ public void floor_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.round(1.0/0.0)' , expectedResult: Infinity}")
@TestParameters("{expr: 'math.round(-1.0/0.0)' , expectedResult: -Infinity}")
public void round_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -820,7 +753,7 @@ public void round_success(String expr, double expectedResult) throws Exception {
@TestParameters("{expr: 'math.round(1u)'}")
public void round_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.round'");
}
@@ -832,9 +765,9 @@ public void round_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.trunc(1.0/0.0)' , expectedResult: Infinity}")
@TestParameters("{expr: 'math.trunc(-1.0/0.0)' , expectedResult: -Infinity}")
public void trunc_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -846,7 +779,7 @@ public void trunc_success(String expr, double expectedResult) throws Exception {
@TestParameters("{expr: 'math.trunc(1u)'}")
public void trunc_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.trunc'");
}
@@ -856,9 +789,9 @@ public void trunc_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.abs(-1657643)', expectedResult: 1657643}")
@TestParameters("{expr: 'math.abs(-2147483648)', expectedResult: 2147483648}")
public void abs_intResult_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -871,9 +804,9 @@ public void abs_intResult_success(String expr, long expectedResult) throws Excep
@TestParameters("{expr: 'math.abs(1.0/0.0)' , expectedResult: Infinity}")
@TestParameters("{expr: 'math.abs(-1.0/0.0)' , expectedResult: Infinity}")
public void abs_doubleResult_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -883,7 +816,7 @@ public void abs_overflow_throwsException() {
CelValidationException e =
assertThrows(
CelValidationException.class,
- () -> CEL_COMPILER.compile("math.abs(-9223372036854775809)").getAst());
+ () -> cel.compile("math.abs(-9223372036854775809)").getAst());
assertThat(e)
.hasMessageThat()
@@ -896,9 +829,9 @@ public void abs_overflow_throwsException() {
@TestParameters("{expr: 'math.sign(-0)', expectedResult: 0}")
@TestParameters("{expr: 'math.sign(11213)', expectedResult: 1}")
public void sign_intResult_success(String expr, int expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -914,9 +847,9 @@ public void sign_intResult_success(String expr, int expectedResult) throws Excep
@TestParameters("{expr: 'math.sign(1.0/0.0)' , expectedResult: 1.0}")
@TestParameters("{expr: 'math.sign(-1.0/0.0)' , expectedResult: -1.0}")
public void sign_doubleResult_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -926,7 +859,7 @@ public void sign_doubleResult_success(String expr, double expectedResult) throws
@TestParameters("{expr: 'math.sign(\"\")'}")
public void sign_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.sign'");
}
@@ -938,9 +871,9 @@ public void sign_invalidArgs_throwsException(String expr) {
"{expr: 'math.bitAnd(9223372036854775807,9223372036854775807)' , expectedResult:"
+ " 9223372036854775807}")
public void bitAnd_signedInt_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -950,9 +883,9 @@ public void bitAnd_signedInt_success(String expr, long expectedResult) throws Ex
@TestParameters("{expr: 'math.bitAnd(1u,3u)' , expectedResult: 1}")
public void bitAnd_unSignedInt_success(String expr, UnsignedLong expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -963,7 +896,7 @@ public void bitAnd_unSignedInt_success(String expr, UnsignedLong expectedResult)
@TestParameters("{expr: 'math.bitAnd(1)'}")
public void bitAnd_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.bitAnd'");
}
@@ -973,10 +906,7 @@ public void bitAnd_maxValArg_throwsException() {
CelValidationException e =
assertThrows(
CelValidationException.class,
- () ->
- CEL_COMPILER
- .compile("math.bitAnd(9223372036854775807,9223372036854775809)")
- .getAst());
+ () -> cel.compile("math.bitAnd(9223372036854775807,9223372036854775809)").getAst());
assertThat(e)
.hasMessageThat()
@@ -987,9 +917,9 @@ public void bitAnd_maxValArg_throwsException() {
@TestParameters("{expr: 'math.bitOr(1,2)' , expectedResult: 3}")
@TestParameters("{expr: 'math.bitOr(1,-1)' , expectedResult: -1}")
public void bitOr_signedInt_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -998,9 +928,9 @@ public void bitOr_signedInt_success(String expr, long expectedResult) throws Exc
@TestParameters("{expr: 'math.bitOr(1u,2u)' , expectedResult: 3}")
@TestParameters("{expr: 'math.bitOr(1090u,3u)' , expectedResult: 1091}")
public void bitOr_unSignedInt_success(String expr, UnsignedLong expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1011,7 +941,7 @@ public void bitOr_unSignedInt_success(String expr, UnsignedLong expectedResult)
@TestParameters("{expr: 'math.bitOr(1)'}")
public void bitOr_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.bitOr'");
}
@@ -1020,9 +950,9 @@ public void bitOr_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.bitXor(1,2)' , expectedResult: 3}")
@TestParameters("{expr: 'math.bitXor(3,5)' , expectedResult: 6}")
public void bitXor_signedInt_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1032,9 +962,9 @@ public void bitXor_signedInt_success(String expr, long expectedResult) throws Ex
@TestParameters("{expr: 'math.bitXor(3u, 5u)' , expectedResult: 6}")
public void bitXor_unSignedInt_success(String expr, UnsignedLong expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1045,7 +975,7 @@ public void bitXor_unSignedInt_success(String expr, UnsignedLong expectedResult)
@TestParameters("{expr: 'math.bitXor(1)'}")
public void bitXor_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.bitXor'");
}
@@ -1055,9 +985,9 @@ public void bitXor_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.bitNot(0)' , expectedResult: -1}")
@TestParameters("{expr: 'math.bitNot(-1)' , expectedResult: 0}")
public void bitNot_signedInt_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1067,9 +997,9 @@ public void bitNot_signedInt_success(String expr, long expectedResult) throws Ex
@TestParameters("{expr: 'math.bitNot(12310u)' , expectedResult: 18446744073709539305}")
public void bitNot_unSignedInt_success(String expr, UnsignedLong expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1080,7 +1010,7 @@ public void bitNot_unSignedInt_success(String expr, UnsignedLong expectedResult)
@TestParameters("{expr: 'math.bitNot(\"\")'}")
public void bitNot_invalidArgs_throwsException(String expr) {
CelValidationException e =
- assertThrows(CelValidationException.class, () -> CEL_COMPILER.compile(expr).getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile(expr).getAst());
assertThat(e).hasMessageThat().contains("found no matching overload for 'math.bitNot'");
}
@@ -1090,9 +1020,9 @@ public void bitNot_invalidArgs_throwsException(String expr) {
@TestParameters("{expr: 'math.bitShiftLeft(12121, 11)' , expectedResult: 24823808}")
@TestParameters("{expr: 'math.bitShiftLeft(-1, 64)' , expectedResult: 0}")
public void bitShiftLeft_signedInt_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1103,9 +1033,9 @@ public void bitShiftLeft_signedInt_success(String expr, long expectedResult) thr
@TestParameters("{expr: 'math.bitShiftLeft(1u, 65)' , expectedResult: 0}")
public void bitShiftLeft_unSignedInt_success(String expr, UnsignedLong expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1114,11 +1044,10 @@ public void bitShiftLeft_unSignedInt_success(String expr, UnsignedLong expectedR
@TestParameters("{expr: 'math.bitShiftLeft(1, -2)'}")
@TestParameters("{expr: 'math.bitShiftLeft(1u, -2)'}")
public void bitShiftLeft_invalidArgs_throwsException(String expr) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
CelEvaluationException e =
- assertThrows(
- CelEvaluationException.class, () -> CEL_UNSIGNED_RUNTIME.createProgram(ast).eval());
+ assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
assertThat(e).hasMessageThat().contains("evaluation error");
assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
@@ -1131,9 +1060,9 @@ public void bitShiftLeft_invalidArgs_throwsException(String expr) throws Excepti
@TestParameters("{expr: 'math.bitShiftRight(12121, 11)' , expectedResult: 5}")
@TestParameters("{expr: 'math.bitShiftRight(-1, 64)' , expectedResult: 0}")
public void bitShiftRight_signedInt_success(String expr, long expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
+ CelAbstractSyntaxTree ast = cel.compile(expr).getAst();
- Object result = CEL_RUNTIME.createProgram(ast).eval();
+ Object result = cel.createProgram(ast).eval();
assertThat(result).isEqualTo(expectedResult);
}
@@ -1144,9 +1073,7 @@ public void bitShiftRight_signedInt_success(String expr, long expectedResult) th
@TestParameters("{expr: 'math.bitShiftRight(1u, 65)' , expectedResult: 0}")
public void bitShiftRight_unSignedInt_success(String expr, UnsignedLong expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
-
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = eval(expr);
assertThat(result).isEqualTo(expectedResult);
}
@@ -1155,11 +1082,7 @@ public void bitShiftRight_unSignedInt_success(String expr, UnsignedLong expected
@TestParameters("{expr: 'math.bitShiftRight(23111u, -212)'}")
@TestParameters("{expr: 'math.bitShiftRight(23, -212)'}")
public void bitShiftRight_invalidArgs_throwsException(String expr) throws Exception {
- CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
-
- CelEvaluationException e =
- assertThrows(
- CelEvaluationException.class, () -> CEL_UNSIGNED_RUNTIME.createProgram(ast).eval());
+ CelEvaluationException e = assertThrows(CelEvaluationException.class, () -> eval(expr));
assertThat(e).hasMessageThat().contains("evaluation error");
assertThat(e).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
@@ -1174,10 +1097,26 @@ public void bitShiftRight_invalidArgs_throwsException(String expr) throws Except
@TestParameters("{expr: 'math.sqrt(1.0/0.0)', expectedResult: Infinity}")
@TestParameters("{expr: 'math.sqrt(-1)', expectedResult: NaN}")
public void sqrt_success(String expr, double expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = CEL_UNSIGNED_COMPILER.compile(expr).getAst();
-
- Object result = CEL_UNSIGNED_RUNTIME.createProgram(ast).eval();
+ Object result = eval(expr);
assertThat(result).isEqualTo(expectedResult);
}
+
+ private Object eval(Cel cel, String expression, Map variables) throws Exception {
+ CelAbstractSyntaxTree ast;
+ if (isParseOnly) {
+ ast = cel.parse(expression).getAst();
+ } else {
+ ast = cel.compile(expression).getAst();
+ }
+ return cel.createProgram(ast).eval(variables);
+ }
+
+ private Object eval(Cel celInstance, String expression) throws Exception {
+ return eval(celInstance, expression, ImmutableMap.of());
+ }
+
+ private Object eval(String expression) throws Exception {
+ return eval(this.cel, expression, ImmutableMap.of());
+ }
}
diff --git a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java
index 1aac5a023..f203a66b8 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java
@@ -19,8 +19,11 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import com.google.testing.junit.testparameterinjector.TestParameters;
+import dev.cel.bundle.Cel;
+import dev.cel.bundle.CelBuilder;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelContainer;
import dev.cel.common.CelFunctionDecl;
@@ -30,47 +33,34 @@
import dev.cel.common.CelValidationResult;
import dev.cel.common.types.ListType;
import dev.cel.common.types.SimpleType;
-import dev.cel.compiler.CelCompiler;
-import dev.cel.compiler.CelCompilerFactory;
import dev.cel.expr.conformance.proto3.TestAllTypes;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime;
-import dev.cel.runtime.CelRuntimeFactory;
+import dev.cel.testing.CelRuntimeFlavor;
import java.util.List;
+import java.util.Map;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TestParameterInjector.class)
public final class CelSetsExtensionsTest {
- private static final CelOptions CEL_OPTIONS = CelOptions.current().build();
- private static final CelCompiler COMPILER =
- CelCompilerFactory.standardCelCompilerBuilder()
- .addMessageTypes(TestAllTypes.getDescriptor())
- .setOptions(CEL_OPTIONS)
- .setContainer(CelContainer.ofName("cel.expr.conformance.proto3"))
- .addLibraries(CelExtensions.sets(CEL_OPTIONS))
- .addVar("list", ListType.create(SimpleType.INT))
- .addVar("subList", ListType.create(SimpleType.INT))
- .addFunctionDeclarations(
- CelFunctionDecl.newFunctionDeclaration(
- "new_int",
- CelOverloadDecl.newGlobalOverload(
- "new_int_int64", SimpleType.INT, SimpleType.INT)))
- .build();
-
- private static final CelRuntime RUNTIME =
- CelRuntimeFactory.standardCelRuntimeBuilder()
- .addMessageTypes(TestAllTypes.getDescriptor())
- .addLibraries(CelExtensions.sets(CEL_OPTIONS))
- .setOptions(CEL_OPTIONS)
- .addFunctionBindings(
- CelFunctionBinding.from(
- "new_int_int64",
- Long.class,
- // Intentionally return java.lang.Integer to test primitive type adaptation
- Math::toIntExact))
- .build();
+ private static final CelOptions CEL_OPTIONS =
+ CelOptions.current().enableHeterogeneousNumericComparisons(true).build();
+
+ @TestParameter public CelRuntimeFlavor runtimeFlavor;
+ @TestParameter public boolean isParseOnly;
+
+ private Cel cel;
+
+ @Before
+ public void setUp() {
+ // Legacy runtime does not support parsed-only evaluation mode.
+ Assume.assumeFalse(runtimeFlavor.equals(CelRuntimeFlavor.LEGACY) && isParseOnly);
+ this.cel = setupEnv(runtimeFlavor.builder());
+ }
@Test
public void library() {
@@ -87,22 +77,13 @@ public void library() {
public void contains_integerListWithSameValue_succeeds() throws Exception {
ImmutableList list = ImmutableList.of(1, 2, 3, 4);
ImmutableList subList = ImmutableList.of(1, 2, 3, 4);
- CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains(list, subList)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval(ImmutableMap.of("list", list, "subList", subList));
-
- assertThat(result).isEqualTo(true);
+ assertThat(eval("sets.contains(list, subList)", ImmutableMap.of("list", list, "subList", subList)))
+ .isEqualTo(true);
}
@Test
public void contains_integerListAsExpression_succeeds() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains([1, 1], [1])").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(true);
+ assertThat(eval("sets.contains([1, 1], [1])")).isEqualTo(true);
}
@Test
@@ -119,12 +100,7 @@ public void contains_integerListAsExpression_succeeds() throws Exception {
+ " [TestAllTypes{single_int64: 2, single_uint64: 3u}])', expected: false}")
public void contains_withProtoMessage_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -133,12 +109,7 @@ public void contains_withProtoMessage_succeeds(String expression, boolean expect
@TestParameters("{expression: 'sets.contains([new_int(2)], [1])', expected: false}")
public void contains_withFunctionReturningInteger_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -157,12 +128,8 @@ public void contains_withFunctionReturningInteger_succeeds(String expression, bo
@TestParameters("{list: [1], subList: [1, 2], expected: false}")
public void contains_withIntTypes_succeeds(
List list, List subList, boolean expected) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains(list, subList)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval(ImmutableMap.of("list", list, "subList", subList));
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval("sets.contains(list, subList)", ImmutableMap.of("list", list, "subList", subList)))
+ .isEqualTo(expected);
}
@Test
@@ -177,12 +144,8 @@ public void contains_withIntTypes_succeeds(
@TestParameters("{list: [2, 3.0], subList: [2, 3], expected: true}")
public void contains_withDoubleTypes_succeeds(
List list, List subList, boolean expected) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains(list, subList)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval(ImmutableMap.of("list", list, "subList", subList));
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval("sets.contains(list, subList)", ImmutableMap.of("list", list, "subList", subList)))
+ .isEqualTo(expected);
}
@Test
@@ -193,12 +156,7 @@ public void contains_withDoubleTypes_succeeds(
@TestParameters("{expression: 'sets.contains([[1], [2, 3.0]], [[2, 3]])', expected: true}")
public void contains_withNestedLists_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -206,19 +164,16 @@ public void contains_withNestedLists_succeeds(String expression, boolean expecte
@TestParameters("{expression: 'sets.contains([1], [1, \"1\"])', expected: false}")
public void contains_withMixingIntAndString_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
- @TestParameters("{expression: 'sets.contains([1], [\"1\"])'}")
- @TestParameters("{expression: 'sets.contains([\"1\"], [1])'}")
- public void contains_withMixingIntAndString_throwsException(String expression) throws Exception {
- CelValidationResult invalidData = COMPILER.compile(expression);
+ public void contains_withMixingIntAndString_throwsException(
+ @TestParameter({"sets.contains([1], [\"1\"])", "sets.contains([\"1\"], [1])"})
+ String expression)
+ throws Exception {
+ Assume.assumeFalse(isParseOnly);
+ CelValidationResult invalidData = cel.compile(expression);
assertThat(invalidData.getErrors()).hasSize(1);
assertThat(invalidData.getErrors().get(0).getMessage())
@@ -227,12 +182,7 @@ public void contains_withMixingIntAndString_throwsException(String expression) t
@Test
public void contains_withMixedValues_succeeds() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("sets.contains([1, 2], [2u, 2.0])").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(true);
+ assertThat(eval("sets.contains([1, 2], [2u, 2.0])")).isEqualTo(true);
}
@Test
@@ -249,12 +199,7 @@ public void contains_withMixedValues_succeeds() throws Exception {
"{expression: 'sets.contains([[[[[[5]]]]]], [[1], [2, 3.0], [[[[[5]]]]]])', expected: false}")
public void contains_withMultiLevelNestedList_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -269,12 +214,7 @@ public void contains_withMultiLevelNestedList_succeeds(String expression, boolea
+ " false}")
public void contains_withMapValues_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -289,12 +229,7 @@ public void contains_withMapValues_succeeds(String expression, boolean expected)
@TestParameters("{expression: 'sets.equivalent([1, 2], [2, 2, 2])', expected: false}")
public void equivalent_withIntTypes_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -308,12 +243,7 @@ public void equivalent_withIntTypes_succeeds(String expression, boolean expected
@TestParameters("{expression: 'sets.equivalent([1, 2], [1u, 2, 2.3])', expected: false}")
public void equivalent_withMixedTypes_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -338,12 +268,7 @@ public void equivalent_withMixedTypes_succeeds(String expression, boolean expect
+ " [TestAllTypes{single_int64: 2, single_uint64: 3u}])', expected: false}")
public void equivalent_withProtoMessage_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -361,12 +286,7 @@ public void equivalent_withProtoMessage_succeeds(String expression, boolean expe
+ " expected: false}")
public void equivalent_withMapValues_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -391,12 +311,7 @@ public void equivalent_withMapValues_succeeds(String expression, boolean expecte
@TestParameters("{expression: 'sets.intersects([1], [1.1, 2u])', expected: false}")
public void intersects_withMixedTypes_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object result = program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -414,12 +329,11 @@ public void intersects_withMixedTypes_succeeds(String expression, boolean expect
@TestParameters("{expression: 'sets.intersects([{2: 1}], [{1: 1}])', expected: false}")
public void intersects_withMapValues_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
+ // The LEGACY runtime is not spec compliant, because decimal keys are not allowed for maps.
+ Assume.assumeFalse(
+ runtimeFlavor.equals(CelRuntimeFlavor.PLANNER) && expression.contains("1.0:"));
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
@@ -444,25 +358,21 @@ public void intersects_withMapValues_succeeds(String expression, boolean expecte
+ " [TestAllTypes{single_int64: 2, single_uint64: 3u}])', expected: false}")
public void intersects_withProtoMessage_succeeds(String expression, boolean expected)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(expression).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- boolean result = (boolean) program.eval();
-
- assertThat(result).isEqualTo(expected);
+ assertThat(eval(expression)).isEqualTo(expected);
}
@Test
public void setsExtension_containsFunctionSubset_succeeds() throws Exception {
CelSetsExtensions setsExtensions =
CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.CONTAINS);
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(setsExtensions).build();
+ Cel cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(setsExtensions)
+ .addRuntimeLibraries(setsExtensions)
+ .build();
- Object evaluatedResult =
- celRuntime.createProgram(celCompiler.compile("sets.contains([1, 2], [2])").getAst()).eval();
+ Object evaluatedResult = eval(cel, "sets.contains([1, 2], [2])", ImmutableMap.of());
assertThat(evaluatedResult).isEqualTo(true);
}
@@ -471,15 +381,14 @@ public void setsExtension_containsFunctionSubset_succeeds() throws Exception {
public void setsExtension_equivalentFunctionSubset_succeeds() throws Exception {
CelSetsExtensions setsExtensions =
CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.EQUIVALENT);
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(setsExtensions).build();
+ Cel cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(setsExtensions)
+ .addRuntimeLibraries(setsExtensions)
+ .build();
- Object evaluatedResult =
- celRuntime
- .createProgram(celCompiler.compile("sets.equivalent([1, 1], [1])").getAst())
- .eval();
+ Object evaluatedResult = eval(cel, "sets.equivalent([1, 1], [1])", ImmutableMap.of());
assertThat(evaluatedResult).isEqualTo(true);
}
@@ -488,44 +397,95 @@ public void setsExtension_equivalentFunctionSubset_succeeds() throws Exception {
public void setsExtension_intersectsFunctionSubset_succeeds() throws Exception {
CelSetsExtensions setsExtensions =
CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.INTERSECTS);
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(setsExtensions).build();
+ Cel cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(setsExtensions)
+ .addRuntimeLibraries(setsExtensions)
+ .build();
- Object evaluatedResult =
- celRuntime
- .createProgram(celCompiler.compile("sets.intersects([1, 1], [1])").getAst())
- .eval();
+ Object evaluatedResult = eval(cel, "sets.intersects([1, 1], [1])", ImmutableMap.of());
assertThat(evaluatedResult).isEqualTo(true);
}
@Test
public void setsExtension_compileUnallowedFunction_throws() {
+ Assume.assumeFalse(isParseOnly);
CelSetsExtensions setsExtensions =
CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.EQUIVALENT);
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build();
+ Cel cel = runtimeFlavor.builder().addCompilerLibraries(setsExtensions).build();
assertThrows(
- CelValidationException.class,
- () -> celCompiler.compile("sets.contains([1, 2], [2])").getAst());
+ CelValidationException.class, () -> cel.compile("sets.contains([1, 2], [2])").getAst());
}
@Test
public void setsExtension_evaluateUnallowedFunction_throws() throws Exception {
CelSetsExtensions setsExtensions =
CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.CONTAINS, SetsFunction.EQUIVALENT);
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder().addLibraries(setsExtensions).build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder()
- .addLibraries(CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.EQUIVALENT))
+ CelSetsExtensions runtimeLibrary =
+ CelExtensions.sets(CelOptions.DEFAULT, SetsFunction.EQUIVALENT);
+ Cel cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(setsExtensions)
+ .addRuntimeLibraries(runtimeLibrary)
.build();
- CelAbstractSyntaxTree ast = celCompiler.compile("sets.contains([1, 2], [2])").getAst();
+ CelAbstractSyntaxTree ast =
+ isParseOnly
+ ? cel.parse("sets.contains([1, 2], [2])").getAst()
+ : cel.compile("sets.contains([1, 2], [2])").getAst();
+
+ if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER) && !isParseOnly) {
+ // Fails at plan time
+ assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast));
+ } else {
+ CelRuntime.Program program = cel.createProgram(ast);
+ assertThrows(CelEvaluationException.class, () -> program.eval());
+ }
+ }
+
+ private Object eval(Cel cel, String expression, Map variables) throws Exception {
+ CelAbstractSyntaxTree ast;
+ if (isParseOnly) {
+ ast = cel.parse(expression).getAst();
+ } else {
+ ast = cel.compile(expression).getAst();
+ }
+ return cel.createProgram(ast).eval(variables);
+ }
+
+ private Object eval(String expression) throws Exception {
+ return eval(this.cel, expression, ImmutableMap.of());
+ }
+
+ private Object eval(String expression, Map variables) throws Exception {
+ return eval(this.cel, expression, variables);
+ }
- assertThrows(CelEvaluationException.class, () -> celRuntime.createProgram(ast).eval());
+ private static Cel setupEnv(CelBuilder celBuilder) {
+ return celBuilder
+ .addMessageTypes(TestAllTypes.getDescriptor())
+ .setOptions(CEL_OPTIONS)
+ .setContainer(CelContainer.ofName("cel.expr.conformance.proto3"))
+ .addCompilerLibraries(CelExtensions.sets(CEL_OPTIONS))
+ .addRuntimeLibraries(CelExtensions.sets(CEL_OPTIONS))
+ .addVar("list", ListType.create(SimpleType.INT))
+ .addVar("subList", ListType.create(SimpleType.INT))
+ .addFunctionDeclarations(
+ CelFunctionDecl.newFunctionDeclaration(
+ "new_int",
+ CelOverloadDecl.newGlobalOverload("new_int_int64", SimpleType.INT, SimpleType.INT)))
+ .addFunctionBindings(
+ CelFunctionBinding.fromOverloads(
+ "new_int",
+ CelFunctionBinding.from(
+ "new_int_int64",
+ Long.class,
+ // Intentionally return java.lang.Integer to test primitive type adaptation
+ Math::toIntExact)))
+ .build();
}
}
diff --git a/extensions/src/test/java/dev/cel/extensions/CelStringExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelStringExtensionsTest.java
index 3624e0902..2ce394b6b 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelStringExtensionsTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelStringExtensionsTest.java
@@ -18,43 +18,56 @@
import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import com.google.testing.junit.testparameterinjector.TestParameters;
+import dev.cel.bundle.Cel;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelFunctionDecl;
import dev.cel.common.CelOptions;
import dev.cel.common.CelValidationException;
+import dev.cel.common.CelValidationResult;
import dev.cel.common.types.SimpleType;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerFactory;
import dev.cel.extensions.CelStringExtensions.Function;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelRuntime;
-import dev.cel.runtime.CelRuntimeFactory;
+import dev.cel.testing.CelRuntimeFlavor;
import java.util.List;
+import java.util.Map;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TestParameterInjector.class)
public final class CelStringExtensionsTest {
- private static final CelCompiler COMPILER =
- CelCompilerFactory.standardCelCompilerBuilder()
- .addLibraries(CelExtensions.strings())
- .addVar("s", SimpleType.STRING)
- .addVar("separator", SimpleType.STRING)
- .addVar("index", SimpleType.INT)
- .addVar("offset", SimpleType.INT)
- .addVar("indexOfParam", SimpleType.STRING)
- .addVar("beginIndex", SimpleType.INT)
- .addVar("endIndex", SimpleType.INT)
- .addVar("limit", SimpleType.INT)
- .build();
-
- private static final CelRuntime RUNTIME =
- CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(CelExtensions.strings()).build();
+ @TestParameter public CelRuntimeFlavor runtimeFlavor;
+ @TestParameter public boolean isParseOnly;
+
+ private Cel cel;
+
+ @Before
+ public void setUp() {
+ // Legacy runtime does not support parsed-only evaluation mode.
+ Assume.assumeFalse(runtimeFlavor.equals(CelRuntimeFlavor.LEGACY) && isParseOnly);
+ this.cel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(CelExtensions.strings())
+ .addRuntimeLibraries(CelExtensions.strings())
+ .addVar("s", SimpleType.STRING)
+ .addVar("separator", SimpleType.STRING)
+ .addVar("index", SimpleType.INT)
+ .addVar("offset", SimpleType.INT)
+ .addVar("indexOfParam", SimpleType.STRING)
+ .addVar("beginIndex", SimpleType.INT)
+ .addVar("endIndex", SimpleType.INT)
+ .addVar("limit", SimpleType.INT)
+ .build();
+ }
@Test
public void library() {
@@ -92,10 +105,8 @@ public void library() {
@TestParameters("{string: '😁😑😦', beginIndex: 3, expectedResult: ''}")
public void substring_beginIndex_success(String string, int beginIndex, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.substring(beginIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "beginIndex", beginIndex));
+ Object evaluatedResult =
+ eval("s.substring(beginIndex)", ImmutableMap.of("s", string, "beginIndex", beginIndex));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -108,10 +119,7 @@ public void substring_beginIndex_success(String string, int beginIndex, String e
@TestParameters(
"{string: 'A!@#$%^&*()-_+=?/<>.,;:''\"\\', expectedResult: 'a!@#$%^&*()-_+=?/<>.,;:''\"\\'}")
public void lowerAscii_success(String string, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lowerAscii()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("s.lowerAscii()", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -127,10 +135,7 @@ public void lowerAscii_success(String string, String expectedResult) throws Exce
@TestParameters("{string: 'A😁B 😑C가😦D', expectedResult: 'a😁b 😑c가😦d'}")
public void lowerAscii_outsideAscii_success(String string, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lowerAscii()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("s.lowerAscii()", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -161,10 +166,8 @@ public void lowerAscii_outsideAscii_success(String string, String expectedResult
+ " ['The quick brown ', ' jumps over the lazy dog']}")
public void split_ascii_success(String string, String separator, List expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.split(separator)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "separator", separator));
+ Object evaluatedResult =
+ eval("s.split(separator)", ImmutableMap.of("s", string, "separator", separator));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -182,34 +185,30 @@ public void split_ascii_success(String string, String separator, List ex
@TestParameters("{string: '😁a😦나😑 😦', separator: '😁a😦나😑 😦', expectedResult: ['','']}")
public void split_unicode_success(String string, String separator, List expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.split(separator)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "separator", separator));
+ Object evaluatedResult =
+ eval("s.split(separator)", ImmutableMap.of("s", string, "separator", separator));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@Test
@SuppressWarnings("unchecked") // Test only, need List cast to test mutability
- public void split_collectionIsMutable() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.split('')").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
+ public void split_collectionIsImmutable() throws Exception {
+ CelAbstractSyntaxTree ast = cel.compile("'test'.split('')").getAst();
+ CelRuntime.Program program = cel.createProgram(ast);
List evaluatedResult = (List) program.eval();
- evaluatedResult.add("a");
- evaluatedResult.add("b");
- evaluatedResult.add("c");
- evaluatedResult.remove("c");
- assertThat(evaluatedResult).containsExactly("t", "e", "s", "t", "a", "b").inOrder();
+ assertThrows(UnsupportedOperationException.class, () -> evaluatedResult.add("a"));
}
@Test
public void split_separatorIsNonString_throwsException() {
+ // This is a type-check failure.
+ Assume.assumeFalse(isParseOnly);
+ CelValidationResult result = cel.compile("'12'.split(2)");
CelValidationException exception =
- assertThrows(
- CelValidationException.class, () -> COMPILER.compile("'12'.split(2)").getAst());
+ assertThrows(CelValidationException.class, () -> result.getAst());
assertThat(exception).hasMessageThat().contains("found no matching overload for 'split'");
}
@@ -295,11 +294,10 @@ public void split_separatorIsNonString_throwsException() {
+ " expectedResult: ['The quick brown ', ' jumps over the lazy dog']}")
public void split_asciiWithLimit_success(
String string, String separator, int limit, List expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.split(separator, limit)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "separator", separator, "limit", limit));
+ eval(
+ "s.split(separator, limit)",
+ ImmutableMap.of("s", string, "separator", separator, "limit", limit));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -351,11 +349,10 @@ public void split_asciiWithLimit_success(
"{string: '😁a😦나😑 😦', separator: '😁a😦나😑 😦', limit: -1, expectedResult: ['','']}")
public void split_unicodeWithLimit_success(
String string, String separator, int limit, List expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.split(separator, limit)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "separator", separator, "limit", limit));
+ eval(
+ "s.split(separator, limit)",
+ ImmutableMap.of("s", string, "separator", separator, "limit", limit));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -368,35 +365,36 @@ public void split_unicodeWithLimit_success(
@TestParameters("{separator: 'te', limit: 1}")
@TestParameters("{separator: 'te', limit: 2}")
@SuppressWarnings("unchecked") // Test only, need List cast to test mutability
- public void split_withLimit_collectionIsMutable(String separator, int limit) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.split(separator, limit)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
+ public void split_withLimit_collectionIsImmutable(String separator, int limit) throws Exception {
List evaluatedResult =
- (List) program.eval(ImmutableMap.of("separator", separator, "limit", limit));
- evaluatedResult.add("a");
+ (List)
+ eval(
+ "'test'.split(separator, limit)",
+ ImmutableMap.of("separator", separator, "limit", limit));
- assertThat(Iterables.getLast(evaluatedResult)).isEqualTo("a");
+ assertThrows(UnsupportedOperationException.class, () -> evaluatedResult.add("a"));
}
@Test
public void split_withLimit_separatorIsNonString_throwsException() {
+ // This is a type-check failure.
+ Assume.assumeFalse(isParseOnly);
+ CelValidationResult result = cel.compile("'12'.split(2, 3)");
CelValidationException exception =
- assertThrows(
- CelValidationException.class, () -> COMPILER.compile("'12'.split(2, 3)").getAst());
+ assertThrows(CelValidationException.class, () -> result.getAst());
assertThat(exception).hasMessageThat().contains("found no matching overload for 'split'");
}
@Test
public void split_withLimitOverflow_throwsException() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.split('', limit)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("limit", 2147483648L))); // INT_MAX + 1
+ () ->
+ eval(
+ "'test'.split('', limit)",
+ ImmutableMap.of("limit", 2147483648L))); // INT_MAX + 1
assertThat(exception)
.hasMessageThat()
@@ -416,11 +414,10 @@ public void split_withLimitOverflow_throwsException() throws Exception {
@TestParameters("{string: '', beginIndex: 0, endIndex: 0, expectedResult: ''}")
public void substring_beginAndEndIndex_ascii_success(
String string, int beginIndex, int endIndex, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.substring(beginIndex, endIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "beginIndex", beginIndex, "endIndex", endIndex));
+ eval(
+ "s.substring(beginIndex, endIndex)",
+ ImmutableMap.of("s", string, "beginIndex", beginIndex, "endIndex", endIndex));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -444,11 +441,10 @@ public void substring_beginAndEndIndex_ascii_success(
@TestParameters("{string: 'a😁나', beginIndex: 3, endIndex: 3, expectedResult: ''}")
public void substring_beginAndEndIndex_unicode_success(
String string, int beginIndex, int endIndex, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.substring(beginIndex, endIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "beginIndex", beginIndex, "endIndex", endIndex));
+ eval(
+ "s.substring(beginIndex, endIndex)",
+ ImmutableMap.of("s", string, "beginIndex", beginIndex, "endIndex", endIndex));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -458,13 +454,13 @@ public void substring_beginAndEndIndex_unicode_success(
@TestParameters("{string: '', beginIndex: 2}")
public void substring_beginIndexOutOfRange_ascii_throwsException(String string, int beginIndex)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.substring(beginIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("s", string, "beginIndex", beginIndex)));
+ () ->
+ eval(
+ "s.substring(beginIndex)",
+ ImmutableMap.of("s", string, "beginIndex", beginIndex)));
String exceptionMessage =
String.format(
@@ -482,13 +478,13 @@ public void substring_beginIndexOutOfRange_ascii_throwsException(String string,
@TestParameters("{string: '😁가나', beginIndex: 4, uniqueCharCount: 3}")
public void substring_beginIndexOutOfRange_unicode_throwsException(
String string, int beginIndex, int uniqueCharCount) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.substring(beginIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("s", string, "beginIndex", beginIndex)));
+ () ->
+ eval(
+ "s.substring(beginIndex)",
+ ImmutableMap.of("s", string, "beginIndex", beginIndex)));
String exceptionMessage =
String.format(
@@ -505,14 +501,12 @@ public void substring_beginIndexOutOfRange_unicode_throwsException(
@TestParameters("{string: '😁😑😦', beginIndex: 2, endIndex: 1}")
public void substring_beginAndEndIndexOutOfRange_throwsException(
String string, int beginIndex, int endIndex) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.substring(beginIndex, endIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
() ->
- program.eval(
+ eval(
+ "s.substring(beginIndex, endIndex)",
ImmutableMap.of("s", string, "beginIndex", beginIndex, "endIndex", endIndex)));
String exceptionMessage =
@@ -522,13 +516,13 @@ public void substring_beginAndEndIndexOutOfRange_throwsException(
@Test
public void substring_beginIndexOverflow_throwsException() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'abcd'.substring(beginIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("beginIndex", 2147483648L))); // INT_MAX + 1
+ () ->
+ eval(
+ "'abcd'.substring(beginIndex)",
+ ImmutableMap.of("beginIndex", 2147483648L))); // INT_MAX + 1
assertThat(exception)
.hasMessageThat()
@@ -540,13 +534,13 @@ public void substring_beginIndexOverflow_throwsException() throws Exception {
@TestParameters("{beginIndex: 2147483648, endIndex: 2147483648}")
public void substring_beginOrEndIndexOverflow_throwsException(long beginIndex, long endIndex)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'abcd'.substring(beginIndex, endIndex)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("beginIndex", beginIndex, "endIndex", endIndex)));
+ () ->
+ eval(
+ "'abcd'.substring(beginIndex, endIndex)",
+ ImmutableMap.of("beginIndex", beginIndex, "endIndex", endIndex)));
assertThat(exception)
.hasMessageThat()
@@ -563,10 +557,7 @@ public void substring_beginOrEndIndexOverflow_throwsException(long beginIndex, l
@TestParameters("{string: 'world', index: 5, expectedResult: ''}")
public void charAt_ascii_success(String string, long index, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.charAt(index)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "index", index));
+ Object evaluatedResult = eval("s.charAt(index)", ImmutableMap.of("s", string, "index", index));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -588,10 +579,7 @@ public void charAt_ascii_success(String string, long index, String expectedResul
@TestParameters("{string: 'a😁나', index: 3, expectedResult: ''}")
public void charAt_unicode_success(String string, long index, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.charAt(index)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "index", index));
+ Object evaluatedResult = eval("s.charAt(index)", ImmutableMap.of("s", string, "index", index));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -602,26 +590,21 @@ public void charAt_unicode_success(String string, long index, String expectedRes
@TestParameters("{string: '😁😑😦', index: -1}")
@TestParameters("{string: '😁😑😦', index: 4}")
public void charAt_outOfBounds_throwsException(String string, long index) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.charAt(index)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("s", string, "index", index)));
+ () -> eval("s.charAt(index)", ImmutableMap.of("s", string, "index", index)));
assertThat(exception).hasMessageThat().contains("charAt failure: Index out of range");
}
@Test
public void charAt_indexOverflow_throwsException() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.charAt(index)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("index", 2147483648L))); // INT_MAX + 1
+ () ->
+ eval("'test'.charAt(index)", ImmutableMap.of("index", 2147483648L))); // INT_MAX + 1
assertThat(exception)
.hasMessageThat()
@@ -650,10 +633,8 @@ public void charAt_indexOverflow_throwsException() throws Exception {
@TestParameters("{string: 'hello mellow', indexOf: ' ', expectedResult: -1}")
public void indexOf_ascii_success(String string, String indexOf, int expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.indexOf(indexOfParam)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "indexOfParam", indexOf));
+ Object evaluatedResult =
+ eval("s.indexOf(indexOfParam)", ImmutableMap.of("s", string, "indexOfParam", indexOf));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -682,10 +663,8 @@ public void indexOf_ascii_success(String string, String indexOf, int expectedRes
@TestParameters("{string: 'a😁😑 나😦😁😑다', indexOf: 'a😁😑 나😦😁😑다😁', expectedResult: -1}")
public void indexOf_unicode_success(String string, String indexOf, int expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.indexOf(indexOfParam)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string, "indexOfParam", indexOf));
+ Object evaluatedResult =
+ eval("s.indexOf(indexOfParam)", ImmutableMap.of("s", string, "indexOfParam", indexOf));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -697,13 +676,10 @@ public void indexOf_unicode_success(String string, String indexOf, int expectedR
@TestParameters("{indexOf: '나'}")
@TestParameters("{indexOf: '😁'}")
public void indexOf_onEmptyString_throwsException(String indexOf) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("''.indexOf(indexOfParam)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("indexOfParam", indexOf)));
+ () -> eval("''.indexOf(indexOfParam)", ImmutableMap.of("indexOfParam", indexOf)));
assertThat(exception).hasMessageThat().contains("indexOf failure: Offset out of range");
}
@@ -728,11 +704,10 @@ public void indexOf_onEmptyString_throwsException(String indexOf) throws Excepti
@TestParameters("{string: 'hello mellow', indexOf: 'l', offset: 10, expectedResult: -1}")
public void indexOf_asciiWithOffset_success(
String string, String indexOf, int offset, int expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.indexOf(indexOfParam, offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "indexOfParam", indexOf, "offset", offset));
+ eval(
+ "s.indexOf(indexOfParam, offset)",
+ ImmutableMap.of("s", string, "indexOfParam", indexOf, "offset", offset));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -779,11 +754,10 @@ public void indexOf_asciiWithOffset_success(
"{string: 'a😁😑 나😦😁😑다', indexOf: 'a😁😑 나😦😁😑다😁', offset: 0, expectedResult: -1}")
public void indexOf_unicodeWithOffset_success(
String string, String indexOf, int offset, int expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.indexOf(indexOfParam, offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "indexOfParam", indexOf, "offset", offset));
+ eval(
+ "s.indexOf(indexOfParam, offset)",
+ ImmutableMap.of("s", string, "indexOfParam", indexOf, "offset", offset));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -797,14 +771,12 @@ public void indexOf_unicodeWithOffset_success(
@TestParameters("{string: '😁😑 😦', indexOf: '😦', offset: 4}")
public void indexOf_withOffsetOutOfBounds_throwsException(
String string, String indexOf, int offset) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.indexOf(indexOfParam, offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
() ->
- program.eval(
+ eval(
+ "s.indexOf(indexOfParam, offset)",
ImmutableMap.of("s", string, "indexOfParam", indexOf, "offset", offset)));
assertThat(exception).hasMessageThat().contains("indexOf failure: Offset out of range");
@@ -812,13 +784,13 @@ public void indexOf_withOffsetOutOfBounds_throwsException(
@Test
public void indexOf_offsetOverflow_throwsException() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.indexOf('t', offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("offset", 2147483648L))); // INT_MAX + 1
+ () ->
+ eval(
+ "'test'.indexOf('t', offset)",
+ ImmutableMap.of("offset", 2147483648L))); // INT_MAX + 1
assertThat(exception)
.hasMessageThat()
@@ -835,10 +807,7 @@ public void indexOf_offsetOverflow_throwsException() throws Exception {
@TestParameters("{list: '[''x'', '' '', '' y '', ''z '']', expectedResult: 'x y z '}")
@TestParameters("{list: '[''hello '', ''world'']', expectedResult: 'hello world'}")
public void join_ascii_success(String list, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(String.format("%s.join()", list)).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- String result = (String) program.eval();
+ String result = (String) eval(String.format("%s.join()", list));
assertThat(result).isEqualTo(expectedResult);
}
@@ -847,10 +816,7 @@ public void join_ascii_success(String list, String expectedResult) throws Except
@TestParameters("{list: '[''가'', ''😁'']', expectedResult: '가😁'}")
@TestParameters("{list: '[''😁😦😑 😦'', ''나'']', expectedResult: '😁😦😑 😦나'}")
public void join_unicode_success(String list, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile(String.format("%s.join()", list)).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- String result = (String) program.eval();
+ String result = (String) eval(String.format("%s.join()", list));
assertThat(result).isEqualTo(expectedResult);
}
@@ -874,11 +840,7 @@ public void join_unicode_success(String list, String expectedResult) throws Exce
"{list: '[''hello '', ''world'']', separator: '/', expectedResult: 'hello /world'}")
public void join_asciiWithSeparator_success(String list, String separator, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast =
- COMPILER.compile(String.format("%s.join('%s')", list, separator)).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- String result = (String) program.eval();
+ String result = (String) eval(String.format("%s.join('%s')", list, separator));
assertThat(result).isEqualTo(expectedResult);
}
@@ -893,20 +855,17 @@ public void join_asciiWithSeparator_success(String list, String separator, Strin
+ " -😑-나'}")
public void join_unicodeWithSeparator_success(
String list, String separator, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast =
- COMPILER.compile(String.format("%s.join('%s')", list, separator)).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- String result = (String) program.eval();
+ String result = (String) eval(String.format("%s.join('%s')", list, separator));
assertThat(result).isEqualTo(expectedResult);
}
@Test
public void join_separatorIsNonString_throwsException() {
+ // This is a type-check failure.
+ Assume.assumeFalse(isParseOnly);
CelValidationException exception =
- assertThrows(
- CelValidationException.class, () -> COMPILER.compile("['x','y'].join(2)").getAst());
+ assertThrows(CelValidationException.class, () -> cel.compile("['x','y'].join(2)").getAst());
assertThat(exception).hasMessageThat().contains("found no matching overload for 'join'");
}
@@ -935,11 +894,10 @@ public void join_separatorIsNonString_throwsException() {
@TestParameters("{string: 'hello mellow', lastIndexOf: ' ', expectedResult: -1}")
public void lastIndexOf_ascii_success(String string, String lastIndexOf, int expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lastIndexOf(indexOfParam)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "indexOfParam", lastIndexOf));
+ eval(
+ "s.lastIndexOf(indexOfParam)",
+ ImmutableMap.of("s", string, "indexOfParam", lastIndexOf));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -969,11 +927,10 @@ public void lastIndexOf_ascii_success(String string, String lastIndexOf, int exp
@TestParameters("{string: 'a😁😑 나😦😁😑다', lastIndexOf: 'a😁😑 나😦😁😑다😁', expectedResult: -1}")
public void lastIndexOf_unicode_success(String string, String lastIndexOf, int expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lastIndexOf(indexOfParam)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "indexOfParam", lastIndexOf));
+ eval(
+ "s.lastIndexOf(indexOfParam)",
+ ImmutableMap.of("s", string, "indexOfParam", lastIndexOf));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -987,10 +944,8 @@ public void lastIndexOf_unicode_success(String string, String lastIndexOf, int e
@TestParameters("{lastIndexOf: '😁'}")
public void lastIndexOf_strLengthLessThanSubstrLength_returnsMinusOne(String lastIndexOf)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("''.lastIndexOf(indexOfParam)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", "", "indexOfParam", lastIndexOf));
+ Object evaluatedResult =
+ eval("''.lastIndexOf(indexOfParam)", ImmutableMap.of("s", "", "indexOfParam", lastIndexOf));
assertThat(evaluatedResult).isEqualTo(-1);
}
@@ -1022,11 +977,10 @@ public void lastIndexOf_strLengthLessThanSubstrLength_returnsMinusOne(String las
"{string: 'hello mellow', lastIndexOf: 'hello mellowwww ', offset: 11, expectedResult: -1}")
public void lastIndexOf_asciiWithOffset_success(
String string, String lastIndexOf, int offset, int expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lastIndexOf(indexOfParam, offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "indexOfParam", lastIndexOf, "offset", offset));
+ eval(
+ "s.lastIndexOf(indexOfParam, offset)",
+ ImmutableMap.of("s", string, "indexOfParam", lastIndexOf, "offset", offset));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1097,11 +1051,10 @@ public void lastIndexOf_asciiWithOffset_success(
"{string: 'a😁😑 나😦😁😑다', lastIndexOf: 'a😁😑 나😦😁😑다😁', offset: 8, expectedResult: -1}")
public void lastIndexOf_unicodeWithOffset_success(
String string, String lastIndexOf, int offset, int expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lastIndexOf(indexOfParam, offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(ImmutableMap.of("s", string, "indexOfParam", lastIndexOf, "offset", offset));
+ eval(
+ "s.lastIndexOf(indexOfParam, offset)",
+ ImmutableMap.of("s", string, "indexOfParam", lastIndexOf, "offset", offset));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1115,14 +1068,12 @@ public void lastIndexOf_unicodeWithOffset_success(
@TestParameters("{string: '😁😑 😦', lastIndexOf: '😦', offset: 4}")
public void lastIndexOf_withOffsetOutOfBounds_throwsException(
String string, String lastIndexOf, int offset) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.lastIndexOf(indexOfParam, offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
() ->
- program.eval(
+ eval(
+ "s.lastIndexOf(indexOfParam, offset)",
ImmutableMap.of("s", string, "indexOfParam", lastIndexOf, "offset", offset)));
assertThat(exception).hasMessageThat().contains("lastIndexOf failure: Offset out of range");
@@ -1130,13 +1081,13 @@ public void lastIndexOf_withOffsetOutOfBounds_throwsException(
@Test
public void lastIndexOf_offsetOverflow_throwsException() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.lastIndexOf('t', offset)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("offset", 2147483648L))); // INT_MAX + 1
+ () ->
+ eval(
+ "'test'.lastIndexOf('t', offset)",
+ ImmutableMap.of("offset", 2147483648L))); // INT_MAX + 1
assertThat(exception)
.hasMessageThat()
@@ -1163,13 +1114,8 @@ public void lastIndexOf_offsetOverflow_throwsException() throws Exception {
public void replace_ascii_success(
String string, String searchString, String replacement, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast =
- COMPILER
- .compile(String.format("'%s'.replace('%s', '%s')", string, searchString, replacement))
- .getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval();
+ Object evaluatedResult =
+ eval(String.format("'%s'.replace('%s', '%s')", string, searchString, replacement));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1188,13 +1134,8 @@ public void replace_ascii_success(
public void replace_unicode_success(
String string, String searchString, String replacement, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast =
- COMPILER
- .compile(String.format("'%s'.replace('%s', '%s')", string, searchString, replacement))
- .getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval();
+ Object evaluatedResult =
+ eval(String.format("'%s'.replace('%s', '%s')", string, searchString, replacement));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1273,15 +1214,10 @@ public void replace_unicode_success(
public void replace_ascii_withLimit_success(
String string, String searchString, String replacement, int limit, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast =
- COMPILER
- .compile(
- String.format(
- "'%s'.replace('%s', '%s', %d)", string, searchString, replacement, limit))
- .getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval();
+ Object evaluatedResult =
+ eval(
+ String.format(
+ "'%s'.replace('%s', '%s', %d)", string, searchString, replacement, limit));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1334,28 +1270,23 @@ public void replace_ascii_withLimit_success(
public void replace_unicode_withLimit_success(
String string, String searchString, String replacement, int limit, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast =
- COMPILER
- .compile(
- String.format(
- "'%s'.replace('%s', '%s', %d)", string, searchString, replacement, limit))
- .getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval();
+ Object evaluatedResult =
+ eval(
+ String.format(
+ "'%s'.replace('%s', '%s', %d)", string, searchString, replacement, limit));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@Test
public void replace_limitOverflow_throwsException() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("'test'.replace('','',index)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
CelEvaluationException exception =
assertThrows(
CelEvaluationException.class,
- () -> program.eval(ImmutableMap.of("index", 2147483648L))); // INT_MAX + 1
+ () ->
+ eval(
+ "'test'.replace('','',index)",
+ ImmutableMap.of("index", 2147483648L))); // INT_MAX + 1
assertThat(exception)
.hasMessageThat()
@@ -1406,10 +1337,7 @@ private enum TrimTestCase {
@Test
public void trim_success(@TestParameter TrimTestCase testCase) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.trim()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", testCase.text));
+ Object evaluatedResult = eval("s.trim()", ImmutableMap.of("s", testCase.text));
assertThat(evaluatedResult).isEqualTo(testCase.expectedResult);
}
@@ -1422,10 +1350,7 @@ public void trim_success(@TestParameter TrimTestCase testCase) throws Exception
@TestParameters(
"{string: 'a!@#$%^&*()-_+=?/<>.,;:''\"\\', expectedResult: 'A!@#$%^&*()-_+=?/<>.,;:''\"\\'}")
public void upperAscii_success(String string, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.upperAscii()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("s.upperAscii()", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1441,30 +1366,25 @@ public void upperAscii_success(String string, String expectedResult) throws Exce
@TestParameters("{string: 'a😁b 😑c가😦d', expectedResult: 'A😁B 😑C가😦D'}")
public void upperAscii_outsideAscii_success(String string, String expectedResult)
throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.upperAscii()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("s.upperAscii()", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@Test
public void stringExtension_functionSubset_success() throws Exception {
- CelStringExtensions stringExtensions =
- CelExtensions.strings(Function.CHAR_AT, Function.SUBSTRING);
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder().addLibraries(stringExtensions).build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder().addLibraries(stringExtensions).build();
+ Cel customCel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(CelExtensions.strings(Function.CHAR_AT, Function.SUBSTRING))
+ .addRuntimeLibraries(CelExtensions.strings(Function.CHAR_AT, Function.SUBSTRING))
+ .build();
Object evaluatedResult =
- celRuntime
- .createProgram(
- celCompiler
- .compile("'test'.substring(2) == 'st' && 'hello'.charAt(1) == 'e'")
- .getAst())
- .eval();
+ eval(
+ customCel,
+ "'test'.substring(2) == 'st' && 'hello'.charAt(1) == 'e'",
+ ImmutableMap.of());
assertThat(evaluatedResult).isEqualTo(true);
}
@@ -1476,10 +1396,7 @@ public void stringExtension_functionSubset_success() throws Exception {
@TestParameters("{string: 'hello world', expectedResult: 'dlrow olleh'}")
@TestParameters("{string: 'ab가cd', expectedResult: 'dc가ba'}")
public void reverse_success(String string, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.reverse()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("s.reverse()", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1490,10 +1407,7 @@ public void reverse_success(String string, String expectedResult) throws Excepti
"{string: '\u180e\u200b\u200c\u200d\u2060\ufeff', expectedResult:"
+ " '\ufeff\u2060\u200d\u200c\u200b\u180e'}")
public void reverse_unicode(String string, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("s.reverse()").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("s.reverse()", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1502,14 +1416,14 @@ public void reverse_unicode(String string, String expectedResult) throws Excepti
@TestParameters("{string: 'hello', expectedResult: '\"hello\"'}")
@TestParameters("{string: '', expectedResult: '\"\"'}")
@TestParameters(
- "{string: 'contains \\\"quotes\\\"', expectedResult: '\"contains \\\\\\\"quotes\\\\\\\"\"'}")
- @TestParameters("{string: 'ends with \\\\', expectedResult: '\"ends with \\\\\\\\\"'}")
- @TestParameters("{string: '\\\\ starts with', expectedResult: '\"\\\\\\\\ starts with\"'}")
+ "{string: 'contains \\\\\\\"quotes\\\\\\\"', expectedResult: '\"contains"
+ + " \\\\\\\\\\\\\\\"quotes\\\\\\\\\\\\\\\"\"'}")
+ @TestParameters(
+ "{string: 'ends with \\\\\\\\', expectedResult: '\"ends with \\\\\\\\\\\\\\\\\"'}")
+ @TestParameters(
+ "{string: '\\\\\\\\ starts with', expectedResult: '\"\\\\\\\\\\\\\\\\ starts with\"'}")
public void quote_success(String string, String expectedResult) throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("strings.quote(s)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval(ImmutableMap.of("s", string));
+ Object evaluatedResult = eval("strings.quote(s)", ImmutableMap.of("s", string));
assertThat(evaluatedResult).isEqualTo(expectedResult);
}
@@ -1518,21 +1432,16 @@ public void quote_success(String string, String expectedResult) throws Exception
public void quote_singleWithDoubleQuotes() throws Exception {
String expr = "strings.quote('single-quote with \"double quote\"')";
String expected = "\"\\\"single-quote with \\\\\\\"double quote\\\\\\\"\\\"\"";
- CelAbstractSyntaxTree ast = COMPILER.compile(expr + " == " + expected).getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
- Object evaluatedResult = program.eval();
+ Object evaluatedResult = eval(expr + " == " + expected);
assertThat(evaluatedResult).isEqualTo(true);
}
@Test
public void quote_escapesSpecialCharacters() throws Exception {
- CelAbstractSyntaxTree ast = COMPILER.compile("strings.quote(s)").getAst();
- CelRuntime.Program program = RUNTIME.createProgram(ast);
-
Object evaluatedResult =
- program.eval(
+ eval(
+ "strings.quote(s)",
ImmutableMap.of("s", "\u0007bell\u000Bvtab\bback\ffeed\rret\nline\ttab\\slash 가 😁"));
assertThat(evaluatedResult)
@@ -1541,25 +1450,19 @@ public void quote_escapesSpecialCharacters() throws Exception {
@Test
public void quote_escapesMalformed_endWithHighSurrogate() throws Exception {
- CelRuntime.Program program =
- RUNTIME.createProgram(COMPILER.compile("strings.quote(s)").getAst());
- assertThat(program.eval(ImmutableMap.of("s", "end with high surrogate \uD83D")))
+ assertThat(eval("strings.quote(s)", ImmutableMap.of("s", "end with high surrogate \uD83D")))
.isEqualTo("\"end with high surrogate \uFFFD\"");
}
@Test
public void quote_escapesMalformed_unpairedHighSurrogate() throws Exception {
- CelRuntime.Program program =
- RUNTIME.createProgram(COMPILER.compile("strings.quote(s)").getAst());
- assertThat(program.eval(ImmutableMap.of("s", "bad pair \uD83DA")))
+ assertThat(eval("strings.quote(s)", ImmutableMap.of("s", "bad pair \uD83DA")))
.isEqualTo("\"bad pair \uFFFDA\"");
}
@Test
public void quote_escapesMalformed_unpairedLowSurrogate() throws Exception {
- CelRuntime.Program program =
- RUNTIME.createProgram(COMPILER.compile("strings.quote(s)").getAst());
- assertThat(program.eval(ImmutableMap.of("s", "bad pair \uDC00A")))
+ assertThat(eval("strings.quote(s)", ImmutableMap.of("s", "bad pair \uDC00A")))
.isEqualTo("\"bad pair \uFFFDA\"");
}
@@ -1570,23 +1473,49 @@ public void stringExtension_compileUnallowedFunction_throws() {
.addLibraries(CelExtensions.strings(Function.REPLACE))
.build();
+ // This is a type-check failure.
+ Assume.assumeFalse(isParseOnly);
+ CelValidationResult result = celCompiler.compile("'test'.substring(2) == 'st'");
assertThrows(
CelValidationException.class,
- () -> celCompiler.compile("'test'.substring(2) == 'st'").getAst());
+ () -> result.getAst());
}
@Test
public void stringExtension_evaluateUnallowedFunction_throws() throws Exception {
- CelCompiler celCompiler =
- CelCompilerFactory.standardCelCompilerBuilder()
- .addLibraries(CelExtensions.strings(Function.SUBSTRING))
+ Cel customCompilerCel =
+ runtimeFlavor
+ .builder()
+ .addCompilerLibraries(CelExtensions.strings(Function.SUBSTRING))
.build();
- CelRuntime celRuntime =
- CelRuntimeFactory.standardCelRuntimeBuilder()
- .addLibraries(CelExtensions.strings(Function.REPLACE))
+ Cel customRuntimeCel =
+ runtimeFlavor
+ .builder()
+ .addRuntimeLibraries(CelExtensions.strings(Function.REPLACE))
.build();
- CelAbstractSyntaxTree ast = celCompiler.compile("'test'.substring(2) == 'st'").getAst();
+ CelAbstractSyntaxTree ast =
+ isParseOnly
+ ? customCompilerCel.parse("'test'.substring(2) == 'st'").getAst()
+ : customCompilerCel.compile("'test'.substring(2) == 'st'").getAst();
+
+ assertThrows(CelEvaluationException.class, () -> customRuntimeCel.createProgram(ast).eval());
+ }
+
+ private Object eval(Cel cel, String expression, Map variables) throws Exception {
+ CelAbstractSyntaxTree ast;
+ if (isParseOnly) {
+ ast = cel.parse(expression).getAst();
+ } else {
+ ast = cel.compile(expression).getAst();
+ }
+ return cel.createProgram(ast).eval(variables);
+ }
+
+ private Object eval(String expression) throws Exception {
+ return eval(this.cel, expression, ImmutableMap.of());
+ }
- assertThrows(CelEvaluationException.class, () -> celRuntime.createProgram(ast).eval());
+ private Object eval(String expression, Map variables) throws Exception {
+ return eval(this.cel, expression, variables);
}
}
diff --git a/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel
index 824c918d8..96382b9a9 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel
+++ b/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel
@@ -365,6 +365,7 @@ java_library(
":activation_wrapper",
":planned_interpretable",
"//common/exceptions:runtime_exception",
+ "//common/values:mutable_map_value",
"//runtime:accumulated_unknowns",
"//runtime:concatenated_list_view",
"//runtime:evaluation_exception",
diff --git a/runtime/src/main/java/dev/cel/runtime/planner/EvalFold.java b/runtime/src/main/java/dev/cel/runtime/planner/EvalFold.java
index 2eb30671e..090a8bfae 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/EvalFold.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/EvalFold.java
@@ -15,8 +15,10 @@
package dev.cel.runtime.planner;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.Immutable;
import dev.cel.common.exceptions.CelRuntimeException;
+import dev.cel.common.values.MutableMapValue;
import dev.cel.runtime.AccumulatedUnknowns;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.ConcatenatedListView;
@@ -131,7 +133,7 @@ private Object evalList(Collection> iterRange, Folder folder, ExecutionFrame f
boolean cond = (boolean) condition.eval(folder, frame);
if (!cond) {
folder.computeResult = true;
- return result.eval(folder, frame);
+ return maybeUnwrapAccumulator(result.eval(folder, frame));
}
folder.accuVal = loopStep.eval(folder, frame);
@@ -139,14 +141,16 @@ private Object evalList(Collection> iterRange, Folder folder, ExecutionFrame f
index++;
}
folder.computeResult = true;
- return result.eval(folder, frame);
+ return maybeUnwrapAccumulator(result.eval(folder, frame));
}
private static Object maybeWrapAccumulator(Object val) {
if (val instanceof Collection) {
return new ConcatenatedListView<>((Collection>) val);
}
- // TODO: Introduce mutable map support (for comp v2)
+ if (val instanceof Map) {
+ return MutableMapValue.create((Map, ?>) val);
+ }
return val;
}
@@ -154,8 +158,9 @@ private static Object maybeUnwrapAccumulator(Object val) {
if (val instanceof ConcatenatedListView) {
return ImmutableList.copyOf((ConcatenatedListView>) val);
}
-
- // TODO: Introduce mutable map support (for comp v2)
+ if (val instanceof MutableMapValue) {
+ return ImmutableMap.copyOf((MutableMapValue) val);
+ }
return val;
}
diff --git a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java
index 54ce24417..73492d126 100644
--- a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java
+++ b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java
@@ -149,9 +149,10 @@ public void toRuntimeBuilder_propertiesCopied() {
assertThat(newRuntimeBuilder.standardFunctionBuilder.build())
.containsExactly(intFunction, equalsOperator)
.inOrder();
- assertThat(newRuntimeBuilder.customFunctionBindings).hasSize(2);
+ assertThat(newRuntimeBuilder.customFunctionBindings).hasSize(3);
assertThat(newRuntimeBuilder.customFunctionBindings).containsKey("string_isEmpty");
assertThat(newRuntimeBuilder.customFunctionBindings).containsKey("list_sets_intersects_list");
+ assertThat(newRuntimeBuilder.customFunctionBindings).containsKey("sets.intersects");
}
@Test