Permalink
Browse files

fix params with custom type should be converted to requested type (#28)

* fix params with custom type should be converted to requested type

* remove comment
  • Loading branch information...
Fs02 committed Aug 31, 2018
1 parent 4324358 commit d2655778c19ec6958b5f48abf28c2c934339ef83
Showing with 88 additions and 11 deletions.
  1. +11 −1 params/json.go
  2. +21 −0 params/json_test.go
  3. +7 −3 params/map.go
  4. +46 −7 params/map_test.go
  5. +3 −0 params/params_test.go
@@ -23,7 +23,7 @@ func (json *JSON) Exists(name string) bool {

// Get returns value as interface.
// returns nil if value doens't exists.
func (json JSON) Get(name string) interface{} {
func (json *JSON) Get(name string) interface{} {
return json.Result.Get(name).Value()
}

@@ -81,6 +81,16 @@ func (json *JSON) GetParamsSlice(name string) ([]Params, bool) {
}

func (json *JSON) convert(value gjson.Result, typ reflect.Type) (interface{}, bool) {
// handle type alias
if typ.PkgPath() != "" && typ.Kind() != reflect.Struct && typ.Kind() != reflect.Slice && typ.Kind() != reflect.Array {
rv := reflect.ValueOf(value.Value())
if !rv.Type().ConvertibleTo(typ) {
return nil, false
}

return rv.Convert(typ).Interface(), true
}

switch value.Type {
case gjson.Null:
return nil, true
@@ -68,6 +68,13 @@ func TestJSON_GetWithType(t *testing.T) {
value: nil,
valid: false,
},
{
name: "incorrect type Number",
field: "incorrect type",
typ: reflect.TypeOf(Number(0)),
value: nil,
valid: false,
},
{
name: "boolean",
field: "boolean",
@@ -236,6 +243,20 @@ func TestJSON_GetWithType(t *testing.T) {
value: []uintptr{1, 2},
valid: true,
},
{
name: "type Number",
field: "number",
typ: reflect.TypeOf(Number(0)),
value: Number(1),
valid: true,
},
{
name: "type Number slice",
field: "number slice",
typ: reflect.TypeOf([]Number{}),
value: []Number{1, 2},
valid: true,
},
{
name: "float32",
field: "float",
@@ -42,14 +42,18 @@ func (m Map) GetWithType(name string, typ reflect.Type) (interface{}, bool) {
return nil, true
}

if typ.Kind() == reflect.Slice && (rt.Kind() == reflect.Slice || rt.Kind() == reflect.Array) && rt.Elem().Kind() == reflect.Interface {
if typ.Kind() == reflect.Slice && (rt.Kind() == reflect.Slice || rt.Kind() == reflect.Array) {
result := reflect.MakeSlice(typ, rv.Len(), rv.Len())
elemTyp := typ.Elem()

for i := 0; i < rv.Len(); i++ {
elem := rv.Index(i)
if elem.Elem().Type().ConvertibleTo(elemTyp) {
result.Index(i).Set(elem.Elem().Convert(elemTyp))
if elem.Kind() == reflect.Interface {
elem = elem.Elem()
}

if elem.Type().ConvertibleTo(elemTyp) {
result.Index(i).Set(elem.Convert(elemTyp))
} else {
return nil, false
}
@@ -22,67 +22,106 @@ func TestMap_Get(t *testing.T) {

func TestMap_GetWithType(t *testing.T) {
p := params.Map{
"nil": (*bool)(nil),
"incorrect type": "some string",
"correct type": true,
"slice": []bool{true, false},
"slice of interface": []interface{}{true, false},
"slice of interface mixed": []interface{}{true, 0},
"nil": (*bool)(nil),
"incorrect type": "some string",
"correct type": true,
"slice": []bool{true, false},
"slice of interface": []interface{}{true, false},
"slice of interface mixed": []interface{}{true, 0},
"number": 1,
"number slice": []int{1, 2},
"number slice of interface": []interface{}{1, 2},
}

tests := []struct {
name string
field string
typ reflect.Type
value interface{}
valid bool
}{
{
name: "not exist",
field: "not exist",
typ: reflect.TypeOf(true),
value: nil,
valid: true,
},
{
name: "nil",
field: "nil",
typ: reflect.TypeOf(true),
value: nil,
valid: true,
},
{
name: "incorrect type",
field: "incorrect type",
typ: reflect.TypeOf(true),
value: nil,
valid: false,
},
{
name: "incorrect type Number",
field: "incorrect type",
typ: reflect.TypeOf(Number(0)),
value: nil,
valid: false,
},
{
name: "correct type",
field: "correct type",
typ: reflect.TypeOf(true),
value: true,
valid: true,
},
{
name: "slice",
field: "slice",
typ: reflect.TypeOf([]bool{}),
value: []bool{true, false},
valid: true,
},
{
name: "slice of interface",
field: "slice of interface",
typ: reflect.TypeOf([]bool{}),
value: []bool{true, false},
valid: true,
},
{
name: "slice of interface mixed",
field: "slice of interface mixed",
typ: reflect.TypeOf([]bool{}),
value: nil,
valid: false,
},
{
name: "type Number",
field: "number",
typ: reflect.TypeOf(Number(0)),
value: Number(1),
valid: true,
},
{
name: "type Number slice",
field: "number slice",
typ: reflect.TypeOf([]Number{}),
value: []Number{1, 2},
valid: true,
},
{
name: "type Number slice of interface",
field: "number slice of interface",
typ: reflect.TypeOf([]Number{}),
value: []Number{1, 2},
valid: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
value, valid := p.GetWithType(tt.name, tt.typ)
value, valid := p.GetWithType(tt.field, tt.typ)
assert.Equal(t, tt.value, value)
assert.Equal(t, tt.valid, valid)
})
@@ -0,0 +1,3 @@
package params_test

type Number int

0 comments on commit d265577

Please sign in to comment.