2018-12-24 17:48:34 +02:00
|
|
|
package values_test
|
|
|
|
|
|
|
|
import (
|
2019-02-13 19:31:18 +02:00
|
|
|
"context"
|
2018-12-24 17:48:34 +02:00
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
|
|
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
)
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
var CustomType = core.NewType("custom")
|
|
|
|
|
|
|
|
type CustomValue struct {
|
2018-12-24 17:48:34 +02:00
|
|
|
properties map[core.Value]core.Value
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) MarshalJSON() ([]byte, error) {
|
2018-12-24 17:48:34 +02:00
|
|
|
return nil, core.ErrNotImplemented
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) Type() core.Type {
|
|
|
|
return CustomType
|
2018-12-24 17:48:34 +02:00
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) String() string {
|
2018-12-24 17:48:34 +02:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) Compare(other core.Value) int64 {
|
2018-12-24 17:48:34 +02:00
|
|
|
return other.Compare(t) * -1
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) Unwrap() interface{} {
|
2018-12-24 17:48:34 +02:00
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) Hash() uint64 {
|
2018-12-24 17:48:34 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) Copy() core.Value {
|
2018-12-24 17:48:34 +02:00
|
|
|
return values.None
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) GetIn(ctx context.Context, path []core.Value) (core.Value, error) {
|
2018-12-24 17:48:34 +02:00
|
|
|
if path == nil || len(path) == 0 {
|
|
|
|
return values.None, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
propKey := path[0]
|
|
|
|
propValue, ok := t.properties[propKey]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
return values.None, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(path) == 1 {
|
|
|
|
return propValue, nil
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
return values.GetIn(ctx, propValue, path[1:])
|
2018-12-24 17:48:34 +02:00
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
func (t *CustomValue) SetIn(ctx context.Context, path []core.Value, value core.Value) error {
|
2018-12-24 17:48:34 +02:00
|
|
|
if path == nil || len(path) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
propKey := path[0]
|
|
|
|
propValue, ok := t.properties[propKey]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(path) == 1 {
|
|
|
|
t.properties[propKey] = value
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
return values.SetIn(ctx, propValue, path[1:], value)
|
2018-12-24 17:48:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestHelpers(t *testing.T) {
|
|
|
|
Convey("Helpers", t, func() {
|
|
|
|
Convey("Getter", func() {
|
|
|
|
Convey("It should get a value by a given path", func() {
|
2019-02-13 19:31:18 +02:00
|
|
|
ct := &CustomValue{
|
2018-12-24 17:48:34 +02:00
|
|
|
properties: map[core.Value]core.Value{
|
|
|
|
values.NewString("foo"): values.NewInt(1),
|
2019-02-13 19:31:18 +02:00
|
|
|
values.NewString("bar"): &CustomValue{
|
2018-12-24 17:48:34 +02:00
|
|
|
properties: map[core.Value]core.Value{
|
|
|
|
values.NewString("qaz"): values.NewInt(2),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
foo, err := values.GetIn(ctx, ct, []core.Value{
|
2018-12-24 17:48:34 +02:00
|
|
|
values.NewString("foo"),
|
|
|
|
})
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(foo, ShouldEqual, values.NewInt(1))
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
qaz, err := values.GetIn(ctx, ct, []core.Value{
|
2018-12-24 17:48:34 +02:00
|
|
|
values.NewString("bar"),
|
|
|
|
values.NewString("qaz"),
|
|
|
|
})
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(qaz, ShouldEqual, values.NewInt(2))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Setter", func() {
|
|
|
|
Convey("It should get a value by a given path", func() {
|
2019-02-13 19:31:18 +02:00
|
|
|
ct := &CustomValue{
|
2018-12-24 17:48:34 +02:00
|
|
|
properties: map[core.Value]core.Value{
|
|
|
|
values.NewString("foo"): values.NewInt(1),
|
2019-02-13 19:31:18 +02:00
|
|
|
values.NewString("bar"): &CustomValue{
|
2018-12-24 17:48:34 +02:00
|
|
|
properties: map[core.Value]core.Value{
|
|
|
|
values.NewString("qaz"): values.NewInt(2),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
err := values.SetIn(ctx, ct, []core.Value{
|
2018-12-24 17:48:34 +02:00
|
|
|
values.NewString("foo"),
|
|
|
|
}, values.NewInt(2))
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(ct.properties[values.NewString("foo")], ShouldEqual, values.NewInt(2))
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
err = values.SetIn(ctx, ct, []core.Value{
|
2018-12-24 17:48:34 +02:00
|
|
|
values.NewString("bar"),
|
|
|
|
values.NewString("qaz"),
|
|
|
|
}, values.NewString("foobar"))
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2019-02-13 19:31:18 +02:00
|
|
|
qaz, err := values.GetIn(ctx, ct, []core.Value{
|
2018-12-24 17:48:34 +02:00
|
|
|
values.NewString("bar"),
|
|
|
|
values.NewString("qaz"),
|
|
|
|
})
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(qaz, ShouldEqual, values.NewString("foobar"))
|
|
|
|
})
|
|
|
|
})
|
2019-02-24 00:52:01 +02:00
|
|
|
|
|
|
|
Convey("ToBoolean", func() {
|
|
|
|
Convey("Should convert values", func() {
|
|
|
|
inputs := [][]core.Value{
|
|
|
|
{
|
|
|
|
values.None,
|
|
|
|
values.False,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.True,
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.False,
|
|
|
|
values.False,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewInt(1),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewInt(0),
|
|
|
|
values.False,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewFloat(1),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewFloat(0),
|
|
|
|
values.False,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewString("Foo"),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.EmptyString,
|
|
|
|
values.False,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewCurrentDateTime(),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewArray(1),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewObject(),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewBinary([]byte("")),
|
|
|
|
values.True,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, pair := range inputs {
|
|
|
|
actual := values.ToBoolean(pair[0])
|
|
|
|
expected := pair[1]
|
|
|
|
|
|
|
|
So(actual, ShouldEqual, expected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("ToFloat", func() {
|
|
|
|
Convey("Should convert Int", func() {
|
|
|
|
input := values.NewInt(100)
|
|
|
|
output, err := values.ToFloat(input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(output, ShouldEqual, values.NewFloat(100))
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should convert Float", func() {
|
|
|
|
input := values.NewFloat(100)
|
|
|
|
output, err := values.ToFloat(input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(output, ShouldEqual, values.NewFloat(100))
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should convert String", func() {
|
|
|
|
input := values.NewString("100.1")
|
|
|
|
output, err := values.ToFloat(input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(output, ShouldEqual, values.NewFloat(100.1))
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should NOT convert other types", func() {
|
|
|
|
inputs := []core.Value{
|
|
|
|
values.NewBoolean(true),
|
|
|
|
values.NewCurrentDateTime(),
|
|
|
|
values.NewArray(1),
|
|
|
|
values.NewObject(),
|
|
|
|
values.NewBinary([]byte("")),
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, input := range inputs {
|
|
|
|
_, err := values.ToFloat(input)
|
|
|
|
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("ToInt", func() {
|
|
|
|
Convey("Should convert Int", func() {
|
|
|
|
input := values.NewInt(100)
|
|
|
|
output, err := values.ToInt(input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(output, ShouldEqual, values.NewInt(100))
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should convert Float", func() {
|
|
|
|
input := values.NewFloat(100.1)
|
|
|
|
output, err := values.ToInt(input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(output, ShouldEqual, values.NewInt(100))
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should convert String", func() {
|
|
|
|
input := values.NewString("100")
|
|
|
|
output, err := values.ToInt(input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(output, ShouldEqual, values.NewInt(100))
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should NOT convert other types", func() {
|
|
|
|
inputs := []core.Value{
|
|
|
|
values.NewBoolean(true),
|
|
|
|
values.NewCurrentDateTime(),
|
|
|
|
values.NewArray(1),
|
|
|
|
values.NewObject(),
|
|
|
|
values.NewBinary([]byte("")),
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, input := range inputs {
|
|
|
|
_, err := values.ToInt(input)
|
|
|
|
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("ToArray", func() {
|
|
|
|
Convey("Should convert primitives", func() {
|
|
|
|
dt := values.NewCurrentDateTime()
|
|
|
|
|
|
|
|
inputs := [][]core.Value{
|
|
|
|
{
|
|
|
|
values.None,
|
|
|
|
values.NewArray(0),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.True,
|
|
|
|
values.NewArrayWith(values.True),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewInt(1),
|
|
|
|
values.NewArrayWith(values.NewInt(1)),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewFloat(1),
|
|
|
|
values.NewArrayWith(values.NewFloat(1)),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
values.NewString("foo"),
|
|
|
|
values.NewArrayWith(values.NewString("foo")),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
dt,
|
|
|
|
values.NewArrayWith(dt),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, pairs := range inputs {
|
|
|
|
actual, err := values.ToArray(context.Background(), pairs[0])
|
|
|
|
expected := pairs[1]
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(actual.Compare(expected), ShouldEqual, 0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should create a copy of a given array", func() {
|
|
|
|
vals := []core.Value{
|
|
|
|
values.NewInt(1),
|
|
|
|
values.NewInt(2),
|
|
|
|
values.NewInt(3),
|
|
|
|
values.NewInt(4),
|
|
|
|
values.NewArray(10),
|
|
|
|
values.NewObject(),
|
|
|
|
}
|
|
|
|
|
|
|
|
input := values.NewArrayWith(vals...)
|
|
|
|
output, err := values.ToArray(context.Background(), input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
arr := output.(*values.Array)
|
|
|
|
|
|
|
|
So(input == arr, ShouldBeFalse)
|
|
|
|
So(arr.Length() == input.Length(), ShouldBeTrue)
|
|
|
|
|
|
|
|
for idx := range vals {
|
|
|
|
expected := input.Get(values.NewInt(idx))
|
|
|
|
actual := arr.Get(values.NewInt(idx))
|
|
|
|
|
|
|
|
// same ref
|
|
|
|
So(actual == expected, ShouldBeTrue)
|
|
|
|
So(actual.Compare(expected), ShouldEqual, 0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Should convert object to an array", func() {
|
|
|
|
input := values.NewObjectWith(
|
|
|
|
values.NewObjectProperty("foo", values.NewString("bar")),
|
|
|
|
values.NewObjectProperty("baz", values.NewInt(1)),
|
|
|
|
values.NewObjectProperty("qaz", values.NewObject()),
|
|
|
|
)
|
|
|
|
|
|
|
|
output, err := values.ToArray(context.Background(), input)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
arr := output.(*values.Array).Sort()
|
|
|
|
|
|
|
|
So(arr.String(), ShouldEqual, "[1,\"bar\",{}]")
|
|
|
|
So(arr.Get(values.NewInt(2)) == input.MustGet("qaz"), ShouldBeTrue)
|
|
|
|
})
|
|
|
|
})
|
2018-12-24 17:48:34 +02:00
|
|
|
})
|
|
|
|
}
|