diff --git a/gock_test.go b/gock_test.go index 4254be1..7430d83 100644 --- a/gock_test.go +++ b/gock_test.go @@ -98,6 +98,23 @@ func TestMockBodyMatchJSON(t *testing.T) { st.Expect(t, string(body)[:13], `{"bar":"foo"}`) } +func TestMockBodyMatchMultiple(t *testing.T) { + defer after() + New("http://foo.com"). + Post("/bar"). + JSON(map[string]string{"foo": "bar", "baz": "foo"}). + BodyString("baz"). + BodyString("bar"). + Reply(201). + BodyString("intercepted") + + res, err := http.Post("http://foo.com/bar", "application/json", bytes.NewBuffer([]byte(`{"foo":"bar", "baz":"foo"}`))) + st.Expect(t, err, nil) + st.Expect(t, res.StatusCode, 201) + body, _ := ioutil.ReadAll(res.Body) + st.Expect(t, string(body), `intercepted`) +} + func TestMockBodyCannotMatchJSON(t *testing.T) { defer after() New("http://foo.com"). diff --git a/matchers.go b/matchers.go index ca0898a..25f338d 100644 --- a/matchers.go +++ b/matchers.go @@ -112,76 +112,80 @@ func MatchQueryParams(req *http.Request, ereq *Request) (bool, error) { // MatchBody tries to match the request body. // TODO: not too smart now, needs several improvements. func MatchBody(req *http.Request, ereq *Request) (bool, error) { - // If match body is empty, just continue - if req.Method == "HEAD" || len(ereq.BodyBuffer) == 0 { - return true, nil - } - - // Only can match certain MIME body types - if !supportedType(req) { - return false, nil - } + for _, bodyBuffer := range ereq.BodyMatchers { + // If match body is empty, just continue + if req.Method == "HEAD" || len(bodyBuffer) == 0 { + continue + } - // Can only match certain compression schemes - if !supportedCompressionScheme(req) { - return false, nil - } + // Only can match certain MIME body types + if !supportedType(req) { + return false, nil + } - // Create a reader for the body depending on compression type - bodyReader := req.Body - if ereq.CompressionScheme != "" { - if ereq.CompressionScheme != req.Header.Get("Content-Encoding") { + // Can only match certain compression schemes + if !supportedCompressionScheme(req) { return false, nil } - compressedBodyReader, err := compressionReader(req.Body, ereq.CompressionScheme) + + // Create a reader for the body depending on compression type + bodyReader := req.Body + if ereq.CompressionScheme != "" { + if ereq.CompressionScheme != req.Header.Get("Content-Encoding") { + return false, nil + } + compressedBodyReader, err := compressionReader(req.Body, ereq.CompressionScheme) + if err != nil { + return false, err + } + bodyReader = compressedBodyReader + } + + // Read the whole request body + body, err := ioutil.ReadAll(bodyReader) if err != nil { return false, err } - bodyReader = compressedBodyReader - } - // Read the whole request body - body, err := ioutil.ReadAll(bodyReader) - if err != nil { - return false, err - } + // Restore body reader stream + req.Body = createReadCloser(body) - // Restore body reader stream - req.Body = createReadCloser(body) + // If empty, ignore the match + if len(body) == 0 && len(bodyBuffer) != 0 { + return false, nil + } - // If empty, ignore the match - if len(body) == 0 && len(ereq.BodyBuffer) != 0 { - return false, nil - } + // Match body by atomic string comparison + bodyStr := castToString(body) + matchStr := castToString(bodyBuffer) + if bodyStr == matchStr { + continue + } - // Match body by atomic string comparison - bodyStr := castToString(body) - matchStr := castToString(ereq.BodyBuffer) - if bodyStr == matchStr { - return true, nil - } + // Match request body by regexp + match, _ := regexp.MatchString(matchStr, bodyStr) + if match == true { + continue + } - // Match request body by regexp - match, _ := regexp.MatchString(matchStr, bodyStr) - if match == true { - return true, nil - } + // todo - add conditional do only perform the conversion of body bytes + // representation of JSON to a map and then compare them for equality. - // todo - add conditional do only perform the conversion of body bytes - // representation of JSON to a map and then compare them for equality. + // Check if the key + value pairs match + var bodyMap map[string]interface{} + var matchMap map[string]interface{} - // Check if the key + value pairs match - var bodyMap map[string]interface{} - var matchMap map[string]interface{} + // Ensure that both byte bodies that that should be JSON can be converted to maps. + umErr := json.Unmarshal(body, &bodyMap) + umErr2 := json.Unmarshal(bodyBuffer, &matchMap) + if umErr == nil && umErr2 == nil && reflect.DeepEqual(bodyMap, matchMap) { + continue + } - // Ensure that both byte bodies that that should be JSON can be converted to maps. - umErr := json.Unmarshal(body, &bodyMap) - umErr2 := json.Unmarshal(ereq.BodyBuffer, &matchMap) - if umErr == nil && umErr2 == nil && reflect.DeepEqual(bodyMap, matchMap) { - return true, nil + return false, nil } - return false, nil + return true, nil } func supportedType(req *http.Request) bool { diff --git a/matchers_test.go b/matchers_test.go index 23d395f..808dca7 100644 --- a/matchers_test.go +++ b/matchers_test.go @@ -177,7 +177,7 @@ func TestMatchBody(t *testing.T) { for _, test := range cases { req := &http.Request{Body: createReadCloser([]byte(test.body))} - ereq := &Request{BodyBuffer: []byte(test.value)} + ereq := &Request{BodyMatchers: [][]byte{[]byte(test.value)}} matches, err := MatchBody(req, ereq) st.Expect(t, err, nil) st.Expect(t, matches, test.matches) diff --git a/request.go b/request.go index cee9a55..6c3badf 100644 --- a/request.go +++ b/request.go @@ -47,8 +47,8 @@ type Request struct { // Cookies stores the Request HTTP cookies values to match. Cookies []*http.Cookie - // BodyBuffer stores the body data to match. - BodyBuffer []byte + // BodyMatchers stores the body data to match. + BodyMatchers [][]byte // Mappers stores the request functions mappers used for matching. Mappers []MapRequestFunc @@ -125,19 +125,23 @@ func (r *Request) method(method, path string) *Request { // Body defines the body data to match based on a io.Reader interface. func (r *Request) Body(body io.Reader) *Request { - r.BodyBuffer, r.Error = ioutil.ReadAll(body) + var bodyBuffer []byte + bodyBuffer, r.Error = ioutil.ReadAll(body) + r.BodyMatchers = append(r.BodyMatchers, bodyBuffer) return r } // BodyString defines the body to match based on a given string. func (r *Request) BodyString(body string) *Request { - r.BodyBuffer = []byte(body) + r.BodyMatchers = append(r.BodyMatchers, []byte(body)) return r } // File defines the body to match based on the given file path string. func (r *Request) File(path string) *Request { - r.BodyBuffer, r.Error = ioutil.ReadFile(path) + var bodyBuffer []byte + bodyBuffer, r.Error = ioutil.ReadFile(path) + r.BodyMatchers = append(r.BodyMatchers, bodyBuffer) return r } @@ -154,7 +158,10 @@ func (r *Request) JSON(data interface{}) *Request { if r.Header.Get("Content-Type") == "" { r.Header.Set("Content-Type", "application/json") } - r.BodyBuffer, r.Error = readAndDecode(data, "json") + + var bodyBuffer []byte + bodyBuffer, r.Error = readAndDecode(data, "json") + r.BodyMatchers = append(r.BodyMatchers, bodyBuffer) return r } @@ -163,7 +170,10 @@ func (r *Request) XML(data interface{}) *Request { if r.Header.Get("Content-Type") == "" { r.Header.Set("Content-Type", "application/xml") } - r.BodyBuffer, r.Error = readAndDecode(data, "xml") + + var bodyBuffer []byte + bodyBuffer, r.Error = readAndDecode(data, "xml") + r.BodyMatchers = append(r.BodyMatchers, bodyBuffer) return r } diff --git a/request_test.go b/request_test.go index 666c892..7f6e2f5 100644 --- a/request_test.go +++ b/request_test.go @@ -38,25 +38,25 @@ func TestRequestPath(t *testing.T) { func TestRequestBody(t *testing.T) { req := NewRequest() req.Body(bytes.NewBuffer([]byte("foo bar"))) - st.Expect(t, string(req.BodyBuffer), "foo bar") + st.Expect(t, string(req.BodyMatchers[0]), "foo bar") } func TestRequestBodyString(t *testing.T) { req := NewRequest() req.BodyString("foo bar") - st.Expect(t, string(req.BodyBuffer), "foo bar") + st.Expect(t, string(req.BodyMatchers[0]), "foo bar") } func TestRequestFile(t *testing.T) { req := NewRequest() req.File("version.go") - st.Expect(t, string(req.BodyBuffer)[:12], "package gock") + st.Expect(t, string(req.BodyMatchers[0])[:12], "package gock") } func TestRequestJSON(t *testing.T) { req := NewRequest() req.JSON(map[string]string{"foo": "bar"}) - st.Expect(t, string(req.BodyBuffer)[:13], `{"foo":"bar"}`) + st.Expect(t, string(req.BodyMatchers[0])[:13], `{"foo":"bar"}`) st.Expect(t, req.Header.Get("Content-Type"), "application/json") } @@ -66,10 +66,25 @@ func TestRequestXML(t *testing.T) { Data string `xml:"data"` } req.XML(xml{Data: "foo"}) - st.Expect(t, string(req.BodyBuffer), `foo`) + st.Expect(t, string(req.BodyMatchers[0]), `foo`) st.Expect(t, req.Header.Get("Content-Type"), "application/xml") } +func TestRequestMultipleMatchers(t *testing.T) { + // Body() + req := NewRequest() + req.Body(bytes.NewBuffer([]byte("foo bar"))) + // BodyString() + req.BodyString("foo bar") + // JSON() + req.JSON(map[string]string{"foo": "bar"}) + + st.Expect(t, string(req.BodyMatchers[0]), "foo bar") + st.Expect(t, string(req.BodyMatchers[1]), "foo bar") + st.Expect(t, string(req.BodyMatchers[2])[:13], `{"foo":"bar"}`) + st.Expect(t, req.Header.Get("Content-Type"), "application/json") +} + func TestRequestMatchType(t *testing.T) { req := NewRequest() req.MatchType("json")