Fix nil pointer error while calling Vars method with nil Vars, that caused due to 1st statement in method was locking the Vars and expecting the mux preset in given Vars.
398 lines
8.1 KiB
Go
398 lines
8.1 KiB
Go
package expr
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// extract typed-value
|
|
|
|
func Example_set_vars() {
|
|
var (
|
|
p = map[string]interface{}{
|
|
"vars": &Vars{},
|
|
"key": "foo",
|
|
"value": &String{value: "foo"},
|
|
}
|
|
)
|
|
|
|
eval(`toJSON(set(vars, key, value))`, p)
|
|
|
|
// output:
|
|
// {"foo":{"@value":"foo","@type":"String"}}
|
|
}
|
|
|
|
func Example_merge_vars() {
|
|
var (
|
|
p = map[string]interface{}{
|
|
"vars": &Vars{},
|
|
"foo": &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
}},
|
|
"bar": &Vars{value: map[string]TypedValue{
|
|
"k2": &String{value: "v2"},
|
|
}},
|
|
}
|
|
)
|
|
|
|
eval(`toJSON(merge(foo, bar))`, p)
|
|
|
|
// output:
|
|
// {"k1":{"@value":"v1","@type":"String"},"k2":{"@value":"v2","@type":"String"}}
|
|
}
|
|
|
|
func Example_filter_vars() {
|
|
var (
|
|
p = map[string]interface{}{
|
|
"vars": &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k5": &String{value: "v5"},
|
|
}},
|
|
"key1": "k1",
|
|
"key2": "k3",
|
|
"key3": "k5",
|
|
}
|
|
)
|
|
|
|
eval(`toJSON(filter(vars, key1, key2, key3))`, p)
|
|
|
|
// output:
|
|
// {"k1":{"@value":"v1","@type":"String"},"k5":{"@value":"v5","@type":"String"}}
|
|
}
|
|
|
|
func Example_omit_vars() {
|
|
var (
|
|
p = map[string]interface{}{
|
|
"vars": &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k2": &String{value: "v2"},
|
|
"k3": &String{value: "v3"},
|
|
}},
|
|
"key1": "k1",
|
|
"key2": "k3",
|
|
}
|
|
)
|
|
|
|
eval(`toJSON(omit(vars, key1, key2))`, p)
|
|
|
|
// output:
|
|
// {"k2":{"@value":"v2","@type":"String"}}
|
|
}
|
|
|
|
func TestVars_Decode(t *testing.T) {
|
|
t.Run("mix", func(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
dst = &struct {
|
|
Int int64
|
|
Uint64 uint64
|
|
String string `var:"STRING"`
|
|
RawString string `var:"rawString"`
|
|
Bool bool
|
|
Unexisting byte
|
|
}{}
|
|
|
|
vars, _ = NewVars(map[string]interface{}{
|
|
"int": Must(NewInteger(42)),
|
|
"STRING": Must(NewString("foo")),
|
|
"bool": Must(NewBoolean(true)),
|
|
"missing": Must(NewBoolean(true)),
|
|
})
|
|
)
|
|
|
|
req.NoError(vars.Decode(dst))
|
|
req.Equal(int64(42), dst.Int)
|
|
req.Equal("foo", dst.String)
|
|
req.Equal(true, dst.Bool)
|
|
req.Empty(dst.Unexisting)
|
|
})
|
|
|
|
t.Run("interfaces", func(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
dst = &struct {
|
|
IString interface{} `var:"iString"`
|
|
IInteger interface{} `var:"iInteger"`
|
|
IBool interface{} `var:"iBool"`
|
|
}{}
|
|
|
|
vars, _ = NewVars(map[string]interface{}{
|
|
"iString": Must(NewString("foo")),
|
|
"iInteger": Must(NewInteger(42)),
|
|
"iBool": Must(NewBoolean(true)),
|
|
})
|
|
)
|
|
|
|
req.NoError(vars.Decode(dst))
|
|
})
|
|
|
|
t.Run("vars-in-vars", func(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
dst = &struct {
|
|
Vars *Vars `var:"vars"`
|
|
}{}
|
|
|
|
vars, _ = NewVars(map[string]interface{}{
|
|
"vars": map[string]interface{}{"foo": Must(NewString("bar"))},
|
|
})
|
|
)
|
|
|
|
req.NoError(vars.Decode(dst))
|
|
})
|
|
|
|
t.Run("int-uint", func(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
dst = &struct {
|
|
Int int64
|
|
Uint64 uint64
|
|
}{}
|
|
|
|
vars, _ = NewVars(map[string]TypedValue{
|
|
"uint64": Must(NewAny("42")),
|
|
"int": Must(NewAny("42")),
|
|
})
|
|
)
|
|
|
|
dst.Uint64 = 0
|
|
dst.Int = 0
|
|
|
|
req.NoError(vars.Decode(dst))
|
|
req.Equal(uint64(42), dst.Uint64)
|
|
req.Equal(int64(42), dst.Int)
|
|
})
|
|
|
|
}
|
|
|
|
func TestVars_Assign(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
vars = &Vars{}
|
|
)
|
|
|
|
req.NoError(Assign(vars, "foo", &String{value: "foo"}))
|
|
req.NoError(Assign(vars, "vars", &Vars{}))
|
|
req.NoError(Assign(vars, "vars.foo", &String{value: "foo"}))
|
|
}
|
|
|
|
func TestVars_Set(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
vars = &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
)
|
|
|
|
out, err := set(vars, "k1", &String{value: "v11"})
|
|
req.NoError(err)
|
|
req.Equal(&String{value: "v11"}, out.(*Vars).GetValue()["k1"])
|
|
|
|
// Making sure empty vars updates without error
|
|
vars = &Vars{}
|
|
out, err = set(vars, "k2", &Array{value: []TypedValue{&String{value: "foo"}, &String{value: "bar"}}})
|
|
req.NoError(err)
|
|
req.Equal(&Array{value: []TypedValue{&String{value: "foo"}, &String{value: "bar"}}}, out.(*Vars).GetValue()["k2"])
|
|
}
|
|
|
|
func TestVars_MergeVars(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
vars Vars
|
|
foo = Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
}}
|
|
bar = Vars{value: map[string]TypedValue{
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
expected = &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
)
|
|
|
|
out := vars.MustMerge(&foo, &bar)
|
|
req.Equal(expected, out)
|
|
}
|
|
|
|
func TestVars_Merge(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
vars = &Vars{}
|
|
foo = &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
}}
|
|
bar = &Vars{value: map[string]TypedValue{
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
expected = &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
)
|
|
|
|
out, err := merge(vars, foo, bar)
|
|
req.NoError(err)
|
|
req.Equal(expected, out)
|
|
}
|
|
|
|
func TestVars_Filter(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
vars = &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
expected = &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
}}
|
|
)
|
|
|
|
out, err := filter(vars, "k1", "k3")
|
|
req.NoError(err)
|
|
req.Equal(expected, out)
|
|
}
|
|
|
|
func TestVars_Omit(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
|
|
vars = Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
"k2": &String{value: "v2"},
|
|
"k3": &String{value: "v3"},
|
|
}}
|
|
expected = &Vars{value: map[string]TypedValue{
|
|
"k2": &String{value: "v2"},
|
|
}}
|
|
)
|
|
|
|
out, err := omit(&vars, "k1", "k3")
|
|
req.NoError(err)
|
|
req.Equal(expected, out)
|
|
}
|
|
|
|
func TestVarsTypeResolving(t *testing.T) {
|
|
var (
|
|
req = require.New(t)
|
|
v = &Vars{}
|
|
)
|
|
|
|
req.NoError(v.Set("unr", &Unresolved{value: "wrapped any", typ: "Any"}))
|
|
req.NoError(v.Set("any", &Any{value: "raw any"}))
|
|
req.NoError(v.ResolveTypes(func(typ string) Type { return Any{} }))
|
|
req.Equal("wrapped any", v.value["unr"].Get())
|
|
req.Equal("raw any", v.value["any"].Get())
|
|
}
|
|
|
|
func TestVars_UnmarshalJSON(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
json string
|
|
vars map[string]interface{}
|
|
}{
|
|
{"empty", "", make(map[string]interface{})},
|
|
{"object", "{}", make(map[string]interface{})},
|
|
{"string", `{"a":{"@value":"b"}}`, map[string]interface{}{"a": &Unresolved{value: "b"}}},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
var (
|
|
r = require.New(t)
|
|
unmarshaled = &Vars{}
|
|
aux, _ = NewVars(c.vars)
|
|
)
|
|
|
|
r.NoError(unmarshaled.UnmarshalJSON([]byte(c.json)))
|
|
r.Equal(aux, unmarshaled)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVars_MarshalJSON(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
json string
|
|
vars map[string]interface{}
|
|
}{
|
|
{"empty", "{}", nil},
|
|
{"string", `{"a":{"@value":"b","@type":"String"}}`, map[string]interface{}{"a": &String{value: "b"}}},
|
|
{"array",
|
|
`{"arr":{"@value":[{"@value":"foo","@type":"String"},{"@value":"bar","@type":"String"}],"@type":"Array"}}`,
|
|
map[string]interface{}{"arr": &Array{value: []TypedValue{&String{value: "foo"}, &String{value: "bar"}}}}},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
var (
|
|
r = require.New(t)
|
|
aux, _ = NewVars(c.vars)
|
|
)
|
|
|
|
j, err := json.Marshal(aux)
|
|
r.NoError(err)
|
|
r.Equal(c.json, string(j))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVars_Dict(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
input *Vars
|
|
expected map[string]any
|
|
}{
|
|
{
|
|
name: "empty",
|
|
input: nil,
|
|
expected: nil,
|
|
},
|
|
{
|
|
name: "string",
|
|
input: &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
}},
|
|
expected: map[string]any{"k1": "v1"},
|
|
},
|
|
{
|
|
name: "string",
|
|
input: &Vars{value: map[string]TypedValue{
|
|
"k1": &String{value: "v1"},
|
|
}},
|
|
expected: map[string]any{"k1": "v1"},
|
|
},
|
|
{
|
|
name: "array",
|
|
input: &Vars{value: map[string]TypedValue{
|
|
"arr": &Array{value: []TypedValue{&String{value: "foo"}}},
|
|
}},
|
|
expected: map[string]any{
|
|
"arr": []any{"foo"},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
var (
|
|
r = require.New(t)
|
|
out = c.input.Dict()
|
|
)
|
|
|
|
r.Equal(c.expected, out)
|
|
})
|
|
}
|
|
}
|