1package mapstructure
2
3import (
4	"errors"
5	"reflect"
6	"testing"
7	"time"
8)
9
10func TestComposeDecodeHookFunc(t *testing.T) {
11	f1 := func(
12		f reflect.Kind,
13		t reflect.Kind,
14		data interface{}) (interface{}, error) {
15		return data.(string) + "foo", nil
16	}
17
18	f2 := func(
19		f reflect.Kind,
20		t reflect.Kind,
21		data interface{}) (interface{}, error) {
22		return data.(string) + "bar", nil
23	}
24
25	f := ComposeDecodeHookFunc(f1, f2)
26
27	result, err := DecodeHookExec(
28		f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "")
29	if err != nil {
30		t.Fatalf("bad: %s", err)
31	}
32	if result.(string) != "foobar" {
33		t.Fatalf("bad: %#v", result)
34	}
35}
36
37func TestComposeDecodeHookFunc_err(t *testing.T) {
38	f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
39		return nil, errors.New("foo")
40	}
41
42	f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
43		panic("NOPE")
44	}
45
46	f := ComposeDecodeHookFunc(f1, f2)
47
48	_, err := DecodeHookExec(
49		f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), 42)
50	if err.Error() != "foo" {
51		t.Fatalf("bad: %s", err)
52	}
53}
54
55func TestComposeDecodeHookFunc_kinds(t *testing.T) {
56	var f2From reflect.Kind
57
58	f1 := func(
59		f reflect.Kind,
60		t reflect.Kind,
61		data interface{}) (interface{}, error) {
62		return int(42), nil
63	}
64
65	f2 := func(
66		f reflect.Kind,
67		t reflect.Kind,
68		data interface{}) (interface{}, error) {
69		f2From = f
70		return data, nil
71	}
72
73	f := ComposeDecodeHookFunc(f1, f2)
74
75	_, err := DecodeHookExec(
76		f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "")
77	if err != nil {
78		t.Fatalf("bad: %s", err)
79	}
80	if f2From != reflect.Int {
81		t.Fatalf("bad: %#v", f2From)
82	}
83}
84
85func TestStringToSliceHookFunc(t *testing.T) {
86	f := StringToSliceHookFunc(",")
87
88	strType := reflect.TypeOf("")
89	sliceType := reflect.TypeOf([]byte(""))
90	cases := []struct {
91		f, t   reflect.Type
92		data   interface{}
93		result interface{}
94		err    bool
95	}{
96		{sliceType, sliceType, 42, 42, false},
97		{strType, strType, 42, 42, false},
98		{
99			strType,
100			sliceType,
101			"foo,bar,baz",
102			[]string{"foo", "bar", "baz"},
103			false,
104		},
105		{
106			strType,
107			sliceType,
108			"",
109			[]string{},
110			false,
111		},
112	}
113
114	for i, tc := range cases {
115		actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
116		if tc.err != (err != nil) {
117			t.Fatalf("case %d: expected err %#v", i, tc.err)
118		}
119		if !reflect.DeepEqual(actual, tc.result) {
120			t.Fatalf(
121				"case %d: expected %#v, got %#v",
122				i, tc.result, actual)
123		}
124	}
125}
126
127func TestStringToTimeDurationHookFunc(t *testing.T) {
128	f := StringToTimeDurationHookFunc()
129
130	strType := reflect.TypeOf("")
131	timeType := reflect.TypeOf(time.Duration(5))
132	cases := []struct {
133		f, t   reflect.Type
134		data   interface{}
135		result interface{}
136		err    bool
137	}{
138		{strType, timeType, "5s", 5 * time.Second, false},
139		{strType, timeType, "5", time.Duration(0), true},
140		{strType, strType, "5", "5", false},
141	}
142
143	for i, tc := range cases {
144		actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
145		if tc.err != (err != nil) {
146			t.Fatalf("case %d: expected err %#v", i, tc.err)
147		}
148		if !reflect.DeepEqual(actual, tc.result) {
149			t.Fatalf(
150				"case %d: expected %#v, got %#v",
151				i, tc.result, actual)
152		}
153	}
154}
155
156func TestWeaklyTypedHook(t *testing.T) {
157	var f DecodeHookFunc = WeaklyTypedHook
158
159	boolType := reflect.TypeOf(true)
160	strType := reflect.TypeOf("")
161	sliceType := reflect.TypeOf([]byte(""))
162	cases := []struct {
163		f, t   reflect.Type
164		data   interface{}
165		result interface{}
166		err    bool
167	}{
168		// TO STRING
169		{
170			boolType,
171			strType,
172			false,
173			"0",
174			false,
175		},
176
177		{
178			boolType,
179			strType,
180			true,
181			"1",
182			false,
183		},
184
185		{
186			reflect.TypeOf(float32(1)),
187			strType,
188			float32(7),
189			"7",
190			false,
191		},
192
193		{
194			reflect.TypeOf(int(1)),
195			strType,
196			int(7),
197			"7",
198			false,
199		},
200
201		{
202			sliceType,
203			strType,
204			[]uint8("foo"),
205			"foo",
206			false,
207		},
208
209		{
210			reflect.TypeOf(uint(1)),
211			strType,
212			uint(7),
213			"7",
214			false,
215		},
216	}
217
218	for i, tc := range cases {
219		actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
220		if tc.err != (err != nil) {
221			t.Fatalf("case %d: expected err %#v", i, tc.err)
222		}
223		if !reflect.DeepEqual(actual, tc.result) {
224			t.Fatalf(
225				"case %d: expected %#v, got %#v",
226				i, tc.result, actual)
227		}
228	}
229}
230