diff --git a/core/mapping/jsonunmarshaler.go b/core/mapping/jsonunmarshaler.go index bcad9993..523a8ca2 100644 --- a/core/mapping/jsonunmarshaler.go +++ b/core/mapping/jsonunmarshaler.go @@ -10,10 +10,12 @@ const jsonTagKey = "json" var jsonUnmarshaler = NewUnmarshaler(jsonTagKey) +// UnmarshalJsonBytes unmarshals content into v. func UnmarshalJsonBytes(content []byte, v interface{}) error { return unmarshalJsonBytes(content, v, jsonUnmarshaler) } +// UnmarshalJsonReader unmarshals content from reader into v. func UnmarshalJsonReader(reader io.Reader, v interface{}) error { return unmarshalJsonReader(reader, v, jsonUnmarshaler) } diff --git a/core/mapping/jsonunmarshaler_test.go b/core/mapping/jsonunmarshaler_test.go index fc561fd4..c98244c7 100644 --- a/core/mapping/jsonunmarshaler_test.go +++ b/core/mapping/jsonunmarshaler_test.go @@ -485,41 +485,41 @@ func TestUnmarshalBytesMap(t *testing.T) { func TestUnmarshalBytesMapStruct(t *testing.T) { var c struct { Persons map[string]struct { - Id int + ID int Name string `json:"name,optional"` } } - content := []byte(`{"Persons": {"first": {"Id": 1, "name": "kevin"}}}`) + content := []byte(`{"Persons": {"first": {"ID": 1, "name": "kevin"}}}`) assert.Nil(t, UnmarshalJsonBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"].Id) + assert.Equal(t, 1, c.Persons["first"].ID) assert.Equal(t, "kevin", c.Persons["first"].Name) } func TestUnmarshalBytesMapStructPtr(t *testing.T) { var c struct { Persons map[string]*struct { - Id int + ID int Name string `json:"name,optional"` } } - content := []byte(`{"Persons": {"first": {"Id": 1, "name": "kevin"}}}`) + content := []byte(`{"Persons": {"first": {"ID": 1, "name": "kevin"}}}`) assert.Nil(t, UnmarshalJsonBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"].Id) + assert.Equal(t, 1, c.Persons["first"].ID) assert.Equal(t, "kevin", c.Persons["first"].Name) } func TestUnmarshalBytesMapStructMissingPartial(t *testing.T) { var c struct { Persons map[string]*struct { - Id int + ID int Name string } } - content := []byte(`{"Persons": {"first": {"Id": 1}}}`) + content := []byte(`{"Persons": {"first": {"ID": 1}}}`) assert.NotNil(t, UnmarshalJsonBytes(content, &c)) } @@ -527,21 +527,21 @@ func TestUnmarshalBytesMapStructMissingPartial(t *testing.T) { func TestUnmarshalBytesMapStructOptional(t *testing.T) { var c struct { Persons map[string]*struct { - Id int + ID int Name string `json:"name,optional"` } } - content := []byte(`{"Persons": {"first": {"Id": 1}}}`) + content := []byte(`{"Persons": {"first": {"ID": 1}}}`) assert.Nil(t, UnmarshalJsonBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"].Id) + assert.Equal(t, 1, c.Persons["first"].ID) } func TestUnmarshalBytesMapEmptyStructSlice(t *testing.T) { var c struct { Persons map[string][]struct { - Id int + ID int Name string `json:"name,optional"` } } @@ -555,22 +555,22 @@ func TestUnmarshalBytesMapEmptyStructSlice(t *testing.T) { func TestUnmarshalBytesMapStructSlice(t *testing.T) { var c struct { Persons map[string][]struct { - Id int + ID int Name string `json:"name,optional"` } } - content := []byte(`{"Persons": {"first": [{"Id": 1, "name": "kevin"}]}}`) + content := []byte(`{"Persons": {"first": [{"ID": 1, "name": "kevin"}]}}`) assert.Nil(t, UnmarshalJsonBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"][0].Id) + assert.Equal(t, 1, c.Persons["first"][0].ID) assert.Equal(t, "kevin", c.Persons["first"][0].Name) } func TestUnmarshalBytesMapEmptyStructPtrSlice(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string `json:"name,optional"` } } @@ -584,26 +584,26 @@ func TestUnmarshalBytesMapEmptyStructPtrSlice(t *testing.T) { func TestUnmarshalBytesMapStructPtrSlice(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string `json:"name,optional"` } } - content := []byte(`{"Persons": {"first": [{"Id": 1, "name": "kevin"}]}}`) + content := []byte(`{"Persons": {"first": [{"ID": 1, "name": "kevin"}]}}`) assert.Nil(t, UnmarshalJsonBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"][0].Id) + assert.Equal(t, 1, c.Persons["first"][0].ID) assert.Equal(t, "kevin", c.Persons["first"][0].Name) } func TestUnmarshalBytesMapStructPtrSliceMissingPartial(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string } } - content := []byte(`{"Persons": {"first": [{"Id": 1}]}}`) + content := []byte(`{"Persons": {"first": [{"ID": 1}]}}`) assert.NotNil(t, UnmarshalJsonBytes(content, &c)) } @@ -611,15 +611,15 @@ func TestUnmarshalBytesMapStructPtrSliceMissingPartial(t *testing.T) { func TestUnmarshalBytesMapStructPtrSliceOptional(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string `json:"name,optional"` } } - content := []byte(`{"Persons": {"first": [{"Id": 1}]}}`) + content := []byte(`{"Persons": {"first": [{"ID": 1}]}}`) assert.Nil(t, UnmarshalJsonBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"][0].Id) + assert.Equal(t, 1, c.Persons["first"][0].ID) } func TestUnmarshalStructOptional(t *testing.T) { diff --git a/core/mapping/unmarshaler.go b/core/mapping/unmarshaler.go index 276b8f50..88371c7a 100644 --- a/core/mapping/unmarshaler.go +++ b/core/mapping/unmarshaler.go @@ -33,23 +33,27 @@ var ( ) type ( + // A Unmarshaler is used to unmarshal with given tag key. Unmarshaler struct { key string opts unmarshalOptions } + // UnmarshalOption defines the method to customize a Unmarshaler. + UnmarshalOption func(*unmarshalOptions) + unmarshalOptions struct { fromString bool } - keyCache map[string][]string - UnmarshalOption func(*unmarshalOptions) + keyCache map[string][]string ) func init() { cacheKeys.Store(make(keyCache)) } +// NewUnmarshaler returns a Unmarshaler. func NewUnmarshaler(key string, opts ...UnmarshalOption) *Unmarshaler { unmarshaler := Unmarshaler{ key: key, @@ -62,14 +66,17 @@ func NewUnmarshaler(key string, opts ...UnmarshalOption) *Unmarshaler { return &unmarshaler } +// UnmarshalKey unmarshals m into v with tag key. func UnmarshalKey(m map[string]interface{}, v interface{}) error { return keyUnmarshaler.Unmarshal(m, v) } +// Unmarshal unmarshals m into v. func (u *Unmarshaler) Unmarshal(m map[string]interface{}, v interface{}) error { return u.UnmarshalValuer(MapValuer(m), v) } +// UnmarshalValuer unmarshals m into v. func (u *Unmarshaler) UnmarshalValuer(m Valuer, v interface{}) error { return u.unmarshalWithFullName(m, v, "") } @@ -590,6 +597,7 @@ func (u *Unmarshaler) parseOptionsWithContext(field reflect.StructField, m Value return key, optsWithContext, nil } +// WithStringValues customizes a Unmarshaler with number values from strings. func WithStringValues() UnmarshalOption { return func(opt *unmarshalOptions) { opt.fromString = true diff --git a/core/mapping/unmarshaler_test.go b/core/mapping/unmarshaler_test.go index b1cd1e53..65b4ea7e 100644 --- a/core/mapping/unmarshaler_test.go +++ b/core/mapping/unmarshaler_test.go @@ -754,13 +754,13 @@ func TestUnmarshalJsonNumberInt64(t *testing.T) { strValue := strconv.FormatInt(intValue, 10) var number = json.Number(strValue) m := map[string]interface{}{ - "Id": number, + "ID": number, } var v struct { - Id int64 + ID int64 } assert.Nil(t, UnmarshalKey(m, &v)) - assert.Equal(t, intValue, v.Id) + assert.Equal(t, intValue, v.ID) } } @@ -770,13 +770,13 @@ func TestUnmarshalJsonNumberUint64(t *testing.T) { strValue := strconv.FormatUint(intValue, 10) var number = json.Number(strValue) m := map[string]interface{}{ - "Id": number, + "ID": number, } var v struct { - Id uint64 + ID uint64 } assert.Nil(t, UnmarshalKey(m, &v)) - assert.Equal(t, intValue, v.Id) + assert.Equal(t, intValue, v.ID) } } @@ -786,15 +786,15 @@ func TestUnmarshalJsonNumberUint64Ptr(t *testing.T) { strValue := strconv.FormatUint(intValue, 10) var number = json.Number(strValue) m := map[string]interface{}{ - "Id": number, + "ID": number, } var v struct { - Id *uint64 + ID *uint64 } ast := assert.New(t) ast.Nil(UnmarshalKey(m, &v)) - ast.NotNil(v.Id) - ast.Equal(intValue, *v.Id) + ast.NotNil(v.ID) + ast.Equal(intValue, *v.ID) } } @@ -1061,38 +1061,38 @@ func TestUnmarshalWithOptionsAndSet(t *testing.T) { func TestUnmarshalNestedKey(t *testing.T) { var c struct { - Id int `json:"Persons.first.Id"` + ID int `json:"Persons.first.ID"` } m := map[string]interface{}{ "Persons": map[string]interface{}{ "first": map[string]interface{}{ - "Id": 1, + "ID": 1, }, }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) - assert.Equal(t, 1, c.Id) + assert.Equal(t, 1, c.ID) } func TestUnmarhsalNestedKeyArray(t *testing.T) { var c struct { First []struct { - Id int + ID int } `json:"Persons.first"` } m := map[string]interface{}{ "Persons": map[string]interface{}{ "first": []map[string]interface{}{ - {"Id": 1}, - {"Id": 2}, + {"ID": 1}, + {"ID": 2}, }, }, } assert.Nil(t, NewUnmarshaler("json").Unmarshal(m, &c)) assert.Equal(t, 2, len(c.First)) - assert.Equal(t, 1, c.First[0].Id) + assert.Equal(t, 1, c.First[0].ID) } func TestUnmarshalAnonymousOptionalRequiredProvided(t *testing.T) { diff --git a/core/mapping/utils.go b/core/mapping/utils.go index 6685ea93..813c93e9 100644 --- a/core/mapping/utils.go +++ b/core/mapping/utils.go @@ -45,6 +45,7 @@ type ( } ) +// Deref dereferences a type, if pointer type, returns its element type. func Deref(t reflect.Type) reflect.Type { if t.Kind() == reflect.Ptr { t = t.Elem() @@ -53,6 +54,7 @@ func Deref(t reflect.Type) reflect.Type { return t } +// Repr returns the string representation of v. func Repr(v interface{}) string { if v == nil { return "" @@ -72,6 +74,7 @@ func Repr(v interface{}) string { return reprOfValue(val) } +// ValidatePtr validates v if it's a valid pointer. func ValidatePtr(v *reflect.Value) error { // sequence is very important, IsNil must be called after checking Kind() with reflect.Ptr, // panic otherwise diff --git a/core/mapping/valuer.go b/core/mapping/valuer.go index 07dcdfcb..d1a0dfea 100644 --- a/core/mapping/valuer.go +++ b/core/mapping/valuer.go @@ -1,13 +1,17 @@ package mapping type ( + // A Valuer interface defines the way to get values from the underlying object with keys. Valuer interface { + // Value gets the value associated with the given key. Value(key string) (interface{}, bool) } + // A MapValuer is a map that can use Value method to get values with given keys. MapValuer map[string]interface{} ) +// Value gets the value associated with the given key from mv. func (mv MapValuer) Value(key string) (interface{}, bool) { v, ok := mv[key] return v, ok diff --git a/core/mapping/yamlunmarshaler.go b/core/mapping/yamlunmarshaler.go index c7f6947f..20a7bf6d 100644 --- a/core/mapping/yamlunmarshaler.go +++ b/core/mapping/yamlunmarshaler.go @@ -13,15 +13,18 @@ import ( const yamlTagKey = "json" var ( + // ErrUnsupportedType is an error that indicates the config format is not supported. ErrUnsupportedType = errors.New("only map-like configs are suported") yamlUnmarshaler = NewUnmarshaler(yamlTagKey) ) +// UnmarshalYamlBytes unmarshals content into v. func UnmarshalYamlBytes(content []byte, v interface{}) error { return unmarshalYamlBytes(content, v, yamlUnmarshaler) } +// UnmarshalYamlReader unmarshals content from reader into v. func UnmarshalYamlReader(reader io.Reader, v interface{}) error { return unmarshalYamlReader(reader, v, yamlUnmarshaler) } diff --git a/core/mapping/yamlunmarshaler_test.go b/core/mapping/yamlunmarshaler_test.go index b9197c1d..d635fd74 100644 --- a/core/mapping/yamlunmarshaler_test.go +++ b/core/mapping/yamlunmarshaler_test.go @@ -502,49 +502,49 @@ func TestUnmarshalYamlBytesMap(t *testing.T) { func TestUnmarshalYamlBytesMapStruct(t *testing.T) { var c struct { Persons map[string]struct { - Id int + ID int Name string `json:"name,optional"` } } content := []byte(`Persons: first: - Id: 1 + ID: 1 name: kevin`) assert.Nil(t, UnmarshalYamlBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"].Id) + assert.Equal(t, 1, c.Persons["first"].ID) assert.Equal(t, "kevin", c.Persons["first"].Name) } func TestUnmarshalYamlBytesMapStructPtr(t *testing.T) { var c struct { Persons map[string]*struct { - Id int + ID int Name string `json:"name,optional"` } } content := []byte(`Persons: first: - Id: 1 + ID: 1 name: kevin`) assert.Nil(t, UnmarshalYamlBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"].Id) + assert.Equal(t, 1, c.Persons["first"].ID) assert.Equal(t, "kevin", c.Persons["first"].Name) } func TestUnmarshalYamlBytesMapStructMissingPartial(t *testing.T) { var c struct { Persons map[string]*struct { - Id int + ID int Name string } } content := []byte(`Persons: first: - Id: 1`) + ID: 1`) assert.NotNil(t, UnmarshalYamlBytes(content, &c)) } @@ -552,41 +552,41 @@ func TestUnmarshalYamlBytesMapStructMissingPartial(t *testing.T) { func TestUnmarshalYamlBytesMapStructOptional(t *testing.T) { var c struct { Persons map[string]*struct { - Id int + ID int Name string `json:"name,optional"` } } content := []byte(`Persons: first: - Id: 1`) + ID: 1`) assert.Nil(t, UnmarshalYamlBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"].Id) + assert.Equal(t, 1, c.Persons["first"].ID) } func TestUnmarshalYamlBytesMapStructSlice(t *testing.T) { var c struct { Persons map[string][]struct { - Id int + ID int Name string `json:"name,optional"` } } content := []byte(`Persons: first: - - Id: 1 + - ID: 1 name: kevin`) assert.Nil(t, UnmarshalYamlBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"][0].Id) + assert.Equal(t, 1, c.Persons["first"][0].ID) assert.Equal(t, "kevin", c.Persons["first"][0].Name) } func TestUnmarshalYamlBytesMapEmptyStructSlice(t *testing.T) { var c struct { Persons map[string][]struct { - Id int + ID int Name string `json:"name,optional"` } } @@ -601,25 +601,25 @@ func TestUnmarshalYamlBytesMapEmptyStructSlice(t *testing.T) { func TestUnmarshalYamlBytesMapStructPtrSlice(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string `json:"name,optional"` } } content := []byte(`Persons: first: - - Id: 1 + - ID: 1 name: kevin`) assert.Nil(t, UnmarshalYamlBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"][0].Id) + assert.Equal(t, 1, c.Persons["first"][0].ID) assert.Equal(t, "kevin", c.Persons["first"][0].Name) } func TestUnmarshalYamlBytesMapEmptyStructPtrSlice(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string `json:"name,optional"` } } @@ -634,13 +634,13 @@ func TestUnmarshalYamlBytesMapEmptyStructPtrSlice(t *testing.T) { func TestUnmarshalYamlBytesMapStructPtrSliceMissingPartial(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string } } content := []byte(`Persons: first: - - Id: 1`) + - ID: 1`) assert.NotNil(t, UnmarshalYamlBytes(content, &c)) } @@ -648,17 +648,17 @@ func TestUnmarshalYamlBytesMapStructPtrSliceMissingPartial(t *testing.T) { func TestUnmarshalYamlBytesMapStructPtrSliceOptional(t *testing.T) { var c struct { Persons map[string][]*struct { - Id int + ID int Name string `json:"name,optional"` } } content := []byte(`Persons: first: - - Id: 1`) + - ID: 1`) assert.Nil(t, UnmarshalYamlBytes(content, &c)) assert.Equal(t, 1, len(c.Persons)) - assert.Equal(t, 1, c.Persons["first"][0].Id) + assert.Equal(t, 1, c.Persons["first"][0].ID) } func TestUnmarshalYamlStructOptional(t *testing.T) {