Skip to content

Commit 3075687

Browse files
l46kokcopybara-github
authored andcommitted
Add parsed-only evaluation coverage to Proto Extensions
PiperOrigin-RevId: 899863532
1 parent 74ffbb3 commit 3075687

1 file changed

Lines changed: 88 additions & 85 deletions

File tree

extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java

Lines changed: 88 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
2727
import com.google.testing.junit.testparameterinjector.TestParameters;
2828
import dev.cel.bundle.Cel;
29-
import dev.cel.bundle.CelFactory;
3029
import dev.cel.common.CelAbstractSyntaxTree;
3130
import dev.cel.common.CelContainer;
3231
import dev.cel.common.CelFunctionDecl;
@@ -35,36 +34,42 @@
3534
import dev.cel.common.CelValidationException;
3635
import dev.cel.common.types.SimpleType;
3736
import dev.cel.common.types.StructTypeReference;
38-
import dev.cel.compiler.CelCompiler;
39-
import dev.cel.compiler.CelCompilerFactory;
4037
import dev.cel.expr.conformance.proto2.Proto2ExtensionScopedMessage;
4138
import dev.cel.expr.conformance.proto2.TestAllTypes;
4239
import dev.cel.expr.conformance.proto2.TestAllTypes.NestedEnum;
4340
import dev.cel.expr.conformance.proto2.TestAllTypesExtensions;
4441
import dev.cel.parser.CelMacro;
4542
import dev.cel.parser.CelStandardMacro;
4643
import dev.cel.runtime.CelFunctionBinding;
47-
import dev.cel.runtime.CelRuntime;
48-
import dev.cel.runtime.CelRuntimeFactory;
44+
import dev.cel.testing.CelRuntimeFlavor;
45+
import java.util.Map;
46+
import org.junit.Assume;
47+
import org.junit.Before;
4948
import org.junit.Test;
5049
import org.junit.runner.RunWith;
5150

