package parser import ( "reflect" "testing" "time" "github.com/containous/traefik/pkg/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestFill(t *testing.T) { type expected struct { element interface{} error bool } testCases := []struct { desc string node *Node element interface{} expected expected }{ { desc: "empty node", node: &Node{}, element: &struct{ Foo string }{}, expected: expected{error: true}, }, { desc: "empty element", node: &Node{Name: "traefik", Kind: reflect.Struct}, element: &struct{}{}, expected: expected{element: &struct{}{}}, }, { desc: "type struct as root", node: &Node{Name: "traefik", Kind: reflect.Struct}, element: struct{}{}, expected: expected{error: true}, }, { desc: "nil node", node: nil, element: &struct{ Foo string }{}, expected: expected{element: &struct{ Foo string }{}}, }, { desc: "nil element", node: &Node{Name: "traefik", Kind: reflect.Struct}, element: nil, expected: expected{element: nil}, }, { desc: "string", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "bar", Kind: reflect.String}, }, }, element: &struct{ Foo string }{}, expected: expected{element: &struct{ Foo string }{Foo: "bar"}}, }, { desc: "field not found", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Fii", Value: "bar", Kind: reflect.String}, }, }, element: &struct{ Foo string }{}, expected: expected{error: true}, }, { desc: "2 children", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Fii", FieldName: "Fii", Value: "bir", Kind: reflect.String}, {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int}, }, }, element: &struct { Fii string Foo int }{}, expected: expected{element: &struct { Fii string Foo int }{Fii: "bir", Foo: 4}}, }, { desc: "case insensitive", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "foo", FieldName: "Foo", Value: "bir", Kind: reflect.String}, }, }, element: &struct { Foo string foo int }{}, expected: expected{element: &struct { Foo string foo int }{Foo: "bir"}}, }, { desc: "func", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Kind: reflect.Func}, }, }, element: &struct{ Foo func() }{}, expected: expected{element: &struct{ Foo func() }{}}, }, { desc: "int", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int}, }, }, element: &struct{ Foo int }{}, expected: expected{element: &struct{ Foo int }{Foo: 4}}, }, { desc: "invalid int", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Int}, }, }, element: &struct{ Foo int }{}, expected: expected{error: true}, }, { desc: "int8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int8}, }, }, element: &struct{ Foo int8 }{}, expected: expected{element: &struct{ Foo int8 }{Foo: 4}}, }, { desc: "invalid int8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Int8}, }, }, element: &struct{ Foo int8 }{}, expected: expected{error: true}, }, { desc: "int16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int16}, }, }, element: &struct{ Foo int16 }{}, expected: expected{element: &struct{ Foo int16 }{Foo: 4}}, }, { desc: "invalid int16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Int16}, }, }, element: &struct{ Foo int16 }{}, expected: expected{error: true}, }, { desc: "int32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int32}, }, }, element: &struct{ Foo int32 }{}, expected: expected{element: &struct{ Foo int32 }{Foo: 4}}, }, { desc: "invalid int32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Int32}, }, }, element: &struct{ Foo int32 }{}, expected: expected{error: true}, }, { desc: "int64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int64}, }, }, element: &struct{ Foo int64 }{}, expected: expected{element: &struct{ Foo int64 }{Foo: 4}}, }, { desc: "invalid int64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Int64}, }, }, element: &struct{ Foo int64 }{}, expected: expected{error: true}, }, { desc: "uint", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Uint}, }, }, element: &struct{ Foo uint }{}, expected: expected{element: &struct{ Foo uint }{Foo: 4}}, }, { desc: "invalid uint", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Uint}, }, }, element: &struct{ Foo uint }{}, expected: expected{error: true}, }, { desc: "uint8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Uint8}, }, }, element: &struct{ Foo uint8 }{}, expected: expected{element: &struct{ Foo uint8 }{Foo: 4}}, }, { desc: "invalid uint8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Uint8}, }, }, element: &struct{ Foo uint8 }{}, expected: expected{error: true}, }, { desc: "uint16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Uint16}, }, }, element: &struct{ Foo uint16 }{}, expected: expected{element: &struct{ Foo uint16 }{Foo: 4}}, }, { desc: "invalid uint16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Uint16}, }, }, element: &struct{ Foo uint16 }{}, expected: expected{error: true}, }, { desc: "uint32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Uint32}, }, }, element: &struct{ Foo uint32 }{}, expected: expected{element: &struct{ Foo uint32 }{Foo: 4}}, }, { desc: "invalid uint32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Uint32}, }, }, element: &struct{ Foo uint32 }{}, expected: expected{error: true}, }, { desc: "uint64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Uint64}, }, }, element: &struct{ Foo uint64 }{}, expected: expected{element: &struct{ Foo uint64 }{Foo: 4}}, }, { desc: "invalid uint64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four", Kind: reflect.Uint64}, }, }, element: &struct{ Foo uint64 }{}, expected: expected{error: true}, }, { desc: "time.Duration with unit", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4s", Kind: reflect.Int64}, }, }, element: &struct{ Foo time.Duration }{}, expected: expected{element: &struct{ Foo time.Duration }{Foo: 4 * time.Second}}, }, { desc: "time.Duration without unit", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int64}, }, }, element: &struct{ Foo time.Duration }{}, expected: expected{element: &struct{ Foo time.Duration }{Foo: 4 * time.Nanosecond}}, }, { desc: "types.Duration with unit", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4s", Kind: reflect.Int64}, }, }, element: &struct{ Foo types.Duration }{}, expected: expected{element: &struct{ Foo types.Duration }{Foo: types.Duration(4 * time.Second)}}, }, { desc: "types.Duration without unit", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Int64}, }, }, element: &struct{ Foo types.Duration }{}, expected: expected{element: &struct{ Foo types.Duration }{Foo: types.Duration(4 * time.Second)}}, }, { desc: "bool", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "true", Kind: reflect.Bool}, }, }, element: &struct{ Foo bool }{}, expected: expected{element: &struct{ Foo bool }{Foo: true}}, }, { desc: "invalid bool", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "bool", Kind: reflect.Bool}, }, }, element: &struct{ Foo bool }{}, expected: expected{error: true}, }, { desc: "float32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "2.1", Kind: reflect.Float32}, }, }, element: &struct{ Foo float32 }{}, expected: expected{element: &struct{ Foo float32 }{Foo: 2.1}}, }, { desc: "invalid float32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "two dot one", Kind: reflect.Float32}, }, }, element: &struct{ Foo float32 }{}, expected: expected{error: true}, }, { desc: "float64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "2.1", Kind: reflect.Float64}, }, }, element: &struct{ Foo float64 }{}, expected: expected{element: &struct{ Foo float64 }{Foo: 2.1}}, }, { desc: "invalid float64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "two dot one", Kind: reflect.Float64}, }, }, element: &struct{ Foo float64 }{}, expected: expected{error: true}, }, { desc: "struct", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{ {Name: "Fii", FieldName: "Fii", Value: "huu", Kind: reflect.String}, {Name: "Fuu", FieldName: "Fuu", Value: "6", Kind: reflect.Int}, }}, }}, element: &struct { Foo struct { Fii string Fuu int } }{}, expected: expected{element: &struct { Foo struct { Fii string Fuu int } }{ Foo: struct { Fii string Fuu int }{ Fii: "huu", Fuu: 6, }}, }, }, { desc: "pointer", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{ {Name: "Fii", FieldName: "Fii", Value: "huu", Kind: reflect.String}, {Name: "Fuu", FieldName: "Fuu", Value: "6", Kind: reflect.Int}, }}, }}, element: &struct { Foo *struct { Fii string Fuu int } }{}, expected: expected{element: &struct { Foo *struct { Fii string Fuu int } }{ Foo: &struct { Fii string Fuu int }{ Fii: "huu", Fuu: 6, }}, }, }, { desc: "pointer disabled false without children", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Ptr, }, }}, element: &struct { Foo *struct { Fii string Fuu int } `label:"allowEmpty"` }{}, expected: expected{element: &struct { Foo *struct { Fii string Fuu int } `label:"allowEmpty"` }{ Foo: &struct { Fii string Fuu int }{}}, }, }, { desc: "pointer disabled true without children", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Ptr, Disabled: true, }, }}, element: &struct { Foo *struct { Fii string Fuu int } `label:"allowEmpty"` }{}, expected: expected{element: &struct { Foo *struct { Fii string Fuu int } `label:"allowEmpty"` }{}, }, }, { desc: "pointer disabled true with children", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Disabled: true, Kind: reflect.Ptr, Children: []*Node{ {Name: "Fii", FieldName: "Fii", Value: "huu", Kind: reflect.String}, {Name: "Fuu", FieldName: "Fuu", Value: "6", Kind: reflect.Int}, }}, }}, element: &struct { Foo *struct { Fii string Fuu int } `label:"allowEmpty"` }{}, expected: expected{element: &struct { Foo *struct { Fii string Fuu int } `label:"allowEmpty"` }{}, }, }, { desc: "map string", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Map, Children: []*Node{ {Name: "name1", Value: "hii", Kind: reflect.String}, {Name: "name2", Value: "huu", Kind: reflect.String}, }}, }}, element: &struct { Foo map[string]string }{}, expected: expected{element: &struct { Foo map[string]string }{ Foo: map[string]string{ "name1": "hii", "name2": "huu", }}, }, }, { desc: "map struct", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Map, Children: []*Node{ { Name: "name1", Kind: reflect.Struct, Children: []*Node{ {Name: "Fii", FieldName: "Fii", Kind: reflect.String, Value: "hii"}, }, }, { Name: "name2", Kind: reflect.Struct, Children: []*Node{ {Name: "Fii", FieldName: "Fii", Kind: reflect.String, Value: "huu"}, }, }, }}, }}, element: &struct { Foo map[string]struct{ Fii string } }{}, expected: expected{element: &struct { Foo map[string]struct{ Fii string } }{ Foo: map[string]struct{ Fii string }{ "name1": {Fii: "hii"}, "name2": {Fii: "huu"}, }}, }, }, { desc: "slice string", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "huu,hii,hoo", Kind: reflect.Slice}, }, }, element: &struct{ Foo []string }{}, expected: expected{element: &struct{ Foo []string }{Foo: []string{"huu", "hii", "hoo"}}}, }, { desc: "slice named type", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "huu,hii,hoo", Kind: reflect.Slice}, }, }, element: &struct{ Foo []NamedType }{}, expected: expected{element: &struct{ Foo []NamedType }{Foo: []NamedType{"huu", "hii", "hoo"}}}, }, { desc: "slice named type int", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "1,2,3", Kind: reflect.Slice}, }, }, element: &struct{ Foo []NamedTypeInt }{}, expected: expected{element: &struct{ Foo []NamedTypeInt }{Foo: []NamedTypeInt{1, 2, 3}}}, }, { desc: "empty slice", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "", Kind: reflect.Slice}, }, }, element: &struct{ Foo []string }{}, expected: expected{element: &struct{ Foo []string }{Foo: nil}}, }, { desc: "slice int", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int }{}, expected: expected{element: &struct{ Foo []int }{Foo: []int{4, 3, 6}}}, }, { desc: "slice invalid int", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int }{}, expected: expected{error: true}, }, { desc: "slice int8", node: &Node{ Name: "traefik", Kind: reflect.Slice, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int8 }{}, expected: expected{element: &struct{ Foo []int8 }{Foo: []int8{4, 3, 6}}}, }, { desc: "slice invalid int8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int8 }{}, expected: expected{error: true}, }, { desc: "slice int16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int16 }{}, expected: expected{element: &struct{ Foo []int16 }{Foo: []int16{4, 3, 6}}}, }, { desc: "slice invalid int16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int16 }{}, expected: expected{error: true}, }, { desc: "slice int32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int32 }{}, expected: expected{element: &struct{ Foo []int32 }{Foo: []int32{4, 3, 6}}}, }, { desc: "slice invalid int32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int32 }{}, expected: expected{error: true}, }, { desc: "slice int64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int64 }{}, expected: expected{element: &struct{ Foo []int64 }{Foo: []int64{4, 3, 6}}}, }, { desc: "slice invalid int64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []int64 }{}, expected: expected{error: true}, }, { desc: "slice uint", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint }{}, expected: expected{element: &struct{ Foo []uint }{Foo: []uint{4, 3, 6}}}, }, { desc: "slice invalid uint", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint }{}, expected: expected{error: true}, }, { desc: "slice uint8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint8 }{}, expected: expected{element: &struct{ Foo []uint8 }{Foo: []uint8{4, 3, 6}}}, }, { desc: "slice invalid uint8", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint8 }{}, expected: expected{error: true}, }, { desc: "slice uint16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint16 }{}, expected: expected{element: &struct{ Foo []uint16 }{Foo: []uint16{4, 3, 6}}}, }, { desc: "slice invalid uint16", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint16 }{}, expected: expected{error: true}, }, { desc: "slice uint32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint32 }{}, expected: expected{element: &struct{ Foo []uint32 }{Foo: []uint32{4, 3, 6}}}, }, { desc: "slice invalid uint32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint32 }{}, expected: expected{error: true}, }, { desc: "slice uint64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint64 }{}, expected: expected{element: &struct{ Foo []uint64 }{Foo: []uint64{4, 3, 6}}}, }, { desc: "slice invalid uint64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []uint64 }{}, expected: expected{error: true}, }, { desc: "slice float32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []float32 }{}, expected: expected{element: &struct{ Foo []float32 }{Foo: []float32{4, 3, 6}}}, }, { desc: "slice invalid float32", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []float32 }{}, expected: expected{error: true}, }, { desc: "slice float64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4,3,6", Kind: reflect.Slice}, }, }, element: &struct{ Foo []float64 }{}, expected: expected{element: &struct{ Foo []float64 }{Foo: []float64{4, 3, 6}}}, }, { desc: "slice invalid float64", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "four,three,six", Kind: reflect.Slice}, }, }, element: &struct{ Foo []float64 }{}, expected: expected{error: true}, }, { desc: "slice bool", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "true, false, true", Kind: reflect.Slice}, }, }, element: &struct{ Foo []bool }{}, expected: expected{element: &struct{ Foo []bool }{Foo: []bool{true, false, true}}}, }, { desc: "slice invalid bool", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "bool, false, true", Kind: reflect.Slice}, }, }, element: &struct{ Foo []bool }{}, expected: expected{error: true}, }, { desc: "slice slice-as-struct", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Fii", FieldName: "Foo", Kind: reflect.Slice, Tag: `label-slice-as-struct:"Fii"`, Children: []*Node{ {Name: "bar", FieldName: "Bar", Kind: reflect.String, Value: "haa"}, {Name: "bir", FieldName: "Bir", Kind: reflect.String, Value: "hii"}, }, }, }, }, element: &struct { Foo []struct { Bar string Bir string } `label-slice-as-struct:"Fii"` }{}, expected: expected{element: &struct { Foo []struct { Bar string Bir string } `label-slice-as-struct:"Fii"` }{ Foo: []struct { Bar string Bir string }{ { Bar: "haa", Bir: "hii", }, }, }}, }, { desc: "slice slice-as-struct pointer", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Fii", FieldName: "Foo", Kind: reflect.Slice, Tag: `label-slice-as-struct:"Fii"`, Children: []*Node{ {Name: "bar", FieldName: "Bar", Kind: reflect.String, Value: "haa"}, {Name: "bir", FieldName: "Bir", Kind: reflect.String, Value: "hii"}, }, }, }, }, element: &struct { Foo []*struct { Bar string Bir string } `label-slice-as-struct:"Fii"` }{}, expected: expected{element: &struct { Foo []*struct { Bar string Bir string } `label-slice-as-struct:"Fii"` }{ Foo: []*struct { Bar string Bir string }{ { Bar: "haa", Bir: "hii", }, }, }}, }, { desc: "slice slice-as-struct without children", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Fii", FieldName: "Foo", Tag: `label-slice-as-struct:"Fii"`, Kind: reflect.Slice, }, }, }, element: &struct { Foo []struct { Bar string Bir string } `label-slice-as-struct:"Fii"` }{}, expected: expected{error: true}, }, { desc: "pointer SetDefaults method", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{ {Name: "Fuu", FieldName: "Fuu", Value: "huu", Kind: reflect.String}, }}, }}, element: &struct { Foo *InitializedFoo }{}, expected: expected{element: &struct { Foo *InitializedFoo }{ Foo: &InitializedFoo{ Fii: "default", Fuu: "huu", }, }}, }, { desc: "pointer wrong SetDefaults method", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{ {Name: "Fuu", FieldName: "Fuu", Value: "huu", Kind: reflect.String}, }}, }}, element: &struct { Foo *wrongInitialledFoo }{}, expected: expected{element: &struct { Foo *wrongInitialledFoo }{ Foo: &wrongInitialledFoo{ Fuu: "huu", }, }}, }, { desc: "int pointer", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "4", Kind: reflect.Ptr}, }, }, element: &struct{ Foo *int }{}, expected: expected{element: &struct{ Foo *int }{Foo: func(v int) *int { return &v }(4)}}, }, { desc: "bool pointer", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "true", Kind: reflect.Ptr}, }, }, element: &struct{ Foo *bool }{}, expected: expected{element: &struct{ Foo *bool }{Foo: func(v bool) *bool { return &v }(true)}}, }, { desc: "string pointer", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Value: "bar", Kind: reflect.Ptr}, }, }, element: &struct{ Foo *string }{}, expected: expected{element: &struct{ Foo *string }{Foo: func(v string) *string { return &v }("bar")}}, }, { desc: "embedded", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ { Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{ {Name: "Fuu", FieldName: "Fuu", Value: "huu", Kind: reflect.String}, }}, }}, element: &struct { Foo struct { FiiFoo } }{}, expected: expected{element: &struct { Foo struct { FiiFoo } }{ Foo: struct { FiiFoo }{ FiiFoo: FiiFoo{ Fii: "", Fuu: "huu", }, }, }}, }, { desc: "slice struct", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Kind: reflect.Slice, Children: []*Node{ {Name: "[0]", Kind: reflect.Struct, Children: []*Node{ {Name: "Field1", FieldName: "Field1", Value: "A", Kind: reflect.String}, {Name: "Field2", FieldName: "Field2", Value: "A", Kind: reflect.String}, }}, {Name: "[1]", Kind: reflect.Struct, Children: []*Node{ {Name: "Field1", FieldName: "Field1", Value: "B", Kind: reflect.String}, {Name: "Field2", FieldName: "Field2", Value: "B", Kind: reflect.String}, }}, {Name: "[2]", Kind: reflect.Struct, Children: []*Node{ {Name: "Field1", FieldName: "Field1", Value: "C", Kind: reflect.String}, {Name: "Field2", FieldName: "Field2", Value: "C", Kind: reflect.String}, }}, }}, }, }, element: &struct { Foo []struct { Field1 string Field2 string } }{}, expected: expected{element: &struct { Foo []struct { Field1 string Field2 string } }{ Foo: []struct { Field1 string Field2 string }{ {Field1: "A", Field2: "A"}, {Field1: "B", Field2: "B"}, {Field1: "C", Field2: "C"}, }, }}, }, { desc: "slice pointer struct", node: &Node{ Name: "traefik", Kind: reflect.Struct, Children: []*Node{ {Name: "Foo", FieldName: "Foo", Kind: reflect.Slice, Children: []*Node{ {Name: "[0]", Kind: reflect.Ptr, Children: []*Node{ {Name: "Field1", FieldName: "Field1", Value: "A", Kind: reflect.String}, {Name: "Field2", FieldName: "Field2", Value: "A", Kind: reflect.String}, }}, {Name: "[1]", Kind: reflect.Ptr, Children: []*Node{ {Name: "Field1", FieldName: "Field1", Value: "B", Kind: reflect.String}, {Name: "Field2", FieldName: "Field2", Value: "B", Kind: reflect.String}, }}, {Name: "[2]", Kind: reflect.Ptr, Children: []*Node{ {Name: "Field1", FieldName: "Field1", Value: "C", Kind: reflect.String}, {Name: "Field2", FieldName: "Field2", Value: "C", Kind: reflect.String}, }}, }}, }, }, element: &struct { Foo []*struct { Field1 string Field2 string } }{}, expected: expected{element: &struct { Foo []*struct { Field1 string Field2 string } }{ Foo: []*struct { Field1 string Field2 string }{ {Field1: "A", Field2: "A"}, {Field1: "B", Field2: "B"}, {Field1: "C", Field2: "C"}, }, }}, }, } for _, test := range testCases { test := test t.Run(test.desc, func(t *testing.T) { t.Parallel() err := Fill(test.element, test.node) if test.expected.error { require.Error(t, err) } else { require.NoError(t, err) assert.Equal(t, test.expected.element, test.element) } }) } } type NamedType string type NamedTypeInt int type InitializedFoo struct { Fii string Fuu string } func (t *InitializedFoo) SetDefaults() { t.Fii = "default" } type wrongInitialledFoo struct { Fii string Fuu string } func (t *wrongInitialledFoo) SetDefaults() error { t.Fii = "default" return nil } type Bouya string type FiiFoo struct { Fii string Fuu Bouya }