1515package dev .cel .extensions ;
1616
1717import static com .google .common .truth .Truth .assertThat ;
18+ import static com .google .common .truth .Truth .assertWithMessage ;
1819import static org .junit .Assert .assertThrows ;
1920
21+ import com .google .common .base .Throwables ;
22+ import com .google .common .collect .ImmutableMap ;
2023import com .google .testing .junit .testparameterinjector .TestParameter ;
2124import com .google .testing .junit .testparameterinjector .TestParameterInjector ;
2225import com .google .testing .junit .testparameterinjector .TestParameters ;
26+ import dev .cel .bundle .Cel ;
2327import dev .cel .common .CelAbstractSyntaxTree ;
2428import dev .cel .common .CelFunctionDecl ;
2529import dev .cel .common .CelOptions ;
2832import dev .cel .common .exceptions .CelIndexOutOfBoundsException ;
2933import dev .cel .common .types .SimpleType ;
3034import dev .cel .common .types .TypeParamType ;
31- import dev .cel .compiler .CelCompiler ;
32- import dev .cel .compiler .CelCompilerFactory ;
3335import dev .cel .parser .CelMacro ;
3436import dev .cel .parser .CelStandardMacro ;
3537import dev .cel .parser .CelUnparser ;
3638import dev .cel .parser .CelUnparserFactory ;
3739import dev .cel .runtime .CelEvaluationException ;
38- import dev .cel .runtime .CelRuntime ;
39- import dev .cel .runtime .CelRuntimeFactory ;
40+ import dev .cel .testing .CelRuntimeFlavor ;
41+ import java .util .Map ;
42+ import org .junit .Assume ;
43+ import org .junit .Before ;
4044import org .junit .Test ;
4145import org .junit .runner .RunWith ;
4246
@@ -46,26 +50,35 @@ public class CelComprehensionsExtensionsTest {
4650
4751 private static final CelOptions CEL_OPTIONS =
4852 CelOptions .current ()
53+ .enableHeterogeneousNumericComparisons (true )
4954 // Enable macro call population for unparsing
5055 .populateMacroCalls (true )
5156 .build ();
5257
53- private static final CelCompiler CEL_COMPILER =
54- CelCompilerFactory .standardCelCompilerBuilder ()
55- .setOptions (CEL_OPTIONS )
56- .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
57- .addLibraries (CelExtensions .comprehensions ())
58- .addLibraries (CelExtensions .lists ())
59- .addLibraries (CelExtensions .strings ())
60- .addLibraries (CelOptionalLibrary .INSTANCE , CelExtensions .bindings ())
61- .build ();
62- private static final CelRuntime CEL_RUNTIME =
63- CelRuntimeFactory .standardCelRuntimeBuilder ()
64- .addLibraries (CelOptionalLibrary .INSTANCE )
65- .addLibraries (CelExtensions .lists ())
66- .addLibraries (CelExtensions .strings ())
67- .addLibraries (CelExtensions .comprehensions ())
68- .build ();
58+ @ TestParameter public CelRuntimeFlavor runtimeFlavor ;
59+ @ TestParameter public boolean isParseOnly ;
60+
61+ private Cel cel ;
62+
63+ @ Before
64+ public void setUp () {
65+ // Legacy runtime does not support parsed-only evaluation mode.
66+ Assume .assumeFalse (runtimeFlavor .equals (CelRuntimeFlavor .LEGACY ) && isParseOnly );
67+ this .cel =
68+ runtimeFlavor
69+ .builder ()
70+ .setOptions (CEL_OPTIONS )
71+ .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
72+ .addCompilerLibraries (CelExtensions .comprehensions ())
73+ .addCompilerLibraries (CelExtensions .lists ())
74+ .addCompilerLibraries (CelExtensions .strings ())
75+ .addCompilerLibraries (CelOptionalLibrary .INSTANCE , CelExtensions .bindings ())
76+ .addRuntimeLibraries (CelOptionalLibrary .INSTANCE )
77+ .addRuntimeLibraries (CelExtensions .lists ())
78+ .addRuntimeLibraries (CelExtensions .strings ())
79+ .addRuntimeLibraries (CelExtensions .comprehensions ())
80+ .build ();
81+ }
6982
7083 private static final CelUnparser UNPARSER = CelUnparserFactory .newUnparser ();
7184
@@ -101,11 +114,7 @@ public void allMacro_twoVarComprehension_success(
101114 })
102115 String expr )
103116 throws Exception {
104- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
105-
106- Object result = CEL_RUNTIME .createProgram (ast ).eval ();
107-
108- assertThat (result ).isEqualTo (true );
117+ assertThat (eval (expr )).isEqualTo (true );
109118 }
110119
111120 @ Test
@@ -127,11 +136,7 @@ public void existsMacro_twoVarComprehension_success(
127136 })
128137 String expr )
129138 throws Exception {
130- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
131-
132- Object result = CEL_RUNTIME .createProgram (ast ).eval ();
133-
134- assertThat (result ).isEqualTo (true );
139+ assertThat (eval (expr )).isEqualTo (true );
135140 }
136141
137142 @ Test
@@ -156,11 +161,7 @@ public void exists_oneMacro_twoVarComprehension_success(
156161 })
157162 String expr )
158163 throws Exception {
159- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
160-
161- Object result = CEL_RUNTIME .createProgram (ast ).eval ();
162-
163- assertThat (result ).isEqualTo (true );
164+ assertThat (eval (expr )).isEqualTo (true );
164165 }
165166
166167 @ Test
@@ -182,11 +183,7 @@ public void transformListMacro_twoVarComprehension_success(
182183 })
183184 String expr )
184185 throws Exception {
185- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
186-
187- Object result = CEL_RUNTIME .createProgram (ast ).eval ();
188-
189- assertThat (result ).isEqualTo (true );
186+ assertThat (eval (expr )).isEqualTo (true );
190187 }
191188
192189 @ Test
@@ -210,11 +207,7 @@ public void transformMapMacro_twoVarComprehension_success(
210207 })
211208 String expr )
212209 throws Exception {
213- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
214-
215- Object result = CEL_RUNTIME .createProgram (ast ).eval ();
216-
217- assertThat (result ).isEqualTo (true );
210+ assertThat (eval (expr )).isEqualTo (true );
218211 }
219212
220213 @ Test
@@ -238,24 +231,22 @@ public void transformMapEntryMacro_twoVarComprehension_success(
238231 })
239232 String expr )
240233 throws Exception {
241- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
242-
243- Object result = CEL_RUNTIME .createProgram (ast ).eval ();
244-
245- assertThat (result ).isEqualTo (true );
234+ assertThat (eval (expr )).isEqualTo (true );
246235 }
247236
248237 @ Test
249238 public void comprehension_onTypeParam_success () throws Exception {
250- CelCompiler celCompiler =
251- CelCompilerFactory .standardCelCompilerBuilder ()
239+ Assume .assumeFalse (isParseOnly );
240+ Cel customCel =
241+ runtimeFlavor
242+ .builder ()
252243 .setOptions (CEL_OPTIONS )
253244 .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
254- .addLibraries (CelExtensions .comprehensions ())
245+ .addCompilerLibraries (CelExtensions .comprehensions ())
255246 .addVar ("items" , TypeParamType .create ("T" ))
256247 .build ();
257248
258- CelAbstractSyntaxTree ast = celCompiler .compile ("items.all(i, v, v > 0)" ).getAst ();
249+ CelAbstractSyntaxTree ast = customCel .compile ("items.all(i, v, v > 0)" ).getAst ();
259250
260251 assertThat (ast .getResultType ()).isEqualTo (SimpleType .BOOL );
261252 }
@@ -275,7 +266,7 @@ public void unparseAST_twoVarComprehension(
275266 })
276267 String expr )
277268 throws Exception {
278- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
269+ CelAbstractSyntaxTree ast = isParseOnly ? cel . parse ( expr ). getAst () : cel .compile (expr ).getAst ();
279270 String unparsed = UNPARSER .unparse (ast );
280271 assertThat (unparsed ).isEqualTo (expr );
281272 }
@@ -318,8 +309,9 @@ public void unparseAST_twoVarComprehension(
318309 "{expr: \" {'hello': 'world', 'greetings': 'tacocat'}.transformMapEntry(k, v, []) == {}\" ,"
319310 + " err: 'no matching overload'}" )
320311 public void twoVarComprehension_compilerErrors (String expr , String err ) throws Exception {
312+ Assume .assumeFalse (isParseOnly );
321313 CelValidationException e =
322- assertThrows (CelValidationException .class , () -> CEL_COMPILER .compile (expr ).getAst ());
314+ assertThrows (CelValidationException .class , () -> cel .compile (expr ).getAst ());
323315
324316 assertThat (e ).hasMessageThat ().contains (err );
325317 }
@@ -339,34 +331,50 @@ public void twoVarComprehension_compilerErrors(String expr, String err) throws E
339331 + " '2.0' already exists\" }" )
340332 public void twoVarComprehension_keyCollision_runtimeError (String expr , String err )
341333 throws Exception {
342- CelAbstractSyntaxTree ast = CEL_COMPILER .compile (expr ).getAst ();
343-
344- CelEvaluationException e =
345- assertThrows (CelEvaluationException .class , () -> CEL_RUNTIME .createProgram (ast ).eval ());
346-
347- assertThat (e ).hasCauseThat ().isInstanceOf (IllegalArgumentException .class );
348- assertThat (e ).hasCauseThat ().hasMessageThat ().contains (err );
334+ // Planner does not allow decimals for map keys
335+ Assume .assumeFalse (runtimeFlavor .equals (CelRuntimeFlavor .PLANNER ) && expr .contains ("2.0" ));
336+
337+ CelEvaluationException e = assertThrows (CelEvaluationException .class , () -> eval (expr ));
338+ Throwable cause =
339+ Throwables .getCausalChain (e ).stream ()
340+ .filter (IllegalArgumentException .class ::isInstance )
341+ .filter (t -> t .getMessage () != null && t .getMessage ().contains (err ))
342+ .findFirst ()
343+ .orElse (null );
344+
345+ assertWithMessage (
346+ "Expected IllegalArgumentException with message containing '%s' in cause chain" , err )
347+ .that (cause )
348+ .isNotNull ();
349349 }
350350
351351 @ Test
352352 public void twoVarComprehension_arithmeticException_runtimeError () throws Exception {
353- CelAbstractSyntaxTree ast = CEL_COMPILER .compile ("[0].all(i, k, i/k < k)" ).getAst ();
354-
355353 CelEvaluationException e =
356- assertThrows (CelEvaluationException .class , () -> CEL_RUNTIME .createProgram (ast ).eval ());
357-
354+ assertThrows (CelEvaluationException .class , () -> eval ("[0].all(i, k, i/k < k)" ));
358355 assertThat (e ).hasCauseThat ().isInstanceOf (CelDivideByZeroException .class );
359356 assertThat (e ).hasCauseThat ().hasMessageThat ().contains ("/ by zero" );
360357 }
361358
362359 @ Test
363360 public void twoVarComprehension_outOfBounds_runtimeError () throws Exception {
364- CelAbstractSyntaxTree ast = CEL_COMPILER .compile ("[1, 2].exists(i, v, [0][v] > 0)" ).getAst ();
365-
366361 CelEvaluationException e =
367- assertThrows (CelEvaluationException .class , () -> CEL_RUNTIME .createProgram (ast ).eval ());
368-
362+ assertThrows (CelEvaluationException .class , () -> eval ("[1, 2].exists(i, v, [0][v] > 0)" ));
369363 assertThat (e ).hasCauseThat ().isInstanceOf (CelIndexOutOfBoundsException .class );
370364 assertThat (e ).hasCauseThat ().hasMessageThat ().contains ("Index out of bounds: 1" );
371365 }
366+
367+ private Object eval (String expression ) throws Exception {
368+ return eval (this .cel , expression , ImmutableMap .of ());
369+ }
370+
371+ private Object eval (Cel cel , String expression , Map <String , ?> variables ) throws Exception {
372+ CelAbstractSyntaxTree ast ;
373+ if (isParseOnly ) {
374+ ast = cel .parse (expression ).getAst ();
375+ } else {
376+ ast = cel .compile (expression ).getAst ();
377+ }
378+ return cel .createProgram (ast ).eval (variables );
379+ }
372380}
0 commit comments