5251
@RunWith(TestParameterInjector.class)
5352
public final class CelProtoExtensionsTest {
5453

55-
private static final CelCompiler CEL_COMPILER =
56-
CelCompilerFactory.standardCelCompilerBuilder()
57-
.addLibraries(CelExtensions.protos())
58-
.setStandardMacros(CelStandardMacro.STANDARD_MACROS)
59-
.addFileTypes(TestAllTypesExtensions.getDescriptor())
60-
.addVar("msg", StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes"))
61-
.setContainer(CelContainer.ofName("cel.expr.conformance.proto2"))
62-
.build();
54+
@TestParameter public CelRuntimeFlavor runtimeFlavor;
55+
@TestParameter public boolean isParseOnly;
6356

64-
private static final CelRuntime CEL_RUNTIME =
65-
CelRuntimeFactory.standardCelRuntimeBuilder()
66-
.addFileTypes(TestAllTypesExtensions.getDescriptor())
67-
.build();
57+
private Cel cel;
58+
59+
@Before
60+
public void setUp() {
61+
// Legacy runtime does not support parsed-only evaluation mode.
62+
Assume.assumeFalse(runtimeFlavor.equals(CelRuntimeFlavor.LEGACY) && isParseOnly);
63+
this.cel =
64+
runtimeFlavor
65+
.builder()
66+
.addCompilerLibraries(CelExtensions.protos())
67+
.setStandardMacros(CelStandardMacro.STANDARD_MACROS)
68+
.addFileTypes(TestAllTypesExtensions.getDescriptor())
69+
.addVar("msg", StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes"))
70+
.setContainer(CelContainer.ofName("cel.expr.conformance.proto2"))
71+
.build();
72+
}
6873

6974
private static final TestAllTypes PACKAGE_SCOPED_EXT_MSG =
7075
TestAllTypes.newBuilder()
@@ -106,10 +111,7 @@ public void library() {
106111
"{expr: 'proto.hasExt(msg, cel.expr.conformance.proto2.repeated_test_all_types)'}")
107112
@TestParameters("{expr: '!proto.hasExt(msg, cel.expr.conformance.proto2.test_all_types_ext)'}")
108113
public void hasExt_packageScoped_success(String expr) throws Exception {
109-
CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
110-
boolean result =
111-
(boolean)
112-
CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
114+
boolean result = (boolean) eval(expr, ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
113115

114116
assertThat(result).isTrue();
115117
}
@@ -128,10 +130,7 @@ public void hasExt_packageScoped_success(String expr) throws Exception {
128130
"{expr: '!proto.hasExt(msg,"
129131
+ " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.nested_enum_ext)'}")
130132
public void hasExt_messageScoped_success(String expr) throws Exception {
131-
CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
132-
boolean result =
133-
(boolean)
134-
CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", MESSAGE_SCOPED_EXT_MSG));
133+
boolean result = (boolean) eval(expr, ImmutableMap.of("msg", MESSAGE_SCOPED_EXT_MSG));
135134

136135
assertThat(result).isTrue();
137136
}
@@ -142,9 +141,10 @@ public void hasExt_messageScoped_success(String expr) throws Exception {
142141
public void hasExt_nonProtoNamespace_success(String expr) throws Exception {
143142
StructTypeReference proto2MessageTypeReference =
144143
StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes");
145-
CelCompiler celCompiler =
146-
CelCompilerFactory.standardCelCompilerBuilder()
147-
.addLibraries(CelExtensions.protos())
144+
Cel customCel =
145+
runtimeFlavor
146+
.builder()
147+
.addCompilerLibraries(CelExtensions.protos())
148148
.addVar("msg", proto2MessageTypeReference)
149149
.addFunctionDeclarations(
150150
CelFunctionDecl.newFunctionDeclaration(
@@ -154,37 +154,35 @@ public void hasExt_nonProtoNamespace_success(String expr) throws Exception {
154154
SimpleType.BOOL,
155155
ImmutableList.of(
156156
proto2MessageTypeReference, SimpleType.STRING, SimpleType.INT))))
157-
.build();
158-
CelRuntime celRuntime =
159-
CelRuntimeFactory.standardCelRuntimeBuilder()
160157
.addFunctionBindings(
161-
CelFunctionBinding.from(
162-
"msg_hasExt",
163-
ImmutableList.of(TestAllTypes.class, String.class, Long.class),
164-
(arg) -> {
165-
TestAllTypes msg = (TestAllTypes) arg[0];
166-
String extensionField = (String) arg[1];
167-
return msg.getAllFields().keySet().stream()
168-
.anyMatch(fd -> fd.getFullName().equals(extensionField));
169-
}))
158+
CelFunctionBinding.fromOverloads(
159+
"hasExt",
160+
CelFunctionBinding.from(
161+
"msg_hasExt",
162+
ImmutableList.of(TestAllTypes.class, String.class, Long.class),
163+
(arg) -> {
164+
TestAllTypes msg = (TestAllTypes) arg[0];
165+
String extensionField = (String) arg[1];
166+
return msg.getAllFields().keySet().stream()
167+
.anyMatch(fd -> fd.getFullName().equals(extensionField));
168+
})))
170169
.build();
171170

172-
CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
173171
boolean result =
174-
(boolean)
175-
celRuntime.createProgram(ast).eval(ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
172+
(boolean) eval(customCel, expr, ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
176173

177174
assertThat(result).isTrue();
178175
}
179176

180177
@Test
181178
public void hasExt_undefinedField_throwsException() {
179+
// This is a type-checking failure
180+
Assume.assumeFalse(isParseOnly);
182181
CelValidationException exception =
183182
assertThrows(
184183
CelValidationException.class,
185184
() ->
186-
CEL_COMPILER
187-
.compile("!proto.hasExt(msg, cel.expr.conformance.proto2.undefined_field)")
185+
cel.compile("!proto.hasExt(msg, cel.expr.conformance.proto2.undefined_field)")
188186
.getAst());
189187

190188
assertThat(exception)
@@ -204,10 +202,7 @@ public void hasExt_undefinedField_throwsException() {
204202
"{expr: 'proto.getExt(msg, cel.expr.conformance.proto2.repeated_test_all_types) =="
205203
+ " [TestAllTypes{single_string: ''A''}, TestAllTypes{single_string: ''B''}]'}")
206204
public void getExt_packageScoped_success(String expr) throws Exception {
207-
CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
208-
boolean result =
209-
(boolean)
210-
CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
205+
boolean result = (boolean) eval(expr, ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
211206

212207
assertThat(result).isTrue();
213208
}
@@ -221,22 +216,20 @@ public void getExt_packageScoped_success(String expr) throws Exception {
221216
"{expr: 'proto.getExt(msg,"
222217
+ " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.int64_ext) == 1'}")
223218
public void getExt_messageScopedSuccess(String expr) throws Exception {
224-
CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst();
225-
boolean result =
226-
(boolean)
227-
CEL_RUNTIME.createProgram(ast).eval(ImmutableMap.of("msg", MESSAGE_SCOPED_EXT_MSG));
219+
boolean result = (boolean) eval(expr, ImmutableMap.of("msg", MESSAGE_SCOPED_EXT_MSG));
228220

229221
assertThat(result).isTrue();
230222
}
231223

232224
@Test
233225
public void getExt_undefinedField_throwsException() {
226+
// This is a type-checking failure
227+
Assume.assumeFalse(isParseOnly);
234228
CelValidationException exception =
235229
assertThrows(
236230
CelValidationException.class,
237231
() ->
238-
CEL_COMPILER
239-
.compile("!proto.getExt(msg, cel.expr.conformance.proto2.undefined_field)")
232+
cel.compile("!proto.getExt(msg, cel.expr.conformance.proto2.undefined_field)")
240233
.getAst());
241234

242235
assertThat(exception)
@@ -250,9 +243,10 @@ public void getExt_undefinedField_throwsException() {
250243
public void getExt_nonProtoNamespace_success(String expr) throws Exception {
251244
StructTypeReference proto2MessageTypeReference =
252245
StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes");
253-
CelCompiler celCompiler =
254-
CelCompilerFactory.standardCelCompilerBuilder()
255-
.addLibraries(CelExtensions.protos())
246+
Cel customCel =
247+
runtimeFlavor
248+
.builder()
249+
.addCompilerLibraries(CelExtensions.protos())
256250
.addVar("msg", proto2MessageTypeReference)
257251
.addFunctionDeclarations(
258252
CelFunctionDecl.newFunctionDeclaration(
@@ -262,29 +256,26 @@ public void getExt_nonProtoNamespace_success(String expr) throws Exception {
262256
SimpleType.DYN,
263257
ImmutableList.of(
264258
proto2MessageTypeReference, SimpleType.STRING, SimpleType.INT))))
265-
.build();
266-
CelRuntime celRuntime =
267-
CelRuntimeFactory.standardCelRuntimeBuilder()
268259
.addFunctionBindings(
269-
CelFunctionBinding.from(
270-
"msg_getExt",
271-
ImmutableList.of(TestAllTypes.class, String.class, Long.class),
272-
(arg) -> {
273-
TestAllTypes msg = (TestAllTypes) arg[0];
274-
String extensionField = (String) arg[1];
275-
FieldDescriptor extensionDescriptor =
276-
msg.getAllFields().keySet().stream()
277-
.filter(fd -> fd.getFullName().equals(extensionField))
278-
.findAny()
279-
.get();
280-
return msg.getField(extensionDescriptor);
281-
}))
260+
CelFunctionBinding.fromOverloads(
261+
"getExt",
262+
CelFunctionBinding.from(
263+
"msg_getExt",
264+
ImmutableList.of(TestAllTypes.class, String.class, Long.class),
265+
(arg) -> {
266+
TestAllTypes msg = (TestAllTypes) arg[0];
267+
String extensionField = (String) arg[1];
268+
FieldDescriptor extensionDescriptor =
269+
msg.getAllFields().keySet().stream()
270+
.filter(fd -> fd.getFullName().equals(extensionField))
271+
.findAny()
272+
.get();
273+
return msg.getField(extensionDescriptor);
274+
})))
282275
.build();
283276

284-
CelAbstractSyntaxTree ast = celCompiler.compile(expr).getAst();
285277
boolean result =
286-
(boolean)
287-
celRuntime.createProgram(ast).eval(ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
278+
(boolean) eval(customCel, expr, ImmutableMap.of("msg", PACKAGE_SCOPED_EXT_MSG));
288279

289280
assertThat(result).isTrue();
290281
}
@@ -293,21 +284,24 @@ public void getExt_nonProtoNamespace_success(String expr) throws Exception {
293284
public void getExt_onAnyPackedExtensionField_success() throws Exception {
294285
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
295286
TestAllTypesExtensions.registerAllExtensions(extensionRegistry);
296-
Cel cel =
297-
CelFactory.standardCelBuilder()
287+
Cel customCel =
288+
runtimeFlavor
289+
.builder()
298290
// CEL-Internal-2
299291
.addCompilerLibraries(CelExtensions.protos())
300292
.addFileTypes(TestAllTypesExtensions.getDescriptor())
301293
.setExtensionRegistry(extensionRegistry)
302294
.addVar("msg", StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes"))
303295
.build();
304-
CelAbstractSyntaxTree ast =
305-
cel.compile("proto.getExt(msg, cel.expr.conformance.proto2.int32_ext)").getAst();
306296
Any anyMsg =
307297
Any.pack(
308298
TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build());
309-
310-
Long result = (Long) cel.createProgram(ast).eval(ImmutableMap.of("msg", anyMsg));
299+
Long result =
300+
(Long)
301+
eval(
302+
customCel,
303+
"proto.getExt(msg, cel.expr.conformance.proto2.int32_ext)",
304+
ImmutableMap.of("msg", anyMsg));
311305

312306
assertThat(result).isEqualTo(1);
313307
}
@@ -343,9 +337,18 @@ private enum ParseErrorTestCase {
343337
@Test
344338
public void parseErrors(@TestParameter ParseErrorTestCase testcase) {
345339
CelValidationException e =
346-
assertThrows(
347-
CelValidationException.class, () -> CEL_COMPILER.compile(testcase.expr).getAst());
340+
assertThrows(CelValidationException.class, () -> cel.parse(testcase.expr).getAst());
348341

349342
assertThat(e).hasMessageThat().isEqualTo(testcase.error);
350343
}
344+
345+
private Object eval(String expression, Map<String, ?> variables) throws Exception {
346+
return eval(this.cel, expression, variables);
347+
}
348+
349+
private Object eval(Cel cel, String expression, Map<String, ?> variables) throws Exception {
350+
CelAbstractSyntaxTree ast =
351+
this.isParseOnly ? cel.parse(expression).getAst() : cel.compile(expression).getAst();
352+
return cel.createProgram(ast).eval(variables);
353+
}
351354
}

0 commit comments

Comments
 (0)