package expr import ( "context" "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestIsExpression(t *testing.T) { now := time.Now() tests := []struct { name string eval string want bool }{ {"equal", "i == 3", true}, {"in array", "i in [1,2,3]", true}, {"contains", "value contains 'some'", true}, {"contains with . + () $ {} ^", "value contains 'something with . + () $ {} ^'", true}, {"startsWith", "value startsWith 'some'", true}, {"startsWith . + () $ {} ^", "value startsWith '. + () $ {} ^'", true}, {"endsWith", "value endsWith 'some'", true}, {"endsWith . + () $ {} ^", "value endsWith '. + () $ {} ^'", true}, {"icontains", "icontains(value, 'some')", true}, {"icontains with . + () $ {} ^", "icontains (value, 'something with . + () $ {} ^')", true}, {"istartsWith", "istartsWith(value, 'Some')", true}, {"istartsWith . + () $ {} ^ . + () $ {} ^", "istartsWith(value, '. + () $ {} ^')", true}, {"iendsWith", "iendsWith(value, 'some')", true}, {"iendsWith . + () $ {} ^", "iendsWith(value,'. + () $ {} ^')", true}, {"or", "i == 2 || i > 10", true}, {"search", "search('some') || i > 10", true}, {"vars:or", "i == a + 2 || i > a + 10", true}, {"near", "near(a, [55.5, 37.5], 1000)", true}, {"within", "within(a, 'box', [[54.54, 36.36], [55.55, 37.37]])", true}, {"time", "d > Time.Date('2021-08-31')", true}, {"time", fmt.Sprintf("d > Time.Time('%s')", now.Format(time.RFC3339)), true}, {"in", "In(s, [1,2,3])", true}, {"in", "In(s, 1)", true}, {"exists#1", "exists(s)", true}, {"exists#2", "exists", false}, {"len#1", "len(s) == 1", true}, {"len#2", "len(s) != 1", true}, {"len#3", "len(s) > 1", true}, {"len#4", "len(s) >= 1", true}, {"len#5", "len(s) < 1", true}, {"len#6", "len(s) <= 1", true}, {"len#7", "len", false}, {"text search or id", "id", false}, {"numbers", "3", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := IsExpression(tt.eval) assert.Equal(t, tt.want, got) }) } } type testEnvStruct struct { ID string `expr:"id"` Size int `expr:"size"` Data interface{} `expr:"data"` } func (s *testEnvStruct) Equal(other *testEnvStruct) bool { return s.ID == other.ID } func TestExpr_Example(t *testing.T) { ctx := context.Background() tests := []struct { name string exp string env map[string]interface{} wantErr bool wantResult interface{} }{ { name: "get field by expr tag", exp: "s.id", env: map[string]interface{}{"s": &testEnvStruct{ID: "id1"}}, wantResult: "id1", }, { name: "get field by field name", exp: "s.ID", env: map[string]interface{}{"s": &testEnvStruct{ID: "id1"}}, wantResult: "id1", }, { name: "get nested field", exp: "m.s.size", env: map[string]interface{}{"m": map[string]interface{}{"s": &testEnvStruct{Size: 1}}}, wantResult: 1, }, { name: "check field", exp: "s.data.size < 100", env: map[string]interface{}{"s": &testEnvStruct{Data: &testEnvStruct{Size: 0}}}, wantResult: true, }, { name: "use method", exp: "s1.Equal(s2)", env: map[string]interface{}{"s1": &testEnvStruct{ID: "id1"}, "s2": &testEnvStruct{ID: "id2"}}, wantResult: false, }, { name: "field not exists", exp: "s.not_exists", env: map[string]interface{}{"s": &testEnvStruct{}}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result, err := Eval(ctx, tt.exp, tt.env) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) require.Equal(t, tt.wantResult, result) }) } }