cloudflare/cfssl_trust

Public

mirrored from https://github.com/cloudflare/cfssl_trustAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
72e5ca0d26bbcab6b255f5495e1c2e255f0300a5

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

vendor/github.com/mitchellh/mapstructure/mapstructure_test.go

1193lines · modecode

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{} = nil
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