fix marshal ptr in httpc (#1789)

* fix marshal ptr in httpc

* add more tests

* add more tests

* add more tests

* fix issue on options and optional both provided
master
Kevin Wan 3 years ago committed by GitHub
parent ee88abce14
commit cb4fcf2c6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,7 +16,13 @@ const (
func Marshal(val interface{}) (map[string]map[string]interface{}, error) { func Marshal(val interface{}) (map[string]map[string]interface{}, error) {
ret := make(map[string]map[string]interface{}) ret := make(map[string]map[string]interface{})
tp := reflect.TypeOf(val) tp := reflect.TypeOf(val)
if tp.Kind() == reflect.Ptr {
tp = tp.Elem()
}
rv := reflect.ValueOf(val) rv := reflect.ValueOf(val)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
for i := 0; i < tp.NumField(); i++ { for i := 0; i < tp.NumField(); i++ {
field := tp.Field(i) field := tp.Field(i)
@ -87,6 +93,10 @@ func validate(field reflect.StructField, value reflect.Value, opt *fieldOptions)
return nil return nil
} }
if opt.Optional && value.IsZero() {
return nil
}
if len(opt.Options) > 0 { if len(opt.Options) > 0 {
if err := validateOptions(value, opt); err != nil { if err := validateOptions(value, opt); err != nil {
return err return err

@ -27,6 +27,27 @@ func TestMarshal(t *testing.T) {
assert.True(t, m[emptyTag]["Anonymous"].(bool)) assert.True(t, m[emptyTag]["Anonymous"].(bool))
} }
func TestMarshal_Ptr(t *testing.T) {
v := &struct {
Name string `path:"name"`
Address string `json:"address,options=[beijing,shanghai]"`
Age int `json:"age"`
Anonymous bool
}{
Name: "kevin",
Address: "shanghai",
Age: 20,
Anonymous: true,
}
m, err := Marshal(v)
assert.Nil(t, err)
assert.Equal(t, "kevin", m["path"]["name"])
assert.Equal(t, "shanghai", m["json"]["address"])
assert.Equal(t, 20, m["json"]["age"].(int))
assert.True(t, m[emptyTag]["Anonymous"].(bool))
}
func TestMarshal_OptionalPtr(t *testing.T) { func TestMarshal_OptionalPtr(t *testing.T) {
var val = 1 var val = 1
v := struct { v := struct {
@ -71,6 +92,26 @@ func TestMarshal_NotInOptions(t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestMarshal_NotInOptionsOptional(t *testing.T) {
v := struct {
Name string `json:"name,options=[a,b],optional"`
}{}
_, err := Marshal(v)
assert.Nil(t, err)
}
func TestMarshal_NotInOptionsOptionalWrongValue(t *testing.T) {
v := struct {
Name string `json:"name,options=[a,b],optional"`
}{
Name: "kevin",
}
_, err := Marshal(v)
assert.NotNil(t, err)
}
func TestMarshal_Nested(t *testing.T) { func TestMarshal_Nested(t *testing.T) {
type address struct { type address struct {
Country string `json:"country"` Country string `json:"country"`

@ -987,6 +987,43 @@ func TestUnmarshalWithStringOptionsCorrect(t *testing.T) {
ast.Equal("2", in.Correct) ast.Equal("2", in.Correct)
} }
func TestUnmarshalOptionsOptional(t *testing.T) {
type inner struct {
Value string `key:"value,options=first|second,optional"`
OptionalValue string `key:"optional_value,options=first|second,optional"`
Foo string `key:"foo,options=[bar,baz]"`
Correct string `key:"correct,options=1|2"`
}
m := map[string]interface{}{
"value": "first",
"foo": "bar",
"correct": "2",
}
var in inner
ast := assert.New(t)
ast.Nil(UnmarshalKey(m, &in))
ast.Equal("first", in.Value)
ast.Equal("", in.OptionalValue)
ast.Equal("bar", in.Foo)
ast.Equal("2", in.Correct)
}
func TestUnmarshalOptionsOptionalWrongValue(t *testing.T) {
type inner struct {
Value string `key:"value,options=first|second,optional"`
OptionalValue string `key:"optional_value,options=first|second,optional"`
WrongValue string `key:"wrong_value,options=first|second,optional"`
}
m := map[string]interface{}{
"value": "first",
"wrong_value": "third",
}
var in inner
assert.NotNil(t, UnmarshalKey(m, &in))
}
func TestUnmarshalStringOptionsWithStringOptionsNotString(t *testing.T) { func TestUnmarshalStringOptionsWithStringOptionsNotString(t *testing.T) {
type inner struct { type inner struct {
Value string `key:"value,options=first|second"` Value string `key:"value,options=first|second"`

@ -73,6 +73,40 @@ func TestDo(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
} }
func TestDo_Ptr(t *testing.T) {
type Data struct {
Key string `path:"key"`
Value int `form:"value"`
Header string `header:"X-Header"`
Body string `json:"body"`
}
rt := router.NewRouter()
err := rt.Handle(http.MethodPost, "/nodes/:key",
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var req Data
assert.Nil(t, httpx.Parse(r, &req))
assert.Equal(t, "foo", req.Key)
assert.Equal(t, 10, req.Value)
assert.Equal(t, "my-header", req.Header)
assert.Equal(t, "my body", req.Body)
}))
assert.Nil(t, err)
svr := httptest.NewServer(http.HandlerFunc(rt.ServeHTTP))
defer svr.Close()
data := &Data{
Key: "foo",
Value: 10,
Header: "my-header",
Body: "my body",
}
resp, err := Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestDo_BadRequest(t *testing.T) { func TestDo_BadRequest(t *testing.T) {
_, err := Do(context.Background(), http.MethodPost, ":/nodes/:key", nil) _, err := Do(context.Background(), http.MethodPost, ":/nodes/:key", nil)
assert.NotNil(t, err) assert.NotNil(t, err)

Loading…
Cancel
Save