Skip to content

Commit

Permalink
Add function accessor to Env (#978)
Browse files Browse the repository at this point in the history
* Add function accessor to env
* Add test to strings verifying that existing versions have a known list of functions
  • Loading branch information
jpbetz authored Jul 9, 2024
1 parent 24a38ef commit 21976cf
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
11 changes: 11 additions & 0 deletions cel/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,17 @@ func (e *Env) Libraries() []string {
return libraries
}

// HasFunction returns whether a specific function has been configured in the environment
func (e *Env) HasFunction(functionName string) bool {
_, ok := e.functions[functionName]
return ok
}

// Functions returns map of Functions, keyed by function name, that have been configured in the environment.
func (e *Env) Functions() map[string]*decls.FunctionDecl {
return e.functions
}

// HasValidator returns whether a specific ASTValidator has been configured in the environment.
func (e *Env) HasValidator(name string) bool {
for _, v := range e.validators {
Expand Down
16 changes: 16 additions & 0 deletions cel/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,22 @@ func TestLibraries(t *testing.T) {
}
}

func TestFunctions(t *testing.T) {
e, err := NewEnv(OptionalTypes())
if err != nil {
t.Fatalf("NewEnv() failed: %v", err)
}
for _, expected := range []string{"optional.of", "or"} {
if !e.HasFunction(expected) {
t.Errorf("Expected HasFunction() to return true for '%s'", expected)
}

if _, ok := e.Functions()[expected]; !ok {
t.Errorf("Expected Functions() to include '%s'", expected)
}
}
}

func BenchmarkNewCustomEnvLazy(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
Expand Down
50 changes: 50 additions & 0 deletions ext/strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,56 @@ func evalWithCEL(input string, expectedRuntimeCost uint64, expectedEstimatedCost
return out.Value().(string)
}

func TestFunctionsForVersions(t *testing.T) {
tests := []struct {
version uint32
introducedFunctions []string
}{
{
version: 0,
introducedFunctions: []string{"lastIndexOf", "lowerAscii", "split", "trim", "join", "charAt", "indexOf", "replace", "substring", "upperAscii"},
},
{
version: 1,
introducedFunctions: []string{"strings.quote", "format"},
},
{
version: 2,
introducedFunctions: []string{}, // join changed, no functions added
},
{
version: 3,
introducedFunctions: []string{"reverse"},
},
}
var functions []string
for _, tt := range tests {
functions = append(functions, tt.introducedFunctions...)
t.Run(fmt.Sprintf("version %d", tt.version), func(t *testing.T) {
e, err := cel.NewCustomEnv(Strings(StringsVersion(tt.version)))
if err != nil {
t.Fatalf("NewEnv() failed: %v", err)
}
if len(functions) != len(e.Functions()) {
var functionNames []string
for name := range e.Functions() {
functionNames = append(functionNames, name)
}
t.Fatalf("Expected functions: %#v, got %#v", functions, functionNames)
}
for _, expected := range functions {
if !e.HasFunction(expected) {
t.Errorf("Expected HasFunction() to return true for '%s'", expected)
}

if _, ok := e.Functions()[expected]; !ok {
t.Errorf("Expected Functions() to include '%s'", expected)
}
}
})
}
}

func FuzzQuote(f *testing.F) {
tests := []string{
"this is a test",
Expand Down

0 comments on commit 21976cf

Please sign in to comment.