Skip to content

Commit 80e7a5a

Browse files
author
Stein Fletcher
committed
Unable to match mock when body is raw array
This is caused by 2 issues: 1. The JSON compare method uses a map[string]interface{}, but it really should use interface{} to support arrays 2. The brackets '[]' in the spec trigger the regexp matcher, so it never works. The solution is to remove support for regexp on body matching (it's undocumented) and provided a separate `BodyRegexp` method if users want to match using regexp. This could potentially break some existing tests, but the inclusion of this new method should ease the migration, and I think not supporting matching arrays is a bigger issue that can't be worked around.
1 parent 706a23e commit 80e7a5a

File tree

2 files changed

+69
-12
lines changed

2 files changed

+69
-12
lines changed

mocks.go

+42-8
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ type MockRequest struct {
269269
cookiePresent []string
270270
cookieNotPresent []string
271271
body string
272+
bodyRegexp string
272273
matchers []Matcher
273274
}
274275

@@ -472,6 +473,12 @@ func (r *MockRequest) Body(b string) *MockRequest {
472473
return r
473474
}
474475

476+
// BodyRegexp configures the mock request to match the given body using the regexp matcher
477+
func (r *MockRequest) BodyRegexp(b string) *MockRequest {
478+
r.body = b
479+
return r
480+
}
481+
475482
// Bodyf configures the mock request to match the given body. Supports formatting the body
476483
func (r *MockRequest) Bodyf(format string, args ...interface{}) *MockRequest {
477484
return r.Body(fmt.Sprintf(format, args...))
@@ -1039,17 +1046,11 @@ var bodyMatcher = func(req *http.Request, spec *MockRequest) error {
10391046
return nil
10401047
}
10411048

1042-
// Perform regexp match
1043-
match, _ := regexp.MatchString(mockBody, bodyStr)
1044-
if match {
1045-
return nil
1046-
}
1047-
10481049
// Perform JSON match
1049-
var reqJSON map[string]interface{}
1050+
var reqJSON interface{}
10501051
reqJSONErr := json.Unmarshal(body, &reqJSON)
10511052

1052-
var matchJSON map[string]interface{}
1053+
var matchJSON interface{}
10531054
specJSONErr := json.Unmarshal([]byte(mockBody), &matchJSON)
10541055

10551056
isJSON := reqJSONErr == nil && specJSONErr == nil
@@ -1064,6 +1065,38 @@ var bodyMatcher = func(req *http.Request, spec *MockRequest) error {
10641065
return fmt.Errorf("received body did not match expected mock body\n%s", diff(mockBody, bodyStr))
10651066
}
10661067

1068+
var bodyRegexpMatcher = func(req *http.Request, spec *MockRequest) error {
1069+
expression := spec.bodyRegexp
1070+
1071+
if len(expression) == 0 {
1072+
return nil
1073+
}
1074+
1075+
if req.Body == nil {
1076+
return errors.New("expected a body but received none")
1077+
}
1078+
1079+
body, err := ioutil.ReadAll(req.Body)
1080+
if err != nil {
1081+
return err
1082+
}
1083+
if len(body) == 0 {
1084+
return errors.New("expected a body but received none")
1085+
}
1086+
1087+
// replace body so it can be read again
1088+
req.Body = ioutil.NopCloser(bytes.NewReader(body))
1089+
1090+
// Perform regexp match
1091+
bodyStr := string(body)
1092+
match, _ := regexp.MatchString(expression, bodyStr)
1093+
if match {
1094+
return nil
1095+
}
1096+
1097+
return fmt.Errorf("received body did not match expected mock body\n%s", diff(expression, bodyStr))
1098+
}
1099+
10671100
func errorOrNil(statement bool, errorMessage func() string) error {
10681101
if statement {
10691102
return nil
@@ -1087,6 +1120,7 @@ var defaultMatchers = []Matcher{
10871120
formDataPresentMatcher,
10881121
formDataNotPresentMatcher,
10891122
bodyMatcher,
1123+
bodyRegexpMatcher,
10901124
cookieMatcher,
10911125
cookiePresentMatcher,
10921126
cookieNotPresentMatcher,

mocks_test.go

+27-4
Original file line numberDiff line numberDiff line change
@@ -617,10 +617,6 @@ func TestMocks_BodyMatcher(t *testing.T) {
617617
}{
618618
{`{"a": 1}`, "", nil},
619619
{``, `{"a":1}`, errors.New("expected a body but received none")},
620-
{"golang\n", "go[lang]?", nil},
621-
{"golang\n", "go[lang]?", nil},
622-
{"go\n", "go[lang]?", nil},
623-
{`{"a":"12345"}\n`, `{"a":"12345"}`, nil},
624620
{`{"x":"12345"}`, `{"x":"12345"}`, nil},
625621
{`{"a": 12345, "b": [{"key": "c", "value": "result"}]}`,
626622
`{"b":[{"key":"c","value":"result"}],"a":12345}`, nil},
@@ -635,6 +631,33 @@ func TestMocks_BodyMatcher(t *testing.T) {
635631
}
636632
}
637633

634+
func TestMocks_BodyMatcher_Regexp(t *testing.T) {
635+
tests := []struct {
636+
requestBody string
637+
matchBody string
638+
expectedError error
639+
}{
640+
{"golang\n", "go[lang]?", nil},
641+
{"golang\n", "go[lang]?", nil},
642+
{"go\n", "go[lang]?", nil},
643+
{`{"a":"12345"}\n`, `{"a":"12345"}`, nil},
644+
}
645+
646+
for _, test := range tests {
647+
t.Run(fmt.Sprintf("body=%v", test.matchBody), func(t *testing.T) {
648+
req := httptest.NewRequest(http.MethodGet, "/path", strings.NewReader(test.requestBody))
649+
matchError := bodyRegexpMatcher(req, NewMock().Get("/path").Body(test.matchBody))
650+
assert.Equal(t, test.expectedError, matchError)
651+
})
652+
}
653+
}
654+
655+
func TestMocks_BodyMatcher_SupportsRawArrays(t *testing.T) {
656+
req := httptest.NewRequest(http.MethodGet, "/path", strings.NewReader(`[{"a":1, "b": 2, "c": "something"}]`))
657+
matchError := bodyMatcher(req, NewMock().Get("/path").JSON(`[{"b": 2, "c": "something", "a": 1}]`))
658+
assert.NoError(t, matchError)
659+
}
660+
638661
func TestMocks_RequestBody(t *testing.T) {
639662
tests := map[string]struct {
640663
requestBody interface{}

0 commit comments

Comments
 (0)