738 lines
16 KiB
Go
738 lines
16 KiB
Go
package parser
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestEncodeToNode(t *testing.T) {
|
|
type expected struct {
|
|
node *Node
|
|
error bool
|
|
}
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
element interface{}
|
|
expected expected
|
|
}{
|
|
{
|
|
desc: "Description",
|
|
element: struct {
|
|
Foo string `description:"text"`
|
|
}{Foo: "bar"},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar", Description: "text"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "string",
|
|
element: struct {
|
|
Foo string
|
|
}{Foo: "bar"},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "2 string fields",
|
|
element: struct {
|
|
Foo string
|
|
Fii string
|
|
}{Foo: "bar", Fii: "hii"},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "bar"},
|
|
{Name: "Fii", FieldName: "Fii", Value: "hii"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "int",
|
|
element: struct {
|
|
Foo int
|
|
}{Foo: 1},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "1"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "int8",
|
|
element: struct {
|
|
Foo int8
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "int16",
|
|
element: struct {
|
|
Foo int16
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "int32",
|
|
element: struct {
|
|
Foo int32
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "int64",
|
|
element: struct {
|
|
Foo int64
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "uint",
|
|
element: struct {
|
|
Foo uint
|
|
}{Foo: 1},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "1"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "uint8",
|
|
element: struct {
|
|
Foo uint8
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "uint16",
|
|
element: struct {
|
|
Foo uint16
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "uint32",
|
|
element: struct {
|
|
Foo uint32
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "uint64",
|
|
element: struct {
|
|
Foo uint64
|
|
}{Foo: 2},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "2"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "float32",
|
|
element: struct {
|
|
Foo float32
|
|
}{Foo: 1.12},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "1.120000"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "float64",
|
|
element: struct {
|
|
Foo float64
|
|
}{Foo: 1.12},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "1.120000"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "bool",
|
|
element: struct {
|
|
Foo bool
|
|
}{Foo: true},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "true"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct",
|
|
element: struct {
|
|
Foo struct {
|
|
Fii string
|
|
Fuu string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Fii string
|
|
Fuu string
|
|
}{
|
|
Fii: "hii",
|
|
Fuu: "huu",
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "hii"},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct unexported field",
|
|
element: struct {
|
|
Foo struct {
|
|
Fii string
|
|
fuu string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Fii string
|
|
fuu string
|
|
}{
|
|
Fii: "hii",
|
|
fuu: "huu",
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "hii"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct pointer",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii string
|
|
Fuu string
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii string
|
|
Fuu string
|
|
}{
|
|
Fii: "hii",
|
|
Fuu: "huu",
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "hii"},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "string pointer",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii *string
|
|
Fuu string
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii *string
|
|
Fuu string
|
|
}{
|
|
Fii: func(v string) *string { return &v }("hii"),
|
|
Fuu: "huu",
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "hii"},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "string nil pointer",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii *string
|
|
Fuu string
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii *string
|
|
Fuu string
|
|
}{
|
|
Fii: nil,
|
|
Fuu: "huu",
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "int pointer",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii *int
|
|
Fuu int
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii *int
|
|
Fuu int
|
|
}{
|
|
Fii: func(v int) *int { return &v }(6),
|
|
Fuu: 4,
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "6"},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "4"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "bool pointer",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii *bool
|
|
Fuu bool
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii *bool
|
|
Fuu bool
|
|
}{
|
|
Fii: func(v bool) *bool { return &v }(true),
|
|
Fuu: true,
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "true"},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "true"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "struct nil struct pointer",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii *string
|
|
Fuu string
|
|
}
|
|
}{
|
|
Foo: nil,
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "struct pointer, not allowEmpty",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii string
|
|
Fuu string
|
|
}
|
|
}{
|
|
Foo: &struct {
|
|
Fii string
|
|
Fuu string
|
|
}{},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "struct pointer, allowEmpty",
|
|
element: struct {
|
|
Foo *struct {
|
|
Fii string
|
|
Fuu string
|
|
} `label:"allowEmpty"`
|
|
}{
|
|
Foo: &struct {
|
|
Fii string
|
|
Fuu string
|
|
}{},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Value: "true"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "map",
|
|
element: struct {
|
|
Foo struct {
|
|
Bar map[string]string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar map[string]string
|
|
}{
|
|
Bar: map[string]string{
|
|
"name1": "huu",
|
|
},
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Children: []*Node{
|
|
{Name: "name1", FieldName: "name1", Value: "huu"},
|
|
}},
|
|
}},
|
|
}}},
|
|
},
|
|
{
|
|
desc: "empty map",
|
|
element: struct {
|
|
Bar map[string]string
|
|
}{
|
|
Bar: map[string]string{},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "map nil",
|
|
element: struct {
|
|
Bar map[string]string
|
|
}{
|
|
Bar: nil,
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "map with non string key",
|
|
element: struct {
|
|
Foo struct {
|
|
Bar map[int]string
|
|
}
|
|
}{
|
|
Foo: struct {
|
|
Bar map[int]string
|
|
}{
|
|
Bar: map[int]string{
|
|
1: "huu",
|
|
},
|
|
},
|
|
},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "slice of string",
|
|
element: struct{ Bar []string }{Bar: []string{"huu", "hii"}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "huu, hii"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of int",
|
|
element: struct{ Bar []int }{Bar: []int{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of int8",
|
|
element: struct{ Bar []int8 }{Bar: []int8{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of int16",
|
|
element: struct{ Bar []int16 }{Bar: []int16{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of int32",
|
|
element: struct{ Bar []int32 }{Bar: []int32{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of int64",
|
|
element: struct{ Bar []int64 }{Bar: []int64{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of uint",
|
|
element: struct{ Bar []uint }{Bar: []uint{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of uint8",
|
|
element: struct{ Bar []uint8 }{Bar: []uint8{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of uint16",
|
|
element: struct{ Bar []uint16 }{Bar: []uint16{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of uint32",
|
|
element: struct{ Bar []uint32 }{Bar: []uint32{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of uint64",
|
|
element: struct{ Bar []uint64 }{Bar: []uint64{4, 2, 3}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4, 2, 3"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of float32",
|
|
element: struct{ Bar []float32 }{Bar: []float32{4.1, 2, 3.2}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4.100000, 2.000000, 3.200000"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of float64",
|
|
element: struct{ Bar []float64 }{Bar: []float64{4.1, 2, 3.2}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "4.100000, 2.000000, 3.200000"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice of bool",
|
|
element: struct{ Bar []bool }{Bar: []bool{true, false, true}},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "true, false, true"},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
desc: "slice label-slice-as-struct",
|
|
element: &struct {
|
|
Foo []struct {
|
|
Bar string
|
|
Bir string
|
|
} `label-slice-as-struct:"Fii"`
|
|
}{
|
|
Foo: []struct {
|
|
Bar string
|
|
Bir string
|
|
}{
|
|
{
|
|
Bar: "haa",
|
|
Bir: "hii",
|
|
},
|
|
},
|
|
},
|
|
expected: expected{node: &Node{
|
|
Name: "traefik",
|
|
Children: []*Node{{
|
|
Name: "Fii",
|
|
FieldName: "Foo",
|
|
Children: []*Node{
|
|
{Name: "Bar", FieldName: "Bar", Value: "haa"},
|
|
{Name: "Bir", FieldName: "Bir", Value: "hii"},
|
|
},
|
|
}},
|
|
}},
|
|
},
|
|
{
|
|
desc: "slice label-slice-as-struct several slice entries",
|
|
element: &struct {
|
|
Foo []struct {
|
|
Bar string
|
|
Bir string
|
|
} `label-slice-as-struct:"Fii"`
|
|
}{
|
|
Foo: []struct {
|
|
Bar string
|
|
Bir string
|
|
}{
|
|
{
|
|
Bar: "haa",
|
|
Bir: "hii",
|
|
},
|
|
{
|
|
Bar: "haa",
|
|
Bir: "hii",
|
|
},
|
|
},
|
|
},
|
|
expected: expected{error: true},
|
|
},
|
|
{
|
|
desc: "slice of struct",
|
|
element: struct {
|
|
Foo []struct {
|
|
Field string
|
|
}
|
|
}{
|
|
Foo: []struct {
|
|
Field string
|
|
}{
|
|
{
|
|
Field: "bar",
|
|
},
|
|
{
|
|
Field: "bir",
|
|
},
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "[0]", Children: []*Node{
|
|
{Name: "Field", FieldName: "Field", Value: "bar"},
|
|
}},
|
|
{Name: "[1]", Children: []*Node{
|
|
{Name: "Field", FieldName: "Field", Value: "bir"},
|
|
}},
|
|
}},
|
|
}}},
|
|
},
|
|
{
|
|
desc: "slice of pointer of struct",
|
|
element: struct {
|
|
Foo []*struct {
|
|
Field string
|
|
}
|
|
}{
|
|
Foo: []*struct {
|
|
Field string
|
|
}{
|
|
{Field: "bar"},
|
|
{Field: "bir"},
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "[0]", Children: []*Node{
|
|
{Name: "Field", FieldName: "Field", Value: "bar"},
|
|
}},
|
|
{Name: "[1]", Children: []*Node{
|
|
{Name: "Field", FieldName: "Field", Value: "bir"},
|
|
}},
|
|
}},
|
|
}}},
|
|
},
|
|
{
|
|
desc: "empty slice",
|
|
element: struct {
|
|
Bar []string
|
|
}{
|
|
Bar: []string{},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "nil slice",
|
|
element: struct {
|
|
Bar []string
|
|
}{
|
|
Bar: nil,
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "ignore slice",
|
|
element: struct {
|
|
Bar []string `label:"-"`
|
|
}{
|
|
Bar: []string{"huu", "hii"},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik"}},
|
|
},
|
|
{
|
|
desc: "embedded",
|
|
element: struct {
|
|
Foo struct{ FiiFoo }
|
|
}{
|
|
Foo: struct{ FiiFoo }{
|
|
FiiFoo: FiiFoo{
|
|
Fii: "hii",
|
|
Fuu: "huu",
|
|
},
|
|
},
|
|
},
|
|
expected: expected{node: &Node{Name: "traefik", Children: []*Node{
|
|
{Name: "Foo", FieldName: "Foo", Children: []*Node{
|
|
{Name: "Fii", FieldName: "Fii", Value: "hii"},
|
|
{Name: "Fuu", FieldName: "Fuu", Value: "huu"},
|
|
}},
|
|
}},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test := test
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
etnOpts := EncoderToNodeOpts{OmitEmpty: true, TagName: TagLabel, AllowSliceAsStruct: true}
|
|
node, err := EncodeToNode(test.element, DefaultRootName, etnOpts)
|
|
|
|
if test.expected.error {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, test.expected.node, node)
|
|
}
|
|
})
|
|
}
|
|
}
|