diff --git a/matchers.go b/matchers.go index 85e3bb51d..223f6ef53 100644 --- a/matchers.go +++ b/matchers.go @@ -423,7 +423,8 @@ func BeADirectory() types.GomegaMatcher { //Expected must be either an int or a string. // Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) // asserts that resp.StatusCode == 200 // Expect(resp).Should(HaveHTTPStatus("404 Not Found")) // asserts that resp.Status == "404 Not Found" -func HaveHTTPStatus(expected interface{}) types.GomegaMatcher { +// Expect(resp).Should(HaveHTTPStatus(http.StatusOK, http.StatusNoContent)) // asserts that resp.StatusCode == 200 || resp.StatusCode == 204 +func HaveHTTPStatus(expected ...interface{}) types.GomegaMatcher { return &matchers.HaveHTTPStatusMatcher{Expected: expected} } diff --git a/matchers/have_http_status_matcher.go b/matchers/have_http_status_matcher.go index 6dfb35fa9..70f54899a 100644 --- a/matchers/have_http_status_matcher.go +++ b/matchers/have_http_status_matcher.go @@ -12,7 +12,7 @@ import ( ) type HaveHTTPStatusMatcher struct { - Expected interface{} + Expected []interface{} } func (matcher *HaveHTTPStatusMatcher) Match(actual interface{}) (success bool, err error) { @@ -26,22 +26,42 @@ func (matcher *HaveHTTPStatusMatcher) Match(actual interface{}) (success bool, e return false, fmt.Errorf("HaveHTTPStatus matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n%s", format.Object(actual, 1)) } - switch e := matcher.Expected.(type) { - case int: - return resp.StatusCode == e, nil - case string: - return resp.Status == e, nil + if len(matcher.Expected) == 0 { + return false, fmt.Errorf("HaveHTTPStatus matcher must be passed an int or a string. Got nothing") } - return false, fmt.Errorf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n%s", format.Object(matcher.Expected, 1)) + for _, expected := range matcher.Expected { + switch e := expected.(type) { + case int: + if resp.StatusCode == e { + return true, nil + } + case string: + if resp.Status == e { + return true, nil + } + default: + return false, fmt.Errorf("HaveHTTPStatus matcher must be passed int or string types. Got:\n%s", format.Object(expected, 1)) + } + } + + return false, nil } func (matcher *HaveHTTPStatusMatcher) FailureMessage(actual interface{}) (message string) { - return fmt.Sprintf("Expected\n%s\n%s\n%s", formatHttpResponse(actual), "to have HTTP status", format.Object(matcher.Expected, 1)) + return fmt.Sprintf("Expected\n%s\n%s\n%s", formatHttpResponse(actual), "to have HTTP status", matcher.expectedString()) } func (matcher *HaveHTTPStatusMatcher) NegatedFailureMessage(actual interface{}) (message string) { - return fmt.Sprintf("Expected\n%s\n%s\n%s", formatHttpResponse(actual), "not to have HTTP status", format.Object(matcher.Expected, 1)) + return fmt.Sprintf("Expected\n%s\n%s\n%s", formatHttpResponse(actual), "not to have HTTP status", matcher.expectedString()) +} + +func (matcher *HaveHTTPStatusMatcher) expectedString() string { + var lines []string + for _, expected := range matcher.Expected { + lines = append(lines, format.Object(expected, 1)) + } + return strings.Join(lines, "\n") } func formatHttpResponse(input interface{}) string { diff --git a/matchers/have_http_status_matcher_test.go b/matchers/have_http_status_matcher_test.go index 741f8d359..43220225b 100644 --- a/matchers/have_http_status_matcher_test.go +++ b/matchers/have_http_status_matcher_test.go @@ -11,31 +11,68 @@ import ( ) var _ = Describe("HaveHTTPStatus", func() { - When("ACTUAL is *http.Response", func() { - When("EXPECTED is integer", func() { - It("matches the StatusCode", func() { + When("EXPECTED is single integer", func() { + It("matches the StatusCode", func() { + resp := &http.Response{StatusCode: http.StatusOK} + Expect(resp).To(HaveHTTPStatus(http.StatusOK)) + Expect(resp).NotTo(HaveHTTPStatus(http.StatusNotFound)) + }) + }) + + When("EXPECTED is single string", func() { + It("matches the Status", func() { + resp := &http.Response{Status: "200 OK"} + Expect(resp).To(HaveHTTPStatus("200 OK")) + Expect(resp).NotTo(HaveHTTPStatus("404 Not Found")) + }) + }) + + When("EXPECTED is empty", func() { + It("errors", func() { + failures := InterceptGomegaFailures(func() { resp := &http.Response{StatusCode: http.StatusOK} - Expect(resp).To(HaveHTTPStatus(http.StatusOK)) - Expect(resp).NotTo(HaveHTTPStatus(http.StatusNotFound)) + Expect(resp).To(HaveHTTPStatus()) }) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal("HaveHTTPStatus matcher must be passed an int or a string. Got nothing")) }) + }) - When("EXPECTED is string", func() { - It("matches the Status", func() { - resp := &http.Response{Status: "200 OK"} - Expect(resp).To(HaveHTTPStatus("200 OK")) - Expect(resp).NotTo(HaveHTTPStatus("404 Not Found")) + When("EXPECTED is not a string or integer", func() { + It("errors", func() { + failures := InterceptGomegaFailures(func() { + resp := &http.Response{StatusCode: http.StatusOK} + Expect(resp).To(HaveHTTPStatus(true)) }) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal("HaveHTTPStatus matcher must be passed int or string types. Got:\n : true")) }) + }) - When("EXPECTED is anything else", func() { - It("does not match", func() { - failures := InterceptGomegaFailures(func() { - resp := &http.Response{StatusCode: http.StatusOK} - Expect(resp).NotTo(HaveHTTPStatus(true)) - }) - Expect(failures).To(ConsistOf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n : true")) + When("EXPECTED is a list of strings and integers", func() { + It("matches the StatusCode and Status", func() { + resp := &http.Response{ + Status: "200 OK", + StatusCode: http.StatusOK, + } + Expect(resp).To(HaveHTTPStatus(http.StatusOK, http.StatusNoContent, http.StatusNotFound)) + Expect(resp).To(HaveHTTPStatus("204 Feeling Fine", "200 OK", "404 Not Found")) + Expect(resp).To(HaveHTTPStatus("204 Feeling Fine", http.StatusOK, "404 Not Found")) + Expect(resp).To(HaveHTTPStatus(http.StatusNoContent, "200 OK", http.StatusNotFound)) + Expect(resp).NotTo(HaveHTTPStatus(http.StatusNotFound, http.StatusNoContent, http.StatusGone)) + Expect(resp).NotTo(HaveHTTPStatus("204 Feeling Fine", "201 Sleeping", "404 Not Found")) + Expect(resp).NotTo(HaveHTTPStatus(http.StatusNotFound, "404 Not Found", http.StatusGone)) + }) + }) + + When("EXPECTED is a list containing non-string or integer types", func() { + It("errors", func() { + failures := InterceptGomegaFailures(func() { + resp := &http.Response{StatusCode: http.StatusOK} + Expect(resp).To(HaveHTTPStatus(http.StatusGone, "204 No Content", true, http.StatusNotFound)) }) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal("HaveHTTPStatus matcher must be passed int or string types. Got:\n : true")) }) }) @@ -62,7 +99,8 @@ var _ = Describe("HaveHTTPStatus", func() { resp := &httptest.ResponseRecorder{Code: http.StatusOK} Expect(resp).NotTo(HaveHTTPStatus(nil)) }) - Expect(failures).To(ConsistOf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n : nil")) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal("HaveHTTPStatus matcher must be passed int or string types. Got:\n : nil")) }) }) }) @@ -72,12 +110,13 @@ var _ = Describe("HaveHTTPStatus", func() { failures := InterceptGomegaFailures(func() { Expect("foo").To(HaveHTTPStatus(http.StatusOK)) }) - Expect(failures).To(ConsistOf("HaveHTTPStatus matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n : foo")) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal("HaveHTTPStatus matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n : foo")) }) }) Describe("FailureMessage", func() { - It("returns message", func() { + It("returns a message for a single expected value", func() { failures := InterceptGomegaFailures(func() { resp := &http.Response{ StatusCode: http.StatusBadGateway, @@ -96,10 +135,32 @@ var _ = Describe("HaveHTTPStatus", func() { to have HTTP status : 200`), failures[0]) }) + + It("returns a message for a multiple expected values", func() { + failures := InterceptGomegaFailures(func() { + resp := &http.Response{ + StatusCode: http.StatusBadGateway, + Status: "502 Bad Gateway", + Body: ioutil.NopCloser(strings.NewReader("did not like it")), + } + Expect(resp).To(HaveHTTPStatus(http.StatusOK, http.StatusNotFound, "204 No content")) + }) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal(`Expected + <*http.Response>: { + Status: : "502 Bad Gateway" + StatusCode: : 502 + Body: : "did not like it" + } +to have HTTP status + : 200 + : 404 + : 204 No content`), failures[0]) + }) }) Describe("NegatedFailureMessage", func() { - It("returns message", func() { + It("returns a message for a single expected value", func() { failures := InterceptGomegaFailures(func() { resp := &http.Response{ StatusCode: http.StatusOK, @@ -118,5 +179,27 @@ to have HTTP status not to have HTTP status : 200`), failures[0]) }) + + It("returns a message for a multiple expected values", func() { + failures := InterceptGomegaFailures(func() { + resp := &http.Response{ + StatusCode: http.StatusOK, + Status: "200 OK", + Body: ioutil.NopCloser(strings.NewReader("got it!")), + } + Expect(resp).NotTo(HaveHTTPStatus(http.StatusOK, "204 No content", http.StatusGone)) + }) + Expect(failures).To(HaveLen(1)) + Expect(failures[0]).To(Equal(`Expected + <*http.Response>: { + Status: : "200 OK" + StatusCode: : 200 + Body: : "got it!" + } +not to have HTTP status + : 200 + : 204 No content + : 410`), failures[0]) + }) }) })