diff --git a/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptor.java b/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptor.java index c066bb18e..fcee6215a 100644 --- a/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptor.java +++ b/protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptor.java @@ -18,6 +18,7 @@ import com.google.errorprone.annotations.Immutable; import com.google.protobuf.MessageLite; +import com.google.protobuf.WireFormat; import dev.cel.common.annotations.Internal; import java.util.Collections; import java.util.HashMap; @@ -184,24 +185,95 @@ public enum JavaType { *

This is exactly the same as com.google.protobuf.Descriptors#Type */ public enum Type { - DOUBLE, - FLOAT, - INT64, - UINT64, - INT32, - FIXED64, - FIXED32, - BOOL, - STRING, - GROUP, - MESSAGE, - BYTES, - UINT32, - ENUM, - SFIXED32, - SFIXED64, - SINT32, - SINT64 + DOUBLE(1, WireFormat.FieldType.DOUBLE), + FLOAT(2, WireFormat.FieldType.FLOAT), + INT64(3, WireFormat.FieldType.INT64), + UINT64(4, WireFormat.FieldType.UINT64), + INT32(5, WireFormat.FieldType.INT32), + FIXED64(6, WireFormat.FieldType.FIXED64), + FIXED32(7, WireFormat.FieldType.FIXED32), + BOOL(8, WireFormat.FieldType.BOOL), + STRING(9, WireFormat.FieldType.STRING), + GROUP(10, WireFormat.FieldType.GROUP), + MESSAGE(11, WireFormat.FieldType.MESSAGE), + BYTES(12, WireFormat.FieldType.BYTES), + UINT32(13, WireFormat.FieldType.UINT32), + ENUM(14, WireFormat.FieldType.ENUM), + SFIXED32(15, WireFormat.FieldType.SFIXED32), + SFIXED64(16, WireFormat.FieldType.SFIXED64), + SINT32(17, WireFormat.FieldType.SINT32), + SINT64(18, WireFormat.FieldType.SINT64); + + private final int number; + private final WireFormat.FieldType wireFormatFieldType; + + /** Gets the type number corresponding to {@code FieldDescriptorProto.Type#getNumber()}. */ + public int getNumber() { + return number; + } + + /** Converts this type to the corresponding {@link WireFormat.FieldType}. */ + public WireFormat.FieldType toWireFormatFieldType() { + return wireFormatFieldType; + } + + /** + * Returns the {@link Type} for the specified protobuf type number. + * + * @throws IllegalArgumentException if the number does not correspond to a valid protobuf + * type. + */ + public static Type forNumber(int number) { + switch (number) { + case 1: + return DOUBLE; + case 2: + return FLOAT; + case 3: + return INT64; + case 4: + return UINT64; + case 5: + return INT32; + case 6: + return FIXED64; + case 7: + return FIXED32; + case 8: + return BOOL; + case 9: + return STRING; + case 10: + return GROUP; + case 11: + return MESSAGE; + case 12: + return BYTES; + case 13: + return UINT32; + case 14: + return ENUM; + case 15: + return SFIXED32; + case 16: + return SFIXED64; + case 17: + return SINT32; + case 18: + return SINT64; + default: + throw new IllegalArgumentException("Unsupported proto type code: " + number); + } + } + + private Type(int number, WireFormat.FieldType wireFormatFieldType) { + this.number = number; + this.wireFormatFieldType = Objects.requireNonNull(wireFormatFieldType); + } + } + + public int getFieldNumber() { + return fieldNumber; } public String getFieldName() { @@ -269,9 +341,9 @@ public FieldLiteDescriptor( String fieldProtoTypeName) { this.fieldNumber = fieldNumber; this.fieldName = Objects.requireNonNull(fieldName); - this.javaType = javaType; - this.encodingType = encodingType; - this.protoFieldType = protoFieldType; + this.javaType = Objects.requireNonNull(javaType); + this.encodingType = Objects.requireNonNull(encodingType); + this.protoFieldType = Objects.requireNonNull(protoFieldType); this.isPacked = isPacked; this.fieldProtoTypeName = Objects.requireNonNull(fieldProtoTypeName); } diff --git a/protobuf/src/test/java/dev/cel/protobuf/BUILD.bazel b/protobuf/src/test/java/dev/cel/protobuf/BUILD.bazel index 58e298b29..635379aab 100644 --- a/protobuf/src/test/java/dev/cel/protobuf/BUILD.bazel +++ b/protobuf/src/test/java/dev/cel/protobuf/BUILD.bazel @@ -16,6 +16,7 @@ java_test( "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto_lite", "@maven//:com_google_testparameterinjector_test_parameter_injector", "@maven//:junit_junit", + "@maven_android//:com_google_protobuf_protobuf_javalite", ], ) diff --git a/protobuf/src/test/java/dev/cel/protobuf/CelLiteDescriptorTest.java b/protobuf/src/test/java/dev/cel/protobuf/CelLiteDescriptorTest.java index 1ceed29bb..95dacd6ef 100644 --- a/protobuf/src/test/java/dev/cel/protobuf/CelLiteDescriptorTest.java +++ b/protobuf/src/test/java/dev/cel/protobuf/CelLiteDescriptorTest.java @@ -15,7 +15,10 @@ package dev.cel.protobuf; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; +import com.google.protobuf.WireFormat; +import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.expr.conformance.proto3.TestAllTypesCelLiteDescriptor; import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor; @@ -146,4 +149,96 @@ public void fieldDescriptor_nestedMessage_fullyQualifiedNames() { assertThat(fieldLiteDescriptor.getFieldProtoTypeName()) .isEqualTo("cel.expr.conformance.proto3.TestAllTypes.NestedMessage"); } + + private enum ProtoFieldTypeTestCase { + DOUBLE(FieldLiteDescriptor.Type.DOUBLE, 1, WireFormat.FieldType.DOUBLE), + FLOAT(FieldLiteDescriptor.Type.FLOAT, 2, WireFormat.FieldType.FLOAT), + INT64(FieldLiteDescriptor.Type.INT64, 3, WireFormat.FieldType.INT64), + UINT64(FieldLiteDescriptor.Type.UINT64, 4, WireFormat.FieldType.UINT64), + INT32(FieldLiteDescriptor.Type.INT32, 5, WireFormat.FieldType.INT32), + FIXED64(FieldLiteDescriptor.Type.FIXED64, 6, WireFormat.FieldType.FIXED64), + FIXED32(FieldLiteDescriptor.Type.FIXED32, 7, WireFormat.FieldType.FIXED32), + BOOL(FieldLiteDescriptor.Type.BOOL, 8, WireFormat.FieldType.BOOL), + STRING(FieldLiteDescriptor.Type.STRING, 9, WireFormat.FieldType.STRING), + GROUP(FieldLiteDescriptor.Type.GROUP, 10, WireFormat.FieldType.GROUP), + MESSAGE(FieldLiteDescriptor.Type.MESSAGE, 11, WireFormat.FieldType.MESSAGE), + BYTES(FieldLiteDescriptor.Type.BYTES, 12, WireFormat.FieldType.BYTES), + UINT32(FieldLiteDescriptor.Type.UINT32, 13, WireFormat.FieldType.UINT32), + ENUM(FieldLiteDescriptor.Type.ENUM, 14, WireFormat.FieldType.ENUM), + SFIXED32(FieldLiteDescriptor.Type.SFIXED32, 15, WireFormat.FieldType.SFIXED32), + SFIXED64(FieldLiteDescriptor.Type.SFIXED64, 16, WireFormat.FieldType.SFIXED64), + SINT32(FieldLiteDescriptor.Type.SINT32, 17, WireFormat.FieldType.SINT32), + SINT64(FieldLiteDescriptor.Type.SINT64, 18, WireFormat.FieldType.SINT64); + + private final FieldLiteDescriptor.Type type; + private final int expectedNumber; + private final WireFormat.FieldType expectedWireType; + + ProtoFieldTypeTestCase( + FieldLiteDescriptor.Type type, int expectedNumber, WireFormat.FieldType expectedWireType) { + this.type = type; + this.expectedNumber = expectedNumber; + this.expectedWireType = expectedWireType; + } + } + + @Test + public void protoFieldType_numbersAndWireTypes(@TestParameter ProtoFieldTypeTestCase testCase) { + assertThat(testCase.type.getNumber()).isEqualTo(testCase.expectedNumber); + assertThat(testCase.type.toWireFormatFieldType()).isEqualTo(testCase.expectedWireType); + } + + @Test + public void protoFieldType_forNumber_roundTripAllTypes( + @TestParameter FieldLiteDescriptor.Type type) { + assertThat(FieldLiteDescriptor.Type.forNumber(type.getNumber())).isEqualTo(type); + } + + @Test + public void protoFieldType_forNumber_outOfRange_throws( + @TestParameter({"-2147483648", "-1", "0", "19", "100", "2147483647"}) int invalidNumber) { + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> FieldLiteDescriptor.Type.forNumber(invalidNumber)); + + assertThat(e).hasMessageThat().isEqualTo("Unsupported proto type code: " + invalidNumber); + } + + @Test + public void fieldLiteDescriptor_nullParameters_throws() { + assertThrows( + NullPointerException.class, + () -> + new FieldLiteDescriptor( + 1, + "field", + null, + EncodingType.SINGULAR, + FieldLiteDescriptor.Type.INT32, + false, + "")); + assertThrows( + NullPointerException.class, + () -> + new FieldLiteDescriptor( + 1, + "field", + FieldLiteDescriptor.JavaType.INT, + null, + FieldLiteDescriptor.Type.INT32, + false, + "")); + assertThrows( + NullPointerException.class, + () -> + new FieldLiteDescriptor( + 1, + "field", + FieldLiteDescriptor.JavaType.INT, + EncodingType.SINGULAR, + null, + false, + "")); + } }