33import static com .google .common .truth .Truth .assertThat ;
44import static org .junit .Assert .assertThrows ;
55
6+ import com .google .testing .junit .testparameterinjector .TestParameter ;
67import com .google .testing .junit .testparameterinjector .TestParameterInjector ;
78import dev .cel .bundle .Cel ;
89import dev .cel .bundle .CelFactory ;
1213import dev .cel .common .ast .CelExpr ;
1314import dev .cel .common .types .SimpleType ;
1415import dev .cel .extensions .CelExtensions ;
16+ import dev .cel .common .CelContainer ;
17+ import dev .cel .common .types .StructTypeReference ;
18+ import dev .cel .expr .conformance .proto3 .TestAllTypes ;
1519import dev .cel .optimizer .CelOptimizationException ;
1620import dev .cel .optimizer .CelOptimizer ;
1721import dev .cel .optimizer .CelOptimizerFactory ;
2529@ RunWith (TestParameterInjector .class )
2630public class InliningOptimizerTest {
2731
32+ private static final Cel CEL = CelFactory .standardCelBuilder ()
33+ .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
34+ .setContainer (CelContainer .ofName ("google.expr.proto3.test" ))
35+ .addFileTypes (TestAllTypes .getDescriptor ().getFile ())
36+ .addCompilerLibraries (CelExtensions .bindings ())
37+ .addVar ("int_var_to_inline" , SimpleType .INT )
38+ .addVar ("a" , SimpleType .DYN )
39+ .addVar ("msg" , StructTypeReference .create (TestAllTypes .getDescriptor ().getFullName ()))
40+ .addVar ("unpacked_wrapper" , SimpleType .STRING )
41+ .addVar ("wrapper_var" , StructTypeReference .create ("google.protobuf.Int64Value" ))
42+ .addVar ("child" , StructTypeReference .create (TestAllTypes .NestedMessage .getDescriptor ().getFullName ()))
43+ .addVar ("shadowed_ident" , SimpleType .INT )
44+ .addVar ("x" , SimpleType .DYN )
45+ .setOptions (CelOptions .current ().populateMacroCalls (true ).build ())
46+ .build ();
47+
2848 @ Test
29- public void inlineConstant ( ) throws Exception {
30- Cel cel = CelFactory . standardCelBuilder (). addVar ( "ident_to_inline" , SimpleType . INT ). build ();
31- String expression = "ident_to_inline + 2 + ident_to_inline" ;
32- CelAbstractSyntaxTree astToInline = cel . compile ( expression ). getAst ();
33- CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (cel )
49+ public void inlining_success ( @ TestParameter SuccessTestCase testCase ) throws Exception {
50+ CelAbstractSyntaxTree astToInline = CEL . compile ( testCase . source ). getAst ();
51+ CelAbstractSyntaxTree replacementAst = CEL . compile ( testCase . replacement ). getAst () ;
52+
53+ CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (CEL )
3454 .addAstOptimizers (InliningOptimizer .newInstance (
35- InlineVariable .of ("ident_to_inline" , cel .compile ("1" ).getAst ())
36- ))
55+ InlineVariable .of (testCase .varName , replacementAst )))
3756 .build ();
3857
3958 CelAbstractSyntaxTree optimized = optimizer .optimize (astToInline );
4059
4160 String unparsed = CelUnparserFactory .newUnparser ().unparse (optimized );
42- assertThat (unparsed ).isEqualTo ("1 + 2 + 1" );
61+ assertThat (unparsed ).isEqualTo (testCase . expected );
4362 }
4463
4564 @ Test
46- public void inline_doesNotInlineIterVar () throws Exception {
47- Cel cel = CelFactory .standardCelBuilder ()
48- .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
49- .setOptions (CelOptions .current ().populateMacroCalls (true ).build ())
50- .addVar ("shadowed_ident" , SimpleType .INT )
51- .build ();
52- String expression = "[0].exists(shadowed_ident, shadowed_ident == 0)" ;
53- CelAbstractSyntaxTree astToInline = cel .compile (expression ).getAst ();
54- CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (cel )
65+ public void inlining_noop (@ TestParameter NoOpTestCase testCase ) throws Exception {
66+ CelAbstractSyntaxTree astToInline = CEL .compile (testCase .source ).getAst ();
67+ CelAbstractSyntaxTree replacementAst = CEL .compile (testCase .replacement ).getAst ();
68+
69+ CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (CEL )
5570 .addAstOptimizers (InliningOptimizer .newInstance (
56- InlineVariable .of ("shadowed_ident" , cel .compile ("1" ).getAst ())
57- ))
71+ InlineVariable .of (testCase .varName , replacementAst )))
5872 .build ();
5973
6074 CelAbstractSyntaxTree optimized = optimizer .optimize (astToInline );
6175
6276 String unparsed = CelUnparserFactory .newUnparser ().unparse (optimized );
63- assertThat (unparsed ).isEqualTo ("[0].exists(shadowed_ident, shadowed_ident == 0)" );
77+ assertThat (unparsed ).isEqualTo (testCase . source );
6478 }
6579
66- @ Test
67- public void inline_bindMacro_doesNotInlineVarName () throws Exception {
68- Cel cel = CelFactory .standardCelBuilder ()
69- .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
70- .addCompilerLibraries (CelExtensions .bindings ())
71- .setOptions (CelOptions .current ().populateMacroCalls (true ).build ())
72- .addVar ("shadowed_ident" , SimpleType .INT )
73- .build ();
74- String expression = "cel.bind(shadowed_ident, 2, shadowed_ident + 1)" ;
75- CelAbstractSyntaxTree astToInline = cel .compile (expression ).getAst ();
76- CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (cel )
77- .addAstOptimizers (InliningOptimizer .newInstance (
78- InlineVariable .of ("shadowed_ident" , cel .compile ("1" ).getAst ())
79- ))
80- .build ();
80+ private enum SuccessTestCase {
81+ CONSTANT (
82+ "int_var_to_inline + 2 + int_var_to_inline" ,
83+ "int_var_to_inline" ,
84+ "1" ,
85+ "1 + 2 + 1" ),
86+ REPEATED (
87+ "a + [a]" ,
88+ "a" ,
89+ "dyn([1, 2])" ,
90+ "dyn([1, 2]) + [dyn([1, 2])]" ),
91+ SELECT (
92+ "has(msg.single_any)" ,
93+ "msg.single_any" ,
94+ "msg.single_int64_wrapper" ,
95+ "has(msg.single_int64_wrapper)" ),
96+ PRESENCE (
97+ "has(msg.single_int64_wrapper)" ,
98+ "msg.single_int64_wrapper" ,
99+ "wrapper_var" ,
100+ "wrapper_var != null" ),
101+ NESTED (
102+ "msg.standalone_message.bb" ,
103+ "msg.standalone_message" ,
104+ "child" ,
105+ "child.bb" ),
106+ ;
81107
82- CelAbstractSyntaxTree optimized = optimizer .optimize (astToInline );
108+ private final String source ;
109+ private final String varName ;
110+ private final String replacement ;
111+ private final String expected ;
83112
84- String unparsed = CelUnparserFactory .newUnparser ().unparse (optimized );
85- assertThat (unparsed ).isEqualTo ("cel.bind(shadowed_ident, 2, shadowed_ident + 1)" );
113+ SuccessTestCase (String source , String varName , String replacement , String expected ) {
114+ this .source = source ;
115+ this .varName = varName ;
116+ this .replacement = replacement ;
117+ this .expected = expected ;
118+ }
119+ }
120+
121+ private enum NoOpTestCase {
122+ NO_INLINE_ITER_VAR (
123+ "[0].exists(shadowed_ident, shadowed_ident == 0)" ,
124+ "shadowed_ident" ,
125+ "1" ),
126+ NO_INLINE_BIND_VAR (
127+ "cel.bind(shadowed_ident, 2, shadowed_ident + 1)" ,
128+ "shadowed_ident" ,
129+ "1" ),
130+ ;
131+
132+ private final String source ;
133+ private final String varName ;
134+ private final String replacement ;
135+
136+ NoOpTestCase (String source , String varName , String replacement ) {
137+ this .source = source ;
138+ this .varName = varName ;
139+ this .replacement = replacement ;
140+ }
86141 }
87142
88143 @ Test
89144 public void inline_exceededIterationLimit_throws () throws Exception {
90- Cel cel = CelFactory .standardCelBuilder ()
91- .setStandardMacros (CelStandardMacro .STANDARD_MACROS )
92- .addCompilerLibraries (CelExtensions .bindings ())
93- .addVar ("ident_to_replace" , SimpleType .INT )
94- .build ();
95- String expression = "ident_to_replace + ident_to_replace + ident_to_replace" ;
96- CelAbstractSyntaxTree astToInline = cel .compile (expression ).getAst ();
97- CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (cel )
145+ String expression = "int_var_to_inline + int_var_to_inline + int_var_to_inline" ;
146+ CelAbstractSyntaxTree astToInline = CEL .compile (expression ).getAst ();
147+ CelOptimizer optimizer = CelOptimizerFactory .standardCelOptimizerBuilder (CEL )
98148 .addAstOptimizers (InliningOptimizer .newInstance (
99149 InliningOptions .newBuilder ().maxIterationLimit (2 ).build (),
100- InlineVariable .of ("ident_to_replace" , cel .compile ("1" ).getAst ())
101- ))
150+ InlineVariable .of ("int_var_to_inline" , CEL .compile ("1" ).getAst ())))
102151 .build ();
103152
104153 CelOptimizationException e = assertThrows (CelOptimizationException .class , () -> optimizer .optimize (astToInline ));
@@ -107,8 +156,8 @@ public void inline_exceededIterationLimit_throws() throws Exception {
107156
108157 @ Test
109158 public void inlineVariableDecl_internalVar_throws () throws Exception {
110- IllegalArgumentException e = assertThrows (IllegalArgumentException .class , () ->
111- InlineVariable . of ( "@internal_var" , CelAbstractSyntaxTree .newParsedAst (CelExpr .ofNotSet (0L ), CelSource .newBuilder ().build ())));
112- assertThat (e ).hasMessageThat ().contains ("Internal variables cannot be inlined: @internal_var" );
159+ IllegalArgumentException e = assertThrows (IllegalArgumentException .class , () -> InlineVariable . of ( "@internal_var" ,
160+ CelAbstractSyntaxTree .newParsedAst (CelExpr .ofNotSet (0L ), CelSource .newBuilder ().build ())));
161+ assertThat (e ).hasMessageThat ().contains ("Internal variables cannot be inlined: @internal_var" );
113162 }
114163}
0 commit comments