Skip to content

Commit

Permalink
fix: handle JSON tags correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
askingcat committed Jun 30, 2020
1 parent aec1bf2 commit 146de2c
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
24 changes: 23 additions & 1 deletion dsl/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,11 @@ func match(srcType reflect.Type, params params) Matcher {

for i := 0; i < srcType.NumField(); i++ {
field := srcType.Field(i)
result[field.Tag.Get("json")] = match(field.Type, pluckParams(field.Type, field.Tag.Get("pact")))
fieldName := getJsonFieldName(field)
if fieldName == "" {
continue
}
result[fieldName] = match(field.Type, pluckParams(field.Type, field.Tag.Get("pact")))
}
return result
case reflect.String:
Expand Down Expand Up @@ -332,6 +336,24 @@ func match(srcType reflect.Type, params params) Matcher {
}
}

// getJsonFieldName retrieves the name for a JSON field as
// https://golang.org/pkg/encoding/json/#Marshal would do.
func getJsonFieldName(field reflect.StructField) string {
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
return field.Name
}
// Field should be ignored according to the JSON marshal documentation.
if jsonTag == "-" {
return ""
}
commaIndex := strings.Index(jsonTag, ",")
if commaIndex > -1 {
return jsonTag[:commaIndex]
}
return jsonTag
}

// params are plucked from 'pact' struct tags as match() traverses
// struct fields. They are passed back into match() along with their
// associated type to serve as parameters for the dsl functions.
Expand Down
51 changes: 51 additions & 0 deletions dsl/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,20 @@ func TestMatch(t *testing.T) {
Integer int `json:"integer" pact:"example=42"`
Float float32 `json:"float" pact:"example=6.66"`
}
type jsonTagOmitemptyDTO struct {
Word string `json:"word,omitempty"`
}
type jsonTagMissingDTO struct {
Word string
}
type jsonTagIgnoreFieldDTO struct {
Word string `json:"word"`
Ignored string `json:"-"`
}
type jsonTagDashDTO struct {
Word string `json:"word"`
WordDash string `json:"-,"`
}
str := "str"
type args struct {
src interface{}
Expand Down Expand Up @@ -648,6 +662,43 @@ func TestMatch(t *testing.T) {
"float": Like(float32(6.66)),
},
},
{
name: "recursive case - struct with json tag including omitempty",
args: args{
src: jsonTagOmitemptyDTO{},
},
want: StructMatcher{
"word": Like("string"),
},
},
{
name: "recursive case - struct without json tag",
args: args{
src: jsonTagMissingDTO{},
},
want: StructMatcher{
"Word": Like("string"),
},
},
{
name: "recursive case - struct with ignored field",
args: args{
src: jsonTagIgnoreFieldDTO{},
},
want: StructMatcher{
"word": Like("string"),
},
},
{
name: "recursive case - struct with field named '-'",
args: args{
src: jsonTagDashDTO{},
},
want: StructMatcher{
"word": Like("string"),
"-": Like("string"),
},
},
{
name: "base case - string",
args: args{
Expand Down

0 comments on commit 146de2c

Please sign in to comment.