2020-02-15 22:13:50 +00:00
|
|
|
package typeobj
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
2020-03-04 23:30:24 +00:00
|
|
|
"strings"
|
2020-02-15 22:13:50 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
type foo struct {
|
|
|
|
A int `yaml:"a"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type bar struct {
|
|
|
|
B int `yaml:"b"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type outer struct {
|
|
|
|
Foo foo `type:"foo"`
|
|
|
|
Bar *bar `type:"bar"`
|
|
|
|
|
|
|
|
Other string `yaml:"other_field,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o outer) MarshalYAML() (interface{}, error) {
|
|
|
|
return MarshalYAML(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *outer) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
|
|
return UnmarshalYAML(o, unmarshal)
|
|
|
|
}
|
|
|
|
|
2020-03-04 23:30:24 +00:00
|
|
|
type outerWDefault struct {
|
|
|
|
Foo foo `type:"foo,default"`
|
|
|
|
Bar *bar `type:"bar"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o outerWDefault) MarshalYAML() (interface{}, error) {
|
|
|
|
return MarshalYAML(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *outerWDefault) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
|
|
return UnmarshalYAML(o, unmarshal)
|
|
|
|
}
|
|
|
|
|
2020-02-15 22:13:50 +00:00
|
|
|
func TestTypeObj(t *testing.T) {
|
|
|
|
|
|
|
|
type test struct {
|
|
|
|
descr string
|
|
|
|
str string
|
|
|
|
|
2020-03-04 23:30:24 +00:00
|
|
|
expErr string
|
|
|
|
expObj interface{}
|
|
|
|
expTypeTag string
|
|
|
|
expElem interface{}
|
|
|
|
expMarshalOut string // defaults to str
|
2020-02-15 22:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := []test{
|
|
|
|
{
|
2020-03-04 23:30:24 +00:00
|
|
|
descr: "no type set",
|
|
|
|
str: `{}`,
|
|
|
|
expErr: "type field not set",
|
|
|
|
expObj: outer{},
|
2020-02-15 22:13:50 +00:00
|
|
|
},
|
|
|
|
{
|
2020-03-04 23:30:24 +00:00
|
|
|
descr: "no type set with nontype field",
|
|
|
|
str: `other_field: aaa`,
|
|
|
|
expErr: "type field not set",
|
|
|
|
expObj: outer{},
|
2020-02-15 22:13:50 +00:00
|
|
|
},
|
|
|
|
{
|
2020-03-04 23:30:24 +00:00
|
|
|
descr: "no type set with default",
|
|
|
|
str: `a: 1`,
|
|
|
|
expObj: outerWDefault{Foo: foo{A: 1}},
|
|
|
|
expTypeTag: "foo",
|
|
|
|
expElem: foo{A: 1},
|
|
|
|
expMarshalOut: "type: foo\na: 1",
|
2020-02-15 22:13:50 +00:00
|
|
|
},
|
|
|
|
{
|
2020-03-04 23:30:24 +00:00
|
|
|
descr: "invalid type value",
|
|
|
|
str: "type: baz",
|
|
|
|
expErr: "invalid type value",
|
|
|
|
expObj: outer{},
|
2020-02-15 22:13:50 +00:00
|
|
|
},
|
|
|
|
{
|
2020-03-04 23:30:24 +00:00
|
|
|
descr: "foo set",
|
|
|
|
str: "type: foo\na: 1",
|
|
|
|
expObj: outer{Foo: foo{A: 1}},
|
|
|
|
expTypeTag: "foo",
|
|
|
|
expElem: foo{A: 1},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
descr: "bar set",
|
|
|
|
str: "type: bar\nb: 1",
|
|
|
|
expObj: outer{Bar: &bar{B: 1}},
|
|
|
|
expTypeTag: "bar",
|
|
|
|
expElem: &bar{B: 1},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
descr: "foo and other_field set",
|
|
|
|
str: "type: foo\na: 1\nother_field: aaa",
|
|
|
|
expObj: outer{Foo: foo{A: 1}, Other: "aaa"},
|
|
|
|
expTypeTag: "foo",
|
|
|
|
expElem: foo{A: 1},
|
2020-02-15 22:13:50 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Run(test.descr, func(t *testing.T) {
|
2020-03-04 23:30:24 +00:00
|
|
|
|
|
|
|
intoV := reflect.New(reflect.TypeOf(test.expObj))
|
|
|
|
|
|
|
|
err := yaml.Unmarshal([]byte(test.str), intoV.Interface())
|
|
|
|
if test.expErr != "" {
|
|
|
|
if err == nil || !strings.HasPrefix(err.Error(), test.expErr) {
|
|
|
|
t.Fatalf("expected error %q when unmarshaling but got: %v", test.expErr, err)
|
|
|
|
}
|
2020-02-15 22:13:50 +00:00
|
|
|
return
|
2020-03-04 23:30:24 +00:00
|
|
|
} else if test.expErr == "" && err != nil {
|
2020-02-15 22:13:50 +00:00
|
|
|
t.Fatalf("unmarshaling %q returned unexpected error: %v", test.str, err)
|
|
|
|
}
|
|
|
|
|
2020-03-04 23:30:24 +00:00
|
|
|
into := intoV.Elem().Interface()
|
|
|
|
if !reflect.DeepEqual(into, test.expObj) {
|
|
|
|
t.Fatalf("test expected value:\n%s\nbut got value:\n%s", spew.Sprint(test.expObj), spew.Sprint(into))
|
2020-02-15 22:13:50 +00:00
|
|
|
}
|
|
|
|
|
2020-03-04 23:30:24 +00:00
|
|
|
elem, typeTag, err := Element(into)
|
2020-02-15 22:13:50 +00:00
|
|
|
if err != nil {
|
2020-03-04 23:30:24 +00:00
|
|
|
t.Fatalf("error when calling Element(%s): %v", spew.Sprint(into), err)
|
|
|
|
} else if !reflect.DeepEqual(elem, test.expElem) {
|
|
|
|
t.Fatalf("test expected elem value:\n%s\nbut got value:\n%s", spew.Sprint(test.expElem), spew.Sprint(elem))
|
|
|
|
} else if typeTag != test.expTypeTag {
|
|
|
|
t.Fatalf("test expected typeTag value %q but got %q", test.expTypeTag, typeTag)
|
|
|
|
}
|
|
|
|
|
|
|
|
expMarshalOut := test.expMarshalOut
|
|
|
|
if expMarshalOut == "" {
|
|
|
|
expMarshalOut = test.str
|
2020-02-15 22:13:50 +00:00
|
|
|
}
|
2020-03-04 23:30:24 +00:00
|
|
|
expMarshalOut = strings.TrimSpace(expMarshalOut)
|
2020-02-15 22:13:50 +00:00
|
|
|
|
2020-03-04 23:30:24 +00:00
|
|
|
b, err := yaml.Marshal(into)
|
2020-02-15 22:13:50 +00:00
|
|
|
if err != nil {
|
2020-03-04 23:30:24 +00:00
|
|
|
t.Fatalf("error marshaling %s: %v", spew.Sprint(into), err)
|
|
|
|
}
|
|
|
|
marshalOut := strings.TrimSpace(string(b))
|
|
|
|
if marshalOut != expMarshalOut {
|
|
|
|
t.Fatalf("test expected to marshal to %q, but instead marshaled to %q", expMarshalOut, marshalOut)
|
2020-02-15 22:13:50 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|