|
17 | 17 | import static com.google.common.truth.Truth.assertThat;
|
18 | 18 | import static java.nio.charset.StandardCharsets.UTF_8;
|
19 | 19 |
|
| 20 | +import com.google.common.collect.ImmutableList; |
| 21 | +import com.google.common.collect.ImmutableListMultimap; |
20 | 22 | import com.google.common.collect.ImmutableSet;
|
| 23 | +import com.google.common.collect.Multimap; |
21 | 24 | import com.google.protobuf.ByteString;
|
22 | 25 | import com.google.protobuf.Duration;
|
| 26 | +import com.google.protobuf.ExtensionRegistryLite; |
23 | 27 | import com.google.protobuf.FloatValue;
|
24 | 28 | import com.google.protobuf.Int32Value;
|
25 | 29 | import com.google.protobuf.Int64Value;
|
|
32 | 36 | import dev.cel.common.internal.CelLiteDescriptorPool;
|
33 | 37 | import dev.cel.common.internal.DefaultLiteDescriptorPool;
|
34 | 38 | import dev.cel.common.internal.WellKnownProto;
|
| 39 | +import dev.cel.common.values.ProtoLiteCelValueConverter.MessageFields; |
35 | 40 | import dev.cel.expr.conformance.proto3.TestAllTypes;
|
36 | 41 | import dev.cel.expr.conformance.proto3.TestAllTypesProto3CelDescriptor;
|
37 | 42 | import java.time.Instant;
|
| 43 | +import java.util.LinkedHashMap; |
38 | 44 | import org.junit.Test;
|
39 | 45 | import org.junit.runner.RunWith;
|
40 | 46 |
|
@@ -107,4 +113,214 @@ public void fromProtoMessageToCelValue_withWellKnownProto_convertsToEquivalentCe
|
107 | 113 |
|
108 | 114 | assertThat(convertedCelValue).isEqualTo(testCase.celValue);
|
109 | 115 | }
|
| 116 | + |
| 117 | + /** Test cases for repeated_int64: 1L,2L,3L */ |
| 118 | + @SuppressWarnings("ImmutableEnumChecker") // Test only |
| 119 | + private enum RepeatedFieldBytesTestCase { |
| 120 | + PACKED(new byte[] {(byte) 0x82, 0x2, 0x3, 0x1, 0x2, 0x3}), |
| 121 | + NON_PACKED(new byte[] {(byte) 0x80, 0x2, 0x1, (byte) 0x80, 0x2, 0x2, (byte) 0x80, 0x2, 0x3}), |
| 122 | + // 1L is not packed, but 2L and 3L are |
| 123 | + MIXED(new byte[] {(byte) 0x80, 0x2, 0x1, (byte) 0x82, 0x2, 0x2, 0x2, 0x3}); |
| 124 | + |
| 125 | + private final byte[] bytes; |
| 126 | + |
| 127 | + RepeatedFieldBytesTestCase(byte[] bytes) { |
| 128 | + this.bytes = bytes; |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + @Test |
| 133 | + public void readAllFields_repeatedFields_packedBytesCombinations( |
| 134 | + @TestParameter RepeatedFieldBytesTestCase testCase) throws Exception { |
| 135 | + MessageFields fields = |
| 136 | + PROTO_LITE_CEL_VALUE_CONVERTER.readAllFields( |
| 137 | + testCase.bytes, "cel.expr.conformance.proto3.TestAllTypes"); |
| 138 | + |
| 139 | + assertThat(fields.values()).containsExactly("repeated_int64", ImmutableList.of(1L, 2L, 3L)); |
| 140 | + } |
| 141 | + |
| 142 | + /** |
| 143 | + * Unknown test with the following hypothetical fields: |
| 144 | + * |
| 145 | + * <pre>{@code |
| 146 | + * message TestAllTypes { |
| 147 | + * int64 single_int64_unknown = 2500; |
| 148 | + * fixed32 single_fixed32_unknown = 2501; |
| 149 | + * fixed64 single_fixed64_unknown = 2502; |
| 150 | + * string single_string_unknown = 2503; |
| 151 | + * repeated int64 repeated_int64_unknown = 2504; |
| 152 | + * map<string, int64> map_string_int64_unknown = 2505; |
| 153 | + * } |
| 154 | + * }</pre> |
| 155 | + */ |
| 156 | + @SuppressWarnings("ImmutableEnumChecker") // Test only |
| 157 | + private enum UnknownFieldsTestCase { |
| 158 | + INT64(new byte[] {-96, -100, 1, 1}, "2500: 1", ImmutableListMultimap.of(2500, 1L)), |
| 159 | + FIXED32( |
| 160 | + new byte[] {-83, -100, 1, 2, 0, 0, 0}, |
| 161 | + "2501: 0x00000002", |
| 162 | + ImmutableListMultimap.of(2501, 2)), |
| 163 | + FIXED64( |
| 164 | + new byte[] {-79, -100, 1, 3, 0, 0, 0, 0, 0, 0, 0}, |
| 165 | + "2502: 0x0000000000000003", |
| 166 | + ImmutableListMultimap.of(2502, 3L)), |
| 167 | + STRING( |
| 168 | + new byte[] {-70, -100, 1, 11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}, |
| 169 | + "2503: \"Hello world\"", |
| 170 | + ImmutableListMultimap.of(2503, ByteString.copyFromUtf8("Hello world"))), |
| 171 | + REPEATED_INT64( |
| 172 | + new byte[] {-62, -100, 1, 2, 4, 5}, |
| 173 | + "2504: \"\\004\\005\"", |
| 174 | + ImmutableListMultimap.of(2504, ByteString.copyFrom(new byte[] {4, 5}))), |
| 175 | + MAP_STRING_INT64( |
| 176 | + new byte[] { |
| 177 | + -54, -100, 1, 7, 10, 3, 102, 111, 111, 16, 4, -54, -100, 1, 7, 10, 3, 98, 97, 114, 16, 5 |
| 178 | + }, |
| 179 | + "2505: {\n" |
| 180 | + + " 1: \"foo\"\n" |
| 181 | + + " 2: 4\n" |
| 182 | + + "}\n" |
| 183 | + + "2505: {\n" |
| 184 | + + " 1: \"bar\"\n" |
| 185 | + + " 2: 5\n" |
| 186 | + + "}", |
| 187 | + ImmutableListMultimap.of( |
| 188 | + 2505, |
| 189 | + ByteString.copyFromUtf8("\n\003foo\020\004"), |
| 190 | + 2505, |
| 191 | + ByteString.copyFromUtf8("\n\003bar\020\005"))); |
| 192 | + |
| 193 | + private final byte[] bytes; |
| 194 | + private final String formattedOutput; |
| 195 | + private final Multimap<Integer, Object> unknownMap; |
| 196 | + |
| 197 | + UnknownFieldsTestCase( |
| 198 | + byte[] bytes, String formattedOutput, Multimap<Integer, Object> unknownMap) { |
| 199 | + this.bytes = bytes; |
| 200 | + this.formattedOutput = formattedOutput; |
| 201 | + this.unknownMap = unknownMap; |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + @Test |
| 206 | + public void unknowns_repeatedEncodedBytes_allRecordsKeptWithKeysSorted() throws Exception { |
| 207 | + // 2500: 2 |
| 208 | + // 2504: \"\\004\\005\"" |
| 209 | + // 2501: 0x00000002 |
| 210 | + // 2500: 1 |
| 211 | + byte[] bytes = |
| 212 | + new byte[] { |
| 213 | + -96, -100, 1, 2, // keep |
| 214 | + -62, -100, 1, 2, 4, 5, // keep |
| 215 | + -83, -100, 1, 2, 0, 0, 0, // keep |
| 216 | + -96, -100, 1, 1 // keep |
| 217 | + }; |
| 218 | + |
| 219 | + MessageFields messageFields = |
| 220 | + PROTO_LITE_CEL_VALUE_CONVERTER.readAllFields( |
| 221 | + bytes, "cel.expr.conformance.proto3.TestAllTypes"); |
| 222 | + |
| 223 | + assertThat(messageFields.values()).isEmpty(); |
| 224 | + assertThat(messageFields.unknowns()) |
| 225 | + .containsExactly( |
| 226 | + 2500, 2L, 2500, 1L, 2501, 2, 2504, ByteString.copyFrom(new byte[] {0x04, 0x05})) |
| 227 | + .inOrder(); |
| 228 | + } |
| 229 | + |
| 230 | + @Test |
| 231 | + public void readAllFields_unknownFields(@TestParameter UnknownFieldsTestCase testCase) |
| 232 | + throws Exception { |
| 233 | + TestAllTypes parsedMsg = |
| 234 | + TestAllTypes.parseFrom(testCase.bytes, ExtensionRegistryLite.getEmptyRegistry()); |
| 235 | + |
| 236 | + MessageFields messageFields = |
| 237 | + PROTO_LITE_CEL_VALUE_CONVERTER.readAllFields( |
| 238 | + testCase.bytes, "cel.expr.conformance.proto3.TestAllTypes"); |
| 239 | + |
| 240 | + assertThat(messageFields.values()).isEmpty(); |
| 241 | + assertThat(messageFields.unknowns()).containsExactlyEntriesIn(testCase.unknownMap).inOrder(); |
| 242 | + assertThat(parsedMsg.toString().trim()).isEqualTo(testCase.formattedOutput); |
| 243 | + } |
| 244 | + |
| 245 | + /** |
| 246 | + * Tests the following message: |
| 247 | + * |
| 248 | + * <pre>{@code |
| 249 | + * TestAllTypes.newBuilder() |
| 250 | + * // Unknowns |
| 251 | + * .setSingleInt64Unknown(1L) |
| 252 | + * .setSingleFixed32Unknown(2) |
| 253 | + * .setSingleFixed64Unknown(3L) |
| 254 | + * .setSingleStringUnknown("Hello world") |
| 255 | + * .addAllRepeatedInt64Unknown(ImmutableList.of(4L, 5L)) |
| 256 | + * .putMapStringInt64Unknown("foo", 4L) |
| 257 | + * .putMapStringInt64Unknown("bar", 5L) |
| 258 | + * // Known values |
| 259 | + * .putMapBoolDouble(true, 1.5d) |
| 260 | + * .putMapBoolDouble(false, 2.5d) |
| 261 | + * .build(); |
| 262 | + * }</pre> |
| 263 | + */ |
| 264 | + @Test |
| 265 | + @SuppressWarnings("unchecked") |
| 266 | + public void readAllFields_unknownFieldsWithValues() throws Exception { |
| 267 | + byte[] unknownMessageBytes = { |
| 268 | + -70, 4, 11, 8, 1, 17, 0, 0, 0, 0, 0, 0, -8, 63, -70, 4, 11, 8, 0, 17, 0, 0, 0, 0, 0, 0, 4, 64, |
| 269 | + -96, -100, 1, 1, -83, -100, 1, 2, 0, 0, 0, -79, -100, 1, 3, 0, 0, 0, 0, 0, 0, 0, -70, -100, 1, |
| 270 | + 11, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, -62, -100, 1, 2, 4, 5, -54, -100, 1, |
| 271 | + 7, 10, 3, 102, 111, 111, 16, 4, -54, -100, 1, 7, 10, 3, 98, 97, 114, 16, 5 |
| 272 | + }; |
| 273 | + TestAllTypes parsedMsg = |
| 274 | + TestAllTypes.parseFrom(unknownMessageBytes, ExtensionRegistryLite.getEmptyRegistry()); |
| 275 | + |
| 276 | + MessageFields fields = |
| 277 | + PROTO_LITE_CEL_VALUE_CONVERTER.readAllFields( |
| 278 | + unknownMessageBytes, "cel.expr.conformance.proto3.TestAllTypes"); |
| 279 | + |
| 280 | + assertThat(parsedMsg.toString()) |
| 281 | + .isEqualTo( |
| 282 | + "map_bool_double {\n" |
| 283 | + + " key: false\n" |
| 284 | + + " value: 2.5\n" |
| 285 | + + "}\n" |
| 286 | + + "map_bool_double {\n" |
| 287 | + + " key: true\n" |
| 288 | + + " value: 1.5\n" |
| 289 | + + "}\n" |
| 290 | + + "2500: 1\n" |
| 291 | + + "2501: 0x00000002\n" |
| 292 | + + "2502: 0x0000000000000003\n" |
| 293 | + + "2503: \"Hello world\"\n" |
| 294 | + + "2504: \"\\004\\005\"\n" |
| 295 | + + "2505: {\n" |
| 296 | + + " 1: \"foo\"\n" |
| 297 | + + " 2: 4\n" |
| 298 | + + "}\n" |
| 299 | + + "2505: {\n" |
| 300 | + + " 1: \"bar\"\n" |
| 301 | + + " 2: 5\n" |
| 302 | + + "}\n"); |
| 303 | + assertThat(fields.values()).containsKey("map_bool_double"); |
| 304 | + LinkedHashMap<Boolean, Double> mapBoolDoubleValues = |
| 305 | + (LinkedHashMap<Boolean, Double>) fields.values().get("map_bool_double"); |
| 306 | + assertThat(mapBoolDoubleValues).containsExactly(true, 1.5d, false, 2.5d).inOrder(); |
| 307 | + Multimap<Integer, Object> unknownValues = fields.unknowns(); |
| 308 | + assertThat(unknownValues) |
| 309 | + .containsExactly( |
| 310 | + 2500, |
| 311 | + 1L, |
| 312 | + 2501, |
| 313 | + 2, |
| 314 | + 2502, |
| 315 | + 3L, |
| 316 | + 2503, |
| 317 | + ByteString.copyFromUtf8("Hello world"), |
| 318 | + 2504, |
| 319 | + ByteString.copyFrom(new byte[] {0x04, 0x05}), |
| 320 | + 2505, |
| 321 | + ByteString.copyFromUtf8("\n\003foo\020\004"), |
| 322 | + 2505, |
| 323 | + ByteString.copyFromUtf8("\n\003bar\020\005")) |
| 324 | + .inOrder(); |
| 325 | + } |
110 | 326 | }
|
0 commit comments