3
0

Fixes string expressions int param casting issue in workflow

This commit is contained in:
Vivek Patel
2021-07-30 19:09:05 +05:30
parent 9e6d5884c2
commit 9d272d5bda
2 changed files with 95 additions and 4 deletions

View File

@@ -476,3 +476,73 @@ func TestIsNil(t *testing.T) {
})
}
}
func TestGvalStringFunctionParamsIntCasting(t *testing.T) {
var (
ctx = context.Background()
req = require.New(t)
scope = &expr.Vars{}
)
t.Run("substring", func(t *testing.T) {
eval, err := expr.NewParser().Parse(`substring("foobar", 1, -1)`)
req.NoError(err)
res, err := eval.Eval(ctx, scope)
req.NoError(err)
req.Equal("oobar", res.(string))
})
t.Run("replace", func(t *testing.T) {
eval, err := expr.NewParser().Parse(`replace(" foo foo foo", "foo", "bar", 1)`)
req.NoError(err)
res, err := eval.Eval(ctx, scope)
req.NoError(err)
req.Equal(" bar foo foo", res.(string))
})
t.Run("split", func(t *testing.T) {
eval, err := expr.NewParser().Parse(`split("foo-bar", "-")`)
req.NoError(err)
res, err := eval.Eval(ctx, scope)
req.NoError(err)
req.Equal([]string{"foo", "bar"}, res.([]string))
})
t.Run("has", func(t *testing.T) {
eval, err := expr.NewParser().Parse(`has([1,2], 2)`)
req.NoError(err)
res, err := eval.Eval(ctx, scope)
req.NoError(err)
req.Equal(true, res)
})
t.Run("repeat", func(t *testing.T) {
eval, err := expr.NewParser().Parse(`repeat("! ", 3)`)
req.NoError(err)
res, err := eval.Eval(ctx, scope)
req.NoError(err)
req.Equal("! ! ! ", res.(string))
})
t.Run("shorten", func(t *testing.T) {
eval, err := expr.NewParser().Parse(`shorten("This is a whole sentence", "word", 4)`)
req.NoError(err)
res, err := eval.Eval(ctx, scope)
req.NoError(err)
req.Equal("This is a whole …", res.(string))
})
}

View File

@@ -3,6 +3,8 @@ package expr
import (
"errors"
"fmt"
"github.com/spf13/cast"
"reflect"
"regexp"
"strings"
@@ -22,22 +24,41 @@ func StringFunctions() []gval.Language {
gval.Function("format", fmt.Sprintf),
gval.Function("title", title),
gval.Function("untitle", untitle),
gval.Function("repeat", strings.Repeat),
gval.Function("replace", strings.Replace),
gvalFunc("repeat", strings.Repeat),
gvalFunc("replace", strings.Replace),
gval.Function("isUrl", valid.IsURL),
gval.Function("isEmail", valid.IsEmail),
gval.Function("split", strings.Split),
gval.Function("join", join),
gval.Function("hasSubstring", hasSubstring),
gval.Function("substring", substring),
gvalFunc("substring", substring),
gval.Function("hasPrefix", strings.HasPrefix),
gval.Function("hasSuffix", strings.HasSuffix),
gval.Function("shorten", shorten),
gvalFunc("shorten", shorten),
gval.Function("camelize", camelize),
gval.Function("snakify", snakify),
}
}
// gvalFunc cast any nth number of float64 param to int
func gvalFunc(name string, fn interface{}) gval.Language {
return gval.Function(name, func(params ...interface{}) (out interface{}) {
in := make([]reflect.Value, len(params))
for i, param := range params {
if reflect.TypeOf(param).Kind() == reflect.Float64 {
param = cast.ToInt(param)
}
in[i] = reflect.ValueOf(param)
}
fun := reflect.ValueOf(fn)
res := fun.Call(in)
if len(res) > 0 {
out = cast.ToString(reflect.ValueOf(res[0]).Interface())
}
return
})
}
func shortest(f string, aa ...string) string {
for _, s := range aa {
if len(f) > len(s) {