From ca0a8da5c2479184554c284ac3d5bc37b448a705 Mon Sep 17 00:00:00 2001 From: 2pac Date: Wed, 30 Apr 2025 00:39:12 +0200 Subject: [PATCH 1/2] fix(785): `get` to work when return is `nil` --- builtin/lib.go | 4 ++++ test/fuzz/fuzz_corpus.txt | 5 +++++ test/issues/785/issue_test.go | 38 +++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 test/issues/785/issue_test.go diff --git a/builtin/lib.go b/builtin/lib.go index 5a70a6b91..579393161 100644 --- a/builtin/lib.go +++ b/builtin/lib.go @@ -374,6 +374,10 @@ func get(params ...any) (out any, err error) { i := params[1] v := reflect.ValueOf(from) + if from == nil { + return nil, nil + } + if v.Kind() == reflect.Invalid { panic(fmt.Sprintf("cannot fetch %v from %T", i, from)) } diff --git a/test/fuzz/fuzz_corpus.txt b/test/fuzz/fuzz_corpus.txt index 72afdf6ce..e1395c7b4 100644 --- a/test/fuzz/fuzz_corpus.txt +++ b/test/fuzz/fuzz_corpus.txt @@ -7221,6 +7221,11 @@ get(true ? i64 : greet, i32) get(true ? score : true, half)?.half get(true ? true : i, f64) get({"foo": foo, "bar": false}, type(i)) +get(nil, "a") +get({}, "a") +get(nil, "a") == nil +get({}, "a") == nil +({} | get("a") | get("b")) == nil greet greet != greet greet != greet != ok diff --git a/test/issues/785/issue_test.go b/test/issues/785/issue_test.go new file mode 100644 index 000000000..4e4f9e53d --- /dev/null +++ b/test/issues/785/issue_test.go @@ -0,0 +1,38 @@ +package issue_test + +import ( + "testing" + + "github.com/expr-lang/expr" + "github.com/expr-lang/expr/internal/testify/require" +) + +func TestIssue785(t *testing.T) { + emptyMap := map[string]any{} + + env := map[string]interface{}{ + "empty_map": emptyMap, + } + + { + code := `get(empty_map, "non_existing_key") | get("some_key") | get("another_key") | get("yet_another_key") | get("last_key")` + + program, err := expr.Compile(code, expr.Env(env)) + require.NoError(t, err) + + output, err := expr.Run(program, env) + require.NoError(t, err) + require.Equal(t, nil, output) + } + + { + code := `{} | get("non_existing_key") | get("some_key") | get("another_key") | get("yet_another_key") | get("last_key")` + + program, err := expr.Compile(code, expr.Env(env)) + require.NoError(t, err) + + output, err := expr.Run(program, env) + require.NoError(t, err) + require.Equal(t, nil, output) + } +} From 2452844bf0b8d18f3c42271b33ba855cd4cd77ae Mon Sep 17 00:00:00 2001 From: 2pac Date: Mon, 12 May 2025 17:16:20 +0200 Subject: [PATCH 2/2] improve testing --- expr_test.go | 21 +++++++++++++++++++++ test/fuzz/fuzz_corpus.txt | 5 ----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/expr_test.go b/expr_test.go index 4d3736a97..faa5cae6d 100644 --- a/expr_test.go +++ b/expr_test.go @@ -2724,3 +2724,24 @@ func TestExpr_wierd_cases(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "unknown name A") } + +func TestIssue785_get_nil(t *testing.T) { + exprStrs := []string{ + `get(nil, "a")`, + `get({}, "a")`, + `get(nil, "a")`, + `get({}, "a")`, + `({} | get("a") | get("b"))`, + } + + for _, exprStr := range exprStrs { + t.Run("get returns nil", func(t *testing.T) { + env := map[string]interface{}{} + + result, err := expr.Eval(exprStr, env) + require.NoError(t, err) + + require.Equal(t, nil, result) + }) + } +} diff --git a/test/fuzz/fuzz_corpus.txt b/test/fuzz/fuzz_corpus.txt index e1395c7b4..72afdf6ce 100644 --- a/test/fuzz/fuzz_corpus.txt +++ b/test/fuzz/fuzz_corpus.txt @@ -7221,11 +7221,6 @@ get(true ? i64 : greet, i32) get(true ? score : true, half)?.half get(true ? true : i, f64) get({"foo": foo, "bar": false}, type(i)) -get(nil, "a") -get({}, "a") -get(nil, "a") == nil -get({}, "a") == nil -({} | get("a") | get("b")) == nil greet greet != greet greet != greet != ok