1250 lines
28 KiB
Go
1250 lines
28 KiB
Go
package parser
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/containous/traefik/v2/pkg/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestEncodeToFlat(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
element interface{}
|
|
node *Node
|
|
opts *FlatOpts
|
|
expected []Flat
|
|
}{
|
|
{
|
|
desc: "string field",
|
|
element: &struct {
|
|
Field string `description:"field description"`
|
|
}{
|
|
Field: "test",
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
FieldName: "Field",
|
|
Description: "field description",
|
|
Value: "test",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "test",
|
|
}},
|
|
},
|
|
{
|
|
desc: "int field",
|
|
element: &struct {
|
|
Field int `description:"field description"`
|
|
}{
|
|
Field: 6,
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "6",
|
|
Kind: reflect.Int,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "6",
|
|
}},
|
|
},
|
|
{
|
|
desc: "bool field",
|
|
element: &struct {
|
|
Field bool `description:"field description"`
|
|
}{
|
|
Field: true,
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "true",
|
|
Kind: reflect.Bool,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "true",
|
|
}},
|
|
},
|
|
{
|
|
desc: "string pointer field",
|
|
element: &struct {
|
|
Field *string `description:"field description"`
|
|
}{
|
|
Field: func(v string) *string { return &v }("test"),
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "test",
|
|
}},
|
|
},
|
|
{
|
|
desc: "string pointer field, custom option",
|
|
element: &struct {
|
|
Field *string `description:"field description"`
|
|
}{
|
|
Field: func(v string) *string { return &v }("test"),
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
opts: &FlatOpts{
|
|
Case: "upper",
|
|
Separator: "_",
|
|
SkipRoot: false,
|
|
},
|
|
expected: []Flat{{
|
|
Name: "TRAEFIK_FIELD",
|
|
Description: "field description",
|
|
Default: "test",
|
|
}},
|
|
},
|
|
{
|
|
desc: "int pointer field",
|
|
element: &struct {
|
|
Field *int `description:"field description"`
|
|
}{
|
|
Field: func(v int) *int { return &v }(6),
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "6",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "6",
|
|
}},
|
|
},
|
|
{
|
|
desc: "bool pointer field",
|
|
element: &struct {
|
|
Field *bool `description:"field description"`
|
|
}{
|
|
Field: func(v bool) *bool { return &v }(true),
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "true",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "true",
|
|
}},
|
|
},
|
|
{
|
|
desc: "slice of string field, no initial value",
|
|
element: &struct {
|
|
Field []string `description:"field description"`
|
|
}{},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Kind: reflect.Slice,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "",
|
|
}},
|
|
},
|
|
{
|
|
desc: "slice of string field, with initial value",
|
|
element: &struct {
|
|
Field []string `description:"field description"`
|
|
}{
|
|
Field: []string{"foo", "bar"},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "foo, bar",
|
|
Kind: reflect.Slice,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "foo, bar",
|
|
}},
|
|
},
|
|
{
|
|
desc: "slice of int field, no initial value",
|
|
element: &struct {
|
|
Field []int `description:"field description"`
|
|
}{},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Kind: reflect.Slice,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "",
|
|
}},
|
|
},
|
|
{
|
|
desc: "slice of int field, with initial value",
|
|
element: &struct {
|
|
Field []int `description:"field description"`
|
|
}{
|
|
Field: []int{6, 3},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "6, 3",
|
|
Kind: reflect.Slice,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "6, 3",
|
|
}},
|
|
},
|
|
{
|
|
desc: "map string field",
|
|
element: &struct {
|
|
Field map[string]string `description:"field description"`
|
|
}{
|
|
Field: map[string]string{
|
|
MapNamePlaceholder: "",
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"field description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.String,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field.<name>",
|
|
Description: "field description",
|
|
Default: "",
|
|
}},
|
|
},
|
|
{
|
|
desc: "struct pointer field",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Field string `description:"field description"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: &struct {
|
|
Field string `description:"field description"`
|
|
}{
|
|
Field: "test",
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.field",
|
|
Description: "field description",
|
|
Default: "test",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct pointer field, hide field",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Field string `description:"-"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: &struct {
|
|
Field string `description:"-"`
|
|
}{
|
|
Field: "test",
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "-",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.String,
|
|
Tag: `description:"-"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: nil,
|
|
},
|
|
{
|
|
desc: "struct pointer field, allow empty",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Field string `description:"field description"`
|
|
} `description:"foo description" label:"allowEmpty"`
|
|
}{
|
|
Foo: &struct {
|
|
Field string `description:"field description"`
|
|
}{
|
|
Field: "test",
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description" label:"allowEmpty"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo",
|
|
Description: "foo description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.field",
|
|
Description: "field description",
|
|
Default: "test",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct pointer field level 2",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Fii *struct {
|
|
Field string `description:"field description"`
|
|
} `description:"fii description"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: &struct {
|
|
Fii *struct {
|
|
Field string `description:"field description"`
|
|
} `description:"fii description"`
|
|
}{
|
|
Fii: &struct {
|
|
Field string `description:"field description"`
|
|
}{
|
|
Field: "test",
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
Description: "fii description",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"fii description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.fii.field",
|
|
Description: "field description",
|
|
Default: "test",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct pointer field level 2, allow empty",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Fii *struct {
|
|
Field string `description:"field description"`
|
|
} `description:"fii description" label:"allowEmpty"`
|
|
} `description:"foo description" label:"allowEmpty"`
|
|
}{
|
|
Foo: &struct {
|
|
Fii *struct {
|
|
Field string `description:"field description"`
|
|
} `description:"fii description" label:"allowEmpty"`
|
|
}{
|
|
Fii: &struct {
|
|
Field string `description:"field description"`
|
|
}{
|
|
Field: "test",
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description" label:"allowEmpty"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
Description: "fii description",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"fii description" label:"allowEmpty"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "test",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo",
|
|
Description: "foo description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.fii",
|
|
Description: "fii description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.fii.field",
|
|
Description: "field description",
|
|
Default: "test",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "map string field level 2",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Fii map[string]string `description:"fii description"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: &struct {
|
|
Fii map[string]string `description:"fii description"`
|
|
}{
|
|
Fii: map[string]string{
|
|
MapNamePlaceholder: "",
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
Description: "fii description",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"fii description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.String,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.fii.<name>",
|
|
Description: "fii description",
|
|
Default: "",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "map string pointer field level 2",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Fii map[string]*string `description:"fii description"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: &struct {
|
|
Fii map[string]*string `description:"fii description"`
|
|
}{
|
|
Fii: map[string]*string{
|
|
MapNamePlaceholder: func(v string) *string { return &v }(""),
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
Description: "fii description",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"fii description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.Ptr,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.fii.<name>",
|
|
Description: "fii description",
|
|
Default: "",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "map struct level 1",
|
|
element: &struct {
|
|
Foo map[string]struct {
|
|
Field string `description:"field description"`
|
|
Yo int `description:"yo description"`
|
|
} `description:"foo description"`
|
|
}{},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
{
|
|
Name: "Yo",
|
|
Description: "yo description",
|
|
FieldName: "Yo",
|
|
Value: "0",
|
|
Kind: reflect.Int,
|
|
Tag: `description:"yo description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.<name>",
|
|
Description: "foo description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.<name>.field",
|
|
Description: "field description",
|
|
Default: "",
|
|
},
|
|
{
|
|
Name: "foo.<name>.yo",
|
|
Description: "yo description",
|
|
Default: "0",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "map struct pointer level 1",
|
|
element: &struct {
|
|
Foo map[string]*struct {
|
|
Field string `description:"field description"`
|
|
Yo string `description:"yo description"`
|
|
} `description:"foo description"`
|
|
}{},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Kind: reflect.String,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
{
|
|
Name: "Yo",
|
|
Description: "yo description",
|
|
FieldName: "Yo",
|
|
Kind: reflect.String,
|
|
Tag: `description:"yo description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.<name>",
|
|
Description: "foo description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.<name>.field",
|
|
Description: "field description",
|
|
Default: "",
|
|
},
|
|
{
|
|
Name: "foo.<name>.yo",
|
|
Description: "yo description",
|
|
Default: "",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "time duration field",
|
|
element: &struct {
|
|
Field time.Duration `description:"field description"`
|
|
}{
|
|
Field: 1 * time.Second,
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "1000000000",
|
|
Kind: reflect.Int64,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "1s",
|
|
}},
|
|
},
|
|
{
|
|
desc: "time duration field map",
|
|
element: &struct {
|
|
Foo map[string]*struct {
|
|
Field time.Duration `description:"field description"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: map[string]*struct {
|
|
Field time.Duration `description:"field description"`
|
|
}{
|
|
"<name>": {
|
|
Field: 0,
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "0",
|
|
Kind: reflect.Int64,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.<name>",
|
|
Description: "foo description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.<name>.field",
|
|
Description: "field description",
|
|
Default: "0s",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "time duration field map 2",
|
|
element: &struct {
|
|
Foo map[string]*struct {
|
|
Fii *struct {
|
|
Field time.Duration `description:"field description"`
|
|
}
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: map[string]*struct {
|
|
Fii *struct {
|
|
Field time.Duration `description:"field description"`
|
|
}
|
|
}{
|
|
"<name>": {
|
|
Fii: &struct {
|
|
Field time.Duration `description:"field description"`
|
|
}{
|
|
Field: 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
Description: "foo description",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Map,
|
|
Tag: `description:"foo description"`,
|
|
Children: []*Node{
|
|
{
|
|
Name: "\u003cname\u003e",
|
|
FieldName: "\u003cname\u003e",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "0",
|
|
Kind: reflect.Int64,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.<name>",
|
|
Description: "foo description",
|
|
Default: "false",
|
|
},
|
|
{
|
|
Name: "foo.<name>.fii.field",
|
|
Description: "field description",
|
|
Default: "0s",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "time duration field 2",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Field time.Duration `description:"field description"`
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Field time.Duration `description:"field description"`
|
|
}{
|
|
Field: 1 * time.Second,
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "1000000000",
|
|
Kind: reflect.Int64,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "foo.field",
|
|
Description: "field description",
|
|
Default: "1s",
|
|
}},
|
|
},
|
|
{
|
|
desc: "time duration field 3",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Fii *struct {
|
|
Field time.Duration `description:"field description"`
|
|
}
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii *struct {
|
|
Field time.Duration `description:"field description"`
|
|
}
|
|
}{
|
|
Fii: &struct {
|
|
Field time.Duration `description:"field description"`
|
|
}{
|
|
Field: 1 * time.Second,
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Foo",
|
|
FieldName: "Foo",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Fii",
|
|
FieldName: "Fii",
|
|
Kind: reflect.Ptr,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "1000000000",
|
|
Kind: reflect.Int64,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "foo.fii.field",
|
|
Description: "field description",
|
|
Default: "1s",
|
|
}},
|
|
},
|
|
{
|
|
desc: "time duration field",
|
|
element: &struct {
|
|
Field types.Duration `description:"field description"`
|
|
}{
|
|
Field: types.Duration(180 * time.Second),
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
FieldName: "",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{
|
|
Name: "Field",
|
|
Description: "field description",
|
|
FieldName: "Field",
|
|
Value: "180000000000",
|
|
Kind: reflect.Int64,
|
|
Tag: `description:"field description"`,
|
|
},
|
|
},
|
|
},
|
|
expected: []Flat{{
|
|
Name: "field",
|
|
Description: "field description",
|
|
Default: "180",
|
|
}},
|
|
},
|
|
{
|
|
desc: "slice of struct",
|
|
element: &struct {
|
|
Foo *struct {
|
|
Fii []struct {
|
|
Field1 string `description:"field1 description"`
|
|
Field2 int `description:"field2 description"`
|
|
} `description:"fii description"`
|
|
} `description:"foo description"`
|
|
}{
|
|
Foo: &struct {
|
|
Fii []struct {
|
|
Field1 string `description:"field1 description"`
|
|
Field2 int `description:"field2 description"`
|
|
} `description:"fii description"`
|
|
}{
|
|
Fii: []struct {
|
|
Field1 string `description:"field1 description"`
|
|
Field2 int `description:"field2 description"`
|
|
}{
|
|
{
|
|
Field1: "",
|
|
Field2: 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
node: &Node{
|
|
Name: "traefik",
|
|
Kind: reflect.Struct,
|
|
Children: []*Node{
|
|
{Name: "Foo", Kind: reflect.Ptr, Description: "foo description", Children: []*Node{
|
|
{Name: "Fii", Kind: reflect.Slice, Description: "fii description", Children: []*Node{
|
|
{Name: "[0]", Kind: reflect.Struct, Children: []*Node{
|
|
{Name: "Field1", Value: "", Kind: reflect.String, Description: "field1 description"},
|
|
{Name: "Field2", Value: "0", Kind: reflect.Int, Description: "field2 description"},
|
|
}},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
expected: []Flat{
|
|
{
|
|
Name: "foo.fii",
|
|
Description: "fii description",
|
|
Default: "",
|
|
},
|
|
{
|
|
Name: "foo.fii[0].field1",
|
|
Description: "field1 description",
|
|
Default: "",
|
|
},
|
|
{
|
|
Name: "foo.fii[0].field2",
|
|
Description: "field2 description",
|
|
Default: "0",
|
|
},
|
|
},
|
|
},
|
|
// Skipped: because realistically not needed in Traefik for now.
|
|
// {
|
|
// desc: "map of map field level 2",
|
|
// element: &struct {
|
|
// Foo *struct {
|
|
// Fii map[string]map[string]string `description:"fii description"`
|
|
// } `description:"foo description"`
|
|
// }{
|
|
// Foo: &struct {
|
|
// Fii map[string]map[string]string `description:"fii description"`
|
|
// }{
|
|
// Fii: map[string]map[string]string{
|
|
// MapNamePlaceholder: {
|
|
// MapNamePlaceholder: "test",
|
|
// },
|
|
// },
|
|
// },
|
|
// },
|
|
// expected: `XXX`,
|
|
// },
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test := test
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var opts FlatOpts
|
|
if test.opts == nil {
|
|
opts = FlatOpts{Separator: ".", SkipRoot: true}
|
|
} else {
|
|
opts = *test.opts
|
|
}
|
|
|
|
entries, err := EncodeToFlat(test.element, test.node, opts)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, test.expected, entries)
|
|
})
|
|
}
|
|
}
|