diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index c4ee4fa7..468c0af9 100644 --- a/checker/src/test/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/test/java/dev/cel/checker/BUILD.bazel @@ -31,6 +31,7 @@ java_library( "//common/internal:errors", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/types", + "//common/types:cel_proto_types", "//common/types:cel_types", "//common/types:json", "//common/types:message_type_provider", diff --git a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java index eaf4aa2c..529a735f 100644 --- a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java +++ b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java @@ -14,10 +14,10 @@ package dev.cel.checker; +import static dev.cel.common.types.CelProtoTypes.createOptionalType; import static dev.cel.common.types.CelTypes.createList; import static dev.cel.common.types.CelTypes.createMap; import static dev.cel.common.types.CelTypes.createMessage; -import static dev.cel.common.types.CelTypes.createOptionalType; import static dev.cel.common.types.CelTypes.createTypeParam; import static dev.cel.common.types.CelTypes.createWrapper; import static dev.cel.common.types.CelTypes.format; diff --git a/common/src/main/java/dev/cel/common/types/BUILD.bazel b/common/src/main/java/dev/cel/common/types/BUILD.bazel index 4f402941..3812755c 100644 --- a/common/src/main/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/types/BUILD.bazel @@ -81,6 +81,22 @@ java_library( ], ) +java_library( + name = "cel_proto_types", + srcs = ["CelProtoTypes.java"], + tags = [ + ], + deps = [ + ":cel_internal_types", + ":cel_types", + ":type_providers", + ":types", + "@cel_spec//proto/cel/expr:expr_java_proto", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + ], +) + java_library( name = "cel_v1alpha1_types", srcs = ["CelV1AlphaTypes.java"], diff --git a/common/src/main/java/dev/cel/common/types/CelProtoTypes.java b/common/src/main/java/dev/cel/common/types/CelProtoTypes.java new file mode 100644 index 00000000..1c240ca1 --- /dev/null +++ b/common/src/main/java/dev/cel/common/types/CelProtoTypes.java @@ -0,0 +1,281 @@ +// Copyright 2024 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.types; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import dev.cel.expr.Type; +import dev.cel.expr.Type.AbstractType; +import dev.cel.expr.Type.PrimitiveType; +import dev.cel.expr.Type.WellKnownType; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Empty; +import com.google.protobuf.NullValue; + +/** + * Utility class for working with {@link Type}. + * + *

This is equivalent to {@link CelTypes}, except this works specifically with canonical CEL expr + * protos. + */ +public final class CelProtoTypes { + + public static final Type ERROR = Type.newBuilder().setError(Empty.getDefaultInstance()).build(); + public static final Type DYN = Type.newBuilder().setDyn(Empty.getDefaultInstance()).build(); + public static final Type NULL_TYPE = Type.newBuilder().setNull(NullValue.NULL_VALUE).build(); + public static final Type BOOL = create(PrimitiveType.BOOL); + public static final Type BYTES = create(PrimitiveType.BYTES); + public static final Type STRING = create(PrimitiveType.STRING); + public static final Type DOUBLE = create(PrimitiveType.DOUBLE); + public static final Type UINT64 = create(PrimitiveType.UINT64); + public static final Type INT64 = create(PrimitiveType.INT64); + public static final Type ANY = create(WellKnownType.ANY); + public static final Type TIMESTAMP = create(WellKnownType.TIMESTAMP); + public static final Type DURATION = create(WellKnownType.DURATION); + + private static final ImmutableMap SIMPLE_CEL_KIND_TO_TYPE = + ImmutableMap.builder() + .put(CelKind.ERROR, ERROR) + .put(CelKind.DYN, DYN) + .put(CelKind.ANY, ANY) + .put(CelKind.BOOL, BOOL) + .put(CelKind.BYTES, BYTES) + .put(CelKind.DOUBLE, DOUBLE) + .put(CelKind.DURATION, DURATION) + .put(CelKind.INT, INT64) + .put(CelKind.NULL_TYPE, NULL_TYPE) + .put(CelKind.STRING, STRING) + .put(CelKind.TIMESTAMP, TIMESTAMP) + .put(CelKind.UINT, UINT64) + .buildOrThrow(); + + private static final ImmutableMap PROTOBUF_TYPE_TO_CEL_TYPE_MAP = + ImmutableMap.builder() + .put(BOOL, SimpleType.BOOL) + .put(BYTES, SimpleType.BYTES) + .put(DOUBLE, SimpleType.DOUBLE) + .put(INT64, SimpleType.INT) + .put(STRING, SimpleType.STRING) + .put(UINT64, SimpleType.UINT) + .put(ANY, SimpleType.ANY) + .put(DURATION, SimpleType.DURATION) + .put(TIMESTAMP, SimpleType.TIMESTAMP) + .put(DYN, SimpleType.DYN) + .put(NULL_TYPE, SimpleType.NULL_TYPE) + .put(ERROR, SimpleType.ERROR) + .buildOrThrow(); + + /** Create a primitive {@code Type}. */ + public static Type create(PrimitiveType type) { + return Type.newBuilder().setPrimitive(type).build(); + } + + /** Create a well-known {@code Type}. */ + public static Type create(WellKnownType type) { + return Type.newBuilder().setWellKnown(type).build(); + } + + /** Create a type {@code Type}. */ + public static Type create(Type target) { + return Type.newBuilder().setType(target).build(); + } + + /** Create a list with {@code elemType}. */ + public static Type createList(Type elemType) { + return Type.newBuilder().setListType(Type.ListType.newBuilder().setElemType(elemType)).build(); + } + + /** Create a map with {@code keyType} and {@code valueType}. */ + public static Type createMap(Type keyType, Type valueType) { + return Type.newBuilder() + .setMapType(Type.MapType.newBuilder().setKeyType(keyType).setValueType(valueType)) + .build(); + } + + /** Create a message {@code Type} for {@code messageName}. */ + public static Type createMessage(String messageName) { + return Type.newBuilder().setMessageType(messageName).build(); + } + + /** Create a message {@code Type} for {@code Descriptor}. */ + public static Type createMessage(Descriptor descriptor) { + return createMessage(descriptor.getFullName()); + } + + /** Create a type param {@code Type}. */ + public static Type createTypeParam(String name) { + return Type.newBuilder().setTypeParam(name).build(); + } + + /** Create a wrapper type for the {@code primitive}. */ + public static Type createWrapper(PrimitiveType primitive) { + return Type.newBuilder().setWrapper(primitive).build(); + } + + /** Create a wrapper type where the input is a {@code Type} of primitive types. */ + public static Type createWrapper(Type type) { + Preconditions.checkArgument(type.getTypeKindCase() == Type.TypeKindCase.PRIMITIVE); + return createWrapper(type.getPrimitive()); + } + + /** + * Create an abstract type indicating that the parameterized type may be contained within the + * object. + */ + public static Type createOptionalType(Type paramType) { + return Type.newBuilder() + .setAbstractType( + AbstractType.newBuilder() + .setName(OptionalType.NAME) + .addParameterTypes(paramType) + .build()) + .build(); + } + + /** Checks if the provided parameter is an optional type */ + public static boolean isOptionalType(Type type) { + return type.hasAbstractType() && type.getAbstractType().getName().equals(OptionalType.NAME); + } + + /** + * Method to adapt a simple {@code Type} into a {@code String} representation. + * + *

This method can also format global functions. See the {@link CelTypes#formatFunction} + * methods for richer control over function formatting. + */ + public static String format(Type type) { + return CelTypes.format(typeToCelType(type), /* typeParamToDyn= */ false); + } + + /** Converts a Protobuf type into CEL native type. */ + public static Type celTypeToType(CelType celType) { + Type type = SIMPLE_CEL_KIND_TO_TYPE.get(celType.kind()); + if (type != null) { + if (celType instanceof NullableType) { + return createWrapper(type); + } + return type; + } + + switch (celType.kind()) { + case UNSPECIFIED: + return Type.getDefaultInstance(); + case LIST: + ListType listType = (ListType) celType; + if (listType.hasElemType()) { + return createList(celTypeToType(listType.elemType())); + } else { + // TODO: Exists for compatibility reason only. Remove after callers have been + // migrated. + return Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build(); + } + case MAP: + MapType mapType = (MapType) celType; + return createMap(celTypeToType(mapType.keyType()), celTypeToType(mapType.valueType())); + case OPAQUE: + if (celType.name().equals("function")) { + Type.FunctionType.Builder functionBuilder = Type.FunctionType.newBuilder(); + if (!celType.parameters().isEmpty()) { + functionBuilder + .setResultType(celTypeToType(celType.parameters().get(0))) + .addAllArgTypes( + celType.parameters().stream() + .skip(1) + .map(CelProtoTypes::celTypeToType) + .collect(toImmutableList())); + } + return Type.newBuilder().setFunction(functionBuilder).build(); + } else { + return Type.newBuilder() + .setAbstractType( + Type.AbstractType.newBuilder() + .setName(celType.name()) + .addAllParameterTypes( + celType.parameters().stream() + .map(CelProtoTypes::celTypeToType) + .collect(toImmutableList()))) + .build(); + } + case STRUCT: + return createMessage(celType.name()); + case TYPE: + TypeType typeType = (TypeType) celType; + return create(celTypeToType(typeType.type())); + case TYPE_PARAM: + return createTypeParam(celType.name()); + default: + throw new IllegalArgumentException(String.format("Unsupported type: %s", celType)); + } + } + + /** Converts a Protobuf type to CEL native type. */ + public static CelType typeToCelType(Type type) { + CelType celType = PROTOBUF_TYPE_TO_CEL_TYPE_MAP.get(type); + if (celType != null) { + return celType; + } + + switch (type.getTypeKindCase()) { + case TYPEKIND_NOT_SET: + return UnspecifiedType.create(); + case WRAPPER: + return NullableType.create(typeToCelType(create(type.getWrapper()))); + case MESSAGE_TYPE: + return StructTypeReference.create(type.getMessageType()); + case LIST_TYPE: + Type.ListType listType = type.getListType(); + if (listType.hasElemType()) { + return ListType.create(typeToCelType(listType.getElemType())); + } else { + // TODO: Exists for compatibility reason only. Remove after callers have been + // migrated. + return ListType.create(); + } + case MAP_TYPE: + Type.MapType mapType = type.getMapType(); + return MapType.create( + typeToCelType(mapType.getKeyType()), typeToCelType(mapType.getValueType())); + case TYPE_PARAM: + return TypeParamType.create(type.getTypeParam()); + case ABSTRACT_TYPE: + Type.AbstractType abstractType = type.getAbstractType(); + ImmutableList params = + abstractType.getParameterTypesList().stream() + .map(CelProtoTypes::typeToCelType) + .collect(toImmutableList()); + if (abstractType.getName().equals(OptionalType.NAME)) { + return OptionalType.create(params.get(0)); + } + return OpaqueType.create(abstractType.getName(), params); + case TYPE: + return TypeType.create(typeToCelType(type.getType())); + case FUNCTION: + Type.FunctionType functionType = type.getFunction(); + return CelTypes.createFunctionType( + typeToCelType(functionType.getResultType()), + functionType.getArgTypesList().stream() + .map(CelProtoTypes::typeToCelType) + .collect(toImmutableList())); + default: + // Add more cases as needed. + throw new IllegalArgumentException(String.format("Unsupported type: %s", type)); + } + } + + private CelProtoTypes() {} +} diff --git a/common/src/main/java/dev/cel/common/types/CelTypes.java b/common/src/main/java/dev/cel/common/types/CelTypes.java index 1d178214..f4d220bc 100644 --- a/common/src/main/java/dev/cel/common/types/CelTypes.java +++ b/common/src/main/java/dev/cel/common/types/CelTypes.java @@ -17,10 +17,8 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import dev.cel.expr.Type; -import dev.cel.expr.Type.AbstractType; import dev.cel.expr.Type.PrimitiveType; import dev.cel.expr.Type.WellKnownType; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -54,22 +52,77 @@ public final class CelTypes { public static final String UINT32_WRAPPER_MESSAGE = "google.protobuf.UInt32Value"; public static final String UINT64_WRAPPER_MESSAGE = "google.protobuf.UInt64Value"; - // Static types. + /** + * TODO: Remove once clients have been migrated. + * + * @deprecated Use {@link CelProtoTypes#ERROR} instead. + */ + @Deprecated public static final Type ERROR = Type.newBuilder().setError(Empty.getDefaultInstance()).build(); + + /** + * @deprecated Use {@link CelProtoTypes#DYN} instead. + */ + @Deprecated public static final Type DYN = Type.newBuilder().setDyn(Empty.getDefaultInstance()).build(); + + /** + * @deprecated Use {@link CelProtoTypes#NULL_TYPE} instead. + */ + @Deprecated public static final Type NULL_TYPE = Type.newBuilder().setNull(NullValue.NULL_VALUE).build(); - public static final Type BOOL = create(PrimitiveType.BOOL); - public static final Type BYTES = create(PrimitiveType.BYTES); - public static final Type STRING = create(PrimitiveType.STRING); - public static final Type DOUBLE = create(PrimitiveType.DOUBLE); - public static final Type UINT64 = create(PrimitiveType.UINT64); - public static final Type INT64 = create(PrimitiveType.INT64); - public static final Type ANY = create(WellKnownType.ANY); - public static final Type TIMESTAMP = create(WellKnownType.TIMESTAMP); - public static final Type DURATION = create(WellKnownType.DURATION); - - /** Map of well-known proto messages and their CEL {@code Type} equivalents. */ - static final ImmutableMap WELL_KNOWN_TYPE_MAP = + + /** + * @deprecated Use {@link CelProtoTypes#BOOL} instead. + */ + @Deprecated public static final Type BOOL = create(PrimitiveType.BOOL); + + /** + * @deprecated Use {@link CelProtoTypes#BYTES} instead. + */ + @Deprecated public static final Type BYTES = create(PrimitiveType.BYTES); + + /** + * @deprecated Use {@link CelProtoTypes#STRING} instead. + */ + @Deprecated public static final Type STRING = create(PrimitiveType.STRING); + + /** + * @deprecated Use {@link CelProtoTypes#DOUBLE} instead. + */ + @Deprecated public static final Type DOUBLE = create(PrimitiveType.DOUBLE); + + /** + * @deprecated Use {@link CelProtoTypes#UINT64} instead. + */ + @Deprecated public static final Type UINT64 = create(PrimitiveType.UINT64); + + /** + * @deprecated Use {@link CelProtoTypes#INT64} instead. + */ + @Deprecated public static final Type INT64 = create(PrimitiveType.INT64); + + /** + * @deprecated Use {@link CelProtoTypes#ANY} instead. + */ + @Deprecated public static final Type ANY = create(WellKnownType.ANY); + + /** + * @deprecated Use {@link CelProtoTypes#TIMESTAMP} instead. + */ + @Deprecated public static final Type TIMESTAMP = create(WellKnownType.TIMESTAMP); + + /** + * @deprecated Use {@link CelProtoTypes#DURATION} instead. + */ + @Deprecated public static final Type DURATION = create(WellKnownType.DURATION); + + /** + * TODO: Remove once clients have been migrated. + * + *

Map of well-known proto messages and their CEL {@code Type} equivalents. + */ + private static final ImmutableMap WELL_KNOWN_TYPE_MAP = ImmutableMap.builder() .put(DOUBLE_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.DOUBLE)) .put(FLOAT_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.DOUBLE)) @@ -107,7 +160,8 @@ public final class CelTypes { .put(VALUE_MESSAGE, SimpleType.DYN) .buildOrThrow(); - static final ImmutableMap SIMPLE_CEL_KIND_TO_TYPE = + /** TODO: Remove once clients have been migrated. */ + private static final ImmutableMap SIMPLE_CEL_KIND_TO_TYPE = ImmutableMap.builder() .put(CelKind.ERROR, CelTypes.ERROR) .put(CelKind.DYN, CelTypes.DYN) @@ -123,6 +177,7 @@ public final class CelTypes { .put(CelKind.UINT, CelTypes.UINT64) .buildOrThrow(); + /** TODO: Remove once clients have been migrated. */ private static final ImmutableMap PROTOBUF_TYPE_TO_CEL_TYPE_MAP = ImmutableMap.builder() .put(CelTypes.BOOL, SimpleType.BOOL) @@ -139,27 +194,40 @@ public final class CelTypes { .put(CelTypes.ERROR, SimpleType.ERROR) .buildOrThrow(); - /** Create a primitive {@code Type}. */ + /** + * Create a primitive {@code Type}. + * + * @deprecated Use {@link CelProtoTypes#create(PrimitiveType)} instead. + */ + @Deprecated public static Type create(PrimitiveType type) { return Type.newBuilder().setPrimitive(type).build(); } - /** Create a well-known {@code Type}. */ + /** + * Create a well-known {@code Type}. + * + * @deprecated Use {@link CelProtoTypes#create(WellKnownType)} instead. + */ + @Deprecated public static Type create(WellKnownType type) { return Type.newBuilder().setWellKnown(type).build(); } /** Create a type {@code Type}. */ + @Deprecated public static Type create(Type target) { return Type.newBuilder().setType(target).build(); } /** Create a list with {@code elemType}. */ + @Deprecated public static Type createList(Type elemType) { return Type.newBuilder().setListType(Type.ListType.newBuilder().setElemType(elemType)).build(); } /** Create a map with {@code keyType} and {@code valueType}. */ + @Deprecated public static Type createMap(Type keyType, Type valueType) { return Type.newBuilder() .setMapType(Type.MapType.newBuilder().setKeyType(keyType).setValueType(valueType)) @@ -167,26 +235,31 @@ public static Type createMap(Type keyType, Type valueType) { } /** Create a message {@code Type} for {@code messageName}. */ + @Deprecated public static Type createMessage(String messageName) { return Type.newBuilder().setMessageType(messageName).build(); } /** Create a message {@code Type} for {@code Descriptor}. */ + @Deprecated public static Type createMessage(Descriptor descriptor) { return createMessage(descriptor.getFullName()); } /** Create a type param {@code Type}. */ + @Deprecated public static Type createTypeParam(String name) { return Type.newBuilder().setTypeParam(name).build(); } /** Create a wrapper type for the {@code primitive}. */ + @Deprecated public static Type createWrapper(PrimitiveType primitive) { return Type.newBuilder().setWrapper(primitive).build(); } /** Create a wrapper type where the input is a {@code Type} of primitive types. */ + @Deprecated public static Type createWrapper(Type type) { Preconditions.checkArgument(type.getTypeKindCase() == Type.TypeKindCase.PRIMITIVE); return createWrapper(type.getPrimitive()); @@ -210,26 +283,6 @@ public static boolean isWrapperType(String typeName) { } } - /** - * Create an abstract type indicating that the parameterized type may be contained within the - * object. - */ - @VisibleForTesting - public static Type createOptionalType(Type paramType) { - return Type.newBuilder() - .setAbstractType( - AbstractType.newBuilder() - .setName(OptionalType.NAME) - .addParameterTypes(paramType) - .build()) - .build(); - } - - /** Checks if the provided parameter is an optional type */ - public static boolean isOptionalType(Type type) { - return type.hasAbstractType() && type.getAbstractType().getName().equals(OptionalType.NAME); - } - /** * Create an abstract type with an expected result type (first argument in the parameter) and the * argument types. @@ -267,7 +320,7 @@ public static String format(CelType type) { return format(type, /* typeParamToDyn= */ false); } - private static String format(CelType type, boolean typeParamToDyn) { + static String format(CelType type, boolean typeParamToDyn) { if (type instanceof NullableType) { return String.format( "wrapper(%s)", format(((NullableType) type).targetType(), typeParamToDyn)); @@ -370,8 +423,12 @@ public static Optional getWellKnownCelType(String typeName) { return Optional.ofNullable(WELL_KNOWN_CEL_TYPE_MAP.getOrDefault(typeName, null)); } - /** Converts a Protobuf type into CEL native type. */ - @Internal + /** + * Converts a Protobuf type into CEL native type. + * + * @deprecated Use {@link CelProtoTypes#celTypeToType(CelType)} instead}. + */ + @Deprecated public static Type celTypeToType(CelType celType) { Type type = SIMPLE_CEL_KIND_TO_TYPE.get(celType.kind()); if (type != null) { @@ -432,8 +489,12 @@ public static Type celTypeToType(CelType celType) { } } - /** Converts a Protobuf type to CEL native type. */ - @Internal + /** + * Converts a Protobuf type to CEL native type. + * + * @deprecated Use {@link CelProtoTypes#typeToCelType(Type)} instead}. + */ + @Deprecated public static CelType typeToCelType(Type type) { CelType celType = PROTOBUF_TYPE_TO_CEL_TYPE_MAP.get(type); if (celType != null) { diff --git a/common/src/test/java/dev/cel/common/types/BUILD.bazel b/common/src/test/java/dev/cel/common/types/BUILD.bazel index 42da475c..541a77ec 100644 --- a/common/src/test/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/types/BUILD.bazel @@ -11,6 +11,7 @@ java_library( "//:java_truth", "//common/types", "//common/types:cel_internal_types", + "//common/types:cel_proto_types", "//common/types:cel_types", "//common/types:message_type_provider", "//common/types:type_providers", diff --git a/common/src/test/java/dev/cel/common/types/CelProtoTypesTest.java b/common/src/test/java/dev/cel/common/types/CelProtoTypesTest.java new file mode 100644 index 00000000..bcddd03f --- /dev/null +++ b/common/src/test/java/dev/cel/common/types/CelProtoTypesTest.java @@ -0,0 +1,122 @@ +// Copyright 2024 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.types; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; + +import dev.cel.expr.Type; +import dev.cel.expr.Type.AbstractType; +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 org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelProtoTypesTest { + + @Test + public void isOptionalType_true() { + Type optionalType = CelProtoTypes.createOptionalType(CelProtoTypes.INT64); + + assertThat(CelProtoTypes.isOptionalType(optionalType)).isTrue(); + } + + @Test + public void isOptionalType_false() { + Type notOptionalType = + Type.newBuilder() + .setAbstractType(AbstractType.newBuilder().setName("notOptional").build()) + .build(); + + assertThat(CelProtoTypes.isOptionalType(notOptionalType)).isFalse(); + } + + @Test + public void createOptionalType() { + Type optionalType = CelProtoTypes.createOptionalType(CelProtoTypes.INT64); + + assertThat(optionalType.hasAbstractType()).isTrue(); + assertThat(optionalType.getAbstractType().getName()).isEqualTo("optional_type"); + assertThat(optionalType.getAbstractType().getParameterTypesCount()).isEqualTo(1); + assertThat(optionalType.getAbstractType().getParameterTypes(0)).isEqualTo(CelProtoTypes.INT64); + } + + private enum TestCases { + UNSPECIFIED(UnspecifiedType.create(), Type.getDefaultInstance()), + STRING(SimpleType.STRING, CelProtoTypes.STRING), + INT(NullableType.create(SimpleType.INT), CelProtoTypes.createWrapper(CelProtoTypes.INT64)), + UINT(NullableType.create(SimpleType.UINT), CelProtoTypes.createWrapper(CelProtoTypes.UINT64)), + DOUBLE( + NullableType.create(SimpleType.DOUBLE), CelProtoTypes.createWrapper(CelProtoTypes.DOUBLE)), + BOOL(NullableType.create(SimpleType.BOOL), CelProtoTypes.createWrapper(CelProtoTypes.BOOL)), + BYTES(SimpleType.BYTES, CelProtoTypes.BYTES), + ANY(SimpleType.ANY, CelProtoTypes.ANY), + LIST( + ListType.create(), + Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build()), + DYN(ListType.create(SimpleType.DYN), CelProtoTypes.createList(CelProtoTypes.DYN)), + ENUM(EnumType.create("CustomEnum", ImmutableMap.of()), CelProtoTypes.INT64), + STRUCT_TYPE_REF( + StructTypeReference.create("MyCustomStruct"), + CelProtoTypes.createMessage("MyCustomStruct")), + OPAQUE( + OpaqueType.create("vector", SimpleType.UINT), + Type.newBuilder() + .setAbstractType( + AbstractType.newBuilder().setName("vector").addParameterTypes(CelProtoTypes.UINT64)) + .build()), + TYPE_PARAM(TypeParamType.create("T"), CelProtoTypes.createTypeParam("T")), + FUNCTION( + CelTypes.createFunctionType( + SimpleType.INT, ImmutableList.of(SimpleType.STRING, SimpleType.UINT)), + Type.newBuilder() + .setFunction( + Type.FunctionType.newBuilder() + .setResultType(CelProtoTypes.INT64) + .addAllArgTypes(ImmutableList.of(CelProtoTypes.STRING, CelProtoTypes.UINT64))) + .build()), + OPTIONAL( + OptionalType.create(SimpleType.INT), CelProtoTypes.createOptionalType(CelProtoTypes.INT64)), + TYPE( + TypeType.create(MapType.create(SimpleType.STRING, SimpleType.STRING)), + CelProtoTypes.create(CelProtoTypes.createMap(CelProtoTypes.STRING, CelProtoTypes.STRING))); + + private final CelType celType; + private final Type type; + + TestCases(CelType celType, Type type) { + this.celType = celType; + this.type = type; + } + } + + @Test + public void celTypeToType(@TestParameter TestCases testCase) { + assertThat(CelProtoTypes.celTypeToType(testCase.celType)).isEqualTo(testCase.type); + } + + @Test + public void typeToCelType(@TestParameter TestCases testCase) { + if (testCase.celType instanceof EnumType) { + // (b/178627883) Strongly typed enum is not supported yet + return; + } + + assertThat(CelProtoTypes.typeToCelType(testCase.type)).isEqualTo(testCase.celType); + } +} diff --git a/common/src/test/java/dev/cel/common/types/CelTypesTest.java b/common/src/test/java/dev/cel/common/types/CelTypesTest.java index da5c556c..ae6e0808 100644 --- a/common/src/test/java/dev/cel/common/types/CelTypesTest.java +++ b/common/src/test/java/dev/cel/common/types/CelTypesTest.java @@ -15,10 +15,8 @@ package dev.cel.common.types; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import dev.cel.expr.Type; -import dev.cel.expr.Type.AbstractType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -29,52 +27,6 @@ @RunWith(TestParameterInjector.class) public final class CelTypesTest { - private enum TestCases { - UNSPECIFIED(UnspecifiedType.create(), Type.getDefaultInstance()), - STRING(SimpleType.STRING, CelTypes.STRING), - INT(NullableType.create(SimpleType.INT), CelTypes.createWrapper(CelTypes.INT64)), - UINT(NullableType.create(SimpleType.UINT), CelTypes.createWrapper(CelTypes.UINT64)), - DOUBLE(NullableType.create(SimpleType.DOUBLE), CelTypes.createWrapper(CelTypes.DOUBLE)), - BOOL(NullableType.create(SimpleType.BOOL), CelTypes.createWrapper(CelTypes.BOOL)), - BYTES(SimpleType.BYTES, CelTypes.BYTES), - ANY(SimpleType.ANY, CelTypes.ANY), - LIST( - ListType.create(), - Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build()), - DYN(ListType.create(SimpleType.DYN), CelTypes.createList(CelTypes.DYN)), - ENUM(EnumType.create("CustomEnum", ImmutableMap.of()), CelTypes.INT64), - STRUCT_TYPE_REF( - StructTypeReference.create("MyCustomStruct"), CelTypes.createMessage("MyCustomStruct")), - OPAQUE( - OpaqueType.create("vector", SimpleType.UINT), - Type.newBuilder() - .setAbstractType( - AbstractType.newBuilder().setName("vector").addParameterTypes(CelTypes.UINT64)) - .build()), - TYPE_PARAM(TypeParamType.create("T"), CelTypes.createTypeParam("T")), - FUNCTION( - CelTypes.createFunctionType( - SimpleType.INT, ImmutableList.of(SimpleType.STRING, SimpleType.UINT)), - Type.newBuilder() - .setFunction( - Type.FunctionType.newBuilder() - .setResultType(CelTypes.INT64) - .addAllArgTypes(ImmutableList.of(CelTypes.STRING, CelTypes.UINT64))) - .build()), - OPTIONAL(OptionalType.create(SimpleType.INT), CelTypes.createOptionalType(CelTypes.INT64)), - TYPE( - TypeType.create(MapType.create(SimpleType.STRING, SimpleType.STRING)), - CelTypes.create(CelTypes.createMap(CelTypes.STRING, CelTypes.STRING))); - - private final CelType celType; - private final Type type; - - TestCases(CelType celType, Type type) { - this.celType = celType; - this.type = type; - } - } - @Test public void isWellKnownType_true() { assertThat(CelTypes.isWellKnownType(CelTypes.ANY_MESSAGE)).isTrue(); @@ -85,48 +37,6 @@ public void isWellKnownType_false() { assertThat(CelTypes.isWellKnownType("CustomType")).isFalse(); } - @Test - public void createOptionalType() { - Type optionalType = CelTypes.createOptionalType(CelTypes.INT64); - - assertThat(optionalType.hasAbstractType()).isTrue(); - assertThat(optionalType.getAbstractType().getName()).isEqualTo("optional_type"); - assertThat(optionalType.getAbstractType().getParameterTypesCount()).isEqualTo(1); - assertThat(optionalType.getAbstractType().getParameterTypes(0)).isEqualTo(CelTypes.INT64); - } - - @Test - public void isOptionalType_true() { - Type optionalType = CelTypes.createOptionalType(CelTypes.INT64); - - assertThat(CelTypes.isOptionalType(optionalType)).isTrue(); - } - - @Test - public void isOptionalType_false() { - Type notOptionalType = - Type.newBuilder() - .setAbstractType(AbstractType.newBuilder().setName("notOptional").build()) - .build(); - - assertThat(CelTypes.isOptionalType(notOptionalType)).isFalse(); - } - - @Test - public void celTypeToType(@TestParameter TestCases testCase) { - assertThat(CelTypes.celTypeToType(testCase.celType)).isEqualTo(testCase.type); - } - - @Test - public void typeToCelType(@TestParameter TestCases testCase) { - if (testCase.celType instanceof EnumType) { - // (b/178627883) Strongly typed enum is not supported yet - return; - } - - assertThat(CelTypes.typeToCelType(testCase.type)).isEqualTo(testCase.celType); - } - private enum FormatTestCases { UNSPECIFIED(UnspecifiedType.create(), ""), STRING(SimpleType.STRING, "string"), @@ -171,9 +81,9 @@ public void format_withCelType(@TestParameter FormatTestCases testCase) { @Test public void format_withType(@TestParameter FormatTestCases testCase) { - Type type = CelTypes.celTypeToType(testCase.celType); + Type type = CelProtoTypes.celTypeToType(testCase.celType); - assertThat(CelTypes.format(type)).isEqualTo(testCase.formattedString); + assertThat(CelProtoTypes.format(type)).isEqualTo(testCase.formattedString); } @Test diff --git a/common/types/BUILD.bazel b/common/types/BUILD.bazel index 76904d76..1802b054 100644 --- a/common/types/BUILD.bazel +++ b/common/types/BUILD.bazel @@ -39,6 +39,11 @@ java_library( exports = ["//common/src/main/java/dev/cel/common/types:cel_types"], ) +java_library( + name = "cel_proto_types", + exports = ["//common/src/main/java/dev/cel/common/types:cel_proto_types"], +) + java_library( name = "cel_v1alpha1_types", visibility = ["//visibility:public"],