Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions query/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,14 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error {
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
sf := typ.Field(i)
if sf.PkgPath != "" && !sf.Anonymous { // unexported
continue
if sf.PkgPath != "" { // unexported
embeddedType := sf.Type
if embeddedType.Kind() == reflect.Ptr {
embeddedType = embeddedType.Elem()
}
if !sf.Anonymous || embeddedType.Kind() != reflect.Struct {
continue
}
}

sv := val.Field(i)
Expand Down
90 changes: 90 additions & 0 deletions query/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,96 @@ func TestValues_EmbeddedStructs(t *testing.T) {
}
}

func TestValues_UnexportedEmbeddedFields(t *testing.T) {
type privateString string
type PublicString string
type privateStruct struct {
Limit int `url:"limit"`
}
value := privateString("private")
tests := []struct {
name string
input interface{}
want url.Values
}{
{
"scalar",
struct {
privateString
Page int `url:"page"`
}{value, 2},
url.Values{"page": {"2"}},
},
{
"scalar pointer",
struct {
*privateString
Page int `url:"page"`
}{&value, 2},
url.Values{"page": {"2"}},
},
{
"nil scalar pointer",
struct {
*privateString
Page int `url:"page"`
}{nil, 2},
url.Values{"page": {"2"}},
},
{
"tagged scalar",
struct {
privateString `url:"private"`
Page int `url:"page"`
}{value, 2},
url.Values{"page": {"2"}},
},
{
"custom encoder",
struct {
customEncodedStrings
Page int `url:"page"`
}{customEncodedStrings{"private"}, 2},
url.Values{"page": {"2"}},
},
{
"exported scalar",
struct {
PublicString
Page int `url:"page"`
}{"public", 2},
url.Values{"PublicString": {"public"}, "page": {"2"}},
},
{
"promoted struct field",
struct {
privateStruct
Page int `url:"page"`
}{privateStruct{Limit: 3}, 2},
url.Values{"limit": {"3"}, "page": {"2"}},
},
{
"promoted pointer field",
struct {
*privateStruct
Page int `url:"page"`
}{&privateStruct{Limit: 3}, 2},
url.Values{"limit": {"3"}, "page": {"2"}},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if err := recover(); err != nil {
t.Fatalf("Values panicked: %v", err)
}
}()
testValue(t, tt.input, tt.want)
})
}
}

func TestValues_InvalidInput(t *testing.T) {
_, err := Values("")
if err == nil {
Expand Down
Loading