1package mapstructure
2
3import (
4	"encoding/json"
5	"io"
6	"reflect"
7	"sort"
8	"strings"
9	"testing"
10)
11
12type Basic struct {
13	Vstring     string
14	Vint        int
15	Vuint       uint
16	Vbool       bool
17	Vfloat      float64
18	Vextra      string
19	vsilent     bool
20	Vdata       interface{}
21	VjsonInt    int
22	VjsonFloat  float64
23	VjsonNumber json.Number
24}
25
26type BasicSquash struct {
27	Test Basic `mapstructure:",squash"`
28}
29
30type Embedded struct {
31	Basic
32	Vunique string
33}
34
35type EmbeddedPointer struct {
36	*Basic
37	Vunique string
38}
39
40type EmbeddedSquash struct {
41	Basic   `mapstructure:",squash"`
42	Vunique string
43}
44
45type SliceAlias []string
46
47type EmbeddedSlice struct {
48	SliceAlias `mapstructure:"slice_alias"`
49	Vunique    string
50}
51
52type SquashOnNonStructType struct {
53	InvalidSquashType int `mapstructure:",squash"`
54}
55
56type Map struct {
57	Vfoo   string
58	Vother map[string]string
59}
60
61type MapOfStruct struct {
62	Value map[string]Basic
63}
64
65type Nested struct {
66	Vfoo string
67	Vbar Basic
68}
69
70type NestedPointer struct {
71	Vfoo string
72	Vbar *Basic
73}
74
75type NilInterface struct {
76	W io.Writer
77}
78
79type Slice struct {
80	Vfoo string
81	Vbar []string
82}
83
84type SliceOfStruct struct {
85	Value []Basic
86}
87
88type Func struct {
89	Foo func() string
90}
91
92type Tagged struct {
93	Extra string `mapstructure:"bar,what,what"`
94	Value string `mapstructure:"foo"`
95}
96
97type TypeConversionResult struct {
98	IntToFloat         float32
99	IntToUint          uint
100	IntToBool          bool
101	IntToString        string
102	UintToInt          int
103	UintToFloat        float32
104	UintToBool         bool
105	UintToString       string
106	BoolToInt          int
107	BoolToUint         uint
108	BoolToFloat        float32
109	BoolToString       string
110	FloatToInt         int
111	FloatToUint        uint
112	FloatToBool        bool
113	FloatToString      string
114	SliceUint8ToString string
115	StringToInt        int
116	StringToUint       uint
117	StringToBool       bool
118	StringToFloat      float32
119	StringToStrSlice   []string
120	StringToIntSlice   []int
121	SliceToMap         map[string]interface{}
122	MapToSlice         []interface{}
123}
124
125func TestBasicTypes(t *testing.T) {
126	t.Parallel()
127
128	input := map[string]interface{}{
129		"vstring":     "foo",
130		"vint":        42,
131		"Vuint":       42,
132		"vbool":       true,
133		"Vfloat":      42.42,
134		"vsilent":     true,
135		"vdata":       42,
136		"vjsonInt":    json.Number("1234"),
137		"vjsonFloat":  json.Number("1234.5"),
138		"vjsonNumber": json.Number("1234.5"),
139	}
140
141	var result Basic
142	err := Decode(input, &result)
143	if err != nil {
144		t.Errorf("got an err: %s", err.Error())
145		t.FailNow()
146	}
147
148	if result.Vstring != "foo" {
149		t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
150	}
151
152	if result.Vint != 42 {
153		t.Errorf("vint value should be 42: %#v", result.Vint)
154	}
155
156	if result.Vuint != 42 {
157		t.Errorf("vuint value should be 42: %#v", result.Vuint)
158	}
159
160	if result.Vbool != true {
161		t.Errorf("vbool value should be true: %#v", result.Vbool)
162	}
163
164	if result.Vfloat != 42.42 {
165		t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat)
166	}
167
168	if result.Vextra != "" {
169		t.Errorf("vextra value should be empty: %#v", result.Vextra)
170	}
171
172	if result.vsilent != false {
173		t.Error("vsilent should not be set, it is unexported")
174	}
175
176	if result.Vdata != 42 {
177		t.Error("vdata should be valid")
178	}
179
180	if result.VjsonInt != 1234 {
181		t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt)
182	}
183
184	if result.VjsonFloat != 1234.5 {
185		t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat)
186	}
187
188	if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) {
189		t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber)
190	}
191}
192
193func TestBasic_IntWithFloat(t *testing.T) {
194	t.Parallel()
195
196	input := map[string]interface{}{
197		"vint": float64(42),
198	}
199
200	var result Basic
201	err := Decode(input, &result)
202	if err != nil {
203		t.Fatalf("got an err: %s", err)
204	}
205}
206
207func TestBasic_Merge(t *testing.T) {
208	t.Parallel()
209
210	input := map[string]interface{}{
211		"vint": 42,
212	}
213
214	var result Basic
215	result.Vuint = 100
216	err := Decode(input, &result)
217	if err != nil {
218		t.Fatalf("got an err: %s", err)
219	}
220
221	expected := Basic{
222		Vint:  42,
223		Vuint: 100,
224	}
225	if !reflect.DeepEqual(result, expected) {
226		t.Fatalf("bad: %#v", result)
227	}
228}
229
230func TestDecode_BasicSquash(t *testing.T) {
231	t.Parallel()
232
233	input := map[string]interface{}{
234		"vstring": "foo",
235	}
236
237	var result BasicSquash
238	err := Decode(input, &result)
239	if err != nil {
240		t.Fatalf("got an err: %s", err.Error())
241	}
242
243	if result.Test.Vstring != "foo" {
244		t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring)
245	}
246}
247
248func TestDecode_Embedded(t *testing.T) {
249	t.Parallel()
250
251	input := map[string]interface{}{
252		"vstring": "foo",
253		"Basic": map[string]interface{}{
254			"vstring": "innerfoo",
255		},
256		"vunique": "bar",
257	}
258
259	var result Embedded
260	err := Decode(input, &result)
261	if err != nil {
262		t.Fatalf("got an err: %s", err.Error())
263	}
264
265	if result.Vstring != "innerfoo" {
266		t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring)
267	}
268
269	if result.Vunique != "bar" {
270		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
271	}
272}
273
274func TestDecode_EmbeddedPointer(t *testing.T) {
275	t.Parallel()
276
277	input := map[string]interface{}{
278		"vstring": "foo",
279		"Basic": map[string]interface{}{
280			"vstring": "innerfoo",
281		},
282		"vunique": "bar",
283	}
284
285	var result EmbeddedPointer
286	err := Decode(input, &result)
287	if err != nil {
288		t.Fatalf("err: %s", err)
289	}
290
291	expected := EmbeddedPointer{
292		Basic: &Basic{
293			Vstring: "innerfoo",
294		},
295		Vunique: "bar",
296	}
297	if !reflect.DeepEqual(result, expected) {
298		t.Fatalf("bad: %#v", result)
299	}
300}
301
302func TestDecode_EmbeddedSlice(t *testing.T) {
303	t.Parallel()
304
305	input := map[string]interface{}{
306		"slice_alias": []string{"foo", "bar"},
307		"vunique":     "bar",
308	}
309
310	var result EmbeddedSlice
311	err := Decode(input, &result)
312	if err != nil {
313		t.Fatalf("got an err: %s", err.Error())
314	}
315
316	if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) {
317		t.Errorf("slice value: %#v", result.SliceAlias)
318	}
319
320	if result.Vunique != "bar" {
321		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
322	}
323}
324
325func TestDecode_EmbeddedSquash(t *testing.T) {
326	t.Parallel()
327
328	input := map[string]interface{}{
329		"vstring": "foo",
330		"vunique": "bar",
331	}
332
333	var result EmbeddedSquash
334	err := Decode(input, &result)
335	if err != nil {
336		t.Fatalf("got an err: %s", err.Error())
337	}
338
339	if result.Vstring != "foo" {
340		t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
341	}
342
343	if result.Vunique != "bar" {
344		t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
345	}
346}
347
348func TestDecode_SquashOnNonStructType(t *testing.T) {
349	t.Parallel()
350
351	input := map[string]interface{}{
352		"InvalidSquashType": 42,
353	}
354
355	var result SquashOnNonStructType
356	err := Decode(input, &result)
357	if err == nil {
358		t.Fatal("unexpected success decoding invalid squash field type")
359	} else if !strings.Contains(err.Error(), "unsupported type for squash") {
360		t.Fatalf("unexpected error message for invalid squash field type: %s", err)
361	}
362}
363
364func TestDecode_DecodeHook(t *testing.T) {
365	t.Parallel()
366
367	input := map[string]interface{}{
368		"vint": "WHAT",
369	}
370
371	decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) {
372		if from == reflect.String && to != reflect.String {
373			return 5, nil
374		}
375
376		return v, nil
377	}
378
379	var result Basic
380	config := &DecoderConfig{
381		DecodeHook: decodeHook,
382		Result:     &result,
383	}
384
385	decoder, err := NewDecoder(config)
386	if err != nil {
387		t.Fatalf("err: %s", err)
388	}
389
390	err = decoder.Decode(input)
391	if err != nil {
392		t.Fatalf("got an err: %s", err)
393	}
394
395	if result.Vint != 5 {
396		t.Errorf("vint should be 5: %#v", result.Vint)
397	}
398}
399
400func TestDecode_DecodeHookType(t *testing.T) {
401	t.Parallel()
402
403	input := map[string]interface{}{
404		"vint": "WHAT",
405	}
406
407	decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) {
408		if from.Kind() == reflect.String &&
409			to.Kind() != reflect.String {
410			return 5, nil
411		}
412
413		return v, nil
414	}
415
416	var result Basic
417	config := &DecoderConfig{
418		DecodeHook: decodeHook,
419		Result:     &result,
420	}
421
422	decoder, err := NewDecoder(config)
423	if err != nil {
424		t.Fatalf("err: %s", err)
425	}
426
427	err = decoder.Decode(input)
428	if err != nil {
429		t.Fatalf("got an err: %s", err)
430	}
431
432	if result.Vint != 5 {
433		t.Errorf("vint should be 5: %#v", result.Vint)
434	}
435}
436
437func TestDecode_Nil(t *testing.T) {
438	t.Parallel()
439
440	var input interface{}
441	result := Basic{
442		Vstring: "foo",
443	}
444
445	err := Decode(input, &result)
446	if err != nil {
447		t.Fatalf("err: %s", err)
448	}
449
450	if result.Vstring != "foo" {
451		t.Fatalf("bad: %#v", result.Vstring)
452	}
453}
454
455func TestDecode_NilInterfaceHook(t *testing.T) {
456	t.Parallel()
457
458	input := map[string]interface{}{
459		"w": "",
460	}
461
462	decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) {
463		if t.String() == "io.Writer" {
464			return nil, nil
465		}
466
467		return v, nil
468	}
469
470	var result NilInterface
471	config := &DecoderConfig{
472		DecodeHook: decodeHook,
473		Result:     &result,
474	}
475
476	decoder, err := NewDecoder(config)
477	if err != nil {
478		t.Fatalf("err: %s", err)
479	}
480
481	err = decoder.Decode(input)
482	if err != nil {
483		t.Fatalf("got an err: %s", err)
484	}
485
486	if result.W != nil {
487		t.Errorf("W should be nil: %#v", result.W)
488	}
489}
490
491func TestDecode_FuncHook(t *testing.T) {
492	t.Parallel()
493
494	input := map[string]interface{}{
495		"foo": "baz",
496	}
497
498	decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) {
499		if t.Kind() != reflect.Func {
500			return v, nil
501		}
502		val := v.(string)
503		return func() string { return val }, nil
504	}
505
506	var result Func
507	config := &DecoderConfig{
508		DecodeHook: decodeHook,
509		Result:     &result,
510	}
511
512	decoder, err := NewDecoder(config)
513	if err != nil {
514		t.Fatalf("err: %s", err)
515	}
516
517	err = decoder.Decode(input)
518	if err != nil {
519		t.Fatalf("got an err: %s", err)
520	}
521
522	if result.Foo() != "baz" {
523		t.Errorf("Foo call result should be 'baz': %s", result.Foo())
524	}
525}
526
527func TestDecode_NonStruct(t *testing.T) {
528	t.Parallel()
529
530	input := map[string]interface{}{
531		"foo": "bar",
532		"bar": "baz",
533	}
534
535	var result map[string]string
536	err := Decode(input, &result)
537	if err != nil {
538		t.Fatalf("err: %s", err)
539	}
540
541	if result["foo"] != "bar" {
542		t.Fatal("foo is not bar")
543	}
544}
545
546func TestDecode_StructMatch(t *testing.T) {
547	t.Parallel()
548
549	input := map[string]interface{}{
550		"vbar": Basic{
551			Vstring: "foo",
552		},
553	}
554
555	var result Nested
556	err := Decode(input, &result)
557	if err != nil {
558		t.Fatalf("got an err: %s", err.Error())
559	}
560
561	if result.Vbar.Vstring != "foo" {
562		t.Errorf("bad: %#v", result)
563	}
564}
565
566func TestDecode_TypeConversion(t *testing.T) {
567	input := map[string]interface{}{
568		"IntToFloat":         42,
569		"IntToUint":          42,
570		"IntToBool":          1,
571		"IntToString":        42,
572		"UintToInt":          42,
573		"UintToFloat":        42,
574		"UintToBool":         42,
575		"UintToString":       42,
576		"BoolToInt":          true,
577		"BoolToUint":         true,
578		"BoolToFloat":        true,
579		"BoolToString":       true,
580		"FloatToInt":         42.42,
581		"FloatToUint":        42.42,
582		"FloatToBool":        42.42,
583		"FloatToString":      42.42,
584		"SliceUint8ToString": []uint8("foo"),
585		"StringToInt":        "42",
586		"StringToUint":       "42",
587		"StringToBool":       "1",
588		"StringToFloat":      "42.42",
589		"StringToStrSlice":   "A",
590		"StringToIntSlice":   "42",
591		"SliceToMap":         []interface{}{},
592		"MapToSlice":         map[string]interface{}{},
593	}
594
595	expectedResultStrict := TypeConversionResult{
596		IntToFloat:  42.0,
597		IntToUint:   42,
598		UintToInt:   42,
599		UintToFloat: 42,
600		BoolToInt:   0,
601		BoolToUint:  0,
602		BoolToFloat: 0,
603		FloatToInt:  42,
604		FloatToUint: 42,
605	}
606
607	expectedResultWeak := TypeConversionResult{
608		IntToFloat:         42.0,
609		IntToUint:          42,
610		IntToBool:          true,
611		IntToString:        "42",
612		UintToInt:          42,
613		UintToFloat:        42,
614		UintToBool:         true,
615		UintToString:       "42",
616		BoolToInt:          1,
617		BoolToUint:         1,
618		BoolToFloat:        1,
619		BoolToString:       "1",
620		FloatToInt:         42,
621		FloatToUint:        42,
622		FloatToBool:        true,
623		FloatToString:      "42.42",
624		SliceUint8ToString: "foo",
625		StringToInt:        42,
626		StringToUint:       42,
627		StringToBool:       true,
628		StringToFloat:      42.42,
629		StringToStrSlice:   []string{"A"},
630		StringToIntSlice:   []int{42},
631		SliceToMap:         map[string]interface{}{},
632		MapToSlice:         []interface{}{},
633	}
634
635	// Test strict type conversion
636	var resultStrict TypeConversionResult
637	err := Decode(input, &resultStrict)
638	if err == nil {
639		t.Errorf("should return an error")
640	}
641	if !reflect.DeepEqual(resultStrict, expectedResultStrict) {
642		t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict)
643	}
644
645	// Test weak type conversion
646	var decoder *Decoder
647	var resultWeak TypeConversionResult
648
649	config := &DecoderConfig{
650		WeaklyTypedInput: true,
651		Result:           &resultWeak,
652	}
653
654	decoder, err = NewDecoder(config)
655	if err != nil {
656		t.Fatalf("err: %s", err)
657	}
658
659	err = decoder.Decode(input)
660	if err != nil {
661		t.Fatalf("got an err: %s", err)
662	}
663
664	if !reflect.DeepEqual(resultWeak, expectedResultWeak) {
665		t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
666	}
667}
668
669func TestDecoder_ErrorUnused(t *testing.T) {
670	t.Parallel()
671
672	input := map[string]interface{}{
673		"vstring": "hello",
674		"foo":     "bar",
675	}
676
677	var result Basic
678	config := &DecoderConfig{
679		ErrorUnused: true,
680		Result:      &result,
681	}
682
683	decoder, err := NewDecoder(config)
684	if err != nil {
685		t.Fatalf("err: %s", err)
686	}
687
688	err = decoder.Decode(input)
689	if err == nil {
690		t.Fatal("expected error")
691	}
692}
693
694func TestMap(t *testing.T) {
695	t.Parallel()
696
697	input := map[string]interface{}{
698		"vfoo": "foo",
699		"vother": map[interface{}]interface{}{
700			"foo": "foo",
701			"bar": "bar",
702		},
703	}
704
705	var result Map
706	err := Decode(input, &result)
707	if err != nil {
708		t.Fatalf("got an error: %s", err)
709	}
710
711	if result.Vfoo != "foo" {
712		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
713	}
714
715	if result.Vother == nil {
716		t.Fatal("vother should not be nil")
717	}
718
719	if len(result.Vother) != 2 {
720		t.Error("vother should have two items")
721	}
722
723	if result.Vother["foo"] != "foo" {
724		t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"])
725	}
726
727	if result.Vother["bar"] != "bar" {
728		t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"])
729	}
730}
731
732func TestMapMerge(t *testing.T) {
733	t.Parallel()
734
735	input := map[string]interface{}{
736		"vfoo": "foo",
737		"vother": map[interface{}]interface{}{
738			"foo": "foo",
739			"bar": "bar",
740		},
741	}
742
743	var result Map
744	result.Vother = map[string]string{"hello": "world"}
745	err := Decode(input, &result)
746	if err != nil {
747		t.Fatalf("got an error: %s", err)
748	}
749
750	if result.Vfoo != "foo" {
751		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
752	}
753
754	expected := map[string]string{
755		"foo":   "foo",
756		"bar":   "bar",
757		"hello": "world",
758	}
759	if !reflect.DeepEqual(result.Vother, expected) {
760		t.Errorf("bad: %#v", result.Vother)
761	}
762}
763
764func TestMapOfStruct(t *testing.T) {
765	t.Parallel()
766
767	input := map[string]interface{}{
768		"value": map[string]interface{}{
769			"foo": map[string]string{"vstring": "one"},
770			"bar": map[string]string{"vstring": "two"},
771		},
772	}
773
774	var result MapOfStruct
775	err := Decode(input, &result)
776	if err != nil {
777		t.Fatalf("got an err: %s", err)
778	}
779
780	if result.Value == nil {
781		t.Fatal("value should not be nil")
782	}
783
784	if len(result.Value) != 2 {
785		t.Error("value should have two items")
786	}
787
788	if result.Value["foo"].Vstring != "one" {
789		t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring)
790	}
791
792	if result.Value["bar"].Vstring != "two" {
793		t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring)
794	}
795}
796
797func TestNestedType(t *testing.T) {
798	t.Parallel()
799
800	input := map[string]interface{}{
801		"vfoo": "foo",
802		"vbar": map[string]interface{}{
803			"vstring": "foo",
804			"vint":    42,
805			"vbool":   true,
806		},
807	}
808
809	var result Nested
810	err := Decode(input, &result)
811	if err != nil {
812		t.Fatalf("got an err: %s", err.Error())
813	}
814
815	if result.Vfoo != "foo" {
816		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
817	}
818
819	if result.Vbar.Vstring != "foo" {
820		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
821	}
822
823	if result.Vbar.Vint != 42 {
824		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
825	}
826
827	if result.Vbar.Vbool != true {
828		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
829	}
830
831	if result.Vbar.Vextra != "" {
832		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
833	}
834}
835
836func TestNestedTypePointer(t *testing.T) {
837	t.Parallel()
838
839	input := map[string]interface{}{
840		"vfoo": "foo",
841		"vbar": &map[string]interface{}{
842			"vstring": "foo",
843			"vint":    42,
844			"vbool":   true,
845		},
846	}
847
848	var result NestedPointer
849	err := Decode(input, &result)
850	if err != nil {
851		t.Fatalf("got an err: %s", err.Error())
852	}
853
854	if result.Vfoo != "foo" {
855		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
856	}
857
858	if result.Vbar.Vstring != "foo" {
859		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
860	}
861
862	if result.Vbar.Vint != 42 {
863		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
864	}
865
866	if result.Vbar.Vbool != true {
867		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
868	}
869
870	if result.Vbar.Vextra != "" {
871		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
872	}
873}
874
875func TestSlice(t *testing.T) {
876	t.Parallel()
877
878	inputStringSlice := map[string]interface{}{
879		"vfoo": "foo",
880		"vbar": []string{"foo", "bar", "baz"},
881	}
882
883	inputStringSlicePointer := map[string]interface{}{
884		"vfoo": "foo",
885		"vbar": &[]string{"foo", "bar", "baz"},
886	}
887
888	outputStringSlice := &Slice{
889		"foo",
890		[]string{"foo", "bar", "baz"},
891	}
892
893	testSliceInput(t, inputStringSlice, outputStringSlice)
894	testSliceInput(t, inputStringSlicePointer, outputStringSlice)
895}
896
897func TestInvalidSlice(t *testing.T) {
898	t.Parallel()
899
900	input := map[string]interface{}{
901		"vfoo": "foo",
902		"vbar": 42,
903	}
904
905	result := Slice{}
906	err := Decode(input, &result)
907	if err == nil {
908		t.Errorf("expected failure")
909	}
910}
911
912func TestSliceOfStruct(t *testing.T) {
913	t.Parallel()
914
915	input := map[string]interface{}{
916		"value": []map[string]interface{}{
917			{"vstring": "one"},
918			{"vstring": "two"},
919		},
920	}
921
922	var result SliceOfStruct
923	err := Decode(input, &result)
924	if err != nil {
925		t.Fatalf("got unexpected error: %s", err)
926	}
927
928	if len(result.Value) != 2 {
929		t.Fatalf("expected two values, got %d", len(result.Value))
930	}
931
932	if result.Value[0].Vstring != "one" {
933		t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring)
934	}
935
936	if result.Value[1].Vstring != "two" {
937		t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring)
938	}
939}
940
941func TestSliceToMap(t *testing.T) {
942	t.Parallel()
943
944	input := []map[string]interface{}{
945		{
946			"foo": "bar",
947		},
948		{
949			"bar": "baz",
950		},
951	}
952
953	var result map[string]interface{}
954	err := WeakDecode(input, &result)
955	if err != nil {
956		t.Fatalf("got an error: %s", err)
957	}
958
959	expected := map[string]interface{}{
960		"foo": "bar",
961		"bar": "baz",
962	}
963	if !reflect.DeepEqual(result, expected) {
964		t.Errorf("bad: %#v", result)
965	}
966}
967
968func TestInvalidType(t *testing.T) {
969	t.Parallel()
970
971	input := map[string]interface{}{
972		"vstring": 42,
973	}
974
975	var result Basic
976	err := Decode(input, &result)
977	if err == nil {
978		t.Fatal("error should exist")
979	}
980
981	derr, ok := err.(*Error)
982	if !ok {
983		t.Fatalf("error should be kind of Error, instead: %#v", err)
984	}
985
986	if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" {
987		t.Errorf("got unexpected error: %s", err)
988	}
989
990	inputNegIntUint := map[string]interface{}{
991		"vuint": -42,
992	}
993
994	err = Decode(inputNegIntUint, &result)
995	if err == nil {
996		t.Fatal("error should exist")
997	}
998
999	derr, ok = err.(*Error)
1000	if !ok {
1001		t.Fatalf("error should be kind of Error, instead: %#v", err)
1002	}
1003
1004	if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" {
1005		t.Errorf("got unexpected error: %s", err)
1006	}
1007
1008	inputNegFloatUint := map[string]interface{}{
1009		"vuint": -42.0,
1010	}
1011
1012	err = Decode(inputNegFloatUint, &result)
1013	if err == nil {
1014		t.Fatal("error should exist")
1015	}
1016
1017	derr, ok = err.(*Error)
1018	if !ok {
1019		t.Fatalf("error should be kind of Error, instead: %#v", err)
1020	}
1021
1022	if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" {
1023		t.Errorf("got unexpected error: %s", err)
1024	}
1025}
1026
1027func TestMetadata(t *testing.T) {
1028	t.Parallel()
1029
1030	input := map[string]interface{}{
1031		"vfoo": "foo",
1032		"vbar": map[string]interface{}{
1033			"vstring": "foo",
1034			"Vuint":   42,
1035			"foo":     "bar",
1036		},
1037		"bar": "nil",
1038	}
1039
1040	var md Metadata
1041	var result Nested
1042	config := &DecoderConfig{
1043		Metadata: &md,
1044		Result:   &result,
1045	}
1046
1047	decoder, err := NewDecoder(config)
1048	if err != nil {
1049		t.Fatalf("err: %s", err)
1050	}
1051
1052	err = decoder.Decode(input)
1053	if err != nil {
1054		t.Fatalf("err: %s", err.Error())
1055	}
1056
1057	expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"}
1058	sort.Strings(md.Keys)
1059	if !reflect.DeepEqual(md.Keys, expectedKeys) {
1060		t.Fatalf("bad keys: %#v", md.Keys)
1061	}
1062
1063	expectedUnused := []string{"Vbar.foo", "bar"}
1064	if !reflect.DeepEqual(md.Unused, expectedUnused) {
1065		t.Fatalf("bad unused: %#v", md.Unused)
1066	}
1067}
1068
1069func TestMetadata_Embedded(t *testing.T) {
1070	t.Parallel()
1071
1072	input := map[string]interface{}{
1073		"vstring": "foo",
1074		"vunique": "bar",
1075	}
1076
1077	var md Metadata
1078	var result EmbeddedSquash
1079	config := &DecoderConfig{
1080		Metadata: &md,
1081		Result:   &result,
1082	}
1083
1084	decoder, err := NewDecoder(config)
1085	if err != nil {
1086		t.Fatalf("err: %s", err)
1087	}
1088
1089	err = decoder.Decode(input)
1090	if err != nil {
1091		t.Fatalf("err: %s", err.Error())
1092	}
1093
1094	expectedKeys := []string{"Vstring", "Vunique"}
1095
1096	sort.Strings(md.Keys)
1097	if !reflect.DeepEqual(md.Keys, expectedKeys) {
1098		t.Fatalf("bad keys: %#v", md.Keys)
1099	}
1100
1101	expectedUnused := []string{}
1102	if !reflect.DeepEqual(md.Unused, expectedUnused) {
1103		t.Fatalf("bad unused: %#v", md.Unused)
1104	}
1105}
1106
1107func TestNonPtrValue(t *testing.T) {
1108	t.Parallel()
1109
1110	err := Decode(map[string]interface{}{}, Basic{})
1111	if err == nil {
1112		t.Fatal("error should exist")
1113	}
1114
1115	if err.Error() != "result must be a pointer" {
1116		t.Errorf("got unexpected error: %s", err)
1117	}
1118}
1119
1120func TestTagged(t *testing.T) {
1121	t.Parallel()
1122
1123	input := map[string]interface{}{
1124		"foo": "bar",
1125		"bar": "value",
1126	}
1127
1128	var result Tagged
1129	err := Decode(input, &result)
1130	if err != nil {
1131		t.Fatalf("unexpected error: %s", err)
1132	}
1133
1134	if result.Value != "bar" {
1135		t.Errorf("value should be 'bar', got: %#v", result.Value)
1136	}
1137
1138	if result.Extra != "value" {
1139		t.Errorf("extra should be 'value', got: %#v", result.Extra)
1140	}
1141}
1142
1143func TestWeakDecode(t *testing.T) {
1144	t.Parallel()
1145
1146	input := map[string]interface{}{
1147		"foo": "4",
1148		"bar": "value",
1149	}
1150
1151	var result struct {
1152		Foo int
1153		Bar string
1154	}
1155
1156	if err := WeakDecode(input, &result); err != nil {
1157		t.Fatalf("err: %s", err)
1158	}
1159	if result.Foo != 4 {
1160		t.Fatalf("bad: %#v", result)
1161	}
1162	if result.Bar != "value" {
1163		t.Fatalf("bad: %#v", result)
1164	}
1165}
1166
1167func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
1168	var result Slice
1169	err := Decode(input, &result)
1170	if err != nil {
1171		t.Fatalf("got error: %s", err)
1172	}
1173
1174	if result.Vfoo != expected.Vfoo {
1175		t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo)
1176	}
1177
1178	if result.Vbar == nil {
1179		t.Fatalf("Vbar a slice, got '%#v'", result.Vbar)
1180	}
1181
1182	if len(result.Vbar) != len(expected.Vbar) {
1183		t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar))
1184	}
1185
1186	for i, v := range result.Vbar {
1187		if v != expected.Vbar[i] {
1188			t.Errorf(
1189				"Vbar[%d] should be '%#v', got '%#v'",
1190				i, expected.Vbar[i], v)
1191		}
1192	}
1193}
1194