Add mitchellh/mapstructure to Godeps
Signed-off-by: Sylvain Baubeau <sbaubeau@redhat.com>master
							parent
							
								
									c4d845cb6c
								
							
						
					
					
						commit
						03188fe394
					
				
							
								
								
									
										7
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/.travis.yml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										7
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/.travis.yml
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					language: go 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go: 
 | 
				
			||||||
 | 
					  - 1.4
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					script:
 | 
				
			||||||
 | 
					  - go test 
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2013 Mitchell Hashimoto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 | 
					all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
				
			||||||
 | 
					THE SOFTWARE.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					# mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mapstructure is a Go library for decoding generic map values to structures
 | 
				
			||||||
 | 
					and vice versa, while providing helpful error handling.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is most useful when decoding values from some data stream (JSON,
 | 
				
			||||||
 | 
					Gob, etc.) where you don't _quite_ know the structure of the underlying data
 | 
				
			||||||
 | 
					until you read a part of it. You can therefore read a `map[string]interface{}`
 | 
				
			||||||
 | 
					and use this library to decode it into the proper underlying native Go
 | 
				
			||||||
 | 
					structure.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Standard `go get`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ go get github.com/mitchellh/mapstructure
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage & Example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `Decode` function has examples associated with it there.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## But Why?!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Go offers fantastic standard libraries for decoding formats such as JSON.
 | 
				
			||||||
 | 
					The standard method is to have a struct pre-created, and populate that struct
 | 
				
			||||||
 | 
					from the bytes of the encoded format. This is great, but the problem is if
 | 
				
			||||||
 | 
					you have configuration or an encoding that changes slightly depending on
 | 
				
			||||||
 | 
					specific fields. For example, consider this JSON:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```json
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "type": "person",
 | 
				
			||||||
 | 
					  "name": "Mitchell"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Perhaps we can't populate a specific structure without first reading
 | 
				
			||||||
 | 
					the "type" field from the JSON. We could always do two passes over the
 | 
				
			||||||
 | 
					decoding of the JSON (reading the "type" first, and the rest later).
 | 
				
			||||||
 | 
					However, it is much simpler to just decode this into a `map[string]interface{}`
 | 
				
			||||||
 | 
					structure, read the "type" key, then use something like this library
 | 
				
			||||||
 | 
					to decode it into the proper structure.
 | 
				
			||||||
							
								
								
									
										151
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/decode_hooks.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										151
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/decode_hooks.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,151 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
 | 
				
			||||||
 | 
					// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
 | 
				
			||||||
 | 
					func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
 | 
				
			||||||
 | 
						// Create variables here so we can reference them with the reflect pkg
 | 
				
			||||||
 | 
						var f1 DecodeHookFuncType
 | 
				
			||||||
 | 
						var f2 DecodeHookFuncKind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Fill in the variables into this interface and the rest is done
 | 
				
			||||||
 | 
						// automatically using the reflect package.
 | 
				
			||||||
 | 
						potential := []interface{}{f1, f2}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v := reflect.ValueOf(h)
 | 
				
			||||||
 | 
						vt := v.Type()
 | 
				
			||||||
 | 
						for _, raw := range potential {
 | 
				
			||||||
 | 
							pt := reflect.ValueOf(raw).Type()
 | 
				
			||||||
 | 
							if vt.ConvertibleTo(pt) {
 | 
				
			||||||
 | 
								return v.Convert(pt).Interface()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeHookExec executes the given decode hook. This should be used
 | 
				
			||||||
 | 
					// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
 | 
				
			||||||
 | 
					// that took reflect.Kind instead of reflect.Type.
 | 
				
			||||||
 | 
					func DecodeHookExec(
 | 
				
			||||||
 | 
						raw DecodeHookFunc,
 | 
				
			||||||
 | 
						from reflect.Type, to reflect.Type,
 | 
				
			||||||
 | 
						data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
						// Build our arguments that reflect expects
 | 
				
			||||||
 | 
						argVals := make([]reflect.Value, 3)
 | 
				
			||||||
 | 
						argVals[0] = reflect.ValueOf(from)
 | 
				
			||||||
 | 
						argVals[1] = reflect.ValueOf(to)
 | 
				
			||||||
 | 
						argVals[2] = reflect.ValueOf(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch f := typedDecodeHook(raw).(type) {
 | 
				
			||||||
 | 
						case DecodeHookFuncType:
 | 
				
			||||||
 | 
							return f(from, to, data)
 | 
				
			||||||
 | 
						case DecodeHookFuncKind:
 | 
				
			||||||
 | 
							return f(from.Kind(), to.Kind(), data)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return nil, errors.New("invalid decode hook signature")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComposeDecodeHookFunc creates a single DecodeHookFunc that
 | 
				
			||||||
 | 
					// automatically composes multiple DecodeHookFuncs.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The composed funcs are called in order, with the result of the
 | 
				
			||||||
 | 
					// previous transformation.
 | 
				
			||||||
 | 
					func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
 | 
				
			||||||
 | 
						return func(
 | 
				
			||||||
 | 
							f reflect.Type,
 | 
				
			||||||
 | 
							t reflect.Type,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							for _, f1 := range fs {
 | 
				
			||||||
 | 
								data, err = DecodeHookExec(f1, f, t, data)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Modify the from kind to be correct with the new data
 | 
				
			||||||
 | 
								f = reflect.ValueOf(data).Type()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return data, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// StringToSliceHookFunc returns a DecodeHookFunc that converts
 | 
				
			||||||
 | 
					// string to []string by splitting on the given sep.
 | 
				
			||||||
 | 
					func StringToSliceHookFunc(sep string) DecodeHookFunc {
 | 
				
			||||||
 | 
						return func(
 | 
				
			||||||
 | 
							f reflect.Kind,
 | 
				
			||||||
 | 
							t reflect.Kind,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							if f != reflect.String || t != reflect.Slice {
 | 
				
			||||||
 | 
								return data, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							raw := data.(string)
 | 
				
			||||||
 | 
							if raw == "" {
 | 
				
			||||||
 | 
								return []string{}, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return strings.Split(raw, sep), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
 | 
				
			||||||
 | 
					// strings to time.Duration.
 | 
				
			||||||
 | 
					func StringToTimeDurationHookFunc() DecodeHookFunc {
 | 
				
			||||||
 | 
						return func(
 | 
				
			||||||
 | 
							f reflect.Type,
 | 
				
			||||||
 | 
							t reflect.Type,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							if f.Kind() != reflect.String {
 | 
				
			||||||
 | 
								return data, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if t != reflect.TypeOf(time.Duration(5)) {
 | 
				
			||||||
 | 
								return data, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Convert it by parsing
 | 
				
			||||||
 | 
							return time.ParseDuration(data.(string))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func WeaklyTypedHook(
 | 
				
			||||||
 | 
						f reflect.Kind,
 | 
				
			||||||
 | 
						t reflect.Kind,
 | 
				
			||||||
 | 
						data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						switch t {
 | 
				
			||||||
 | 
						case reflect.String:
 | 
				
			||||||
 | 
							switch f {
 | 
				
			||||||
 | 
							case reflect.Bool:
 | 
				
			||||||
 | 
								if dataVal.Bool() {
 | 
				
			||||||
 | 
									return "1", nil
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return "0", nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case reflect.Float32:
 | 
				
			||||||
 | 
								return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
 | 
				
			||||||
 | 
							case reflect.Int:
 | 
				
			||||||
 | 
								return strconv.FormatInt(dataVal.Int(), 10), nil
 | 
				
			||||||
 | 
							case reflect.Slice:
 | 
				
			||||||
 | 
								dataType := dataVal.Type()
 | 
				
			||||||
 | 
								elemKind := dataType.Elem().Kind()
 | 
				
			||||||
 | 
								if elemKind == reflect.Uint8 {
 | 
				
			||||||
 | 
									return string(dataVal.Interface().([]uint8)), nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case reflect.Uint:
 | 
				
			||||||
 | 
								return strconv.FormatUint(dataVal.Uint(), 10), nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										229
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/decode_hooks_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										229
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/decode_hooks_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,229 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestComposeDecodeHookFunc(t *testing.T) {
 | 
				
			||||||
 | 
						f1 := func(
 | 
				
			||||||
 | 
							f reflect.Kind,
 | 
				
			||||||
 | 
							t reflect.Kind,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							return data.(string) + "foo", nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f2 := func(
 | 
				
			||||||
 | 
							f reflect.Kind,
 | 
				
			||||||
 | 
							t reflect.Kind,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							return data.(string) + "bar", nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f := ComposeDecodeHookFunc(f1, f2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result, err := DecodeHookExec(
 | 
				
			||||||
 | 
							f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if result.(string) != "foobar" {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %#v", result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestComposeDecodeHookFunc_err(t *testing.T) {
 | 
				
			||||||
 | 
						f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							return nil, errors.New("foo")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							panic("NOPE")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f := ComposeDecodeHookFunc(f1, f2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := DecodeHookExec(
 | 
				
			||||||
 | 
							f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), 42)
 | 
				
			||||||
 | 
						if err.Error() != "foo" {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestComposeDecodeHookFunc_kinds(t *testing.T) {
 | 
				
			||||||
 | 
						var f2From reflect.Kind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f1 := func(
 | 
				
			||||||
 | 
							f reflect.Kind,
 | 
				
			||||||
 | 
							t reflect.Kind,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							return int(42), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f2 := func(
 | 
				
			||||||
 | 
							f reflect.Kind,
 | 
				
			||||||
 | 
							t reflect.Kind,
 | 
				
			||||||
 | 
							data interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							f2From = f
 | 
				
			||||||
 | 
							return data, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f := ComposeDecodeHookFunc(f1, f2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := DecodeHookExec(
 | 
				
			||||||
 | 
							f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if f2From != reflect.Int {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %#v", f2From)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestStringToSliceHookFunc(t *testing.T) {
 | 
				
			||||||
 | 
						f := StringToSliceHookFunc(",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strType := reflect.TypeOf("")
 | 
				
			||||||
 | 
						sliceType := reflect.TypeOf([]byte(""))
 | 
				
			||||||
 | 
						cases := []struct {
 | 
				
			||||||
 | 
							f, t   reflect.Type
 | 
				
			||||||
 | 
							data   interface{}
 | 
				
			||||||
 | 
							result interface{}
 | 
				
			||||||
 | 
							err    bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{sliceType, sliceType, 42, 42, false},
 | 
				
			||||||
 | 
							{strType, strType, 42, 42, false},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								sliceType,
 | 
				
			||||||
 | 
								"foo,bar,baz",
 | 
				
			||||||
 | 
								[]string{"foo", "bar", "baz"},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								sliceType,
 | 
				
			||||||
 | 
								"",
 | 
				
			||||||
 | 
								[]string{},
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, tc := range cases {
 | 
				
			||||||
 | 
							actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
 | 
				
			||||||
 | 
							if tc.err != (err != nil) {
 | 
				
			||||||
 | 
								t.Fatalf("case %d: expected err %#v", i, tc.err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !reflect.DeepEqual(actual, tc.result) {
 | 
				
			||||||
 | 
								t.Fatalf(
 | 
				
			||||||
 | 
									"case %d: expected %#v, got %#v",
 | 
				
			||||||
 | 
									i, tc.result, actual)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestStringToTimeDurationHookFunc(t *testing.T) {
 | 
				
			||||||
 | 
						f := StringToTimeDurationHookFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strType := reflect.TypeOf("")
 | 
				
			||||||
 | 
						timeType := reflect.TypeOf(time.Duration(5))
 | 
				
			||||||
 | 
						cases := []struct {
 | 
				
			||||||
 | 
							f, t   reflect.Type
 | 
				
			||||||
 | 
							data   interface{}
 | 
				
			||||||
 | 
							result interface{}
 | 
				
			||||||
 | 
							err    bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{strType, timeType, "5s", 5 * time.Second, false},
 | 
				
			||||||
 | 
							{strType, timeType, "5", time.Duration(0), true},
 | 
				
			||||||
 | 
							{strType, strType, "5", "5", false},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, tc := range cases {
 | 
				
			||||||
 | 
							actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
 | 
				
			||||||
 | 
							if tc.err != (err != nil) {
 | 
				
			||||||
 | 
								t.Fatalf("case %d: expected err %#v", i, tc.err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !reflect.DeepEqual(actual, tc.result) {
 | 
				
			||||||
 | 
								t.Fatalf(
 | 
				
			||||||
 | 
									"case %d: expected %#v, got %#v",
 | 
				
			||||||
 | 
									i, tc.result, actual)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestWeaklyTypedHook(t *testing.T) {
 | 
				
			||||||
 | 
						var f DecodeHookFunc = WeaklyTypedHook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						boolType := reflect.TypeOf(true)
 | 
				
			||||||
 | 
						strType := reflect.TypeOf("")
 | 
				
			||||||
 | 
						sliceType := reflect.TypeOf([]byte(""))
 | 
				
			||||||
 | 
						cases := []struct {
 | 
				
			||||||
 | 
							f, t   reflect.Type
 | 
				
			||||||
 | 
							data   interface{}
 | 
				
			||||||
 | 
							result interface{}
 | 
				
			||||||
 | 
							err    bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							// TO STRING
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								boolType,
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
								"0",
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								boolType,
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								true,
 | 
				
			||||||
 | 
								"1",
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								reflect.TypeOf(float32(1)),
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								float32(7),
 | 
				
			||||||
 | 
								"7",
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								reflect.TypeOf(int(1)),
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								int(7),
 | 
				
			||||||
 | 
								"7",
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								sliceType,
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								[]uint8("foo"),
 | 
				
			||||||
 | 
								"foo",
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								reflect.TypeOf(uint(1)),
 | 
				
			||||||
 | 
								strType,
 | 
				
			||||||
 | 
								uint(7),
 | 
				
			||||||
 | 
								"7",
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, tc := range cases {
 | 
				
			||||||
 | 
							actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data)
 | 
				
			||||||
 | 
							if tc.err != (err != nil) {
 | 
				
			||||||
 | 
								t.Fatalf("case %d: expected err %#v", i, tc.err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !reflect.DeepEqual(actual, tc.result) {
 | 
				
			||||||
 | 
								t.Fatalf(
 | 
				
			||||||
 | 
									"case %d: expected %#v, got %#v",
 | 
				
			||||||
 | 
									i, tc.result, actual)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Error implements the error interface and can represents multiple
 | 
				
			||||||
 | 
					// errors that occur in the course of a single decode.
 | 
				
			||||||
 | 
					type Error struct {
 | 
				
			||||||
 | 
						Errors []string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (e *Error) Error() string {
 | 
				
			||||||
 | 
						points := make([]string, len(e.Errors))
 | 
				
			||||||
 | 
						for i, err := range e.Errors {
 | 
				
			||||||
 | 
							points[i] = fmt.Sprintf("* %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Strings(points)
 | 
				
			||||||
 | 
						return fmt.Sprintf(
 | 
				
			||||||
 | 
							"%d error(s) decoding:\n\n%s",
 | 
				
			||||||
 | 
							len(e.Errors), strings.Join(points, "\n"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WrappedErrors implements the errwrap.Wrapper interface to make this
 | 
				
			||||||
 | 
					// return value more useful with the errwrap and go-multierror libraries.
 | 
				
			||||||
 | 
					func (e *Error) WrappedErrors() []error {
 | 
				
			||||||
 | 
						if e == nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result := make([]error, len(e.Errors))
 | 
				
			||||||
 | 
						for i, e := range e.Errors {
 | 
				
			||||||
 | 
							result[i] = errors.New(e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func appendErrors(errors []string, err error) []string {
 | 
				
			||||||
 | 
						switch e := err.(type) {
 | 
				
			||||||
 | 
						case *Error:
 | 
				
			||||||
 | 
							return append(errors, e.Errors...)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return append(errors, e.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										746
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										746
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,746 @@
 | 
				
			||||||
 | 
					// The mapstructure package exposes functionality to convert an
 | 
				
			||||||
 | 
					// abitrary map[string]interface{} into a native Go structure.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The Go structure can be arbitrarily complex, containing slices,
 | 
				
			||||||
 | 
					// other structs, etc. and the decoder will properly decode nested
 | 
				
			||||||
 | 
					// maps and so on into the proper structures in the native Go struct.
 | 
				
			||||||
 | 
					// See the examples to see what the decoder is capable of.
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeHookFunc is the callback function that can be used for
 | 
				
			||||||
 | 
					// data transformations. See "DecodeHook" in the DecoderConfig
 | 
				
			||||||
 | 
					// struct.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The type should be DecodeHookFuncType or DecodeHookFuncKind.
 | 
				
			||||||
 | 
					// Either is accepted. Types are a superset of Kinds (Types can return
 | 
				
			||||||
 | 
					// Kinds) and are generally a richer thing to use, but Kinds are simpler
 | 
				
			||||||
 | 
					// if you only need those.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The reason DecodeHookFunc is multi-typed is for backwards compatibility:
 | 
				
			||||||
 | 
					// we started with Kinds and then realized Types were the better solution,
 | 
				
			||||||
 | 
					// but have a promise to not break backwards compat so we now support
 | 
				
			||||||
 | 
					// both.
 | 
				
			||||||
 | 
					type DecodeHookFunc interface{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error)
 | 
				
			||||||
 | 
					type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecoderConfig is the configuration that is used to create a new decoder
 | 
				
			||||||
 | 
					// and allows customization of various aspects of decoding.
 | 
				
			||||||
 | 
					type DecoderConfig struct {
 | 
				
			||||||
 | 
						// DecodeHook, if set, will be called before any decoding and any
 | 
				
			||||||
 | 
						// type conversion (if WeaklyTypedInput is on). This lets you modify
 | 
				
			||||||
 | 
						// the values before they're set down onto the resulting struct.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// If an error is returned, the entire decode will fail with that
 | 
				
			||||||
 | 
						// error.
 | 
				
			||||||
 | 
						DecodeHook DecodeHookFunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If ErrorUnused is true, then it is an error for there to exist
 | 
				
			||||||
 | 
						// keys in the original map that were unused in the decoding process
 | 
				
			||||||
 | 
						// (extra keys).
 | 
				
			||||||
 | 
						ErrorUnused bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ZeroFields, if set to true, will zero fields before writing them.
 | 
				
			||||||
 | 
						// For example, a map will be emptied before decoded values are put in
 | 
				
			||||||
 | 
						// it. If this is false, a map will be merged.
 | 
				
			||||||
 | 
						ZeroFields bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If WeaklyTypedInput is true, the decoder will make the following
 | 
				
			||||||
 | 
						// "weak" conversions:
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						//   - bools to string (true = "1", false = "0")
 | 
				
			||||||
 | 
						//   - numbers to string (base 10)
 | 
				
			||||||
 | 
						//   - bools to int/uint (true = 1, false = 0)
 | 
				
			||||||
 | 
						//   - strings to int/uint (base implied by prefix)
 | 
				
			||||||
 | 
						//   - int to bool (true if value != 0)
 | 
				
			||||||
 | 
						//   - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F,
 | 
				
			||||||
 | 
						//     FALSE, false, False. Anything else is an error)
 | 
				
			||||||
 | 
						//   - empty array = empty map and vice versa
 | 
				
			||||||
 | 
						//   - negative numbers to overflowed uint values (base 10)
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						WeaklyTypedInput bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Metadata is the struct that will contain extra metadata about
 | 
				
			||||||
 | 
						// the decoding. If this is nil, then no metadata will be tracked.
 | 
				
			||||||
 | 
						Metadata *Metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Result is a pointer to the struct that will contain the decoded
 | 
				
			||||||
 | 
						// value.
 | 
				
			||||||
 | 
						Result interface{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The tag name that mapstructure reads for field names. This
 | 
				
			||||||
 | 
						// defaults to "mapstructure"
 | 
				
			||||||
 | 
						TagName string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A Decoder takes a raw interface value and turns it into structured
 | 
				
			||||||
 | 
					// data, keeping track of rich error information along the way in case
 | 
				
			||||||
 | 
					// anything goes wrong. Unlike the basic top-level Decode method, you can
 | 
				
			||||||
 | 
					// more finely control how the Decoder behaves using the DecoderConfig
 | 
				
			||||||
 | 
					// structure. The top-level Decode method is just a convenience that sets
 | 
				
			||||||
 | 
					// up the most basic Decoder.
 | 
				
			||||||
 | 
					type Decoder struct {
 | 
				
			||||||
 | 
						config *DecoderConfig
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Metadata contains information about decoding a structure that
 | 
				
			||||||
 | 
					// is tedious or difficult to get otherwise.
 | 
				
			||||||
 | 
					type Metadata struct {
 | 
				
			||||||
 | 
						// Keys are the keys of the structure which were successfully decoded
 | 
				
			||||||
 | 
						Keys []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Unused is a slice of keys that were found in the raw value but
 | 
				
			||||||
 | 
						// weren't decoded since there was no matching field in the result interface
 | 
				
			||||||
 | 
						Unused []string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decode takes a map and uses reflection to convert it into the
 | 
				
			||||||
 | 
					// given Go native structure. val must be a pointer to a struct.
 | 
				
			||||||
 | 
					func Decode(m interface{}, rawVal interface{}) error {
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata: nil,
 | 
				
			||||||
 | 
							Result:   rawVal,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return decoder.Decode(m)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WeakDecode is the same as Decode but is shorthand to enable
 | 
				
			||||||
 | 
					// WeaklyTypedInput. See DecoderConfig for more info.
 | 
				
			||||||
 | 
					func WeakDecode(input, output interface{}) error {
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata:         nil,
 | 
				
			||||||
 | 
							Result:           output,
 | 
				
			||||||
 | 
							WeaklyTypedInput: true,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return decoder.Decode(input)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewDecoder returns a new decoder for the given configuration. Once
 | 
				
			||||||
 | 
					// a decoder has been returned, the same configuration must not be used
 | 
				
			||||||
 | 
					// again.
 | 
				
			||||||
 | 
					func NewDecoder(config *DecoderConfig) (*Decoder, error) {
 | 
				
			||||||
 | 
						val := reflect.ValueOf(config.Result)
 | 
				
			||||||
 | 
						if val.Kind() != reflect.Ptr {
 | 
				
			||||||
 | 
							return nil, errors.New("result must be a pointer")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val = val.Elem()
 | 
				
			||||||
 | 
						if !val.CanAddr() {
 | 
				
			||||||
 | 
							return nil, errors.New("result must be addressable (a pointer)")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if config.Metadata != nil {
 | 
				
			||||||
 | 
							if config.Metadata.Keys == nil {
 | 
				
			||||||
 | 
								config.Metadata.Keys = make([]string, 0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if config.Metadata.Unused == nil {
 | 
				
			||||||
 | 
								config.Metadata.Unused = make([]string, 0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if config.TagName == "" {
 | 
				
			||||||
 | 
							config.TagName = "mapstructure"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result := &Decoder{
 | 
				
			||||||
 | 
							config: config,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decode decodes the given raw interface to the target pointer specified
 | 
				
			||||||
 | 
					// by the configuration.
 | 
				
			||||||
 | 
					func (d *Decoder) Decode(raw interface{}) error {
 | 
				
			||||||
 | 
						return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decodes an unknown data type into a specific reflection value.
 | 
				
			||||||
 | 
					func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						if data == nil {
 | 
				
			||||||
 | 
							// If the data is nil, then we don't set anything.
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						if !dataVal.IsValid() {
 | 
				
			||||||
 | 
							// If the data value is invalid, then we just set the value
 | 
				
			||||||
 | 
							// to be the zero value.
 | 
				
			||||||
 | 
							val.Set(reflect.Zero(val.Type()))
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d.config.DecodeHook != nil {
 | 
				
			||||||
 | 
							// We have a DecodeHook, so let's pre-process the data.
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							data, err = DecodeHookExec(
 | 
				
			||||||
 | 
								d.config.DecodeHook,
 | 
				
			||||||
 | 
								dataVal.Type(), val.Type(), data)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						dataKind := getKind(val)
 | 
				
			||||||
 | 
						switch dataKind {
 | 
				
			||||||
 | 
						case reflect.Bool:
 | 
				
			||||||
 | 
							err = d.decodeBool(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Interface:
 | 
				
			||||||
 | 
							err = d.decodeBasic(name, data, val)
 | 
				
			||||||
 | 
						case reflect.String:
 | 
				
			||||||
 | 
							err = d.decodeString(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Int:
 | 
				
			||||||
 | 
							err = d.decodeInt(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Uint:
 | 
				
			||||||
 | 
							err = d.decodeUint(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Float32:
 | 
				
			||||||
 | 
							err = d.decodeFloat(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Struct:
 | 
				
			||||||
 | 
							err = d.decodeStruct(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Map:
 | 
				
			||||||
 | 
							err = d.decodeMap(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							err = d.decodePtr(name, data, val)
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							err = d.decodeSlice(name, data, val)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							// If we reached this point then we weren't able to decode it
 | 
				
			||||||
 | 
							return fmt.Errorf("%s: unsupported type: %s", name, dataKind)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If we reached here, then we successfully decoded SOMETHING, so
 | 
				
			||||||
 | 
						// mark the key as used if we're tracking metadata.
 | 
				
			||||||
 | 
						if d.config.Metadata != nil && name != "" {
 | 
				
			||||||
 | 
							d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This decodes a basic type (bool, int, string, etc.) and sets the
 | 
				
			||||||
 | 
					// value to "data" of that type.
 | 
				
			||||||
 | 
					func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						dataValType := dataVal.Type()
 | 
				
			||||||
 | 
						if !dataValType.AssignableTo(val.Type()) {
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' expected type '%s', got '%s'",
 | 
				
			||||||
 | 
								name, val.Type(), dataValType)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val.Set(dataVal)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						dataKind := getKind(dataVal)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						converted := true
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case dataKind == reflect.String:
 | 
				
			||||||
 | 
							val.SetString(dataVal.String())
 | 
				
			||||||
 | 
						case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							if dataVal.Bool() {
 | 
				
			||||||
 | 
								val.SetString("1")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								val.SetString("0")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case dataKind == reflect.Int && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							val.SetString(strconv.FormatInt(dataVal.Int(), 10))
 | 
				
			||||||
 | 
						case dataKind == reflect.Uint && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							val.SetString(strconv.FormatUint(dataVal.Uint(), 10))
 | 
				
			||||||
 | 
						case dataKind == reflect.Float32 && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64))
 | 
				
			||||||
 | 
						case dataKind == reflect.Slice && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							dataType := dataVal.Type()
 | 
				
			||||||
 | 
							elemKind := dataType.Elem().Kind()
 | 
				
			||||||
 | 
							switch {
 | 
				
			||||||
 | 
							case elemKind == reflect.Uint8:
 | 
				
			||||||
 | 
								val.SetString(string(dataVal.Interface().([]uint8)))
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								converted = false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							converted = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !converted {
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' expected type '%s', got unconvertible type '%s'",
 | 
				
			||||||
 | 
								name, val.Type(), dataVal.Type())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						dataKind := getKind(dataVal)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case dataKind == reflect.Int:
 | 
				
			||||||
 | 
							val.SetInt(dataVal.Int())
 | 
				
			||||||
 | 
						case dataKind == reflect.Uint:
 | 
				
			||||||
 | 
							val.SetInt(int64(dataVal.Uint()))
 | 
				
			||||||
 | 
						case dataKind == reflect.Float32:
 | 
				
			||||||
 | 
							val.SetInt(int64(dataVal.Float()))
 | 
				
			||||||
 | 
						case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							if dataVal.Bool() {
 | 
				
			||||||
 | 
								val.SetInt(1)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								val.SetInt(0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case dataKind == reflect.String && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							i, err := strconv.ParseInt(dataVal.String(), 0, val.Type().Bits())
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								val.SetInt(i)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot parse '%s' as int: %s", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' expected type '%s', got unconvertible type '%s'",
 | 
				
			||||||
 | 
								name, val.Type(), dataVal.Type())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						dataKind := getKind(dataVal)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case dataKind == reflect.Int:
 | 
				
			||||||
 | 
							i := dataVal.Int()
 | 
				
			||||||
 | 
							if i < 0 && !d.config.WeaklyTypedInput {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot parse '%s', %d overflows uint",
 | 
				
			||||||
 | 
									name, i)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							val.SetUint(uint64(i))
 | 
				
			||||||
 | 
						case dataKind == reflect.Uint:
 | 
				
			||||||
 | 
							val.SetUint(dataVal.Uint())
 | 
				
			||||||
 | 
						case dataKind == reflect.Float32:
 | 
				
			||||||
 | 
							f := dataVal.Float()
 | 
				
			||||||
 | 
							if f < 0 && !d.config.WeaklyTypedInput {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot parse '%s', %f overflows uint",
 | 
				
			||||||
 | 
									name, f)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							val.SetUint(uint64(f))
 | 
				
			||||||
 | 
						case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							if dataVal.Bool() {
 | 
				
			||||||
 | 
								val.SetUint(1)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								val.SetUint(0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case dataKind == reflect.String && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							i, err := strconv.ParseUint(dataVal.String(), 0, val.Type().Bits())
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								val.SetUint(i)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot parse '%s' as uint: %s", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' expected type '%s', got unconvertible type '%s'",
 | 
				
			||||||
 | 
								name, val.Type(), dataVal.Type())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						dataKind := getKind(dataVal)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case dataKind == reflect.Bool:
 | 
				
			||||||
 | 
							val.SetBool(dataVal.Bool())
 | 
				
			||||||
 | 
						case dataKind == reflect.Int && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							val.SetBool(dataVal.Int() != 0)
 | 
				
			||||||
 | 
						case dataKind == reflect.Uint && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							val.SetBool(dataVal.Uint() != 0)
 | 
				
			||||||
 | 
						case dataKind == reflect.Float32 && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							val.SetBool(dataVal.Float() != 0)
 | 
				
			||||||
 | 
						case dataKind == reflect.String && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							b, err := strconv.ParseBool(dataVal.String())
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								val.SetBool(b)
 | 
				
			||||||
 | 
							} else if dataVal.String() == "" {
 | 
				
			||||||
 | 
								val.SetBool(false)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot parse '%s' as bool: %s", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' expected type '%s', got unconvertible type '%s'",
 | 
				
			||||||
 | 
								name, val.Type(), dataVal.Type())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.ValueOf(data)
 | 
				
			||||||
 | 
						dataKind := getKind(dataVal)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case dataKind == reflect.Int:
 | 
				
			||||||
 | 
							val.SetFloat(float64(dataVal.Int()))
 | 
				
			||||||
 | 
						case dataKind == reflect.Uint:
 | 
				
			||||||
 | 
							val.SetFloat(float64(dataVal.Uint()))
 | 
				
			||||||
 | 
						case dataKind == reflect.Float32:
 | 
				
			||||||
 | 
							val.SetFloat(float64(dataVal.Float()))
 | 
				
			||||||
 | 
						case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							if dataVal.Bool() {
 | 
				
			||||||
 | 
								val.SetFloat(1)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								val.SetFloat(0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case dataKind == reflect.String && d.config.WeaklyTypedInput:
 | 
				
			||||||
 | 
							f, err := strconv.ParseFloat(dataVal.String(), val.Type().Bits())
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								val.SetFloat(f)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("cannot parse '%s' as float: %s", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' expected type '%s', got unconvertible type '%s'",
 | 
				
			||||||
 | 
								name, val.Type(), dataVal.Type())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						valType := val.Type()
 | 
				
			||||||
 | 
						valKeyType := valType.Key()
 | 
				
			||||||
 | 
						valElemType := valType.Elem()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// By default we overwrite keys in the current map
 | 
				
			||||||
 | 
						valMap := val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the map is nil or we're purposely zeroing fields, make a new map
 | 
				
			||||||
 | 
						if valMap.IsNil() || d.config.ZeroFields {
 | 
				
			||||||
 | 
							// Make a new map to hold our result
 | 
				
			||||||
 | 
							mapType := reflect.MapOf(valKeyType, valElemType)
 | 
				
			||||||
 | 
							valMap = reflect.MakeMap(mapType)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check input type
 | 
				
			||||||
 | 
						dataVal := reflect.Indirect(reflect.ValueOf(data))
 | 
				
			||||||
 | 
						if dataVal.Kind() != reflect.Map {
 | 
				
			||||||
 | 
							// Accept empty array/slice instead of an empty map in weakly typed mode
 | 
				
			||||||
 | 
							if d.config.WeaklyTypedInput &&
 | 
				
			||||||
 | 
								(dataVal.Kind() == reflect.Slice || dataVal.Kind() == reflect.Array) &&
 | 
				
			||||||
 | 
								dataVal.Len() == 0 {
 | 
				
			||||||
 | 
								val.Set(valMap)
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Accumulate errors
 | 
				
			||||||
 | 
						errors := make([]string, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, k := range dataVal.MapKeys() {
 | 
				
			||||||
 | 
							fieldName := fmt.Sprintf("%s[%s]", name, k)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// First decode the key into the proper type
 | 
				
			||||||
 | 
							currentKey := reflect.Indirect(reflect.New(valKeyType))
 | 
				
			||||||
 | 
							if err := d.decode(fieldName, k.Interface(), currentKey); err != nil {
 | 
				
			||||||
 | 
								errors = appendErrors(errors, err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Next decode the data into the proper type
 | 
				
			||||||
 | 
							v := dataVal.MapIndex(k).Interface()
 | 
				
			||||||
 | 
							currentVal := reflect.Indirect(reflect.New(valElemType))
 | 
				
			||||||
 | 
							if err := d.decode(fieldName, v, currentVal); err != nil {
 | 
				
			||||||
 | 
								errors = appendErrors(errors, err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							valMap.SetMapIndex(currentKey, currentVal)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set the built up map to the value
 | 
				
			||||||
 | 
						val.Set(valMap)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If we had errors, return those
 | 
				
			||||||
 | 
						if len(errors) > 0 {
 | 
				
			||||||
 | 
							return &Error{errors}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						// Create an element of the concrete (non pointer) type and decode
 | 
				
			||||||
 | 
						// into that. Then set the value of the pointer to this type.
 | 
				
			||||||
 | 
						valType := val.Type()
 | 
				
			||||||
 | 
						valElemType := valType.Elem()
 | 
				
			||||||
 | 
						realVal := reflect.New(valElemType)
 | 
				
			||||||
 | 
						if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						val.Set(realVal)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.Indirect(reflect.ValueOf(data))
 | 
				
			||||||
 | 
						dataValKind := dataVal.Kind()
 | 
				
			||||||
 | 
						valType := val.Type()
 | 
				
			||||||
 | 
						valElemType := valType.Elem()
 | 
				
			||||||
 | 
						sliceType := reflect.SliceOf(valElemType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check input type
 | 
				
			||||||
 | 
						if dataValKind != reflect.Array && dataValKind != reflect.Slice {
 | 
				
			||||||
 | 
							// Accept empty map instead of array/slice in weakly typed mode
 | 
				
			||||||
 | 
							if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 {
 | 
				
			||||||
 | 
								val.Set(reflect.MakeSlice(sliceType, 0, 0))
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf(
 | 
				
			||||||
 | 
									"'%s': source data must be an array or slice, got %s", name, dataValKind)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make a new slice to hold our result, same size as the original data.
 | 
				
			||||||
 | 
						valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Accumulate any errors
 | 
				
			||||||
 | 
						errors := make([]string, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < dataVal.Len(); i++ {
 | 
				
			||||||
 | 
							currentData := dataVal.Index(i).Interface()
 | 
				
			||||||
 | 
							currentField := valSlice.Index(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fieldName := fmt.Sprintf("%s[%d]", name, i)
 | 
				
			||||||
 | 
							if err := d.decode(fieldName, currentData, currentField); err != nil {
 | 
				
			||||||
 | 
								errors = appendErrors(errors, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Finally, set the value to the slice we built up
 | 
				
			||||||
 | 
						val.Set(valSlice)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there were errors, we return those
 | 
				
			||||||
 | 
						if len(errors) > 0 {
 | 
				
			||||||
 | 
							return &Error{errors}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
 | 
				
			||||||
 | 
						dataVal := reflect.Indirect(reflect.ValueOf(data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the type of the value to write to and the data match directly,
 | 
				
			||||||
 | 
						// then we just set it directly instead of recursing into the structure.
 | 
				
			||||||
 | 
						if dataVal.Type() == val.Type() {
 | 
				
			||||||
 | 
							val.Set(dataVal)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dataValKind := dataVal.Kind()
 | 
				
			||||||
 | 
						if dataValKind != reflect.Map {
 | 
				
			||||||
 | 
							return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dataValType := dataVal.Type()
 | 
				
			||||||
 | 
						if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface {
 | 
				
			||||||
 | 
							return fmt.Errorf(
 | 
				
			||||||
 | 
								"'%s' needs a map with string keys, has '%s' keys",
 | 
				
			||||||
 | 
								name, dataValType.Key().Kind())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dataValKeys := make(map[reflect.Value]struct{})
 | 
				
			||||||
 | 
						dataValKeysUnused := make(map[interface{}]struct{})
 | 
				
			||||||
 | 
						for _, dataValKey := range dataVal.MapKeys() {
 | 
				
			||||||
 | 
							dataValKeys[dataValKey] = struct{}{}
 | 
				
			||||||
 | 
							dataValKeysUnused[dataValKey.Interface()] = struct{}{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						errors := make([]string, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This slice will keep track of all the structs we'll be decoding.
 | 
				
			||||||
 | 
						// There can be more than one struct if there are embedded structs
 | 
				
			||||||
 | 
						// that are squashed.
 | 
				
			||||||
 | 
						structs := make([]reflect.Value, 1, 5)
 | 
				
			||||||
 | 
						structs[0] = val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Compile the list of all the fields that we're going to be decoding
 | 
				
			||||||
 | 
						// from all the structs.
 | 
				
			||||||
 | 
						fields := make(map[*reflect.StructField]reflect.Value)
 | 
				
			||||||
 | 
						for len(structs) > 0 {
 | 
				
			||||||
 | 
							structVal := structs[0]
 | 
				
			||||||
 | 
							structs = structs[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							structType := structVal.Type()
 | 
				
			||||||
 | 
							for i := 0; i < structType.NumField(); i++ {
 | 
				
			||||||
 | 
								fieldType := structType.Field(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if fieldType.Anonymous {
 | 
				
			||||||
 | 
									fieldKind := fieldType.Type.Kind()
 | 
				
			||||||
 | 
									if fieldKind != reflect.Struct {
 | 
				
			||||||
 | 
										errors = appendErrors(errors,
 | 
				
			||||||
 | 
											fmt.Errorf("%s: unsupported type: %s", fieldType.Name, fieldKind))
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// We have an embedded field. We "squash" the fields down
 | 
				
			||||||
 | 
									// if specified in the tag.
 | 
				
			||||||
 | 
									squash := false
 | 
				
			||||||
 | 
									tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
 | 
				
			||||||
 | 
									for _, tag := range tagParts[1:] {
 | 
				
			||||||
 | 
										if tag == "squash" {
 | 
				
			||||||
 | 
											squash = true
 | 
				
			||||||
 | 
											break
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if squash {
 | 
				
			||||||
 | 
										structs = append(structs, val.FieldByName(fieldType.Name))
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Normal struct field, store it away
 | 
				
			||||||
 | 
								fields[&fieldType] = structVal.Field(i)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for fieldType, field := range fields {
 | 
				
			||||||
 | 
							fieldName := fieldType.Name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tagValue := fieldType.Tag.Get(d.config.TagName)
 | 
				
			||||||
 | 
							tagValue = strings.SplitN(tagValue, ",", 2)[0]
 | 
				
			||||||
 | 
							if tagValue != "" {
 | 
				
			||||||
 | 
								fieldName = tagValue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rawMapKey := reflect.ValueOf(fieldName)
 | 
				
			||||||
 | 
							rawMapVal := dataVal.MapIndex(rawMapKey)
 | 
				
			||||||
 | 
							if !rawMapVal.IsValid() {
 | 
				
			||||||
 | 
								// Do a slower search by iterating over each key and
 | 
				
			||||||
 | 
								// doing case-insensitive search.
 | 
				
			||||||
 | 
								for dataValKey, _ := range dataValKeys {
 | 
				
			||||||
 | 
									mK, ok := dataValKey.Interface().(string)
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										// Not a string key
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if strings.EqualFold(mK, fieldName) {
 | 
				
			||||||
 | 
										rawMapKey = dataValKey
 | 
				
			||||||
 | 
										rawMapVal = dataVal.MapIndex(dataValKey)
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if !rawMapVal.IsValid() {
 | 
				
			||||||
 | 
									// There was no matching key in the map for the value in
 | 
				
			||||||
 | 
									// the struct. Just ignore.
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Delete the key we're using from the unused map so we stop tracking
 | 
				
			||||||
 | 
							delete(dataValKeysUnused, rawMapKey.Interface())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !field.IsValid() {
 | 
				
			||||||
 | 
								// This should never happen
 | 
				
			||||||
 | 
								panic("field is not valid")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If we can't set the field, then it is unexported or something,
 | 
				
			||||||
 | 
							// and we just continue onwards.
 | 
				
			||||||
 | 
							if !field.CanSet() {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If the name is empty string, then we're at the root, and we
 | 
				
			||||||
 | 
							// don't dot-join the fields.
 | 
				
			||||||
 | 
							if name != "" {
 | 
				
			||||||
 | 
								fieldName = fmt.Sprintf("%s.%s", name, fieldName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil {
 | 
				
			||||||
 | 
								errors = appendErrors(errors, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
 | 
				
			||||||
 | 
							keys := make([]string, 0, len(dataValKeysUnused))
 | 
				
			||||||
 | 
							for rawKey, _ := range dataValKeysUnused {
 | 
				
			||||||
 | 
								keys = append(keys, rawKey.(string))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sort.Strings(keys)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", "))
 | 
				
			||||||
 | 
							errors = appendErrors(errors, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(errors) > 0 {
 | 
				
			||||||
 | 
							return &Error{errors}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Add the unused keys to the list of unused keys if we're tracking metadata
 | 
				
			||||||
 | 
						if d.config.Metadata != nil {
 | 
				
			||||||
 | 
							for rawKey, _ := range dataValKeysUnused {
 | 
				
			||||||
 | 
								key := rawKey.(string)
 | 
				
			||||||
 | 
								if name != "" {
 | 
				
			||||||
 | 
									key = fmt.Sprintf("%s.%s", name, key)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								d.config.Metadata.Unused = append(d.config.Metadata.Unused, key)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getKind(val reflect.Value) reflect.Kind {
 | 
				
			||||||
 | 
						kind := val.Kind()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case kind >= reflect.Int && kind <= reflect.Int64:
 | 
				
			||||||
 | 
							return reflect.Int
 | 
				
			||||||
 | 
						case kind >= reflect.Uint && kind <= reflect.Uint64:
 | 
				
			||||||
 | 
							return reflect.Uint
 | 
				
			||||||
 | 
						case kind >= reflect.Float32 && kind <= reflect.Float64:
 | 
				
			||||||
 | 
							return reflect.Float32
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return kind
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										243
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_benchmark_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										243
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_benchmark_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,243 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_Decode(b *testing.B) {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name   string
 | 
				
			||||||
 | 
							Age    int
 | 
				
			||||||
 | 
							Emails []string
 | 
				
			||||||
 | 
							Extra  map[string]string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":   "Mitchell",
 | 
				
			||||||
 | 
							"age":    91,
 | 
				
			||||||
 | 
							"emails": []string{"one", "two", "three"},
 | 
				
			||||||
 | 
							"extra": map[string]string{
 | 
				
			||||||
 | 
								"twitter": "mitchellh",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeBasic(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"vint":    42,
 | 
				
			||||||
 | 
							"Vuint":   42,
 | 
				
			||||||
 | 
							"vbool":   true,
 | 
				
			||||||
 | 
							"Vfloat":  42.42,
 | 
				
			||||||
 | 
							"vsilent": true,
 | 
				
			||||||
 | 
							"vdata":   42,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeEmbedded(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"Basic": map[string]interface{}{
 | 
				
			||||||
 | 
								"vstring": "innerfoo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"vunique": "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Embedded
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeTypeConversion(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"IntToFloat":    42,
 | 
				
			||||||
 | 
							"IntToUint":     42,
 | 
				
			||||||
 | 
							"IntToBool":     1,
 | 
				
			||||||
 | 
							"IntToString":   42,
 | 
				
			||||||
 | 
							"UintToInt":     42,
 | 
				
			||||||
 | 
							"UintToFloat":   42,
 | 
				
			||||||
 | 
							"UintToBool":    42,
 | 
				
			||||||
 | 
							"UintToString":  42,
 | 
				
			||||||
 | 
							"BoolToInt":     true,
 | 
				
			||||||
 | 
							"BoolToUint":    true,
 | 
				
			||||||
 | 
							"BoolToFloat":   true,
 | 
				
			||||||
 | 
							"BoolToString":  true,
 | 
				
			||||||
 | 
							"FloatToInt":    42.42,
 | 
				
			||||||
 | 
							"FloatToUint":   42.42,
 | 
				
			||||||
 | 
							"FloatToBool":   42.42,
 | 
				
			||||||
 | 
							"FloatToString": 42.42,
 | 
				
			||||||
 | 
							"StringToInt":   "42",
 | 
				
			||||||
 | 
							"StringToUint":  "42",
 | 
				
			||||||
 | 
							"StringToBool":  "1",
 | 
				
			||||||
 | 
							"StringToFloat": "42.42",
 | 
				
			||||||
 | 
							"SliceToMap":    []interface{}{},
 | 
				
			||||||
 | 
							"MapToSlice":    map[string]interface{}{},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var resultStrict TypeConversionResult
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &resultStrict)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeMap(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vother": map[interface{}]interface{}{
 | 
				
			||||||
 | 
								"foo": "foo",
 | 
				
			||||||
 | 
								"bar": "bar",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Map
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeMapOfStruct(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"value": map[string]interface{}{
 | 
				
			||||||
 | 
								"foo": map[string]string{"vstring": "one"},
 | 
				
			||||||
 | 
								"bar": map[string]string{"vstring": "two"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result MapOfStruct
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeSlice(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": []string{"foo", "bar", "baz"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Slice
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeSliceOfStruct(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"value": []map[string]interface{}{
 | 
				
			||||||
 | 
								{"vstring": "one"},
 | 
				
			||||||
 | 
								{"vstring": "two"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result SliceOfStruct
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeWeaklyTypedInput(b *testing.B) {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name   string
 | 
				
			||||||
 | 
							Age    int
 | 
				
			||||||
 | 
							Emails []string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This input can come from anywhere, but typically comes from
 | 
				
			||||||
 | 
						// something like decoding JSON, generated by a weakly typed language
 | 
				
			||||||
 | 
						// such as PHP.
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":   123,                      // number => string
 | 
				
			||||||
 | 
							"age":    "42",                     // string => number
 | 
				
			||||||
 | 
							"emails": map[string]interface{}{}, // empty map => empty array
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							WeaklyTypedInput: true,
 | 
				
			||||||
 | 
							Result:           &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							decoder.Decode(input)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeMetadata(b *testing.B) {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name string
 | 
				
			||||||
 | 
							Age  int
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":  "Mitchell",
 | 
				
			||||||
 | 
							"age":   91,
 | 
				
			||||||
 | 
							"email": "foo@bar.com",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var md Metadata
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata: &md,
 | 
				
			||||||
 | 
							Result:   &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							decoder.Decode(input)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeMetadataEmbedded(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"vunique": "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var md Metadata
 | 
				
			||||||
 | 
						var result EmbeddedSquash
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata: &md,
 | 
				
			||||||
 | 
							Result:   &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							b.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							decoder.Decode(input)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Benchmark_DecodeTagged(b *testing.B) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"foo": "bar",
 | 
				
			||||||
 | 
							"bar": "value",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Tagged
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							Decode(input, &result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										47
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GH-1
 | 
				
			||||||
 | 
					func TestDecode_NilValue(t *testing.T) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo":   nil,
 | 
				
			||||||
 | 
							"vother": nil,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Map
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("should not error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != "" {
 | 
				
			||||||
 | 
							t.Fatalf("value should be default: %s", result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vother != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Vother should be nil: %s", result.Vother)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GH-10
 | 
				
			||||||
 | 
					func TestDecode_mapInterfaceInterface(t *testing.T) {
 | 
				
			||||||
 | 
						input := map[interface{}]interface{}{
 | 
				
			||||||
 | 
							"vfoo":   nil,
 | 
				
			||||||
 | 
							"vother": nil,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Map
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("should not error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != "" {
 | 
				
			||||||
 | 
							t.Fatalf("value should be default: %s", result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vother != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Vother should be nil: %s", result.Vother)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										203
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_examples_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										203
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_examples_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,203 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ExampleDecode() {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name   string
 | 
				
			||||||
 | 
							Age    int
 | 
				
			||||||
 | 
							Emails []string
 | 
				
			||||||
 | 
							Extra  map[string]string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This input can come from anywhere, but typically comes from
 | 
				
			||||||
 | 
						// something like decoding JSON where we're not quite sure of the
 | 
				
			||||||
 | 
						// struct initially.
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":   "Mitchell",
 | 
				
			||||||
 | 
							"age":    91,
 | 
				
			||||||
 | 
							"emails": []string{"one", "two", "three"},
 | 
				
			||||||
 | 
							"extra": map[string]string{
 | 
				
			||||||
 | 
								"twitter": "mitchellh",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Printf("%#v", result)
 | 
				
			||||||
 | 
						// Output:
 | 
				
			||||||
 | 
						// mapstructure.Person{Name:"Mitchell", Age:91, Emails:[]string{"one", "two", "three"}, Extra:map[string]string{"twitter":"mitchellh"}}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ExampleDecode_errors() {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name   string
 | 
				
			||||||
 | 
							Age    int
 | 
				
			||||||
 | 
							Emails []string
 | 
				
			||||||
 | 
							Extra  map[string]string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This input can come from anywhere, but typically comes from
 | 
				
			||||||
 | 
						// something like decoding JSON where we're not quite sure of the
 | 
				
			||||||
 | 
						// struct initially.
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":   123,
 | 
				
			||||||
 | 
							"age":    "bad value",
 | 
				
			||||||
 | 
							"emails": []int{1, 2, 3},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							panic("should have an error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Println(err.Error())
 | 
				
			||||||
 | 
						// Output:
 | 
				
			||||||
 | 
						// 5 error(s) decoding:
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// * 'Age' expected type 'int', got unconvertible type 'string'
 | 
				
			||||||
 | 
						// * 'Emails[0]' expected type 'string', got unconvertible type 'int'
 | 
				
			||||||
 | 
						// * 'Emails[1]' expected type 'string', got unconvertible type 'int'
 | 
				
			||||||
 | 
						// * 'Emails[2]' expected type 'string', got unconvertible type 'int'
 | 
				
			||||||
 | 
						// * 'Name' expected type 'string', got unconvertible type 'int'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ExampleDecode_metadata() {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name string
 | 
				
			||||||
 | 
							Age  int
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This input can come from anywhere, but typically comes from
 | 
				
			||||||
 | 
						// something like decoding JSON where we're not quite sure of the
 | 
				
			||||||
 | 
						// struct initially.
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":  "Mitchell",
 | 
				
			||||||
 | 
							"age":   91,
 | 
				
			||||||
 | 
							"email": "foo@bar.com",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// For metadata, we make a more advanced DecoderConfig so we can
 | 
				
			||||||
 | 
						// more finely configure the decoder that is used. In this case, we
 | 
				
			||||||
 | 
						// just tell the decoder we want to track metadata.
 | 
				
			||||||
 | 
						var md Metadata
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata: &md,
 | 
				
			||||||
 | 
							Result:   &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := decoder.Decode(input); err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Printf("Unused keys: %#v", md.Unused)
 | 
				
			||||||
 | 
						// Output:
 | 
				
			||||||
 | 
						// Unused keys: []string{"email"}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ExampleDecode_weaklyTypedInput() {
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name   string
 | 
				
			||||||
 | 
							Age    int
 | 
				
			||||||
 | 
							Emails []string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This input can come from anywhere, but typically comes from
 | 
				
			||||||
 | 
						// something like decoding JSON, generated by a weakly typed language
 | 
				
			||||||
 | 
						// such as PHP.
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"name":   123,                      // number => string
 | 
				
			||||||
 | 
							"age":    "42",                     // string => number
 | 
				
			||||||
 | 
							"emails": map[string]interface{}{}, // empty map => empty array
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							WeaklyTypedInput: true,
 | 
				
			||||||
 | 
							Result:           &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Printf("%#v", result)
 | 
				
			||||||
 | 
						// Output: mapstructure.Person{Name:"123", Age:42, Emails:[]string{}}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ExampleDecode_tags() {
 | 
				
			||||||
 | 
						// Note that the mapstructure tags defined in the struct type
 | 
				
			||||||
 | 
						// can indicate which fields the values are mapped to.
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Name string `mapstructure:"person_name"`
 | 
				
			||||||
 | 
							Age  int    `mapstructure:"person_age"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"person_name": "Mitchell",
 | 
				
			||||||
 | 
							"person_age":  91,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Printf("%#v", result)
 | 
				
			||||||
 | 
						// Output:
 | 
				
			||||||
 | 
						// mapstructure.Person{Name:"Mitchell", Age:91}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ExampleDecode_embeddedStruct() {
 | 
				
			||||||
 | 
						// Squashing multiple embedded structs is allowed using the squash tag.
 | 
				
			||||||
 | 
						// This is demonstrated by creating a composite struct of multiple types
 | 
				
			||||||
 | 
						// and decoding into it. In this case, a person can carry with it both
 | 
				
			||||||
 | 
						// a Family and a Location, as well as their own FirstName.
 | 
				
			||||||
 | 
						type Family struct {
 | 
				
			||||||
 | 
							LastName string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						type Location struct {
 | 
				
			||||||
 | 
							City string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						type Person struct {
 | 
				
			||||||
 | 
							Family    `mapstructure:",squash"`
 | 
				
			||||||
 | 
							Location  `mapstructure:",squash"`
 | 
				
			||||||
 | 
							FirstName string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"FirstName": "Mitchell",
 | 
				
			||||||
 | 
							"LastName":  "Hashimoto",
 | 
				
			||||||
 | 
							"City":      "San Francisco",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Person
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City)
 | 
				
			||||||
 | 
						// Output:
 | 
				
			||||||
 | 
						// Mitchell Hashimoto, San Francisco
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										954
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										954
									
								
								Godeps/_workspace/src/github.com/mitchellh/mapstructure/mapstructure_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
					@ -0,0 +1,954 @@
 | 
				
			||||||
 | 
					package mapstructure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Basic struct {
 | 
				
			||||||
 | 
						Vstring string
 | 
				
			||||||
 | 
						Vint    int
 | 
				
			||||||
 | 
						Vuint   uint
 | 
				
			||||||
 | 
						Vbool   bool
 | 
				
			||||||
 | 
						Vfloat  float64
 | 
				
			||||||
 | 
						Vextra  string
 | 
				
			||||||
 | 
						vsilent bool
 | 
				
			||||||
 | 
						Vdata   interface{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Embedded struct {
 | 
				
			||||||
 | 
						Basic
 | 
				
			||||||
 | 
						Vunique string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EmbeddedPointer struct {
 | 
				
			||||||
 | 
						*Basic
 | 
				
			||||||
 | 
						Vunique string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EmbeddedSquash struct {
 | 
				
			||||||
 | 
						Basic   `mapstructure:",squash"`
 | 
				
			||||||
 | 
						Vunique string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Map struct {
 | 
				
			||||||
 | 
						Vfoo   string
 | 
				
			||||||
 | 
						Vother map[string]string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MapOfStruct struct {
 | 
				
			||||||
 | 
						Value map[string]Basic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Nested struct {
 | 
				
			||||||
 | 
						Vfoo string
 | 
				
			||||||
 | 
						Vbar Basic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type NestedPointer struct {
 | 
				
			||||||
 | 
						Vfoo string
 | 
				
			||||||
 | 
						Vbar *Basic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Slice struct {
 | 
				
			||||||
 | 
						Vfoo string
 | 
				
			||||||
 | 
						Vbar []string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SliceOfStruct struct {
 | 
				
			||||||
 | 
						Value []Basic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Tagged struct {
 | 
				
			||||||
 | 
						Extra string `mapstructure:"bar,what,what"`
 | 
				
			||||||
 | 
						Value string `mapstructure:"foo"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TypeConversionResult struct {
 | 
				
			||||||
 | 
						IntToFloat         float32
 | 
				
			||||||
 | 
						IntToUint          uint
 | 
				
			||||||
 | 
						IntToBool          bool
 | 
				
			||||||
 | 
						IntToString        string
 | 
				
			||||||
 | 
						UintToInt          int
 | 
				
			||||||
 | 
						UintToFloat        float32
 | 
				
			||||||
 | 
						UintToBool         bool
 | 
				
			||||||
 | 
						UintToString       string
 | 
				
			||||||
 | 
						BoolToInt          int
 | 
				
			||||||
 | 
						BoolToUint         uint
 | 
				
			||||||
 | 
						BoolToFloat        float32
 | 
				
			||||||
 | 
						BoolToString       string
 | 
				
			||||||
 | 
						FloatToInt         int
 | 
				
			||||||
 | 
						FloatToUint        uint
 | 
				
			||||||
 | 
						FloatToBool        bool
 | 
				
			||||||
 | 
						FloatToString      string
 | 
				
			||||||
 | 
						SliceUint8ToString string
 | 
				
			||||||
 | 
						StringToInt        int
 | 
				
			||||||
 | 
						StringToUint       uint
 | 
				
			||||||
 | 
						StringToBool       bool
 | 
				
			||||||
 | 
						StringToFloat      float32
 | 
				
			||||||
 | 
						SliceToMap         map[string]interface{}
 | 
				
			||||||
 | 
						MapToSlice         []interface{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestBasicTypes(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"vint":    42,
 | 
				
			||||||
 | 
							"Vuint":   42,
 | 
				
			||||||
 | 
							"vbool":   true,
 | 
				
			||||||
 | 
							"Vfloat":  42.42,
 | 
				
			||||||
 | 
							"vsilent": true,
 | 
				
			||||||
 | 
							"vdata":   42,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("got an err: %s", err.Error())
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vstring != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vint != 42 {
 | 
				
			||||||
 | 
							t.Errorf("vint value should be 42: %#v", result.Vint)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vuint != 42 {
 | 
				
			||||||
 | 
							t.Errorf("vuint value should be 42: %#v", result.Vuint)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbool != true {
 | 
				
			||||||
 | 
							t.Errorf("vbool value should be true: %#v", result.Vbool)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfloat != 42.42 {
 | 
				
			||||||
 | 
							t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vextra != "" {
 | 
				
			||||||
 | 
							t.Errorf("vextra value should be empty: %#v", result.Vextra)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.vsilent != false {
 | 
				
			||||||
 | 
							t.Error("vsilent should not be set, it is unexported")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vdata != 42 {
 | 
				
			||||||
 | 
							t.Error("vdata should be valid")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestBasic_IntWithFloat(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vint": float64(42),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_Embedded(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"Basic": map[string]interface{}{
 | 
				
			||||||
 | 
								"vstring": "innerfoo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"vunique": "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Embedded
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vstring != "innerfoo" {
 | 
				
			||||||
 | 
							t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vunique != "bar" {
 | 
				
			||||||
 | 
							t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_EmbeddedPointer(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"Basic": map[string]interface{}{
 | 
				
			||||||
 | 
								"vstring": "innerfoo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"vunique": "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result EmbeddedPointer
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatal("should get error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_EmbeddedSquash(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"vunique": "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result EmbeddedSquash
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vstring != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vstring value should be 'foo': %#v", result.Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vunique != "bar" {
 | 
				
			||||||
 | 
							t.Errorf("vunique value should be 'bar': %#v", result.Vunique)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_DecodeHook(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vint": "WHAT",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							if from == reflect.String && to != reflect.String {
 | 
				
			||||||
 | 
								return 5, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return v, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							DecodeHook: decodeHook,
 | 
				
			||||||
 | 
							Result:     &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vint != 5 {
 | 
				
			||||||
 | 
							t.Errorf("vint should be 5: %#v", result.Vint)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_DecodeHookType(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vint": "WHAT",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
							if from.Kind() == reflect.String &&
 | 
				
			||||||
 | 
								to.Kind() != reflect.String {
 | 
				
			||||||
 | 
								return 5, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return v, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							DecodeHook: decodeHook,
 | 
				
			||||||
 | 
							Result:     &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vint != 5 {
 | 
				
			||||||
 | 
							t.Errorf("vint should be 5: %#v", result.Vint)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_Nil(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var input interface{} = nil
 | 
				
			||||||
 | 
						result := Basic{
 | 
				
			||||||
 | 
							Vstring: "foo",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vstring != "foo" {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %#v", result.Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_NonStruct(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"foo": "bar",
 | 
				
			||||||
 | 
							"bar": "baz",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result map[string]string
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result["foo"] != "bar" {
 | 
				
			||||||
 | 
							t.Fatal("foo is not bar")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_StructMatch(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vbar": Basic{
 | 
				
			||||||
 | 
								Vstring: "foo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Nested
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vstring != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("bad: %#v", result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecode_TypeConversion(t *testing.T) {
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"IntToFloat":         42,
 | 
				
			||||||
 | 
							"IntToUint":          42,
 | 
				
			||||||
 | 
							"IntToBool":          1,
 | 
				
			||||||
 | 
							"IntToString":        42,
 | 
				
			||||||
 | 
							"UintToInt":          42,
 | 
				
			||||||
 | 
							"UintToFloat":        42,
 | 
				
			||||||
 | 
							"UintToBool":         42,
 | 
				
			||||||
 | 
							"UintToString":       42,
 | 
				
			||||||
 | 
							"BoolToInt":          true,
 | 
				
			||||||
 | 
							"BoolToUint":         true,
 | 
				
			||||||
 | 
							"BoolToFloat":        true,
 | 
				
			||||||
 | 
							"BoolToString":       true,
 | 
				
			||||||
 | 
							"FloatToInt":         42.42,
 | 
				
			||||||
 | 
							"FloatToUint":        42.42,
 | 
				
			||||||
 | 
							"FloatToBool":        42.42,
 | 
				
			||||||
 | 
							"FloatToString":      42.42,
 | 
				
			||||||
 | 
							"SliceUint8ToString": []uint8("foo"),
 | 
				
			||||||
 | 
							"StringToInt":        "42",
 | 
				
			||||||
 | 
							"StringToUint":       "42",
 | 
				
			||||||
 | 
							"StringToBool":       "1",
 | 
				
			||||||
 | 
							"StringToFloat":      "42.42",
 | 
				
			||||||
 | 
							"SliceToMap":         []interface{}{},
 | 
				
			||||||
 | 
							"MapToSlice":         map[string]interface{}{},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedResultStrict := TypeConversionResult{
 | 
				
			||||||
 | 
							IntToFloat:  42.0,
 | 
				
			||||||
 | 
							IntToUint:   42,
 | 
				
			||||||
 | 
							UintToInt:   42,
 | 
				
			||||||
 | 
							UintToFloat: 42,
 | 
				
			||||||
 | 
							BoolToInt:   0,
 | 
				
			||||||
 | 
							BoolToUint:  0,
 | 
				
			||||||
 | 
							BoolToFloat: 0,
 | 
				
			||||||
 | 
							FloatToInt:  42,
 | 
				
			||||||
 | 
							FloatToUint: 42,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedResultWeak := TypeConversionResult{
 | 
				
			||||||
 | 
							IntToFloat:         42.0,
 | 
				
			||||||
 | 
							IntToUint:          42,
 | 
				
			||||||
 | 
							IntToBool:          true,
 | 
				
			||||||
 | 
							IntToString:        "42",
 | 
				
			||||||
 | 
							UintToInt:          42,
 | 
				
			||||||
 | 
							UintToFloat:        42,
 | 
				
			||||||
 | 
							UintToBool:         true,
 | 
				
			||||||
 | 
							UintToString:       "42",
 | 
				
			||||||
 | 
							BoolToInt:          1,
 | 
				
			||||||
 | 
							BoolToUint:         1,
 | 
				
			||||||
 | 
							BoolToFloat:        1,
 | 
				
			||||||
 | 
							BoolToString:       "1",
 | 
				
			||||||
 | 
							FloatToInt:         42,
 | 
				
			||||||
 | 
							FloatToUint:        42,
 | 
				
			||||||
 | 
							FloatToBool:        true,
 | 
				
			||||||
 | 
							FloatToString:      "42.42",
 | 
				
			||||||
 | 
							SliceUint8ToString: "foo",
 | 
				
			||||||
 | 
							StringToInt:        42,
 | 
				
			||||||
 | 
							StringToUint:       42,
 | 
				
			||||||
 | 
							StringToBool:       true,
 | 
				
			||||||
 | 
							StringToFloat:      42.42,
 | 
				
			||||||
 | 
							SliceToMap:         map[string]interface{}{},
 | 
				
			||||||
 | 
							MapToSlice:         []interface{}{},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test strict type conversion
 | 
				
			||||||
 | 
						var resultStrict TypeConversionResult
 | 
				
			||||||
 | 
						err := Decode(input, &resultStrict)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Errorf("should return an error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(resultStrict, expectedResultStrict) {
 | 
				
			||||||
 | 
							t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test weak type conversion
 | 
				
			||||||
 | 
						var decoder *Decoder
 | 
				
			||||||
 | 
						var resultWeak TypeConversionResult
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							WeaklyTypedInput: true,
 | 
				
			||||||
 | 
							Result:           &resultWeak,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err = NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(resultWeak, expectedResultWeak) {
 | 
				
			||||||
 | 
							t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDecoder_ErrorUnused(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "hello",
 | 
				
			||||||
 | 
							"foo":     "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							ErrorUnused: true,
 | 
				
			||||||
 | 
							Result:      &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatal("expected error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMap(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vother": map[interface{}]interface{}{
 | 
				
			||||||
 | 
								"foo": "foo",
 | 
				
			||||||
 | 
								"bar": "bar",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Map
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vother == nil {
 | 
				
			||||||
 | 
							t.Fatal("vother should not be nil")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(result.Vother) != 2 {
 | 
				
			||||||
 | 
							t.Error("vother should have two items")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vother["foo"] != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vother["bar"] != "bar" {
 | 
				
			||||||
 | 
							t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMapMerge(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vother": map[interface{}]interface{}{
 | 
				
			||||||
 | 
								"foo": "foo",
 | 
				
			||||||
 | 
								"bar": "bar",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Map
 | 
				
			||||||
 | 
						result.Vother = map[string]string{"hello": "world"}
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expected := map[string]string{
 | 
				
			||||||
 | 
							"foo":   "foo",
 | 
				
			||||||
 | 
							"bar":   "bar",
 | 
				
			||||||
 | 
							"hello": "world",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(result.Vother, expected) {
 | 
				
			||||||
 | 
							t.Errorf("bad: %#v", result.Vother)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMapOfStruct(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"value": map[string]interface{}{
 | 
				
			||||||
 | 
								"foo": map[string]string{"vstring": "one"},
 | 
				
			||||||
 | 
								"bar": map[string]string{"vstring": "two"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result MapOfStruct
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Value == nil {
 | 
				
			||||||
 | 
							t.Fatal("value should not be nil")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(result.Value) != 2 {
 | 
				
			||||||
 | 
							t.Error("value should have two items")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Value["foo"].Vstring != "one" {
 | 
				
			||||||
 | 
							t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Value["bar"].Vstring != "two" {
 | 
				
			||||||
 | 
							t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNestedType(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": map[string]interface{}{
 | 
				
			||||||
 | 
								"vstring": "foo",
 | 
				
			||||||
 | 
								"vint":    42,
 | 
				
			||||||
 | 
								"vbool":   true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Nested
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vstring != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vint != 42 {
 | 
				
			||||||
 | 
							t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vbool != true {
 | 
				
			||||||
 | 
							t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vextra != "" {
 | 
				
			||||||
 | 
							t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNestedTypePointer(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": &map[string]interface{}{
 | 
				
			||||||
 | 
								"vstring": "foo",
 | 
				
			||||||
 | 
								"vint":    42,
 | 
				
			||||||
 | 
								"vbool":   true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result NestedPointer
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got an err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vstring != "foo" {
 | 
				
			||||||
 | 
							t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vint != 42 {
 | 
				
			||||||
 | 
							t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vbool != true {
 | 
				
			||||||
 | 
							t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar.Vextra != "" {
 | 
				
			||||||
 | 
							t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSlice(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputStringSlice := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": []string{"foo", "bar", "baz"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputStringSlicePointer := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": &[]string{"foo", "bar", "baz"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						outputStringSlice := &Slice{
 | 
				
			||||||
 | 
							"foo",
 | 
				
			||||||
 | 
							[]string{"foo", "bar", "baz"},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testSliceInput(t, inputStringSlice, outputStringSlice)
 | 
				
			||||||
 | 
						testSliceInput(t, inputStringSlicePointer, outputStringSlice)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestInvalidSlice(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": 42,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result := Slice{}
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Errorf("expected failure")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSliceOfStruct(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"value": []map[string]interface{}{
 | 
				
			||||||
 | 
								{"vstring": "one"},
 | 
				
			||||||
 | 
								{"vstring": "two"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result SliceOfStruct
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got unexpected error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(result.Value) != 2 {
 | 
				
			||||||
 | 
							t.Fatalf("expected two values, got %d", len(result.Value))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Value[0].Vstring != "one" {
 | 
				
			||||||
 | 
							t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Value[1].Vstring != "two" {
 | 
				
			||||||
 | 
							t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestInvalidType(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": 42,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Basic
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatal("error should exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						derr, ok := err.(*Error)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							t.Fatalf("error should be kind of Error, instead: %#v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" {
 | 
				
			||||||
 | 
							t.Errorf("got unexpected error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputNegIntUint := map[string]interface{}{
 | 
				
			||||||
 | 
							"vuint": -42,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = Decode(inputNegIntUint, &result)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatal("error should exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						derr, ok = err.(*Error)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							t.Fatalf("error should be kind of Error, instead: %#v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" {
 | 
				
			||||||
 | 
							t.Errorf("got unexpected error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inputNegFloatUint := map[string]interface{}{
 | 
				
			||||||
 | 
							"vuint": -42.0,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = Decode(inputNegFloatUint, &result)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatal("error should exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						derr, ok = err.(*Error)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							t.Fatalf("error should be kind of Error, instead: %#v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" {
 | 
				
			||||||
 | 
							t.Errorf("got unexpected error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMetadata(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vfoo": "foo",
 | 
				
			||||||
 | 
							"vbar": map[string]interface{}{
 | 
				
			||||||
 | 
								"vstring": "foo",
 | 
				
			||||||
 | 
								"Vuint":   42,
 | 
				
			||||||
 | 
								"foo":     "bar",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"bar": "nil",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var md Metadata
 | 
				
			||||||
 | 
						var result Nested
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata: &md,
 | 
				
			||||||
 | 
							Result:   &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"}
 | 
				
			||||||
 | 
						sort.Strings(md.Keys)
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(md.Keys, expectedKeys) {
 | 
				
			||||||
 | 
							t.Fatalf("bad keys: %#v", md.Keys)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedUnused := []string{"Vbar.foo", "bar"}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(md.Unused, expectedUnused) {
 | 
				
			||||||
 | 
							t.Fatalf("bad unused: %#v", md.Unused)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMetadata_Embedded(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"vstring": "foo",
 | 
				
			||||||
 | 
							"vunique": "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var md Metadata
 | 
				
			||||||
 | 
						var result EmbeddedSquash
 | 
				
			||||||
 | 
						config := &DecoderConfig{
 | 
				
			||||||
 | 
							Metadata: &md,
 | 
				
			||||||
 | 
							Result:   &result,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decoder, err := NewDecoder(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = decoder.Decode(input)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedKeys := []string{"Vstring", "Vunique"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Strings(md.Keys)
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(md.Keys, expectedKeys) {
 | 
				
			||||||
 | 
							t.Fatalf("bad keys: %#v", md.Keys)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedUnused := []string{}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(md.Unused, expectedUnused) {
 | 
				
			||||||
 | 
							t.Fatalf("bad unused: %#v", md.Unused)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNonPtrValue(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := Decode(map[string]interface{}{}, Basic{})
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatal("error should exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err.Error() != "result must be a pointer" {
 | 
				
			||||||
 | 
							t.Errorf("got unexpected error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTagged(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"foo": "bar",
 | 
				
			||||||
 | 
							"bar": "value",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result Tagged
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Value != "bar" {
 | 
				
			||||||
 | 
							t.Errorf("value should be 'bar', got: %#v", result.Value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Extra != "value" {
 | 
				
			||||||
 | 
							t.Errorf("extra should be 'value', got: %#v", result.Extra)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestWeakDecode(t *testing.T) {
 | 
				
			||||||
 | 
						t.Parallel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input := map[string]interface{}{
 | 
				
			||||||
 | 
							"foo": "4",
 | 
				
			||||||
 | 
							"bar": "value",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result struct {
 | 
				
			||||||
 | 
							Foo int
 | 
				
			||||||
 | 
							Bar string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := WeakDecode(input, &result); err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("err: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if result.Foo != 4 {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %#v", result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if result.Bar != "value" {
 | 
				
			||||||
 | 
							t.Fatalf("bad: %#v", result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) {
 | 
				
			||||||
 | 
						var result Slice
 | 
				
			||||||
 | 
						err := Decode(input, &result)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("got error: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vfoo != expected.Vfoo {
 | 
				
			||||||
 | 
							t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.Vbar == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Vbar a slice, got '%#v'", result.Vbar)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(result.Vbar) != len(expected.Vbar) {
 | 
				
			||||||
 | 
							t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, v := range result.Vbar {
 | 
				
			||||||
 | 
							if v != expected.Vbar[i] {
 | 
				
			||||||
 | 
								t.Errorf(
 | 
				
			||||||
 | 
									"Vbar[%d] should be '%#v', got '%#v'",
 | 
				
			||||||
 | 
									i, expected.Vbar[i], v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue