1168 lines
25 KiB
Go
1168 lines
25 KiB
Go
package parser
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAddMetadata(t *testing.T) {
|
|
type expected struct {
|
|
node *Node
|
|
error bool
|
|
}
|
|
|
|
type interf interface{}
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
tree *Node
|
|
structure interface{}
|
|
expected expected
|
|
}{
|
|
{
|
|
desc: "Node Nil",
|
|
tree: nil,
|
|
structure: nil,
|
|
expected: expected{node: nil},
|
|
},
|
|
{
|
|
desc: "Empty Node",
|
|
tree: &Node{},
|
|
structure: nil,
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "Nil structure",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "bar"},
|
|
},
|
|
},
|
|
structure: nil,
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 0",
|
|
tree: &Node{Name: "traefik", Value: "bar"},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 1",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar"},
|
|
},
|
|
},
|
|
structure: struct{ Foo string }{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar", Kind: reflect.String},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, pointer",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "bar"},
|
|
},
|
|
},
|
|
structure: &struct{ Foo string }{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar", Kind: reflect.String},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, slice",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "bar,bur"},
|
|
},
|
|
},
|
|
structure: struct{ Foo []string }{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar,bur", Kind: reflect.Slice},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, interface",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "", Children: []*Node{
|
|
{Name: "Fii", Value: "hii"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct{ Foo interf }{},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 1, map string",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "name1", Value: "bar"},
|
|
{Name: "name2", Value: "bur"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct{ Foo map[string]string }{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Kind: reflect.Map, Children: []*Node{
|
|
{Name: "name1", Value: "bar", Kind: reflect.String},
|
|
{Name: "name2", Value: "bur", Kind: reflect.String},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, map struct",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "name1", Children: []*Node{
|
|
{Name: "Fii", Value: "bar"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo map[string]struct{ Fii string }
|
|
}{},
|
|
expected: expected{
|
|
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", Value: "bar", Kind: reflect.String},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, map int as key",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "name1", Children: []*Node{
|
|
{Name: "Fii", Value: "bar"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo map[int]struct{ Fii string }
|
|
}{},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 1, int pointer",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "0"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo *int
|
|
}{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "0", Kind: reflect.Ptr},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, bool pointer",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "0"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo *bool
|
|
}{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "0", Kind: reflect.Ptr},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, string pointer",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "0"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo *string
|
|
}{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "0", Kind: reflect.Ptr},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, 2 children with different types",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "bar"},
|
|
{Name: "Fii", Value: "1"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo string
|
|
Fii int
|
|
}{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar", Kind: reflect.String},
|
|
{Name: "Fii", FieldName: "Fii", Value: "1", Kind: reflect.Int},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, use exported instead of unexported",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "foo", Value: "bar"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
foo int
|
|
Foo string
|
|
}{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "foo", Value: "bar", FieldName: "Foo", Kind: reflect.String},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 1, unexported",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "foo", Value: "bar"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
foo string
|
|
}{},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 1, 3 children with different types",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "bar"},
|
|
{Name: "Fii", Value: "1"},
|
|
{Name: "Fuu", Value: "true"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo string
|
|
Fii int
|
|
Fuu bool
|
|
}{},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar", Kind: reflect.String},
|
|
{Name: "Fii", FieldName: "Fii", Value: "1", Kind: reflect.Int},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "true", Kind: reflect.Bool},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "Bar", Value: "bir"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "bir", Kind: reflect.String},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2, struct without children",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 2, slice-as-struct",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Fii", Children: []*Node{
|
|
{Name: "bar", Value: "haa"},
|
|
{Name: "bir", Value: "hii"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo []struct {
|
|
Bar string
|
|
Bir string
|
|
} `label-slice-as-struct:"Fii"`
|
|
}{
|
|
Foo: []struct {
|
|
Bar string
|
|
Bir string
|
|
}{},
|
|
},
|
|
expected: expected{node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Slice,
|
|
Tag: reflect.StructTag(`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"},
|
|
},
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "level 2, slice-as-struct without children",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Fii"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo []struct {
|
|
Bar string
|
|
Bir string
|
|
} `label-slice-as-struct:"Fii"`
|
|
}{
|
|
Foo: []struct {
|
|
Bar string
|
|
Bir string
|
|
}{},
|
|
},
|
|
expected: expected{node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Slice,
|
|
Tag: reflect.StructTag(`label-slice-as-struct:"Fii"`),
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "level 2, struct with allowEmpty, value true",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "true"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
} `label:"allowEmpty"`
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "true", Kind: reflect.Struct, Tag: reflect.StructTag(`label:"allowEmpty"`)},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2, struct with allowEmpty, value true with case variation",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "TruE"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
} `label:"allowEmpty"`
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "TruE", Kind: reflect.Struct, Tag: reflect.StructTag(`label:"allowEmpty"`)},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2, struct with allowEmpty, value false",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "false"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
} `label:"allowEmpty"`
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "false", Disabled: true, Kind: reflect.Struct, Tag: reflect.StructTag(`label:"allowEmpty"`)},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2, struct with allowEmpty with children, value false",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Value: "false", Children: []*Node{
|
|
{Name: "Bar", Value: "hii"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
} `label:"allowEmpty"`
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
FieldName: "Foo",
|
|
Value: "false",
|
|
Disabled: true,
|
|
Kind: reflect.Struct,
|
|
Tag: reflect.StructTag(`label:"allowEmpty"`),
|
|
Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "hii", Kind: reflect.String},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2, struct pointer without children",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo *struct {
|
|
Bar string
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 2, map without children",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo map[string]string
|
|
}{
|
|
Foo: map[string]string{},
|
|
},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "level 2, pointer",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "Bar", Value: "bir"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo *struct {
|
|
Bar string
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Bar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Kind: reflect.Ptr, Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "bir", Kind: reflect.String},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 2, 2 children",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "Bar", Value: "bir"},
|
|
{Name: "Bur", Value: "fuu"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar string
|
|
Bur string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar string
|
|
Bur string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "bir", Kind: reflect.String},
|
|
{Name: "Bur", FieldName: "Bur", Value: "fuu", Kind: reflect.String},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 3",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "Bar", Children: []*Node{
|
|
{Name: "Bur", Value: "fuu"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar struct {
|
|
Bur string
|
|
}
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar struct {
|
|
Bur string
|
|
}
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Bar",
|
|
FieldName: "Bar",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Bur", FieldName: "Bur", Value: "fuu", Kind: reflect.String},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "level 3, 2 children level 1, 2 children level 2, 2 children level 3",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "Bar", Children: []*Node{
|
|
{Name: "Fii", Value: "fii"},
|
|
{Name: "Fee", Value: "1"},
|
|
}},
|
|
{Name: "Bur", Children: []*Node{
|
|
{Name: "Faa", Value: "faa"},
|
|
}},
|
|
}},
|
|
{Name: "Fii", Children: []*Node{
|
|
{Name: "FiiBar", Value: "fiiBar"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
Bar struct {
|
|
Fii string
|
|
Fee int
|
|
}
|
|
Bur struct {
|
|
Faa string
|
|
}
|
|
}
|
|
Fii struct {
|
|
FiiBar string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar struct {
|
|
Fii string
|
|
Fee int
|
|
}
|
|
Bur struct {
|
|
Faa string
|
|
}
|
|
}{},
|
|
Fii: struct {
|
|
FiiBar string
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Bar",
|
|
FieldName: "Bar",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Kind: reflect.String, Value: "fii"},
|
|
{Name: "Fee", FieldName: "Fee", Kind: reflect.Int, Value: "1"},
|
|
},
|
|
},
|
|
{
|
|
Name: "Bur",
|
|
FieldName: "Bur",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Faa", FieldName: "Faa", Kind: reflect.String, Value: "faa"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Fii",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "FiiBar", FieldName: "FiiBar", Kind: reflect.String, Value: "fiiBar"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "Slice struct",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "[0]", Children: []*Node{
|
|
{Name: "Field1", Value: "A"},
|
|
{Name: "Field2", Value: "A"},
|
|
}},
|
|
{Name: "[1]", Children: []*Node{
|
|
{Name: "Field1", Value: "B"},
|
|
{Name: "Field2", Value: "B"},
|
|
}},
|
|
{Name: "[2]", Children: []*Node{
|
|
{Name: "Field1", Value: "C"},
|
|
{Name: "Field2", Value: "C"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo []struct {
|
|
Field1 string
|
|
Field2 string
|
|
}
|
|
}{},
|
|
expected: expected{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},
|
|
}},
|
|
}},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "Slice pointer struct",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "[0]", Children: []*Node{
|
|
{Name: "Field1", Value: "A"},
|
|
{Name: "Field2", Value: "A"},
|
|
}},
|
|
{Name: "[1]", Children: []*Node{
|
|
{Name: "Field1", Value: "B"},
|
|
{Name: "Field2", Value: "B"},
|
|
}},
|
|
{Name: "[2]", Children: []*Node{
|
|
{Name: "Field1", Value: "C"},
|
|
{Name: "Field2", Value: "C"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo []*struct {
|
|
Field1 string
|
|
Field2 string
|
|
}
|
|
}{},
|
|
expected: expected{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},
|
|
}},
|
|
}},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "embedded",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "Fii", Value: "bir"},
|
|
{Name: "Fuu", Value: "bur"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
FiiFoo
|
|
}
|
|
}{},
|
|
expected: expected{node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "bir", Kind: reflect.String},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "bur", Kind: reflect.String},
|
|
}},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "embedded slice",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "MySliceType", Value: "foo,fii"},
|
|
},
|
|
},
|
|
structure: struct {
|
|
MySliceType
|
|
}{},
|
|
expected: expected{node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "MySliceType", FieldName: "MySliceType", Value: "foo,fii", Kind: reflect.Slice},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "embedded slice 2",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", Children: []*Node{
|
|
{Name: "MySliceType", Value: "foo,fii"},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo struct {
|
|
MySliceType
|
|
}
|
|
}{},
|
|
expected: expected{node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Kind: reflect.Struct, Children: []*Node{
|
|
{Name: "MySliceType", FieldName: "MySliceType", Value: "foo,fii", Kind: reflect.Slice},
|
|
}},
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
desc: "raw value",
|
|
tree: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Children: []*Node{
|
|
{Name: "AAA", FieldName: "AAA", Value: "valueA"},
|
|
{Name: "BBB", FieldName: "BBB", Children: []*Node{
|
|
{Name: "CCC", FieldName: "CCC", Children: []*Node{
|
|
{Name: "DDD", FieldName: "DDD", Value: "valueD"},
|
|
}},
|
|
}},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
structure: struct {
|
|
Foo *struct {
|
|
Bar map[string]interface{}
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Bar map[string]interface{}
|
|
}{},
|
|
},
|
|
expected: expected{
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Kind: reflect.Ptr, Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Kind: reflect.Map, RawValue: map[string]interface{}{
|
|
"AAA": "valueA",
|
|
"BBB": map[string]interface{}{
|
|
"CCC": map[string]interface{}{
|
|
"DDD": "valueD",
|
|
},
|
|
},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test := test
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
err := metadata{MetadataOpts{TagName: TagLabel, AllowSliceAsStruct: true}}.Add(test.structure, test.tree)
|
|
|
|
if test.expected.error {
|
|
assert.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
|
|
if !assert.Equal(t, test.expected.node, test.tree) {
|
|
bytes, errM := json.MarshalIndent(test.tree, "", " ")
|
|
require.NoError(t, errM)
|
|
fmt.Println(string(bytes))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_nodeToRawMap(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
root *Node
|
|
expected map[string]interface{}
|
|
}{
|
|
{
|
|
desc: "simple",
|
|
root: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "meta", Children: []*Node{
|
|
{Name: "aaa", Value: "test1"},
|
|
{Name: "bbb", Children: []*Node{
|
|
{Name: "ccc", Value: "test2"},
|
|
{Name: "ddd", Children: []*Node{
|
|
{Name: "eee", Value: "test3"},
|
|
}},
|
|
}},
|
|
}},
|
|
{Name: "name", Value: "bla"},
|
|
},
|
|
},
|
|
expected: map[string]interface{}{
|
|
"meta": map[string]interface{}{
|
|
"aaa": "test1",
|
|
"bbb": map[string]interface{}{
|
|
"ccc": "test2",
|
|
"ddd": map[string]interface{}{
|
|
"eee": "test3",
|
|
},
|
|
},
|
|
},
|
|
"name": "bla",
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of struct, level 1",
|
|
root: &Node{
|
|
Name: "aaa",
|
|
Children: []*Node{
|
|
{Name: "[0]", Children: []*Node{
|
|
{Name: "bbb", Value: "test1"},
|
|
{Name: "ccc", Value: "test2"},
|
|
}},
|
|
},
|
|
},
|
|
expected: map[string]interface{}{
|
|
"aaa": []interface{}{
|
|
map[string]interface{}{
|
|
"bbb": "test1",
|
|
"ccc": "test2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of struct, level 2",
|
|
root: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{
|
|
{Name: "meta", Children: []*Node{{
|
|
Name: "aaa", Children: []*Node{
|
|
{Name: "[0]", Children: []*Node{
|
|
{Name: "bbb", Value: "test2"},
|
|
{Name: "ccc", Value: "test3"},
|
|
}},
|
|
{Name: "[1]", Children: []*Node{
|
|
{Name: "bbb", Value: "test4"},
|
|
{Name: "ccc", Value: "test5"},
|
|
}},
|
|
},
|
|
}}},
|
|
{Name: "name", Value: "test1"},
|
|
},
|
|
},
|
|
expected: map[string]interface{}{
|
|
"meta": map[string]interface{}{
|
|
"aaa": []interface{}{
|
|
map[string]interface{}{
|
|
"bbb": "test2",
|
|
"ccc": "test3",
|
|
},
|
|
map[string]interface{}{
|
|
"bbb": "test4",
|
|
"ccc": "test5",
|
|
},
|
|
},
|
|
},
|
|
"name": "test1",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test := test
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
actual := nodeToRawMap(test.root)
|
|
assert.Equal(t, test.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
type MySliceType []string
|