FrontInterfaceCenter/internal/pkg/mapstructure/decode_hooks_test.go

568 lines
11 KiB
Go

package mapstructure
import (
"errors"
"math/big"
"net"
"reflect"
"testing"
"time"
)
func TestComposeDecodeHookFunc(t *testing.T) {
f1 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return data.(string) + "foo", nil
}
f2 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return data.(string) + "bar", nil
}
f := ComposeDecodeHookFunc(f1, f2)
result, err := DecodeHookExec(
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
if err != nil {
t.Fatalf("bad: %s", err)
}
if result.(string) != "foobar" {
t.Fatalf("bad: %#v", result)
}
}
func TestComposeDecodeHookFunc_err(t *testing.T) {
f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
return nil, errors.New("foo")
}
f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
panic("NOPE")
}
f := ComposeDecodeHookFunc(f1, f2)
_, err := DecodeHookExec(
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
if err.Error() != "foo" {
t.Fatalf("bad: %s", err)
}
}
func TestComposeDecodeHookFunc_kinds(t *testing.T) {
var f2From reflect.Kind
f1 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return int(42), nil
}
f2 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
f2From = f
return data, nil
}
f := ComposeDecodeHookFunc(f1, f2)
_, err := DecodeHookExec(
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
if err != nil {
t.Fatalf("bad: %s", err)
}
if f2From != reflect.Int {
t.Fatalf("bad: %#v", f2From)
}
}
func TestOrComposeDecodeHookFunc(t *testing.T) {
f1 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return data.(string) + "foo", nil
}
f2 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return data.(string) + "bar", nil
}
f := OrComposeDecodeHookFunc(f1, f2)
result, err := DecodeHookExec(
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
if err != nil {
t.Fatalf("bad: %s", err)
}
if result.(string) != "foo" {
t.Fatalf("bad: %#v", result)
}
}
func TestOrComposeDecodeHookFunc_correctValueIsLast(t *testing.T) {
f1 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return nil, errors.New("f1 error")
}
f2 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return nil, errors.New("f2 error")
}
f3 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return data.(string) + "bar", nil
}
f := OrComposeDecodeHookFunc(f1, f2, f3)
result, err := DecodeHookExec(
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
if err != nil {
t.Fatalf("bad: %s", err)
}
if result.(string) != "bar" {
t.Fatalf("bad: %#v", result)
}
}
func TestOrComposeDecodeHookFunc_err(t *testing.T) {
f1 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return nil, errors.New("f1 error")
}
f2 := func(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
return nil, errors.New("f2 error")
}
f := OrComposeDecodeHookFunc(f1, f2)
_, err := DecodeHookExec(
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
if err == nil {
t.Fatalf("bad: should return an error")
}
if err.Error() != "f1 error\nf2 error\n" {
t.Fatalf("bad: %s", err)
}
}
func TestComposeDecodeHookFunc_safe_nofuncs(t *testing.T) {
f := ComposeDecodeHookFunc()
type myStruct2 struct {
MyInt int
}
type myStruct1 struct {
Blah map[string]myStruct2
}
src := &myStruct1{Blah: map[string]myStruct2{
"test": {
MyInt: 1,
},
}}
dst := &myStruct1{}
dConf := &DecoderConfig{
Result: dst,
ErrorUnused: true,
DecodeHook: f,
}
d, err := NewDecoder(dConf)
if err != nil {
t.Fatal(err)
}
err = d.Decode(src)
if err != nil {
t.Fatal(err)
}
}
func TestStringToSliceHookFunc(t *testing.T) {
f := StringToSliceHookFunc(",")
strValue := reflect.ValueOf("42")
sliceValue := reflect.ValueOf([]byte("42"))
cases := []struct {
f, t reflect.Value
result interface{}
err bool
}{
{sliceValue, sliceValue, []byte("42"), false},
{strValue, strValue, "42", false},
{
reflect.ValueOf("foo,bar,baz"),
sliceValue,
[]string{"foo", "bar", "baz"},
false,
},
{
reflect.ValueOf(""),
sliceValue,
[]string{},
false,
},
}
for i, tc := range cases {
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}
func TestStringToTimeDurationHookFunc(t *testing.T) {
f := StringToTimeDurationHookFunc()
timeValue := reflect.ValueOf(time.Duration(5))
strValue := reflect.ValueOf("")
cases := []struct {
f, t reflect.Value
result interface{}
err bool
}{
{reflect.ValueOf("5s"), timeValue, 5 * time.Second, false},
{reflect.ValueOf("5"), timeValue, time.Duration(0), true},
{reflect.ValueOf("5"), strValue, "5", false},
}
for i, tc := range cases {
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}
func TestStringToTimeHookFunc(t *testing.T) {
strValue := reflect.ValueOf("5")
timeValue := reflect.ValueOf(time.Time{})
cases := []struct {
f, t reflect.Value
layout string
result interface{}
err bool
}{
{reflect.ValueOf("2006-01-02T15:04:05Z"), timeValue, time.RFC3339,
time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false},
{strValue, timeValue, time.RFC3339, time.Time{}, true},
{strValue, strValue, time.RFC3339, "5", false},
}
for i, tc := range cases {
f := StringToTimeHookFunc(tc.layout)
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}
func TestStringToIPHookFunc(t *testing.T) {
strValue := reflect.ValueOf("5")
ipValue := reflect.ValueOf(net.IP{})
cases := []struct {
f, t reflect.Value
result interface{}
err bool
}{
{reflect.ValueOf("1.2.3.4"), ipValue,
net.IPv4(0x01, 0x02, 0x03, 0x04), false},
{strValue, ipValue, net.IP{}, true},
{strValue, strValue, "5", false},
}
for i, tc := range cases {
f := StringToIPHookFunc()
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}
func TestStringToIPNetHookFunc(t *testing.T) {
strValue := reflect.ValueOf("5")
ipNetValue := reflect.ValueOf(net.IPNet{})
var nilNet *net.IPNet = nil
cases := []struct {
f, t reflect.Value
result interface{}
err bool
}{
{reflect.ValueOf("1.2.3.4/24"), ipNetValue,
&net.IPNet{
IP: net.IP{0x01, 0x02, 0x03, 0x00},
Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
}, false},
{strValue, ipNetValue, nilNet, true},
{strValue, strValue, "5", false},
}
for i, tc := range cases {
f := StringToIPNetHookFunc()
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}
func TestWeaklyTypedHook(t *testing.T) {
var f DecodeHookFunc = WeaklyTypedHook
strValue := reflect.ValueOf("")
cases := []struct {
f, t reflect.Value
result interface{}
err bool
}{
// TO STRING
{
reflect.ValueOf(false),
strValue,
"0",
false,
},
{
reflect.ValueOf(true),
strValue,
"1",
false,
},
{
reflect.ValueOf(float32(7)),
strValue,
"7",
false,
},
{
reflect.ValueOf(int(7)),
strValue,
"7",
false,
},
{
reflect.ValueOf([]uint8("foo")),
strValue,
"foo",
false,
},
{
reflect.ValueOf(uint(7)),
strValue,
"7",
false,
},
}
for i, tc := range cases {
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}
func TestStructToMapHookFuncTabled(t *testing.T) {
var f DecodeHookFunc = RecursiveStructToMapHookFunc()
type b struct {
TestKey string
}
type a struct {
Sub b
}
testStruct := a{
Sub: b{
TestKey: "testval",
},
}
testMap := map[string]interface{}{
"Sub": map[string]interface{}{
"TestKey": "testval",
},
}
cases := []struct {
name string
receiver interface{}
input interface{}
expected interface{}
err bool
}{
{
"map receiver",
func() interface{} {
var res map[string]interface{}
return &res
}(),
testStruct,
&testMap,
false,
},
{
"interface receiver",
func() interface{} {
var res interface{}
return &res
}(),
testStruct,
func() interface{} {
var exp interface{} = testMap
return &exp
}(),
false,
},
{
"slice receiver errors",
func() interface{} {
var res []string
return &res
}(),
testStruct,
new([]string),
true,
},
{
"slice to slice - no change",
func() interface{} {
var res []string
return &res
}(),
[]string{"a", "b"},
&[]string{"a", "b"},
false,
},
{
"string to string - no change",
func() interface{} {
var res string
return &res
}(),
"test",
func() *string {
s := "test"
return &s
}(),
false,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cfg := &DecoderConfig{
DecodeHook: f,
Result: tc.receiver,
}
d, err := NewDecoder(cfg)
if err != nil {
t.Fatalf("unexpected err %#v", err)
}
err = d.Decode(tc.input)
if tc.err != (err != nil) {
t.Fatalf("expected err %#v", err)
}
if !reflect.DeepEqual(tc.expected, tc.receiver) {
t.Fatalf("expected %#v, got %#v",
tc.expected, tc.receiver)
}
})
}
}
func TestTextUnmarshallerHookFunc(t *testing.T) {
cases := []struct {
f, t reflect.Value
result interface{}
err bool
}{
{reflect.ValueOf("42"), reflect.ValueOf(big.Int{}), big.NewInt(42), false},
{reflect.ValueOf("invalid"), reflect.ValueOf(big.Int{}), nil, true},
{reflect.ValueOf("5"), reflect.ValueOf("5"), "5", false},
}
for i, tc := range cases {
f := TextUnmarshallerHookFunc()
actual, err := DecodeHookExec(f, tc.f, tc.t)
if tc.err != (err != nil) {
t.Fatalf("case %d: expected err %#v", i, tc.err)
}
if !reflect.DeepEqual(actual, tc.result) {
t.Fatalf(
"case %d: expected %#v, got %#v",
i, tc.result, actual)
}
}
}