@@ -17,12 +17,15 @@ package cel
1717import (
1818 "reflect"
1919 "sort"
20+ "strings"
2021 "testing"
2122
2223 "google.golang.org/protobuf/encoding/prototext"
2324 "google.golang.org/protobuf/proto"
2425
2526 "github.com/google/cel-go/common/ast"
27+ "github.com/google/cel-go/common/types"
28+ "github.com/google/cel-go/common/types/ref"
2629
2730 proto3pb "github.com/google/cel-go/test/proto3pb"
2831 exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
@@ -313,6 +316,83 @@ func TestConstantFoldingOptimizer(t *testing.T) {
313316 }
314317}
315318
319+ func TestConstantFoldingCallsWithSideEffects (t * testing.T ) {
320+ tests := []struct {
321+ expr string
322+ folded string
323+ error string
324+ }{
325+ {
326+ expr : `noSideEffect(3)` ,
327+ folded : `3` ,
328+ },
329+ {
330+ expr : `withSideEffect(3)` ,
331+ folded : `withSideEffect(3)` ,
332+ },
333+ {
334+ expr : `noImpl(3)` ,
335+ error : `constant-folding evaluation failed: no such overload: noImpl` ,
336+ },
337+ }
338+ e , err := NewEnv (
339+ OptionalTypes (),
340+ EnableMacroCallTracking (),
341+ Function ("noSideEffect" ,
342+ Overload ("noSideEffect_int_int" ,
343+ []* Type {IntType },
344+ IntType , FunctionBinding (func (args ... ref.Val ) ref.Val {
345+ return args [0 ]
346+ }))),
347+ Function ("withSideEffect" ,
348+ Overload ("withSideEffect_int_int" ,
349+ []* Type {IntType },
350+ IntType , FunctionBinding (func (args ... ref.Val ) ref.Val {
351+ return & types.Unknown {}
352+ }))),
353+ Function ("noImpl" ,
354+ Overload ("noImpl_int_int" ,
355+ []* Type {IntType },
356+ IntType )),
357+ )
358+ if err != nil {
359+ t .Fatalf ("NewEnv() failed: %v" , err )
360+ }
361+ for _ , tst := range tests {
362+ tc := tst
363+ t .Run (tc .expr , func (t * testing.T ) {
364+ checked , iss := e .Compile (tc .expr )
365+ if iss .Err () != nil {
366+ t .Fatalf ("Compile() failed: %v" , iss .Err ())
367+ }
368+ folder , err := NewConstantFoldingOptimizer ()
369+ if err != nil {
370+ t .Fatalf ("NewConstantFoldingOptimizer() failed: %v" , err )
371+ }
372+ opt := NewStaticOptimizer (folder )
373+ optimized , iss := opt .Optimize (e , checked )
374+ if tc .error != "" {
375+ if iss .Err () == nil {
376+ t .Errorf ("got nil, wanted error containing %q" , tc .error )
377+ } else if ! strings .Contains (iss .Err ().Error (), tc .error ) {
378+ t .Errorf ("got %q, wanted error containing %q" , iss .Err ().Error (), tc .error )
379+ }
380+ return
381+ }
382+ if iss .Err () != nil {
383+ t .Fatalf ("Optimize() generated an invalid AST: %v" , iss .Err ())
384+ }
385+ folded , err := AstToString (optimized )
386+ if err != nil {
387+ t .Fatalf ("AstToString() failed: %v" , err )
388+ }
389+ if folded != tc .folded {
390+ t .Errorf ("got %q, wanted %q" , folded , tc .folded )
391+ }
392+ })
393+ }
394+ }
395+
316396func TestConstantFoldingOptimizerMacroElimination (t * testing.T ) {
317397 tests := []struct {
318398 expr string
0 commit comments