1package mapstructure
2
3import "testing"
4
5// GH-1
6func TestDecode_NilValue(t *testing.T) {
7	input := map[string]interface{}{
8		"vfoo":   nil,
9		"vother": nil,
10	}
11
12	var result Map
13	err := Decode(input, &result)
14	if err != nil {
15		t.Fatalf("should not error: %s", err)
16	}
17
18	if result.Vfoo != "" {
19		t.Fatalf("value should be default: %s", result.Vfoo)
20	}
21
22	if result.Vother != nil {
23		t.Fatalf("Vother should be nil: %s", result.Vother)
24	}
25}
26
27// GH-10
28func TestDecode_mapInterfaceInterface(t *testing.T) {
29	input := map[interface{}]interface{}{
30		"vfoo":   nil,
31		"vother": nil,
32	}
33
34	var result Map
35	err := Decode(input, &result)
36	if err != nil {
37		t.Fatalf("should not error: %s", err)
38	}
39
40	if result.Vfoo != "" {
41		t.Fatalf("value should be default: %s", result.Vfoo)
42	}
43
44	if result.Vother != nil {
45		t.Fatalf("Vother should be nil: %s", result.Vother)
46	}
47}
48
49// #48
50func TestNestedTypePointerWithDefaults(t *testing.T) {
51	t.Parallel()
52
53	input := map[string]interface{}{
54		"vfoo": "foo",
55		"vbar": map[string]interface{}{
56			"vstring": "foo",
57			"vint":    42,
58			"vbool":   true,
59		},
60	}
61
62	result := NestedPointer{
63		Vbar: &Basic{
64			Vuint: 42,
65		},
66	}
67	err := Decode(input, &result)
68	if err != nil {
69		t.Fatalf("got an err: %s", err.Error())
70	}
71
72	if result.Vfoo != "foo" {
73		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
74	}
75
76	if result.Vbar.Vstring != "foo" {
77		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
78	}
79
80	if result.Vbar.Vint != 42 {
81		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
82	}
83
84	if result.Vbar.Vbool != true {
85		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
86	}
87
88	if result.Vbar.Vextra != "" {
89		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
90	}
91
92	// this is the error
93	if result.Vbar.Vuint != 42 {
94		t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint)
95	}
96
97}
98
99type NestedSlice struct {
100	Vfoo   string
101	Vbars  []Basic
102	Vempty []Basic
103}
104
105// #48
106func TestNestedTypeSliceWithDefaults(t *testing.T) {
107	t.Parallel()
108
109	input := map[string]interface{}{
110		"vfoo": "foo",
111		"vbars": []map[string]interface{}{
112			{"vstring": "foo", "vint": 42, "vbool": true},
113			{"vint": 42, "vbool": true},
114		},
115		"vempty": []map[string]interface{}{
116			{"vstring": "foo", "vint": 42, "vbool": true},
117			{"vint": 42, "vbool": true},
118		},
119	}
120
121	result := NestedSlice{
122		Vbars: []Basic{
123			{Vuint: 42},
124			{Vstring: "foo"},
125		},
126	}
127	err := Decode(input, &result)
128	if err != nil {
129		t.Fatalf("got an err: %s", err.Error())
130	}
131
132	if result.Vfoo != "foo" {
133		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
134	}
135
136	if result.Vbars[0].Vstring != "foo" {
137		t.Errorf("vstring value should be 'foo': %#v", result.Vbars[0].Vstring)
138	}
139	// this is the error
140	if result.Vbars[0].Vuint != 42 {
141		t.Errorf("vuint value should be 42: %#v", result.Vbars[0].Vuint)
142	}
143}
144
145// #48 workaround
146func TestNestedTypeWithDefaults(t *testing.T) {
147	t.Parallel()
148
149	input := map[string]interface{}{
150		"vfoo": "foo",
151		"vbar": map[string]interface{}{
152			"vstring": "foo",
153			"vint":    42,
154			"vbool":   true,
155		},
156	}
157
158	result := Nested{
159		Vbar: Basic{
160			Vuint: 42,
161		},
162	}
163	err := Decode(input, &result)
164	if err != nil {
165		t.Fatalf("got an err: %s", err.Error())
166	}
167
168	if result.Vfoo != "foo" {
169		t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
170	}
171
172	if result.Vbar.Vstring != "foo" {
173		t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
174	}
175
176	if result.Vbar.Vint != 42 {
177		t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
178	}
179
180	if result.Vbar.Vbool != true {
181		t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
182	}
183
184	if result.Vbar.Vextra != "" {
185		t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
186	}
187
188	// this is the error
189	if result.Vbar.Vuint != 42 {
190		t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint)
191	}
192
193}
194
195// #67 panic() on extending slices (decodeSlice with disabled ZeroValues)
196func TestDecodeSliceToEmptySliceWOZeroing(t *testing.T) {
197	t.Parallel()
198
199	type TestStruct struct {
200		Vfoo []string
201	}
202
203	decode := func(m interface{}, rawVal interface{}) error {
204		config := &DecoderConfig{
205			Metadata:   nil,
206			Result:     rawVal,
207			ZeroFields: false,
208		}
209
210		decoder, err := NewDecoder(config)
211		if err != nil {
212			return err
213		}
214
215		return decoder.Decode(m)
216	}
217
218	{
219		input := map[string]interface{}{
220			"vfoo": []string{"1"},
221		}
222
223		result := &TestStruct{}
224
225		err := decode(input, &result)
226		if err != nil {
227			t.Fatalf("got an err: %s", err.Error())
228		}
229	}
230
231	{
232		input := map[string]interface{}{
233			"vfoo": []string{"1"},
234		}
235
236		result := &TestStruct{
237			Vfoo: []string{},
238		}
239
240		err := decode(input, &result)
241		if err != nil {
242			t.Fatalf("got an err: %s", err.Error())
243		}
244	}
245
246	{
247		input := map[string]interface{}{
248			"vfoo": []string{"2", "3"},
249		}
250
251		result := &TestStruct{
252			Vfoo: []string{"1"},
253		}
254
255		err := decode(input, &result)
256		if err != nil {
257			t.Fatalf("got an err: %s", err.Error())
258		}
259	}
260}
261