From 11e102e1378414d34df98a9cb9af5c60609c7db5 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 8 Nov 2020 16:21:09 +0800 Subject: [PATCH] fix issue in internal/structs.MapField --- internal/structs/structs_map.go | 47 ++++++++++++++----- internal/structs/structs_z_unit_test.go | 23 ++++++++++ net/ghttp/ghttp_unit_param_test.go | 60 ++++++++++++------------- 3 files changed, 90 insertions(+), 40 deletions(-) diff --git a/internal/structs/structs_map.go b/internal/structs/structs_map.go index afb64603f..0585a04d9 100644 --- a/internal/structs/structs_map.go +++ b/internal/structs/structs_map.go @@ -12,21 +12,48 @@ package structs // // The parameter specifies the priority tag array for retrieving from high to low. // -// The parameter specifies whether retrieving the struct field recursively. -// // Note that it only retrieves the exported attributes with first letter up-case from struct. func MapField(pointer interface{}, priority []string) (map[string]*Field, error) { - tagFields, err := getFieldValuesByTagPriority(pointer, priority, map[string]struct{}{}) + fields, err := getFieldValues(pointer) if err != nil { return nil, err } - tagFieldMap := make(map[string]*Field, len(tagFields)) - for _, field := range tagFields { - tagField := field - tagFieldMap[field.Name()] = tagField - if tagField.TagValue != "" { - tagFieldMap[tagField.TagValue] = tagField + var ( + tagValue = "" + mapField = make(map[string]*Field) + ) + for _, field := range fields { + // Only retrieve exported attributes. + if !field.IsExported() { + continue + } + tagValue = "" + for _, p := range priority { + tagValue = field.Tag(p) + if tagValue != "" && tagValue != "-" { + break + } + } + tempField := field + tempField.TagValue = tagValue + if tagValue != "" { + mapField[tagValue] = tempField + } else { + if field.IsEmbedded() { + m, err := MapField(field.value, priority) + if err != nil { + return nil, err + } + for k, v := range m { + if _, ok := mapField[k]; !ok { + tempV := v + mapField[k] = tempV + } + } + } else { + mapField[field.Name()] = tempField + } } } - return tagFieldMap, nil + return mapField, nil } diff --git a/internal/structs/structs_z_unit_test.go b/internal/structs/structs_z_unit_test.go index 19a864ce1..f3bdba4de 100644 --- a/internal/structs/structs_z_unit_test.go +++ b/internal/structs/structs_z_unit_test.go @@ -101,3 +101,26 @@ func Test_StructOfNilPointer(t *testing.T) { t.Assert(m, g.Map{"name": "Name", "pass2": "Pass"}) }) } + +func Test_MapField(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Name string `params:"name"` + Pass string `my-tag1:"pass1" my-tag2:"pass2" params:"pass"` + } + var user *User + m, _ := structs.MapField(user, []string{"params"}) + t.Assert(len(m), 3) + _, ok := m["Id"] + t.Assert(ok, true) + _, ok = m["Name"] + t.Assert(ok, false) + _, ok = m["name"] + t.Assert(ok, true) + _, ok = m["Pass"] + t.Assert(ok, false) + _, ok = m["pass"] + t.Assert(ok, true) + }) +} diff --git a/net/ghttp/ghttp_unit_param_test.go b/net/ghttp/ghttp_unit_param_test.go index 7e2ebdf99..112a1b7db 100644 --- a/net/ghttp/ghttp_unit_param_test.go +++ b/net/ghttp/ghttp_unit_param_test.go @@ -556,33 +556,33 @@ func Test_Params_Modify(t *testing.T) { }) } -//func Test_Params_Parse_DefaultValueTag(t *testing.T) { -// type T struct { -// Name string `d:"john"` -// Score float32 `d:"60"` -// } -// p, _ := ports.PopRand() -// s := g.Server(p) -// s.BindHandler("/parse", func(r *ghttp.Request) { -// var t *T -// if err := r.Parse(&t); err != nil { -// r.Response.WriteExit(err) -// } -// r.Response.WriteExit(t) -// }) -// s.SetPort(p) -// s.SetDumpRouterMap(false) -// s.Start() -// defer s.Shutdown() -// -// time.Sleep(100 * time.Millisecond) -// gtest.C(t, func(t *gtest.T) { -// prefix := fmt.Sprintf("http://127.0.0.1:%d", p) -// client := g.Client() -// client.SetPrefix(prefix) -// -// t.Assert(client.PostContent("/parse"), `{"Name":"john","Score":60}`) -// t.Assert(client.PostContent("/parse", `{"name":"smith"}`), `{"Name":"smith","Score":60}`) -// t.Assert(client.PostContent("/parse", `{"name":"smith", "score":100}`), `{"Name":"smith","Score":100}`) -// }) -//} +func Test_Params_Parse_DefaultValueTag(t *testing.T) { + type T struct { + Name string `d:"john"` + Score float32 `d:"60"` + } + p, _ := ports.PopRand() + s := g.Server(p) + s.BindHandler("/parse", func(r *ghttp.Request) { + var t *T + if err := r.Parse(&t); err != nil { + r.Response.WriteExit(err) + } + r.Response.WriteExit(t) + }) + s.SetPort(p) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + prefix := fmt.Sprintf("http://127.0.0.1:%d", p) + client := g.Client() + client.SetPrefix(prefix) + + t.Assert(client.PostContent("/parse"), `{"Name":"john","Score":60}`) + t.Assert(client.PostContent("/parse", `{"name":"smith"}`), `{"Name":"smith","Score":60}`) + t.Assert(client.PostContent("/parse", `{"name":"smith", "score":100}`), `{"Name":"smith","Score":100}`) + }) +}