568 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			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 jderr %#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 jderr %#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 jderr %#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 jderr %#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 jderr %#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 jderr %#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 jderr %#v", err)
 | 
						|
			}
 | 
						|
 | 
						|
			err = d.Decode(tc.input)
 | 
						|
			if tc.err != (err != nil) {
 | 
						|
				t.Fatalf("expected jderr %#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 jderr %#v", i, tc.err)
 | 
						|
		}
 | 
						|
		if !reflect.DeepEqual(actual, tc.result) {
 | 
						|
			t.Fatalf(
 | 
						|
				"case %d: expected %#v, got %#v",
 | 
						|
				i, tc.result, actual)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |