2764 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			2764 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Go
		
	
	
	
package mapstructure
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"io"
 | 
						|
	"reflect"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
type Basic struct {
 | 
						|
	Vstring     string
 | 
						|
	Vint        int
 | 
						|
	Vint8       int8
 | 
						|
	Vint16      int16
 | 
						|
	Vint32      int32
 | 
						|
	Vint64      int64
 | 
						|
	Vuint       uint
 | 
						|
	Vbool       bool
 | 
						|
	Vfloat      float64
 | 
						|
	Vextra      string
 | 
						|
	vsilent     bool
 | 
						|
	Vdata       interface{}
 | 
						|
	VjsonInt    int
 | 
						|
	VjsonUint   uint
 | 
						|
	VjsonUint64 uint64
 | 
						|
	VjsonFloat  float64
 | 
						|
	VjsonNumber json.Number
 | 
						|
}
 | 
						|
 | 
						|
type BasicPointer struct {
 | 
						|
	Vstring     *string
 | 
						|
	Vint        *int
 | 
						|
	Vuint       *uint
 | 
						|
	Vbool       *bool
 | 
						|
	Vfloat      *float64
 | 
						|
	Vextra      *string
 | 
						|
	vsilent     *bool
 | 
						|
	Vdata       *interface{}
 | 
						|
	VjsonInt    *int
 | 
						|
	VjsonFloat  *float64
 | 
						|
	VjsonNumber *json.Number
 | 
						|
}
 | 
						|
 | 
						|
type BasicSquash struct {
 | 
						|
	Test Basic `mapstructure:",squash"`
 | 
						|
}
 | 
						|
 | 
						|
type Embedded struct {
 | 
						|
	Basic
 | 
						|
	Vunique string
 | 
						|
}
 | 
						|
 | 
						|
type EmbeddedPointer struct {
 | 
						|
	*Basic
 | 
						|
	Vunique string
 | 
						|
}
 | 
						|
 | 
						|
type EmbeddedSquash struct {
 | 
						|
	Basic   `mapstructure:",squash"`
 | 
						|
	Vunique string
 | 
						|
}
 | 
						|
 | 
						|
type EmbeddedPointerSquash struct {
 | 
						|
	*Basic  `mapstructure:",squash"`
 | 
						|
	Vunique string
 | 
						|
}
 | 
						|
 | 
						|
type BasicMapStructure struct {
 | 
						|
	Vunique string     `mapstructure:"vunique"`
 | 
						|
	Vtime   *time.Time `mapstructure:"time"`
 | 
						|
}
 | 
						|
 | 
						|
type NestedPointerWithMapstructure struct {
 | 
						|
	Vbar *BasicMapStructure `mapstructure:"vbar"`
 | 
						|
}
 | 
						|
 | 
						|
type EmbeddedPointerSquashWithNestedMapstructure struct {
 | 
						|
	*NestedPointerWithMapstructure `mapstructure:",squash"`
 | 
						|
	Vunique                        string
 | 
						|
}
 | 
						|
 | 
						|
type EmbeddedAndNamed struct {
 | 
						|
	Basic
 | 
						|
	Named   Basic
 | 
						|
	Vunique string
 | 
						|
}
 | 
						|
 | 
						|
type SliceAlias []string
 | 
						|
 | 
						|
type EmbeddedSlice struct {
 | 
						|
	SliceAlias `mapstructure:"slice_alias"`
 | 
						|
	Vunique    string
 | 
						|
}
 | 
						|
 | 
						|
type ArrayAlias [2]string
 | 
						|
 | 
						|
type EmbeddedArray struct {
 | 
						|
	ArrayAlias `mapstructure:"array_alias"`
 | 
						|
	Vunique    string
 | 
						|
}
 | 
						|
 | 
						|
type SquashOnNonStructType struct {
 | 
						|
	InvalidSquashType int `mapstructure:",squash"`
 | 
						|
}
 | 
						|
 | 
						|
type Map struct {
 | 
						|
	Vfoo   string
 | 
						|
	Vother map[string]string
 | 
						|
}
 | 
						|
 | 
						|
type MapOfStruct struct {
 | 
						|
	Value map[string]Basic
 | 
						|
}
 | 
						|
 | 
						|
type Nested struct {
 | 
						|
	Vfoo string
 | 
						|
	Vbar Basic
 | 
						|
}
 | 
						|
 | 
						|
type NestedPointer struct {
 | 
						|
	Vfoo string
 | 
						|
	Vbar *Basic
 | 
						|
}
 | 
						|
 | 
						|
type NilInterface struct {
 | 
						|
	W io.Writer
 | 
						|
}
 | 
						|
 | 
						|
type NilPointer struct {
 | 
						|
	Value *string
 | 
						|
}
 | 
						|
 | 
						|
type Slice struct {
 | 
						|
	Vfoo string
 | 
						|
	Vbar []string
 | 
						|
}
 | 
						|
 | 
						|
type SliceOfAlias struct {
 | 
						|
	Vfoo string
 | 
						|
	Vbar SliceAlias
 | 
						|
}
 | 
						|
 | 
						|
type SliceOfStruct struct {
 | 
						|
	Value []Basic
 | 
						|
}
 | 
						|
 | 
						|
type SlicePointer struct {
 | 
						|
	Vbar *[]string
 | 
						|
}
 | 
						|
 | 
						|
type Array struct {
 | 
						|
	Vfoo string
 | 
						|
	Vbar [2]string
 | 
						|
}
 | 
						|
 | 
						|
type ArrayOfStruct struct {
 | 
						|
	Value [2]Basic
 | 
						|
}
 | 
						|
 | 
						|
type Func struct {
 | 
						|
	Foo func() string
 | 
						|
}
 | 
						|
 | 
						|
type Tagged struct {
 | 
						|
	Extra string `mapstructure:"bar,what,what"`
 | 
						|
	Value string `mapstructure:"foo"`
 | 
						|
}
 | 
						|
 | 
						|
type Remainder struct {
 | 
						|
	A     string
 | 
						|
	Extra map[string]interface{} `mapstructure:",remain"`
 | 
						|
}
 | 
						|
 | 
						|
