25 | 25 |
f := ComposeDecodeHookFunc(f1, f2)
|
26 | 26 |
|
27 | 27 |
result, err := DecodeHookExec(
|
28 | |
f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "")
|
|
28 |
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
29 | 29 |
if err != nil {
|
30 | 30 |
t.Fatalf("bad: %s", err)
|
31 | 31 |
}
|
|
46 | 46 |
f := ComposeDecodeHookFunc(f1, f2)
|
47 | 47 |
|
48 | 48 |
_, err := DecodeHookExec(
|
49 | |
f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), 42)
|
|
49 |
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
50 | 50 |
if err.Error() != "foo" {
|
51 | 51 |
t.Fatalf("bad: %s", err)
|
52 | 52 |
}
|
|
73 | 73 |
f := ComposeDecodeHookFunc(f1, f2)
|
74 | 74 |
|
75 | 75 |
_, err := DecodeHookExec(
|
76 | |
f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "")
|
|
76 |
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
77 | 77 |
if err != nil {
|
78 | 78 |
t.Fatalf("bad: %s", err)
|
79 | 79 |
}
|
|
85 | 85 |
func TestStringToSliceHookFunc(t *testing.T) {
|
86 | 86 |
f := StringToSliceHookFunc(",")
|
87 | 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",
|
|
88 |
strValue := reflect.ValueOf("42")
|
|
89 |
sliceValue := reflect.ValueOf([]byte("42"))
|
|
90 |
cases := []struct {
|
|
91 |
f, t reflect.Value
|
|
92 |
result interface{}
|
|
93 |
err bool
|
|
94 |
}{
|
|
95 |
{sliceValue, sliceValue, []byte("42"), false},
|
|
96 |
{strValue, strValue, "42", false},
|
|
97 |
{
|
|
98 |
reflect.ValueOf("foo,bar,baz"),
|
|
99 |
sliceValue,
|
102 | 100 |
[]string{"foo", "bar", "baz"},
|
103 | 101 |
false,
|
104 | 102 |
},
|
105 | 103 |
{
|
106 | |
strType,
|
107 | |
sliceType,
|
108 | |
"",
|
|
104 |
reflect.ValueOf(""),
|
|
105 |
sliceValue,
|
109 | 106 |
[]string{},
|
110 | 107 |
false,
|
111 | 108 |
},
|
112 | 109 |
}
|
113 | 110 |
|
114 | 111 |
for i, tc := range cases {
|
115 | |
actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
|
|
112 |
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
116 | 113 |
if tc.err != (err != nil) {
|
117 | 114 |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
118 | 115 |
}
|
|
127 | 124 |
func TestStringToTimeDurationHookFunc(t *testing.T) {
|
128 | 125 |
f := StringToTimeDurationHookFunc()
|
129 | 126 |
|
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)
|
|
127 |
timeValue := reflect.ValueOf(time.Duration(5))
|
|
128 |
strValue := reflect.ValueOf("")
|
|
129 |
cases := []struct {
|
|
130 |
f, t reflect.Value
|
|
131 |
result interface{}
|
|
132 |
err bool
|
|
133 |
}{
|
|
134 |
{reflect.ValueOf("5s"), timeValue, 5 * time.Second, false},
|
|
135 |
{reflect.ValueOf("5"), timeValue, time.Duration(0), true},
|
|
136 |
{reflect.ValueOf("5"), strValue, "5", false},
|
|
137 |
}
|
|
138 |
|
|
139 |
for i, tc := range cases {
|
|
140 |
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
145 | 141 |
if tc.err != (err != nil) {
|
146 | 142 |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
147 | 143 |
}
|
|
154 | 150 |
}
|
155 | 151 |
|
156 | 152 |
func TestStringToTimeHookFunc(t *testing.T) {
|
157 | |
strType := reflect.TypeOf("")
|
158 | |
timeType := reflect.TypeOf(time.Time{})
|
159 | |
cases := []struct {
|
160 | |
f, t reflect.Type
|
|
153 |
strValue := reflect.ValueOf("5")
|
|
154 |
timeValue := reflect.ValueOf(time.Time{})
|
|
155 |
cases := []struct {
|
|
156 |
f, t reflect.Value
|
161 | 157 |
layout string
|
162 | |
data interface{}
|
163 | |
result interface{}
|
164 | |
err bool
|
165 | |
}{
|
166 | |
{strType, timeType, time.RFC3339, "2006-01-02T15:04:05Z",
|
|
158 |
result interface{}
|
|
159 |
err bool
|
|
160 |
}{
|
|
161 |
{reflect.ValueOf("2006-01-02T15:04:05Z"), timeValue, time.RFC3339,
|
167 | 162 |
time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false},
|
168 | |
{strType, timeType, time.RFC3339, "5", time.Time{}, true},
|
169 | |
{strType, strType, time.RFC3339, "5", "5", false},
|
|
163 |
{strValue, timeValue, time.RFC3339, time.Time{}, true},
|
|
164 |
{strValue, strValue, time.RFC3339, "5", false},
|
170 | 165 |
}
|
171 | 166 |
|
172 | 167 |
for i, tc := range cases {
|
173 | 168 |
f := StringToTimeHookFunc(tc.layout)
|
174 | |
actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
|
|
169 |
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
175 | 170 |
if tc.err != (err != nil) {
|
176 | 171 |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
177 | 172 |
}
|
|
184 | 179 |
}
|
185 | 180 |
|
186 | 181 |
func TestStringToIPHookFunc(t *testing.T) {
|
187 | |
strType := reflect.TypeOf("")
|
188 | |
ipType := reflect.TypeOf(net.IP{})
|
189 | |
cases := []struct {
|
190 | |
f, t reflect.Type
|
191 | |
data interface{}
|
192 | |
result interface{}
|
193 | |
err bool
|
194 | |
}{
|
195 | |
{strType, ipType, "1.2.3.4",
|
|
182 |
strValue := reflect.ValueOf("5")
|
|
183 |
ipValue := reflect.ValueOf(net.IP{})
|
|
184 |
cases := []struct {
|
|
185 |
f, t reflect.Value
|
|
186 |
result interface{}
|
|
187 |
err bool
|
|
188 |
}{
|
|
189 |
{reflect.ValueOf("1.2.3.4"), ipValue,
|
196 | 190 |
net.IPv4(0x01, 0x02, 0x03, 0x04), false},
|
197 | |
{strType, ipType, "5", net.IP{}, true},
|
198 | |
{strType, strType, "5", "5", false},
|
|
191 |
{strValue, ipValue, net.IP{}, true},
|
|
192 |
{strValue, strValue, "5", false},
|
199 | 193 |
}
|
200 | 194 |
|
201 | 195 |
for i, tc := range cases {
|
202 | 196 |
f := StringToIPHookFunc()
|
203 | |
actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
|
|
197 |
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
204 | 198 |
if tc.err != (err != nil) {
|
205 | 199 |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
206 | 200 |
}
|
|
213 | 207 |
}
|
214 | 208 |
|
215 | 209 |
func TestStringToIPNetHookFunc(t *testing.T) {
|
216 | |
strType := reflect.TypeOf("")
|
217 | |
ipNetType := reflect.TypeOf(net.IPNet{})
|
|
210 |
strValue := reflect.ValueOf("5")
|
|
211 |
ipNetValue := reflect.ValueOf(net.IPNet{})
|
218 | 212 |
var nilNet *net.IPNet = nil
|
219 | 213 |
|
220 | 214 |
cases := []struct {
|
221 | |
f, t reflect.Type
|
222 | |
data interface{}
|
223 | |
result interface{}
|
224 | |
err bool
|
225 | |
}{
|
226 | |
{strType, ipNetType, "1.2.3.4/24",
|
|
215 |
f, t reflect.Value
|
|
216 |
result interface{}
|
|
217 |
err bool
|
|
218 |
}{
|
|
219 |
{reflect.ValueOf("1.2.3.4/24"), ipNetValue,
|
227 | 220 |
&net.IPNet{
|
228 | 221 |
IP: net.IP{0x01, 0x02, 0x03, 0x00},
|
229 | 222 |
Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
|
230 | 223 |
}, false},
|
231 | |
{strType, ipNetType, "5", nilNet, true},
|
232 | |
{strType, strType, "5", "5", false},
|
|
224 |
{strValue, ipNetValue, nilNet, true},
|
|
225 |
{strValue, strValue, "5", false},
|
233 | 226 |
}
|
234 | 227 |
|
235 | 228 |
for i, tc := range cases {
|
236 | 229 |
f := StringToIPNetHookFunc()
|
237 | |
actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
|
|
230 |
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
238 | 231 |
if tc.err != (err != nil) {
|
239 | 232 |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
240 | 233 |
}
|
|
249 | 242 |
func TestWeaklyTypedHook(t *testing.T) {
|
250 | 243 |
var f DecodeHookFunc = WeaklyTypedHook
|
251 | 244 |
|
252 | |
boolType := reflect.TypeOf(true)
|
253 | |
strType := reflect.TypeOf("")
|
254 | |
sliceType := reflect.TypeOf([]byte(""))
|
255 | |
cases := []struct {
|
256 | |
f, t reflect.Type
|
257 | |
data interface{}
|
|
245 |
strValue := reflect.ValueOf("")
|
|
246 |
cases := []struct {
|
|
247 |
f, t reflect.Value
|
258 | 248 |
result interface{}
|
259 | 249 |
err bool
|
260 | 250 |
}{
|
261 | 251 |
// TO STRING
|
262 | 252 |
{
|
263 | |
boolType,
|
264 | |
strType,
|
265 | |
false,
|
|
253 |
reflect.ValueOf(false),
|
|
254 |
strValue,
|
266 | 255 |
"0",
|
267 | 256 |
false,
|
268 | 257 |
},
|
269 | 258 |
|
270 | 259 |
{
|
271 | |
boolType,
|
272 | |
strType,
|
|
260 |
reflect.ValueOf(true),
|
|
261 |
strValue,
|
|
262 |
"1",
|
|
263 |
false,
|
|
264 |
},
|
|
265 |
|
|
266 |
{
|
|
267 |
reflect.ValueOf(float32(7)),
|
|
268 |
strValue,
|
|
269 |
"7",
|
|
270 |
false,
|
|
271 |
},
|
|
272 |
|
|
273 |
{
|
|
274 |
reflect.ValueOf(int(7)),
|
|
275 |
strValue,
|
|
276 |
"7",
|
|
277 |
false,
|
|
278 |
},
|
|
279 |
|
|
280 |
{
|
|
281 |
reflect.ValueOf([]uint8("foo")),
|
|
282 |
strValue,
|
|
283 |
"foo",
|
|
284 |
false,
|
|
285 |
},
|
|
286 |
|
|
287 |
{
|
|
288 |
reflect.ValueOf(uint(7)),
|
|
289 |
strValue,
|
|
290 |
"7",
|
|
291 |
false,
|
|
292 |
},
|
|
293 |
}
|
|
294 |
|
|
295 |
for i, tc := range cases {
|
|
296 |
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
|
297 |
if tc.err != (err != nil) {
|
|
298 |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
|
299 |
}
|
|
300 |
if !reflect.DeepEqual(actual, tc.result) {
|
|
301 |
t.Fatalf(
|
|
302 |
"case %d: expected %#v, got %#v",
|
|
303 |
i, tc.result, actual)
|
|
304 |
}
|
|
305 |
}
|
|
306 |
}
|
|
307 |
|
|
308 |
func TestStructToMapHookFuncTabled(t *testing.T) {
|
|
309 |
var f DecodeHookFunc = RecursiveStructToMapHookFunc()
|
|
310 |
|
|
311 |
type b struct {
|
|
312 |
TestKey string
|
|
313 |
}
|
|
314 |
|
|
315 |
type a struct {
|
|
316 |
Sub b
|
|
317 |
}
|
|
318 |
|
|
319 |
testStruct := a{
|
|
320 |
Sub: b{
|
|
321 |
TestKey: "testval",
|
|
322 |
},
|
|
323 |
}
|
|
324 |
|
|
325 |
testMap := map[string]interface{}{
|
|
326 |
"Sub": map[string]interface{}{
|
|
327 |
"TestKey": "testval",
|
|
328 |
},
|
|
329 |
}
|
|
330 |
|
|
331 |
cases := []struct {
|
|
332 |
name string
|
|
333 |
receiver interface{}
|
|
334 |
input interface{}
|
|
335 |
expected interface{}
|
|
336 |
err bool
|
|
337 |
}{
|
|
338 |
{
|
|
339 |
"map receiver",
|
|
340 |
func() interface{} {
|
|
341 |
var res map[string]interface{}
|
|
342 |
return &res
|
|
343 |
}(),
|
|
344 |
testStruct,
|
|
345 |
&testMap,
|
|
346 |
false,
|
|
347 |
},
|
|
348 |
{
|
|
349 |
"interface receiver",
|
|
350 |
func() interface{} {
|
|
351 |
var res interface{}
|
|
352 |
return &res
|
|
353 |
}(),
|
|
354 |
testStruct,
|
|
355 |
func() interface{} {
|
|
356 |
var exp interface{} = testMap
|
|
357 |
return &exp
|
|
358 |
}(),
|
|
359 |
false,
|
|
360 |
},
|
|
361 |
{
|
|
362 |
"slice receiver errors",
|
|
363 |
func() interface{} {
|
|
364 |
var res []string
|
|
365 |
return &res
|
|
366 |
}(),
|
|
367 |
testStruct,
|
|
368 |
new([]string),
|
273 | 369 |
true,
|
274 | |
"1",
|
275 | |
false,
|
276 | |
},
|
277 | |
|
278 | |
{
|
279 | |
reflect.TypeOf(float32(1)),
|
280 | |
strType,
|
281 | |
float32(7),
|
282 | |
"7",
|
283 | |
false,
|
284 | |
},
|
285 | |
|
286 | |
{
|
287 | |
reflect.TypeOf(int(1)),
|
288 | |
strType,
|
289 | |
int(7),
|
290 | |
"7",
|
291 | |
false,
|
292 | |
},
|
293 | |
|
294 | |
{
|
295 | |
sliceType,
|
296 | |
strType,
|
297 | |
[]uint8("foo"),
|
298 | |
"foo",
|
299 | |
false,
|
300 | |
},
|
301 | |
|
302 | |
{
|
303 | |
reflect.TypeOf(uint(1)),
|
304 | |
strType,
|
305 | |
uint(7),
|
306 | |
"7",
|
307 | |
false,
|
308 | |
},
|
309 | |
}
|
310 | |
|
311 | |
for i, tc := range cases {
|
312 | |
actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
|
313 | |
if tc.err != (err != nil) {
|
314 | |
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
315 | |
}
|
316 | |
if !reflect.DeepEqual(actual, tc.result) {
|
317 | |
t.Fatalf(
|
318 | |
"case %d: expected %#v, got %#v",
|
319 | |
i, tc.result, actual)
|
320 | |
}
|
321 | |
}
|
322 | |
}
|
|
370 |
},
|
|
371 |
{
|
|
372 |
"slice to slice - no change",
|
|
373 |
func() interface{} {
|
|
374 |
var res []string
|
|
375 |
return &res
|
|
376 |
}(),
|
|
377 |
[]string{"a", "b"},
|
|
378 |
&[]string{"a", "b"},
|
|
379 |
false,
|
|
380 |
},
|
|
381 |
{
|
|
382 |
"string to string - no change",
|
|
383 |
func() interface{} {
|
|
384 |
var res string
|
|
385 |
return &res
|
|
386 |
}(),
|
|
387 |
"test",
|
|
388 |
func() *string {
|
|
389 |
s := "test"
|
|
390 |
return &s
|
|
391 |
}(),
|
|
392 |
false,
|
|
393 |
},
|
|
394 |
}
|
|
395 |
|
|
396 |
for _, tc := range cases {
|
|
397 |
t.Run(tc.name, func(t *testing.T) {
|
|
398 |
cfg := &DecoderConfig{
|
|
399 |
DecodeHook: f,
|
|
400 |
Result: tc.receiver,
|
|
401 |
}
|
|
402 |
|
|
403 |
d, err := NewDecoder(cfg)
|
|
404 |
if err != nil {
|
|
405 |
t.Fatalf("unexpected err %#v", err)
|
|
406 |
}
|
|
407 |
|
|
408 |
err = d.Decode(tc.input)
|
|
409 |
if tc.err != (err != nil) {
|
|
410 |
t.Fatalf("expected err %#v", err)
|
|
411 |
}
|
|
412 |
|
|
413 |
if !reflect.DeepEqual(tc.expected, tc.receiver) {
|
|
414 |
t.Fatalf("expected %#v, got %#v",
|
|
415 |
tc.expected, tc.receiver)
|
|
416 |
}
|
|
417 |
})
|
|
418 |
|
|
419 |
}
|
|
420 |
}
|