fix: type matching supports string to int (#2038)
* fix: type matching supports string to int * feat: type matching supports string to int Co-authored-by: 程家福 <chengjiafu@uniontech.com>
This commit is contained in:
@@ -534,8 +534,10 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
|
|||||||
baseKind reflect.Kind, value interface{}) error {
|
baseKind reflect.Kind, value interface{}) error {
|
||||||
ithVal := slice.Index(index)
|
ithVal := slice.Index(index)
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case json.Number:
|
case fmt.Stringer:
|
||||||
return setValue(baseKind, ithVal, v.String())
|
return setValue(baseKind, ithVal, v.String())
|
||||||
|
case string:
|
||||||
|
return setValue(baseKind, ithVal, v)
|
||||||
default:
|
default:
|
||||||
// don't need to consider the difference between int, int8, int16, int32, int64,
|
// don't need to consider the difference between int, int8, int16, int32, int64,
|
||||||
// uint, uint8, uint16, uint32, uint64, because they're handled as json.Number.
|
// uint, uint8, uint16, uint32, uint64, because they're handled as json.Number.
|
||||||
|
|||||||
@@ -2681,7 +2681,7 @@ func TestUnmarshalJsonReaderMultiArray(t *testing.T) {
|
|||||||
assert.Equal(t, 2, len(res.B))
|
assert.Equal(t, 2, len(res.B))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalJsonReaderPtrMultiArray(t *testing.T) {
|
func TestUnmarshalJsonReaderPtrMultiArrayString(t *testing.T) {
|
||||||
payload := `{"a": "133", "b": [["add", "cccd"], ["eeee"]]}`
|
payload := `{"a": "133", "b": [["add", "cccd"], ["eeee"]]}`
|
||||||
var res struct {
|
var res struct {
|
||||||
A string `json:"a"`
|
A string `json:"a"`
|
||||||
@@ -2694,6 +2694,32 @@ func TestUnmarshalJsonReaderPtrMultiArray(t *testing.T) {
|
|||||||
assert.Equal(t, 2, len(res.B[0]))
|
assert.Equal(t, 2, len(res.B[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJsonReaderPtrMultiArrayString_Int(t *testing.T) {
|
||||||
|
payload := `{"a": "133", "b": [[11, 22], [33]]}`
|
||||||
|
var res struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B [][]*string `json:"b"`
|
||||||
|
}
|
||||||
|
reader := strings.NewReader(payload)
|
||||||
|
err := UnmarshalJsonReader(reader, &res)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 2, len(res.B))
|
||||||
|
assert.Equal(t, 2, len(res.B[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJsonReaderPtrMultiArrayInt(t *testing.T) {
|
||||||
|
payload := `{"a": "133", "b": [[11, 22], [33]]}`
|
||||||
|
var res struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B [][]*int `json:"b"`
|
||||||
|
}
|
||||||
|
reader := strings.NewReader(payload)
|
||||||
|
err := UnmarshalJsonReader(reader, &res)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 2, len(res.B))
|
||||||
|
assert.Equal(t, 2, len(res.B[0]))
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnmarshalJsonReaderPtrArray(t *testing.T) {
|
func TestUnmarshalJsonReaderPtrArray(t *testing.T) {
|
||||||
payload := `{"a": "133", "b": ["add", "cccd", "eeee"]}`
|
payload := `{"a": "133", "b": ["add", "cccd", "eeee"]}`
|
||||||
var res struct {
|
var res struct {
|
||||||
@@ -2706,6 +2732,30 @@ func TestUnmarshalJsonReaderPtrArray(t *testing.T) {
|
|||||||
assert.Equal(t, 3, len(res.B))
|
assert.Equal(t, 3, len(res.B))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJsonReaderPtrArray_Int(t *testing.T) {
|
||||||
|
payload := `{"a": "133", "b": [11, 22, 33]}`
|
||||||
|
var res struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B []*string `json:"b"`
|
||||||
|
}
|
||||||
|
reader := strings.NewReader(payload)
|
||||||
|
err := UnmarshalJsonReader(reader, &res)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 3, len(res.B))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJsonReaderPtrInt(t *testing.T) {
|
||||||
|
payload := `{"a": "133", "b": [11, 22, 33]}`
|
||||||
|
var res struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B []*string `json:"b"`
|
||||||
|
}
|
||||||
|
reader := strings.NewReader(payload)
|
||||||
|
err := UnmarshalJsonReader(reader, &res)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 3, len(res.B))
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnmarshalJsonWithoutKey(t *testing.T) {
|
func TestUnmarshalJsonWithoutKey(t *testing.T) {
|
||||||
payload := `{"A": "1", "B": "2"}`
|
payload := `{"A": "1", "B": "2"}`
|
||||||
var res struct {
|
var res struct {
|
||||||
|
|||||||
@@ -60,6 +60,20 @@ func Deref(t reflect.Type) reflect.Type {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DerefVal dereferences a value, if pointer value nil set new a value, returns is not a ptr element value.
|
||||||
|
func DerefVal(v reflect.Value) reflect.Value {
|
||||||
|
for {
|
||||||
|
if v.Kind() != reflect.Ptr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// Repr returns the string representation of v.
|
// Repr returns the string representation of v.
|
||||||
func Repr(v interface{}) string {
|
func Repr(v interface{}) string {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
@@ -477,6 +491,7 @@ func setValue(kind reflect.Kind, value reflect.Value, str string) error {
|
|||||||
if !value.CanSet() {
|
if !value.CanSet() {
|
||||||
return errValueNotSettable
|
return errValueNotSettable
|
||||||
}
|
}
|
||||||
|
value = DerefVal(value)
|
||||||
|
|
||||||
v, err := convertType(kind, str)
|
v, err := convertType(kind, str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type Foo struct {
|
|||||||
StrWithTagAndOption string `key:"stringwithtag,string"`
|
StrWithTagAndOption string `key:"stringwithtag,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeferInt(t *testing.T) {
|
func TestDerefInt(t *testing.T) {
|
||||||
i := 1
|
i := 1
|
||||||
s := "hello"
|
s := "hello"
|
||||||
number := struct {
|
number := struct {
|
||||||
@@ -60,6 +60,51 @@ func TestDeferInt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDerefValInt(t *testing.T) {
|
||||||
|
i := 1
|
||||||
|
s := "hello"
|
||||||
|
number := struct {
|
||||||
|
f float64
|
||||||
|
}{
|
||||||
|
f: 6.4,
|
||||||
|
}
|
||||||
|
cases := []struct {
|
||||||
|
t reflect.Value
|
||||||
|
expect reflect.Kind
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
t: reflect.ValueOf(i),
|
||||||
|
expect: reflect.Int,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
t: reflect.ValueOf(&i),
|
||||||
|
expect: reflect.Int,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
t: reflect.ValueOf(s),
|
||||||
|
expect: reflect.String,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
t: reflect.ValueOf(&s),
|
||||||
|
expect: reflect.String,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
t: reflect.ValueOf(number.f),
|
||||||
|
expect: reflect.Float64,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
t: reflect.ValueOf(&number.f),
|
||||||
|
expect: reflect.Float64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, each := range cases {
|
||||||
|
t.Run(each.t.String(), func(t *testing.T) {
|
||||||
|
assert.Equal(t, each.expect, DerefVal(each.t).Kind())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseKeyAndOptionWithoutTag(t *testing.T) {
|
func TestParseKeyAndOptionWithoutTag(t *testing.T) {
|
||||||
var foo Foo
|
var foo Foo
|
||||||
rte := reflect.TypeOf(&foo).Elem()
|
rte := reflect.TypeOf(&foo).Elem()
|
||||||
|
|||||||
@@ -38,3 +38,14 @@ func TestParseHeadersMulti(t *testing.T) {
|
|||||||
assert.Equal(t, 1, val.Baz)
|
assert.Equal(t, 1, val.Baz)
|
||||||
assert.True(t, val.Qux)
|
assert.True(t, val.Qux)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseHeadersArrayInt(t *testing.T) {
|
||||||
|
var val struct {
|
||||||
|
Foo []int `header:"foo"`
|
||||||
|
}
|
||||||
|
r := httptest.NewRequest(http.MethodGet, "/any", nil)
|
||||||
|
r.Header.Set("foo", "1")
|
||||||
|
r.Header.Add("foo", "2")
|
||||||
|
assert.Nil(t, ParseHeaders(r.Header, &val))
|
||||||
|
assert.Equal(t, []int{1, 2}, val.Foo)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user