type StructWithOmitEmpty struct {
 | 
						|
	VisibleStringField string                 `mapstructure:"visible-string"`
 | 
						|
	OmitStringField    string                 `mapstructure:"omittable-string,omitempty"`
 | 
						|
	VisibleIntField    int                    `mapstructure:"visible-int"`
 | 
						|
	OmitIntField       int                    `mapstructure:"omittable-int,omitempty"`
 | 
						|
	VisibleFloatField  float64                `mapstructure:"visible-float"`
 | 
						|
	OmitFloatField     float64                `mapstructure:"omittable-float,omitempty"`
 | 
						|
	VisibleSliceField  []interface{}          `mapstructure:"visible-slice"`
 | 
						|
	OmitSliceField     []interface{}          `mapstructure:"omittable-slice,omitempty"`
 | 
						|
	VisibleMapField    map[string]interface{} `mapstructure:"visible-map"`
 | 
						|
	OmitMapField       map[string]interface{} `mapstructure:"omittable-map,omitempty"`
 | 
						|
	NestedField        *Nested                `mapstructure:"visible-nested"`
 | 
						|
	OmitNestedField    *Nested                `mapstructure:"omittable-nested,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
type TypeConversionResult struct {
 | 
						|
	IntToFloat         float32
 | 
						|
	IntToUint          uint
 | 
						|
	IntToBool          bool
 | 
						|
	IntToString        string
 | 
						|
	UintToInt          int
 | 
						|
	UintToFloat        float32
 | 
						|
	UintToBool         bool
 | 
						|
	UintToString       string
 | 
						|
	BoolToInt          int
 | 
						|
	BoolToUint         uint
 | 
						|
	BoolToFloat        float32
 | 
						|
	BoolToString       string
 | 
						|
	FloatToInt         int
 | 
						|
	FloatToUint        uint
 | 
						|
	FloatToBool        bool
 | 
						|
	FloatToString      string
 | 
						|
	SliceUint8ToString string
 | 
						|
	StringToSliceUint8 []byte
 | 
						|
	ArrayUint8ToString string
 | 
						|
	StringToInt        int
 | 
						|
	StringToUint       uint
 | 
						|
	StringToBool       bool
 | 
						|
	StringToFloat      float32
 | 
						|
	StringToStrSlice   []string
 | 
						|
	StringToIntSlice   []int
 | 
						|
	StringToStrArray   [1]string
 | 
						|
	StringToIntArray   [1]int
 | 
						|
	SliceToMap         map[string]interface{}
 | 
						|
	MapToSlice         []interface{}
 | 
						|
	ArrayToMap         map[string]interface{}
 | 
						|
	MapToArray         [1]interface{}
 | 
						|
}
 | 
						|
 | 
						|
func TestBasicTypes(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring":     "foo",
 | 
						|
		"vint":        42,
 | 
						|
		"vint8":       42,
 | 
						|
		"vint16":      42,
 | 
						|
		"vint32":      42,
 | 
						|
		"vint64":      42,
 | 
						|
		"Vuint":       42,
 | 
						|
		"vbool":       true,
 | 
						|
		"Vfloat":      42.42,
 | 
						|
		"vsilent":     true,
 | 
						|
		"vdata":       42,
 | 
						|
		"vjsonInt":    json.Number("1234"),
 | 
						|
		"vjsonUint":   json.Number("1234"),
 | 
						|
		"vjsonUint64": json.Number("9223372036854775809"), // 2^63 + 1
 | 
						|
		"vjsonFloat":  json.Number("1234.5"),
 | 
						|
		"vjsonNumber": json.Number("1234.5"),
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Errorf("got an jderr: %s", err.Error())
 | 
						|
		t.FailNow()
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vint != 42 {
 | 
						|
		t.Errorf("vint value should be 42: %#v", result.Vint)
 | 
						|
	}
 | 
						|
	if result.Vint8 != 42 {
 | 
						|
		t.Errorf("vint8 value should be 42: %#v", result.Vint)
 | 
						|
	}
 | 
						|
	if result.Vint16 != 42 {
 | 
						|
		t.Errorf("vint16 value should be 42: %#v", result.Vint)
 | 
						|
	}
 | 
						|
	if result.Vint32 != 42 {
 | 
						|
		t.Errorf("vint32 value should be 42: %#v", result.Vint)
 | 
						|
	}
 | 
						|
	if result.Vint64 != 42 {
 | 
						|
		t.Errorf("vint64 value should be 42: %#v", result.Vint)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vuint != 42 {
 | 
						|
		t.Errorf("vuint value should be 42: %#v", result.Vuint)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbool != true {
 | 
						|
		t.Errorf("vbool value should be true: %#v", result.Vbool)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfloat != 42.42 {
 | 
						|
		t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vextra != "" {
 | 
						|
		t.Errorf("vextra value should be empty: %#v", result.Vextra)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.vsilent != false {
 | 
						|
		t.Error("vsilent should not be set, it is unexported")
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vdata != 42 {
 | 
						|
		t.Error("vdata should be valid")
 | 
						|
	}
 | 
						|
 | 
						|
	if result.VjsonInt != 1234 {
 | 
						|
		t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.VjsonUint != 1234 {
 | 
						|
		t.Errorf("vjsonuint value should be 1234: %#v", result.VjsonUint)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.VjsonUint64 != 9223372036854775809 {
 | 
						|
		t.Errorf("vjsonuint64 value should be 9223372036854775809: %#v", result.VjsonUint64)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.VjsonFloat != 1234.5 {
 | 
						|
		t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat)
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) {
 | 
						|
		t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestBasic_IntWithFloat(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vint": float64(42),
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestBasic_Merge(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vint": 42,
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	result.Vuint = 100
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := Basic{
 | 
						|
		Vint:  42,
 | 
						|
		Vuint: 100,
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Test for issue #46.
 | 
						|
func TestBasic_Struct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vdata": map[string]interface{}{
 | 
						|
			"vstring": "foo",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result, inner Basic
 | 
						|
	result.Vdata = &inner
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
	expected := Basic{
 | 
						|
		Vdata: &Basic{
 | 
						|
			Vstring: "foo",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestBasic_interfaceStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	var iface interface{} = &Basic{}
 | 
						|
	err := Decode(input, &iface)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := &Basic{
 | 
						|
		Vstring: "foo",
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(iface, expected) {
 | 
						|
		t.Fatalf("bad: %#v", iface)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Issue 187
 | 
						|
func TestBasic_interfaceStructNonPtr(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	var iface interface{} = Basic{}
 | 
						|
	err := Decode(input, &iface)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := Basic{
 | 
						|
		Vstring: "foo",
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(iface, expected) {
 | 
						|
		t.Fatalf("bad: %#v", iface)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_BasicSquash(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	var result BasicSquash
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Test.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecodeFrom_BasicSquash(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	var v interface{}
 | 
						|
	var ok bool
 | 
						|
 | 
						|
	input := BasicSquash{
 | 
						|
		Test: Basic{
 | 
						|
			Vstring: "foo",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]interface{}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if _, ok = result["Test"]; ok {
 | 
						|
		t.Error("test should not be present in map")
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Vstring"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vstring should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "foo") {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", v)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_Embedded(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"Basic": map[string]interface{}{
 | 
						|
			"vstring": "innerfoo",
 | 
						|
		},
 | 
						|
		"vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result Embedded
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "innerfoo" {
 | 
						|
		t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedPointer(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"Basic": map[string]interface{}{
 | 
						|
			"vstring": "innerfoo",
 | 
						|
		},
 | 
						|
		"vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result EmbeddedPointer
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := EmbeddedPointer{
 | 
						|
		Basic: &Basic{
 | 
						|
			Vstring: "innerfoo",
 | 
						|
		},
 | 
						|
		Vunique: "bar",
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedSlice(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"slice_alias": []string{"foo", "bar"},
 | 
						|
		"vunique":     "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result EmbeddedSlice
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) {
 | 
						|
		t.Errorf("slice value: %#v", result.SliceAlias)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedArray(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"array_alias": [2]string{"foo", "bar"},
 | 
						|
		"vunique":     "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result EmbeddedArray
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(result.ArrayAlias, ArrayAlias([2]string{"foo", "bar"})) {
 | 
						|
		t.Errorf("array value: %#v", result.ArrayAlias)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_decodeSliceWithArray(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	var result []int
 | 
						|
	input := [1]int{1}
 | 
						|
	expected := []int{1}
 | 
						|
	if err := Decode(input, &result); err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(expected, result) {
 | 
						|
		t.Errorf("wanted %+v, got %+v", expected, result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedNoSquash(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result Embedded
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "" {
 | 
						|
		t.Errorf("vstring value should be empty: %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedPointerNoSquash(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	result := EmbeddedPointer{
 | 
						|
		Basic: &Basic{},
 | 
						|
	}
 | 
						|
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "" {
 | 
						|
		t.Errorf("vstring value should be empty: %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedSquash(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result EmbeddedSquash
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecodeFrom_EmbeddedSquash(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	var v interface{}
 | 
						|
	var ok bool
 | 
						|
 | 
						|
	input := EmbeddedSquash{
 | 
						|
		Basic: Basic{
 | 
						|
			Vstring: "foo",
 | 
						|
		},
 | 
						|
		Vunique: "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]interface{}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if _, ok = result["Basic"]; ok {
 | 
						|
		t.Error("basic should not be present in map")
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Vstring"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vstring should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "foo") {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", v)
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Vunique"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vunique should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "bar") {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", v)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedPointerSquash_FromStructToMap(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := EmbeddedPointerSquash{
 | 
						|
		Basic: &Basic{
 | 
						|
			Vstring: "foo",
 | 
						|
		},
 | 
						|
		Vunique: "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]interface{}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result["Vstring"] != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result["Vstring"])
 | 
						|
	}
 | 
						|
 | 
						|
	if result["Vunique"] != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result["Vunique"])
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedPointerSquash_FromMapToStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"Vstring": "foo",
 | 
						|
		"Vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	result := EmbeddedPointerSquash{
 | 
						|
		Basic: &Basic{},
 | 
						|
	}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedPointerSquashWithNestedMapstructure_FromStructToMap(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	vTime := time.Now()
 | 
						|
 | 
						|
	input := EmbeddedPointerSquashWithNestedMapstructure{
 | 
						|
		NestedPointerWithMapstructure: &NestedPointerWithMapstructure{
 | 
						|
			Vbar: &BasicMapStructure{
 | 
						|
				Vunique: "bar",
 | 
						|
				Vtime:   &vTime,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		Vunique: "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]interface{}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
	expected := map[string]interface{}{
 | 
						|
		"vbar": map[string]interface{}{
 | 
						|
			"vunique": "bar",
 | 
						|
			"time":    &vTime,
 | 
						|
		},
 | 
						|
		"Vunique": "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Errorf("result should be %#v: got %#v", expected, result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedPointerSquashWithNestedMapstructure_FromMapToStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	vTime := time.Now()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vbar": map[string]interface{}{
 | 
						|
			"vunique": "bar",
 | 
						|
			"time":    &vTime,
 | 
						|
		},
 | 
						|
		"Vunique": "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	result := EmbeddedPointerSquashWithNestedMapstructure{
 | 
						|
		NestedPointerWithMapstructure: &NestedPointerWithMapstructure{},
 | 
						|
	}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
	expected := EmbeddedPointerSquashWithNestedMapstructure{
 | 
						|
		NestedPointerWithMapstructure: &NestedPointerWithMapstructure{
 | 
						|
			Vbar: &BasicMapStructure{
 | 
						|
				Vunique: "bar",
 | 
						|
				Vtime:   &vTime,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		Vunique: "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Errorf("result should be %#v: got %#v", expected, result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_EmbeddedSquashConfig(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"vunique": "bar",
 | 
						|
		"Named": map[string]interface{}{
 | 
						|
			"vstring": "baz",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result EmbeddedAndNamed
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Squash: true,
 | 
						|
		Result: &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vunique != "bar" {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Named.Vstring != "baz" {
 | 
						|
		t.Errorf("Named.vstring value should be 'baz': %#v", result.Named.Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecodeFrom_EmbeddedSquashConfig(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := EmbeddedAndNamed{
 | 
						|
		Basic:   Basic{Vstring: "foo"},
 | 
						|
		Named:   Basic{Vstring: "baz"},
 | 
						|
		Vunique: "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	result := map[string]interface{}{}
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Squash: true,
 | 
						|
		Result: &result,
 | 
						|
	}
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if _, ok := result["Basic"]; ok {
 | 
						|
		t.Error("basic should not be present in map")
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok := result["Vstring"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vstring should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "foo") {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", v)
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Vunique"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vunique should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "bar") {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", v)
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Named"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("Named should be present in map")
 | 
						|
	} else {
 | 
						|
		named := v.(map[string]interface{})
 | 
						|
		v, ok := named["Vstring"]
 | 
						|
		if !ok {
 | 
						|
			t.Error("Named: vstring should be present in map")
 | 
						|
		} else if !reflect.DeepEqual(v, "baz") {
 | 
						|
			t.Errorf("Named: vstring should be 'baz': %#v", v)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecodeFrom_EmbeddedSquashConfig_WithTags(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	var v interface{}
 | 
						|
	var ok bool
 | 
						|
 | 
						|
	input := EmbeddedSquash{
 | 
						|
		Basic: Basic{
 | 
						|
			Vstring: "foo",
 | 
						|
		},
 | 
						|
		Vunique: "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	result := map[string]interface{}{}
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Squash: true,
 | 
						|
		Result: &result,
 | 
						|
	}
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if _, ok = result["Basic"]; ok {
 | 
						|
		t.Error("basic should not be present in map")
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Vstring"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vstring should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "foo") {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", v)
 | 
						|
	}
 | 
						|
 | 
						|
	v, ok = result["Vunique"]
 | 
						|
	if !ok {
 | 
						|
		t.Error("vunique should be present in map")
 | 
						|
	} else if !reflect.DeepEqual(v, "bar") {
 | 
						|
		t.Errorf("vunique value should be 'bar': %#v", v)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_SquashOnNonStructType(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"InvalidSquashType": 42,
 | 
						|
	}
 | 
						|
 | 
						|
	var result SquashOnNonStructType
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("unexpected success decoding invalid squash field type")
 | 
						|
	} else if !strings.Contains(err.Error(), "unsupported type for squash") {
 | 
						|
		t.Fatalf("unexpected error message for invalid squash field type: %s", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_DecodeHook(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vint": "WHAT",
 | 
						|
	}
 | 
						|
 | 
						|
	decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) {
 | 
						|
		if from == reflect.String && to != reflect.String {
 | 
						|
			return 5, nil
 | 
						|
		}
 | 
						|
 | 
						|
		return v, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	config := &DecoderConfig{
 | 
						|
		DecodeHook: decodeHook,
 | 
						|
		Result:     &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vint != 5 {
 | 
						|
		t.Errorf("vint should be 5: %#v", result.Vint)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_DecodeHookType(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vint": "WHAT",
 | 
						|
	}
 | 
						|
 | 
						|
	decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) {
 | 
						|
		if from.Kind() == reflect.String &&
 | 
						|
			to.Kind() != reflect.String {
 | 
						|
			return 5, nil
 | 
						|
		}
 | 
						|
 | 
						|
		return v, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	config := &DecoderConfig{
 | 
						|
		DecodeHook: decodeHook,
 | 
						|
		Result:     &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vint != 5 {
 | 
						|
		t.Errorf("vint should be 5: %#v", result.Vint)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_Nil(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	var input interface{}
 | 
						|
	result := Basic{
 | 
						|
		Vstring: "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vstring != "foo" {
 | 
						|
		t.Fatalf("bad: %#v", result.Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_NilInterfaceHook(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"w": "",
 | 
						|
	}
 | 
						|
 | 
						|
	decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) {
 | 
						|
		if t.String() == "io.Writer" {
 | 
						|
			return nil, nil
 | 
						|
		}
 | 
						|
 | 
						|
		return v, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var result NilInterface
 | 
						|
	config := &DecoderConfig{
 | 
						|
		DecodeHook: decodeHook,
 | 
						|
		Result:     &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.W != nil {
 | 
						|
		t.Errorf("W should be nil: %#v", result.W)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_NilPointerHook(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"value": "",
 | 
						|
	}
 | 
						|
 | 
						|
	decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) {
 | 
						|
		if typed, ok := v.(string); ok {
 | 
						|
			if typed == "" {
 | 
						|
				return nil, nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return v, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var result NilPointer
 | 
						|
	config := &DecoderConfig{
 | 
						|
		DecodeHook: decodeHook,
 | 
						|
		Result:     &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value != nil {
 | 
						|
		t.Errorf("W should be nil: %#v", result.Value)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_FuncHook(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"foo": "baz",
 | 
						|
	}
 | 
						|
 | 
						|
	decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) {
 | 
						|
		if t.Kind() != reflect.Func {
 | 
						|
			return v, nil
 | 
						|
		}
 | 
						|
		val := v.(string)
 | 
						|
		return func() string { return val }, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var result Func
 | 
						|
	config := &DecoderConfig{
 | 
						|
		DecodeHook: decodeHook,
 | 
						|
		Result:     &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Foo() != "baz" {
 | 
						|
		t.Errorf("Foo call result should be 'baz': %s", result.Foo())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_NonStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"foo": "bar",
 | 
						|
		"bar": "baz",
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]string
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result["foo"] != "bar" {
 | 
						|
		t.Fatal("foo is not bar")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_StructMatch(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vbar": Basic{
 | 
						|
			Vstring: "foo",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result Nested
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vstring != "foo" {
 | 
						|
		t.Errorf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_TypeConversion(t *testing.T) {
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"IntToFloat":         42,
 | 
						|
		"IntToUint":          42,
 | 
						|
		"IntToBool":          1,
 | 
						|
		"IntToString":        42,
 | 
						|
		"UintToInt":          42,
 | 
						|
		"UintToFloat":        42,
 | 
						|
		"UintToBool":         42,
 | 
						|
		"UintToString":       42,
 | 
						|
		"BoolToInt":          true,
 | 
						|
		"BoolToUint":         true,
 | 
						|
		"BoolToFloat":        true,
 | 
						|
		"BoolToString":       true,
 | 
						|
		"FloatToInt":         42.42,
 | 
						|
		"FloatToUint":        42.42,
 | 
						|
		"FloatToBool":        42.42,
 | 
						|
		"FloatToString":      42.42,
 | 
						|
		"SliceUint8ToString": []uint8("foo"),
 | 
						|
		"StringToSliceUint8": "foo",
 | 
						|
		"ArrayUint8ToString": [3]uint8{'f', 'o', 'o'},
 | 
						|
		"StringToInt":        "42",
 | 
						|
		"StringToUint":       "42",
 | 
						|
		"StringToBool":       "1",
 | 
						|
		"StringToFloat":      "42.42",
 | 
						|
		"StringToStrSlice":   "A",
 | 
						|
		"StringToIntSlice":   "42",
 | 
						|
		"StringToStrArray":   "A",
 | 
						|
		"StringToIntArray":   "42",
 | 
						|
		"SliceToMap":         []interface{}{},
 | 
						|
		"MapToSlice":         map[string]interface{}{},
 | 
						|
		"ArrayToMap":         []interface{}{},
 | 
						|
		"MapToArray":         map[string]interface{}{},
 | 
						|
	}
 | 
						|
 | 
						|
	expectedResultStrict := TypeConversionResult{
 | 
						|
		IntToFloat:  42.0,
 | 
						|
		IntToUint:   42,
 | 
						|
		UintToInt:   42,
 | 
						|
		UintToFloat: 42,
 | 
						|
		BoolToInt:   0,
 | 
						|
		BoolToUint:  0,
 | 
						|
		BoolToFloat: 0,
 | 
						|
		FloatToInt:  42,
 | 
						|
		FloatToUint: 42,
 | 
						|
	}
 | 
						|
 | 
						|
	expectedResultWeak := TypeConversionResult{
 | 
						|
		IntToFloat:         42.0,
 | 
						|
		IntToUint:          42,
 | 
						|
		IntToBool:          true,
 | 
						|
		IntToString:        "42",
 | 
						|
		UintToInt:          42,
 | 
						|
		UintToFloat:        42,
 | 
						|
		UintToBool:         true,
 | 
						|
		UintToString:       "42",
 | 
						|
		BoolToInt:          1,
 | 
						|
		BoolToUint:         1,
 | 
						|
		BoolToFloat:        1,
 | 
						|
		BoolToString:       "1",
 | 
						|
		FloatToInt:         42,
 | 
						|
		FloatToUint:        42,
 | 
						|
		FloatToBool:        true,
 | 
						|
		FloatToString:      "42.42",
 | 
						|
		SliceUint8ToString: "foo",
 | 
						|
		StringToSliceUint8: []byte("foo"),
 | 
						|
		ArrayUint8ToString: "foo",
 | 
						|
		StringToInt:        42,
 | 
						|
		StringToUint:       42,
 | 
						|
		StringToBool:       true,
 | 
						|
		StringToFloat:      42.42,
 | 
						|
		StringToStrSlice:   []string{"A"},
 | 
						|
		StringToIntSlice:   []int{42},
 | 
						|
		StringToStrArray:   [1]string{"A"},
 | 
						|
		StringToIntArray:   [1]int{42},
 | 
						|
		SliceToMap:         map[string]interface{}{},
 | 
						|
		MapToSlice:         []interface{}{},
 | 
						|
		ArrayToMap:         map[string]interface{}{},
 | 
						|
		MapToArray:         [1]interface{}{},
 | 
						|
	}
 | 
						|
 | 
						|
	// Test strict type conversion
 | 
						|
	var resultStrict TypeConversionResult
 | 
						|
	err := Decode(input, &resultStrict)
 | 
						|
	if err == nil {
 | 
						|
		t.Errorf("should return an error")
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(resultStrict, expectedResultStrict) {
 | 
						|
		t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict)
 | 
						|
	}
 | 
						|
 | 
						|
	// Test weak type conversion
 | 
						|
	var decoder *Decoder
 | 
						|
	var resultWeak TypeConversionResult
 | 
						|
 | 
						|
	config := &DecoderConfig{
 | 
						|
		WeaklyTypedInput: true,
 | 
						|
		Result:           &resultWeak,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err = NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(resultWeak, expectedResultWeak) {
 | 
						|
		t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecoder_ErrorUnused(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "hello",
 | 
						|
		"foo":     "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	config := &DecoderConfig{
 | 
						|
		ErrorUnused: true,
 | 
						|
		Result:      &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("expected error")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecoder_ErrorUnused_NotSetable(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	// lowercase vsilent is unexported and cannot be set
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vsilent": "false",
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	config := &DecoderConfig{
 | 
						|
		ErrorUnused: true,
 | 
						|
		Result:      &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("expected error")
 | 
						|
	}
 | 
						|
}
 | 
						|
func TestDecoder_ErrorUnset(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "hello",
 | 
						|
		"foo":     "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	config := &DecoderConfig{
 | 
						|
		ErrorUnset: true,
 | 
						|
		Result:     &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("expected error")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMap(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vother": map[interface{}]interface{}{
 | 
						|
			"foo": "foo",
 | 
						|
			"bar": "bar",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result Map
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != "foo" {
 | 
						|
		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vother == nil {
 | 
						|
		t.Fatal("vother should not be nil")
 | 
						|
	}
 | 
						|
 | 
						|
	if len(result.Vother) != 2 {
 | 
						|
		t.Error("vother should have two items")
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vother["foo"] != "foo" {
 | 
						|
		t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"])
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vother["bar"] != "bar" {
 | 
						|
		t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"])
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMapMerge(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vother": map[interface{}]interface{}{
 | 
						|
			"foo": "foo",
 | 
						|
			"bar": "bar",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result Map
 | 
						|
	result.Vother = map[string]string{"hello": "world"}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != "foo" {
 | 
						|
		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := map[string]string{
 | 
						|
		"foo":   "foo",
 | 
						|
		"bar":   "bar",
 | 
						|
		"hello": "world",
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(result.Vother, expected) {
 | 
						|
		t.Errorf("bad: %#v", result.Vother)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMapOfStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"value": map[string]interface{}{
 | 
						|
			"foo": map[string]string{"vstring": "one"},
 | 
						|
			"bar": map[string]string{"vstring": "two"},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result MapOfStruct
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value == nil {
 | 
						|
		t.Fatal("value should not be nil")
 | 
						|
	}
 | 
						|
 | 
						|
	if len(result.Value) != 2 {
 | 
						|
		t.Error("value should have two items")
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value["foo"].Vstring != "one" {
 | 
						|
		t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value["bar"].Vstring != "two" {
 | 
						|
		t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestNestedType(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": map[string]interface{}{
 | 
						|
			"vstring": "foo",
 | 
						|
			"vint":    42,
 | 
						|
			"vbool":   true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result Nested
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != "foo" {
 | 
						|
		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vint != 42 {
 | 
						|
		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vbool != true {
 | 
						|
		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vextra != "" {
 | 
						|
		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestNestedTypePointer(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": &map[string]interface{}{
 | 
						|
			"vstring": "foo",
 | 
						|
			"vint":    42,
 | 
						|
			"vbool":   true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result NestedPointer
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != "foo" {
 | 
						|
		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vint != 42 {
 | 
						|
		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vbool != true {
 | 
						|
		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vextra != "" {
 | 
						|
		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Test for issue #46.
 | 
						|
func TestNestedTypeInterface(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": &map[string]interface{}{
 | 
						|
			"vstring": "foo",
 | 
						|
			"vint":    42,
 | 
						|
			"vbool":   true,
 | 
						|
 | 
						|
			"vdata": map[string]interface{}{
 | 
						|
				"vstring": "bar",
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result NestedPointer
 | 
						|
	result.Vbar = new(Basic)
 | 
						|
	result.Vbar.Vdata = new(Basic)
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != "foo" {
 | 
						|
		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vstring != "foo" {
 | 
						|
		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vint != 42 {
 | 
						|
		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vbool != true {
 | 
						|
		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vextra != "" {
 | 
						|
		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar.Vdata.(*Basic).Vstring != "bar" {
 | 
						|
		t.Errorf("vstring value should be 'bar': %#v", result.Vbar.Vdata.(*Basic).Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestSlice(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	inputStringSlice := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": []string{"foo", "bar", "baz"},
 | 
						|
	}
 | 
						|
 | 
						|
	inputStringSlicePointer := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": &[]string{"foo", "bar", "baz"},
 | 
						|
	}
 | 
						|
 | 
						|
	outputStringSlice := &Slice{
 | 
						|
		"foo",
 | 
						|
		[]string{"foo", "bar", "baz"},
 | 
						|
	}
 | 
						|
 | 
						|
	testSliceInput(t, inputStringSlice, outputStringSlice)
 | 
						|
	testSliceInput(t, inputStringSlicePointer, outputStringSlice)
 | 
						|
}
 | 
						|
 | 
						|
func TestInvalidSlice(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": 42,
 | 
						|
	}
 | 
						|
 | 
						|
	result := Slice{}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err == nil {
 | 
						|
		t.Errorf("expected failure")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestSliceOfStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"value": []map[string]interface{}{
 | 
						|
			{"vstring": "one"},
 | 
						|
			{"vstring": "two"},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result SliceOfStruct
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(result.Value) != 2 {
 | 
						|
		t.Fatalf("expected two values, got %d", len(result.Value))
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value[0].Vstring != "one" {
 | 
						|
		t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value[1].Vstring != "two" {
 | 
						|
		t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestSliceCornerCases(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	// Input with a map with zero values
 | 
						|
	input := map[string]interface{}{}
 | 
						|
	var resultWeak []Basic
 | 
						|
 | 
						|
	err := WeakDecode(input, &resultWeak)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(resultWeak) != 0 {
 | 
						|
		t.Errorf("length should be 0")
 | 
						|
	}
 | 
						|
	// Input with more values
 | 
						|
	input = map[string]interface{}{
 | 
						|
		"Vstring": "foo",
 | 
						|
	}
 | 
						|
 | 
						|
	resultWeak = nil
 | 
						|
	err = WeakDecode(input, &resultWeak)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if resultWeak[0].Vstring != "foo" {
 | 
						|
		t.Errorf("value does not match")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestSliceToMap(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := []map[string]interface{}{
 | 
						|
		{
 | 
						|
			"foo": "bar",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"bar": "baz",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]interface{}
 | 
						|
	err := WeakDecode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := map[string]interface{}{
 | 
						|
		"foo": "bar",
 | 
						|
		"bar": "baz",
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Errorf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestArray(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	inputStringArray := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": [2]string{"foo", "bar"},
 | 
						|
	}
 | 
						|
 | 
						|
	inputStringArrayPointer := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": &[2]string{"foo", "bar"},
 | 
						|
	}
 | 
						|
 | 
						|
	outputStringArray := &Array{
 | 
						|
		"foo",
 | 
						|
		[2]string{"foo", "bar"},
 | 
						|
	}
 | 
						|
 | 
						|
	testArrayInput(t, inputStringArray, outputStringArray)
 | 
						|
	testArrayInput(t, inputStringArrayPointer, outputStringArray)
 | 
						|
}
 | 
						|
 | 
						|
func TestInvalidArray(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": 42,
 | 
						|
	}
 | 
						|
 | 
						|
	result := Array{}
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err == nil {
 | 
						|
		t.Errorf("expected failure")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestArrayOfStruct(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"value": []map[string]interface{}{
 | 
						|
			{"vstring": "one"},
 | 
						|
			{"vstring": "two"},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result ArrayOfStruct
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(result.Value) != 2 {
 | 
						|
		t.Fatalf("expected two values, got %d", len(result.Value))
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value[0].Vstring != "one" {
 | 
						|
		t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value[1].Vstring != "two" {
 | 
						|
		t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestArrayToMap(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := []map[string]interface{}{
 | 
						|
		{
 | 
						|
			"foo": "bar",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"bar": "baz",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	var result map[string]interface{}
 | 
						|
	err := WeakDecode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got an error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := map[string]interface{}{
 | 
						|
		"foo": "bar",
 | 
						|
		"bar": "baz",
 | 
						|
	}
 | 
						|
	if !reflect.DeepEqual(result, expected) {
 | 
						|
		t.Errorf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecodeTable(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	// We need to make new types so that we don't get the short-circuit
 | 
						|
	// copy functionality. We want to test the deep copying functionality.
 | 
						|
	type BasicCopy Basic
 | 
						|
	type NestedPointerCopy NestedPointer
 | 
						|
	type MapCopy Map
 | 
						|
 | 
						|
	tests := []struct {
 | 
						|
		name    string
 | 
						|
		in      interface{}
 | 
						|
		target  interface{}
 | 
						|
		out     interface{}
 | 
						|
		wantErr bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			"basic struct input",
 | 
						|
			&Basic{
 | 
						|
				Vstring: "vstring",
 | 
						|
				Vint:    2,
 | 
						|
				Vint8:   2,
 | 
						|
				Vint16:  2,
 | 
						|
				Vint32:  2,
 | 
						|
				Vint64:  2,
 | 
						|
				Vuint:   3,
 | 
						|
				Vbool:   true,
 | 
						|
				Vfloat:  4.56,
 | 
						|
				Vextra:  "vextra",
 | 
						|
				vsilent: true,
 | 
						|
				Vdata:   []byte("data"),
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{
 | 
						|
				"Vstring":     "vstring",
 | 
						|
				"Vint":        2,
 | 
						|
				"Vint8":       int8(2),
 | 
						|
				"Vint16":      int16(2),
 | 
						|
				"Vint32":      int32(2),
 | 
						|
				"Vint64":      int64(2),
 | 
						|
				"Vuint":       uint(3),
 | 
						|
				"Vbool":       true,
 | 
						|
				"Vfloat":      4.56,
 | 
						|
				"Vextra":      "vextra",
 | 
						|
				"Vdata":       []byte("data"),
 | 
						|
				"VjsonInt":    0,
 | 
						|
				"VjsonUint":   uint(0),
 | 
						|
				"VjsonUint64": uint64(0),
 | 
						|
				"VjsonFloat":  0.0,
 | 
						|
				"VjsonNumber": json.Number(""),
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"embedded struct input",
 | 
						|
			&Embedded{
 | 
						|
				Vunique: "vunique",
 | 
						|
				Basic: Basic{
 | 
						|
					Vstring: "vstring",
 | 
						|
					Vint:    2,
 | 
						|
					Vint8:   2,
 | 
						|
					Vint16:  2,
 | 
						|
					Vint32:  2,
 | 
						|
					Vint64:  2,
 | 
						|
					Vuint:   3,
 | 
						|
					Vbool:   true,
 | 
						|
					Vfloat:  4.56,
 | 
						|
					Vextra:  "vextra",
 | 
						|
					vsilent: true,
 | 
						|
					Vdata:   []byte("data"),
 | 
						|
				},
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{
 | 
						|
				"Vunique": "vunique",
 | 
						|
				"Basic": map[string]interface{}{
 | 
						|
					"Vstring":     "vstring",
 | 
						|
					"Vint":        2,
 | 
						|
					"Vint8":       int8(2),
 | 
						|
					"Vint16":      int16(2),
 | 
						|
					"Vint32":      int32(2),
 | 
						|
					"Vint64":      int64(2),
 | 
						|
					"Vuint":       uint(3),
 | 
						|
					"Vbool":       true,
 | 
						|
					"Vfloat":      4.56,
 | 
						|
					"Vextra":      "vextra",
 | 
						|
					"Vdata":       []byte("data"),
 | 
						|
					"VjsonInt":    0,
 | 
						|
					"VjsonUint":   uint(0),
 | 
						|
					"VjsonUint64": uint64(0),
 | 
						|
					"VjsonFloat":  0.0,
 | 
						|
					"VjsonNumber": json.Number(""),
 | 
						|
				},
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct => struct",
 | 
						|
			&Basic{
 | 
						|
				Vstring: "vstring",
 | 
						|
				Vint:    2,
 | 
						|
				Vuint:   3,
 | 
						|
				Vbool:   true,
 | 
						|
				Vfloat:  4.56,
 | 
						|
				Vextra:  "vextra",
 | 
						|
				Vdata:   []byte("data"),
 | 
						|
				vsilent: true,
 | 
						|
			},
 | 
						|
			&BasicCopy{},
 | 
						|
			&BasicCopy{
 | 
						|
				Vstring: "vstring",
 | 
						|
				Vint:    2,
 | 
						|
				Vuint:   3,
 | 
						|
				Vbool:   true,
 | 
						|
				Vfloat:  4.56,
 | 
						|
				Vextra:  "vextra",
 | 
						|
				Vdata:   []byte("data"),
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct => struct with pointers",
 | 
						|
			&NestedPointer{
 | 
						|
				Vfoo: "hello",
 | 
						|
				Vbar: nil,
 | 
						|
			},
 | 
						|
			&NestedPointerCopy{},
 | 
						|
			&NestedPointerCopy{
 | 
						|
				Vfoo: "hello",
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"basic pointer to non-pointer",
 | 
						|
			&BasicPointer{
 | 
						|
				Vstring: stringPtr("vstring"),
 | 
						|
				Vint:    intPtr(2),
 | 
						|
				Vuint:   uintPtr(3),
 | 
						|
				Vbool:   boolPtr(true),
 | 
						|
				Vfloat:  floatPtr(4.56),
 | 
						|
				Vdata:   interfacePtr([]byte("data")),
 | 
						|
			},
 | 
						|
			&Basic{},
 | 
						|
			&Basic{
 | 
						|
				Vstring: "vstring",
 | 
						|
				Vint:    2,
 | 
						|
				Vuint:   3,
 | 
						|
				Vbool:   true,
 | 
						|
				Vfloat:  4.56,
 | 
						|
				Vdata:   []byte("data"),
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"slice non-pointer to pointer",
 | 
						|
			&Slice{},
 | 
						|
			&SlicePointer{},
 | 
						|
			&SlicePointer{},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"slice non-pointer to pointer, zero field",
 | 
						|
			&Slice{},
 | 
						|
			&SlicePointer{
 | 
						|
				Vbar: &[]string{"yo"},
 | 
						|
			},
 | 
						|
			&SlicePointer{},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"slice to slice alias",
 | 
						|
			&Slice{},
 | 
						|
			&SliceOfAlias{},
 | 
						|
			&SliceOfAlias{},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"nil map to map",
 | 
						|
			&Map{},
 | 
						|
			&MapCopy{},
 | 
						|
			&MapCopy{},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"nil map to non-empty map",
 | 
						|
			&Map{},
 | 
						|
			&MapCopy{Vother: map[string]string{"foo": "bar"}},
 | 
						|
			&MapCopy{},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
 | 
						|
		{
 | 
						|
			"slice input - should error",
 | 
						|
			[]string{"foo", "bar"},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct with slice property",
 | 
						|
			&Slice{
 | 
						|
				Vfoo: "vfoo",
 | 
						|
				Vbar: []string{"foo", "bar"},
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{
 | 
						|
				"Vfoo": "vfoo",
 | 
						|
				"Vbar": []string{"foo", "bar"},
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct with empty slice",
 | 
						|
			&map[string]interface{}{
 | 
						|
				"Vbar": []string{},
 | 
						|
			},
 | 
						|
			&Slice{},
 | 
						|
			&Slice{
 | 
						|
				Vbar: []string{},
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct with slice of struct property",
 | 
						|
			&SliceOfStruct{
 | 
						|
				Value: []Basic{
 | 
						|
					Basic{
 | 
						|
						Vstring: "vstring",
 | 
						|
						Vint:    2,
 | 
						|
						Vuint:   3,
 | 
						|
						Vbool:   true,
 | 
						|
						Vfloat:  4.56,
 | 
						|
						Vextra:  "vextra",
 | 
						|
						vsilent: true,
 | 
						|
						Vdata:   []byte("data"),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{
 | 
						|
				"Value": []Basic{
 | 
						|
					Basic{
 | 
						|
						Vstring: "vstring",
 | 
						|
						Vint:    2,
 | 
						|
						Vuint:   3,
 | 
						|
						Vbool:   true,
 | 
						|
						Vfloat:  4.56,
 | 
						|
						Vextra:  "vextra",
 | 
						|
						vsilent: true,
 | 
						|
						Vdata:   []byte("data"),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct with map property",
 | 
						|
			&Map{
 | 
						|
				Vfoo:   "vfoo",
 | 
						|
				Vother: map[string]string{"vother": "vother"},
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{
 | 
						|
				"Vfoo": "vfoo",
 | 
						|
				"Vother": map[string]string{
 | 
						|
					"vother": "vother",
 | 
						|
				}},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"tagged struct",
 | 
						|
			&Tagged{
 | 
						|
				Extra: "extra",
 | 
						|
				Value: "value",
 | 
						|
			},
 | 
						|
			&map[string]string{},
 | 
						|
			&map[string]string{
 | 
						|
				"bar": "extra",
 | 
						|
				"foo": "value",
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"omit tag struct",
 | 
						|
			&struct {
 | 
						|
				Value string `mapstructure:"value"`
 | 
						|
				Omit  string `mapstructure:"-"`
 | 
						|
			}{
 | 
						|
				Value: "value",
 | 
						|
				Omit:  "omit",
 | 
						|
			},
 | 
						|
			&map[string]string{},
 | 
						|
			&map[string]string{
 | 
						|
				"value": "value",
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"decode to wrong map type",
 | 
						|
			&struct {
 | 
						|
				Value string
 | 
						|
			}{
 | 
						|
				Value: "string",
 | 
						|
			},
 | 
						|
			&map[string]int{},
 | 
						|
			&map[string]int{},
 | 
						|
			true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"remainder",
 | 
						|
			map[string]interface{}{
 | 
						|
				"A": "hello",
 | 
						|
				"B": "goodbye",
 | 
						|
				"C": "yo",
 | 
						|
			},
 | 
						|
			&Remainder{},
 | 
						|
			&Remainder{
 | 
						|
				A: "hello",
 | 
						|
				Extra: map[string]interface{}{
 | 
						|
					"B": "goodbye",
 | 
						|
					"C": "yo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"remainder with no extra",
 | 
						|
			map[string]interface{}{
 | 
						|
				"A": "hello",
 | 
						|
			},
 | 
						|
			&Remainder{},
 | 
						|
			&Remainder{
 | 
						|
				A:     "hello",
 | 
						|
				Extra: nil,
 | 
						|
			},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct with omitempty tag return non-empty values",
 | 
						|
			&struct {
 | 
						|
				VisibleField interface{} `mapstructure:"visible"`
 | 
						|
				OmitField    interface{} `mapstructure:"omittable,omitempty"`
 | 
						|
			}{
 | 
						|
				VisibleField: nil,
 | 
						|
				OmitField:    "string",
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{"visible": nil, "omittable": "string"},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"struct with omitempty tag ignore empty values",
 | 
						|
			&struct {
 | 
						|
				VisibleField interface{} `mapstructure:"visible"`
 | 
						|
				OmitField    interface{} `mapstructure:"omittable,omitempty"`
 | 
						|
			}{
 | 
						|
				VisibleField: nil,
 | 
						|
				OmitField:    nil,
 | 
						|
			},
 | 
						|
			&map[string]interface{}{},
 | 
						|
			&map[string]interface{}{"visible": nil},
 | 
						|
			false,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			if err := Decode(tt.in, tt.target); (err != nil) != tt.wantErr {
 | 
						|
				t.Fatalf("%q: TestMapOutputForStructuredInputs() unexpected error: %s", tt.name, err)
 | 
						|
			}
 | 
						|
 | 
						|
			if !reflect.DeepEqual(tt.out, tt.target) {
 | 
						|
				t.Fatalf("%q: TestMapOutputForStructuredInputs() expected: %#v, got: %#v", tt.name, tt.out, tt.target)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestInvalidType(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": 42,
 | 
						|
	}
 | 
						|
 | 
						|
	var result Basic
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("error should exist")
 | 
						|
	}
 | 
						|
 | 
						|
	derr, ok := err.(*Error)
 | 
						|
	if !ok {
 | 
						|
		t.Fatalf("error should be kind of Error, instead: %#v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if derr.Errors[0] !=
 | 
						|
		"'Vstring' expected type 'string', got unconvertible type 'int', value: '42'" {
 | 
						|
		t.Errorf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	inputNegIntUint := map[string]interface{}{
 | 
						|
		"vuint": -42,
 | 
						|
	}
 | 
						|
 | 
						|
	err = Decode(inputNegIntUint, &result)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("error should exist")
 | 
						|
	}
 | 
						|
 | 
						|
	derr, ok = err.(*Error)
 | 
						|
	if !ok {
 | 
						|
		t.Fatalf("error should be kind of Error, instead: %#v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" {
 | 
						|
		t.Errorf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	inputNegFloatUint := map[string]interface{}{
 | 
						|
		"vuint": -42.0,
 | 
						|
	}
 | 
						|
 | 
						|
	err = Decode(inputNegFloatUint, &result)
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("error should exist")
 | 
						|
	}
 | 
						|
 | 
						|
	derr, ok = err.(*Error)
 | 
						|
	if !ok {
 | 
						|
		t.Fatalf("error should be kind of Error, instead: %#v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" {
 | 
						|
		t.Errorf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecodeMetadata(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": map[string]interface{}{
 | 
						|
			"vstring": "foo",
 | 
						|
			"Vuint":   42,
 | 
						|
			"vsilent": "false",
 | 
						|
			"foo":     "bar",
 | 
						|
		},
 | 
						|
		"bar": "nil",
 | 
						|
	}
 | 
						|
 | 
						|
	var md Metadata
 | 
						|
	var result Nested
 | 
						|
 | 
						|
	err := DecodeMetadata(input, &result, &md)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"}
 | 
						|
	sort.Strings(md.Keys)
 | 
						|
	if !reflect.DeepEqual(md.Keys, expectedKeys) {
 | 
						|
		t.Fatalf("bad keys: %#v", md.Keys)
 | 
						|
	}
 | 
						|
 | 
						|
	expectedUnused := []string{"Vbar.foo", "Vbar.vsilent", "bar"}
 | 
						|
	sort.Strings(md.Unused)
 | 
						|
	if !reflect.DeepEqual(md.Unused, expectedUnused) {
 | 
						|
		t.Fatalf("bad unused: %#v", md.Unused)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMetadata(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	type testResult struct {
 | 
						|
		Vfoo string
 | 
						|
		Vbar BasicPointer
 | 
						|
	}
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vfoo": "foo",
 | 
						|
		"vbar": map[string]interface{}{
 | 
						|
			"vstring": "foo",
 | 
						|
			"Vuint":   42,
 | 
						|
			"vsilent": "false",
 | 
						|
			"foo":     "bar",
 | 
						|
		},
 | 
						|
		"bar": "nil",
 | 
						|
	}
 | 
						|
 | 
						|
	var md Metadata
 | 
						|
	var result testResult
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Metadata: &md,
 | 
						|
		Result:   &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"}
 | 
						|
	sort.Strings(md.Keys)
 | 
						|
	if !reflect.DeepEqual(md.Keys, expectedKeys) {
 | 
						|
		t.Fatalf("bad keys: %#v", md.Keys)
 | 
						|
	}
 | 
						|
 | 
						|
	expectedUnused := []string{"Vbar.foo", "Vbar.vsilent", "bar"}
 | 
						|
	sort.Strings(md.Unused)
 | 
						|
	if !reflect.DeepEqual(md.Unused, expectedUnused) {
 | 
						|
		t.Fatalf("bad unused: %#v", md.Unused)
 | 
						|
	}
 | 
						|
 | 
						|
	expectedUnset := []string{
 | 
						|
		"Vbar.Vbool", "Vbar.Vdata", "Vbar.Vextra", "Vbar.Vfloat", "Vbar.Vint",
 | 
						|
		"Vbar.VjsonFloat", "Vbar.VjsonInt", "Vbar.VjsonNumber"}
 | 
						|
	sort.Strings(md.Unset)
 | 
						|
	if !reflect.DeepEqual(md.Unset, expectedUnset) {
 | 
						|
		t.Fatalf("bad unset: %#v", md.Unset)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestMetadata_Embedded(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"vstring": "foo",
 | 
						|
		"vunique": "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var md Metadata
 | 
						|
	var result EmbeddedSquash
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Metadata: &md,
 | 
						|
		Result:   &result,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	expectedKeys := []string{"Vstring", "Vunique"}
 | 
						|
 | 
						|
	sort.Strings(md.Keys)
 | 
						|
	if !reflect.DeepEqual(md.Keys, expectedKeys) {
 | 
						|
		t.Fatalf("bad keys: %#v", md.Keys)
 | 
						|
	}
 | 
						|
 | 
						|
	expectedUnused := []string{}
 | 
						|
	if !reflect.DeepEqual(md.Unused, expectedUnused) {
 | 
						|
		t.Fatalf("bad unused: %#v", md.Unused)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestNonPtrValue(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	err := Decode(map[string]interface{}{}, Basic{})
 | 
						|
	if err == nil {
 | 
						|
		t.Fatal("error should exist")
 | 
						|
	}
 | 
						|
 | 
						|
	if err.Error() != "result must be a pointer" {
 | 
						|
		t.Errorf("got unexpected error: %s", err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestTagged(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"foo": "bar",
 | 
						|
		"bar": "value",
 | 
						|
	}
 | 
						|
 | 
						|
	var result Tagged
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("unexpected error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Value != "bar" {
 | 
						|
		t.Errorf("value should be 'bar', got: %#v", result.Value)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Extra != "value" {
 | 
						|
		t.Errorf("extra should be 'value', got: %#v", result.Extra)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestWeakDecode(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"foo": "4",
 | 
						|
		"bar": "value",
 | 
						|
	}
 | 
						|
 | 
						|
	var result struct {
 | 
						|
		Foo int
 | 
						|
		Bar string
 | 
						|
	}
 | 
						|
 | 
						|
	if err := WeakDecode(input, &result); err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
	if result.Foo != 4 {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
	if result.Bar != "value" {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestWeakDecodeMetadata(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"foo":        "4",
 | 
						|
		"bar":        "value",
 | 
						|
		"unused":     "value",
 | 
						|
		"unexported": "value",
 | 
						|
	}
 | 
						|
 | 
						|
	var md Metadata
 | 
						|
	var result struct {
 | 
						|
		Foo        int
 | 
						|
		Bar        string
 | 
						|
		unexported string
 | 
						|
	}
 | 
						|
 | 
						|
	if err := WeakDecodeMetadata(input, &result, &md); err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
	if result.Foo != 4 {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
	if result.Bar != "value" {
 | 
						|
		t.Fatalf("bad: %#v", result)
 | 
						|
	}
 | 
						|
 | 
						|
	expectedKeys := []string{"Bar", "Foo"}
 | 
						|
	sort.Strings(md.Keys)
 | 
						|
	if !reflect.DeepEqual(md.Keys, expectedKeys) {
 | 
						|
		t.Fatalf("bad keys: %#v", md.Keys)
 | 
						|
	}
 | 
						|
 | 
						|
	expectedUnused := []string{"unexported", "unused"}
 | 
						|
	sort.Strings(md.Unused)
 | 
						|
	if !reflect.DeepEqual(md.Unused, expectedUnused) {
 | 
						|
		t.Fatalf("bad unused: %#v", md.Unused)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_StructTaggedWithOmitempty_OmitEmptyValues(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := &StructWithOmitEmpty{}
 | 
						|
 | 
						|
	var emptySlice []interface{}
 | 
						|
	var emptyMap map[string]interface{}
 | 
						|
	var emptyNested *Nested
 | 
						|
	expected := &map[string]interface{}{
 | 
						|
		"visible-string": "",
 | 
						|
		"visible-int":    0,
 | 
						|
		"visible-float":  0.0,
 | 
						|
		"visible-slice":  emptySlice,
 | 
						|
		"visible-map":    emptyMap,
 | 
						|
		"visible-nested": emptyNested,
 | 
						|
	}
 | 
						|
 | 
						|
	actual := &map[string]interface{}{}
 | 
						|
	Decode(input, actual)
 | 
						|
 | 
						|
	if !reflect.DeepEqual(actual, expected) {
 | 
						|
		t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	input := &StructWithOmitEmpty{
 | 
						|
		VisibleStringField: "",
 | 
						|
		OmitStringField:    "string",
 | 
						|
		VisibleIntField:    0,
 | 
						|
		OmitIntField:       1,
 | 
						|
		VisibleFloatField:  0.0,
 | 
						|
		OmitFloatField:     1.0,
 | 
						|
		VisibleSliceField:  nil,
 | 
						|
		OmitSliceField:     []interface{}{1},
 | 
						|
		VisibleMapField:    nil,
 | 
						|
		OmitMapField:       map[string]interface{}{"k": "v"},
 | 
						|
		NestedField:        nil,
 | 
						|
		OmitNestedField:    &Nested{},
 | 
						|
	}
 | 
						|
 | 
						|
	var emptySlice []interface{}
 | 
						|
	var emptyMap map[string]interface{}
 | 
						|
	var emptyNested *Nested
 | 
						|
	expected := &map[string]interface{}{
 | 
						|
		"visible-string":   "",
 | 
						|
		"omittable-string": "string",
 | 
						|
		"visible-int":      0,
 | 
						|
		"omittable-int":    1,
 | 
						|
		"visible-float":    0.0,
 | 
						|
		"omittable-float":  1.0,
 | 
						|
		"visible-slice":    emptySlice,
 | 
						|
		"omittable-slice":  []interface{}{1},
 | 
						|
		"visible-map":      emptyMap,
 | 
						|
		"omittable-map":    map[string]interface{}{"k": "v"},
 | 
						|
		"visible-nested":   emptyNested,
 | 
						|
		"omittable-nested": &Nested{},
 | 
						|
	}
 | 
						|
 | 
						|
	actual := &map[string]interface{}{}
 | 
						|
	Decode(input, actual)
 | 
						|
 | 
						|
	if !reflect.DeepEqual(actual, expected) {
 | 
						|
		t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecode_mapToStruct(t *testing.T) {
 | 
						|
	type Target struct {
 | 
						|
		String    string
 | 
						|
		StringPtr *string
 | 
						|
	}
 | 
						|
 | 
						|
	expected := Target{
 | 
						|
		String: "hello",
 | 
						|
	}
 | 
						|
 | 
						|
	var target Target
 | 
						|
	err := Decode(map[string]interface{}{
 | 
						|
		"string":    "hello",
 | 
						|
		"StringPtr": "goodbye",
 | 
						|
	}, &target)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Pointers fail reflect test so do those manually
 | 
						|
	if target.StringPtr == nil || *target.StringPtr != "goodbye" {
 | 
						|
		t.Fatalf("bad: %#v", target)
 | 
						|
	}
 | 
						|
	target.StringPtr = nil
 | 
						|
 | 
						|
	if !reflect.DeepEqual(target, expected) {
 | 
						|
		t.Fatalf("bad: %#v", target)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecoder_MatchName(t *testing.T) {
 | 
						|
	t.Parallel()
 | 
						|
 | 
						|
	type Target struct {
 | 
						|
		FirstMatch  string `mapstructure:"first_match"`
 | 
						|
		SecondMatch string
 | 
						|
		NoMatch     string `mapstructure:"no_match"`
 | 
						|
	}
 | 
						|
 | 
						|
	input := map[string]interface{}{
 | 
						|
		"first_match": "foo",
 | 
						|
		"SecondMatch": "bar",
 | 
						|
		"NO_MATCH":    "baz",
 | 
						|
	}
 | 
						|
 | 
						|
	expected := Target{
 | 
						|
		FirstMatch:  "foo",
 | 
						|
		SecondMatch: "bar",
 | 
						|
	}
 | 
						|
 | 
						|
	var actual Target
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Result: &actual,
 | 
						|
		MatchName: func(mapKey, fieldName string) bool {
 | 
						|
			return mapKey == fieldName
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(expected, actual) {
 | 
						|
		t.Fatalf("Decode() expected: %#v, got: %#v", expected, actual)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDecoder_IgnoreUntaggedFields(t *testing.T) {
 | 
						|
	type Input struct {
 | 
						|
		UntaggedNumber int
 | 
						|
		TaggedNumber   int `mapstructure:"tagged_number"`
 | 
						|
		UntaggedString string
 | 
						|
		TaggedString   string `mapstructure:"tagged_string"`
 | 
						|
	}
 | 
						|
	input := &Input{
 | 
						|
		UntaggedNumber: 31,
 | 
						|
		TaggedNumber:   42,
 | 
						|
		UntaggedString: "hidden",
 | 
						|
		TaggedString:   "visible",
 | 
						|
	}
 | 
						|
 | 
						|
	actual := make(map[string]interface{})
 | 
						|
	config := &DecoderConfig{
 | 
						|
		Result:               &actual,
 | 
						|
		IgnoreUntaggedFields: true,
 | 
						|
	}
 | 
						|
 | 
						|
	decoder, err := NewDecoder(config)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	err = decoder.Decode(input)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("jderr: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	expected := map[string]interface{}{
 | 
						|
		"tagged_number": 42,
 | 
						|
		"tagged_string": "visible",
 | 
						|
	}
 | 
						|
 | 
						|
	if !reflect.DeepEqual(expected, actual) {
 | 
						|
		t.Fatalf("Decode() expected: %#v\ngot: %#v", expected, actual)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
 | 
						|
	var result Slice
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != expected.Vfoo {
 | 
						|
		t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar == nil {
 | 
						|
		t.Fatalf("Vbar a slice, got '%#v'", result.Vbar)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(result.Vbar) != len(expected.Vbar) {
 | 
						|
		t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar))
 | 
						|
	}
 | 
						|
 | 
						|
	for i, v := range result.Vbar {
 | 
						|
		if v != expected.Vbar[i] {
 | 
						|
			t.Errorf(
 | 
						|
				"Vbar[%d] should be '%#v', got '%#v'",
 | 
						|
				i, expected.Vbar[i], v)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func testArrayInput(t *testing.T, input map[string]interface{}, expected *Array) {
 | 
						|
	var result Array
 | 
						|
	err := Decode(input, &result)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("got error: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vfoo != expected.Vfoo {
 | 
						|
		t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo)
 | 
						|
	}
 | 
						|
 | 
						|
	if result.Vbar == [2]string{} {
 | 
						|
		t.Fatalf("Vbar a slice, got '%#v'", result.Vbar)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(result.Vbar) != len(expected.Vbar) {
 | 
						|
		t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar))
 | 
						|
	}
 | 
						|
 | 
						|
	for i, v := range result.Vbar {
 | 
						|
		if v != expected.Vbar[i] {
 | 
						|
			t.Errorf(
 | 
						|
				"Vbar[%d] should be '%#v', got '%#v'",
 | 
						|
				i, expected.Vbar[i], v)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func stringPtr(v string) *string              { return &v }
 | 
						|
func intPtr(v int) *int                       { return &v }
 | 
						|
func uintPtr(v uint) *uint                    { return &v }
 | 
						|
func boolPtr(v bool) *bool                    { return &v }
 | 
						|
func floatPtr(v float64) *float64             { return &v }
 | 
						|
func interfacePtr(v interface{}) *interface{} { return &v }
 |