3
0

Additional tests & bool handling

This commit is contained in:
Denis Arh
2021-03-30 20:07:20 +02:00
parent 565a64d0c1
commit d49f4fbbad
4 changed files with 140 additions and 19 deletions

View File

@@ -58,6 +58,9 @@ func TestRecordFieldValuesAccess(t *testing.T) {
&types.ModuleField{Name: "s2", Multi: false, Kind: "String"},
&types.ModuleField{Name: "b0", Multi: false, Kind: "Bool"},
&types.ModuleField{Name: "b1", Multi: false, Kind: "Bool"},
&types.ModuleField{Name: "n1", Multi: false, Kind: "Number"},
&types.ModuleField{Name: "n2", Multi: false, Kind: "Number"},
&types.ModuleField{Name: "n3", Multi: false, Kind: "Number"},
}}
raw = &types.Record{Values: types.RecordValueSet{
@@ -67,10 +70,15 @@ func TestRecordFieldValuesAccess(t *testing.T) {
&types.RecordValue{Name: "m1", Value: "mVal1.2", Place: 2},
&types.RecordValue{Name: "m2", Value: "mVal2.0", Place: 0},
&types.RecordValue{Name: "b1", Value: "1", Place: 0},
&types.RecordValue{Name: "n2", Value: "0", Place: 0},
&types.RecordValue{Name: "n3", Value: "2", Place: 0},
}}
tval = &ComposeRecord{value: raw}
scope = expr.RVars{"rec": tval}.Vars()
scope = expr.RVars{
"rec": tval,
"nil": nil,
}.Vars()
)
// @todo see not above re. back-ref to record
@@ -108,6 +116,8 @@ func TestRecordFieldValuesAccess(t *testing.T) {
test bool
expr string
}{
{false, `nil`},
// interaction with set values
{true, `rec.values.s1 == "sVal1"`},
{false, `rec.values.s1 == "sVal2"`},
@@ -130,16 +140,37 @@ func TestRecordFieldValuesAccess(t *testing.T) {
{false, `rec.values.b0`},
{true, `rec.values.b1`},
{false, `!rec.values.b1`},
// numbers
{false, `rec.values.n1`},
{false, `rec.values.n2`},
{true, `rec.values.n3`},
{true, `rec.values.n1 == 0`},
{true, `rec.values.n2 == 0`},
{false, `rec.values.n3 == 0`},
{false, `rec.values.n1 == 2`},
{false, `rec.values.n2 == 2`},
{true, `rec.values.n3 == 2`},
//{true, `rec.values.n1 < 3`}, // invalid op <nil> < 3
{true, `rec.values.n2 < 3`},
{true, `rec.values.n3 < 3`},
//{false, `rec.values.n1 > 1`}, // invalid op <nil> > 3
{false, `rec.values.n2 > 2`},
{false, `rec.values.n3 > 2`},
}
for _, tc := range tcc {
var (
req = require.New(t)
parser = expr.NewParser()
)
t.Run(tc.expr, func(t *testing.T) {
eval, err := parser.Parse(tc.expr)
var (
req = require.New(t)
parser = expr.NewParser()
eval, err = parser.Parse(tc.expr)
)
req.NoError(err)
test, err := eval.Test(context.Background(), scope)

View File

@@ -229,12 +229,27 @@ func (t Array) Select(k string) (TypedValue, error) {
}
}
// emptyStringFailsafe returns 0 on empty strings
func emptyStringFailsafe(val interface{}) interface{} {
val = UntypedValue(val)
if aux, is := val.(string); is && len(strings.TrimSpace(aux)) == 0 {
return 0
} else {
return val
}
}
func (t ID) MarshalJSON() ([]byte, error) {
return json.Marshal(fmt.Sprintf("%d", t.value))
}
func CastToBoolean(val interface{}) (out bool, err error) {
return cast.ToBoolE(UntypedValue(val))
val = UntypedValue(val)
if aux, is := val.(string); is && len(strings.TrimSpace(aux)) == 0 {
return false, nil
}
return cast.ToBoolE(val)
}
func CastToString(val interface{}) (out string, err error) {
@@ -258,7 +273,7 @@ func CastToHandle(val interface{}) (string, error) {
}
func CastToDuration(val interface{}) (out time.Duration, err error) {
return cast.ToDurationE(UntypedValue(val))
return cast.ToDurationE(emptyStringFailsafe(val))
}
func CastToDateTime(val interface{}) (out *time.Time, err error) {
@@ -279,21 +294,19 @@ func CastToDateTime(val interface{}) (out *time.Time, err error) {
}
func CastToFloat(val interface{}) (out float64, err error) {
return cast.ToFloat64E(UntypedValue(val))
return cast.ToFloat64E(emptyStringFailsafe(val))
}
func CastToID(val interface{}) (out uint64, err error) {
out, err = cast.ToUint64E(UntypedValue(val))
return
return cast.ToUint64E(emptyStringFailsafe(val))
}
func CastToInteger(val interface{}) (out int64, err error) {
return cast.ToInt64E(UntypedValue(val))
return cast.ToInt64E(emptyStringFailsafe(val))
}
func CastToUnsignedInteger(val interface{}) (out uint64, err error) {
return cast.ToUint64E(UntypedValue(val))
return cast.ToUint64E(emptyStringFailsafe(val))
}
func (t *KV) Has(k string) bool {

View File

@@ -1,12 +1,60 @@
package expr
import (
"context"
"github.com/stretchr/testify/require"
"net/http"
"net/url"
"testing"
)
func TestTypedValueOperations(t *testing.T) {
scope := RVars{
"xUint": Must(NewUnsignedInteger(1)),
"xInt": Must(NewInteger(1)),
"xBoolT": Must(NewBoolean(true)),
"xBoolF": Must(NewBoolean(false)),
"xString": Must(NewString("foo")),
}.Vars()
tcc := []struct {
expects interface{}
expr string
}{
// sanity check
{true, "xBoolT"},
{false, "xBoolF"},
// uint ops
{true, "xUint == 1"},
{uint64(1), "xUint"},
// uint ops
{true, "xInt == 1"},
{int64(1), "xInt"},
// string ops
{true, `xString == "foo"`},
{"foo", "xString"},
}
for _, tc := range tcc {
t.Run(tc.expr, func(t *testing.T) {
var (
req = require.New(t)
parser = NewParser()
eval, err = parser.Parse(tc.expr)
)
req.NoError(err)
result, err := eval.Eval(context.Background(), scope)
req.NoError(err)
req.Equal(tc.expects, UntypedValue(result))
})
}
}
func TestKV_Set(t *testing.T) {
var (
req = require.New(t)
@@ -46,6 +94,37 @@ func TestKVV_Set(t *testing.T) {
req.Equal([]string{"bar"}, kvv.value["foo"])
}
func TestCastEmptyString(t *testing.T) {
var (
req = require.New(t)
)
{
f, err := CastToFloat("")
req.NoError(err)
req.Zero(f)
}
{
i, err := CastToInteger("")
req.NoError(err)
req.Zero(i)
}
{
u, err := CastToUnsignedInteger("")
req.NoError(err)
req.Zero(u)
}
{
u, err := CastToDuration("")
req.NoError(err)
req.Zero(u)
}
{
u, err := CastToBoolean("")
req.NoError(err)
req.False(u)
}
}
func TestCastToArray(t *testing.T) {
var (
req = require.New(t)

View File

@@ -66,13 +66,11 @@ func (p *gvalParser) ParseEvaluators(ee ...Evaluator) error {
}
func (e *gvalEval) Eval(ctx context.Context, scope *Vars) (interface{}, error) {
return e.evaluable(ctx, scope)
//return e.evaluable(ctx, scope.Dict())
return e.evaluable(ctx, scope.Dict())
}
func (e *gvalEval) Test(ctx context.Context, scope *Vars) (bool, error) {
r, err := e.evaluable(ctx, scope)
//r, err := e.evaluable(ctx, scope.Dict())
r, err := e.evaluable(ctx, scope.Dict())
if err != nil {
return false, err
}