diff --git a/hammy/httpassert/example_test.go b/hammy/httpassert/example_test.go index cc1aec1..71e7bda 100644 --- a/hammy/httpassert/example_test.go +++ b/hammy/httpassert/example_test.go @@ -9,52 +9,52 @@ import ( "github.com/gogunit/gunit/hammy/httpassert" ) -func ExampleStatus() { - printExample(httpassert.Status(exampleResponse(http.StatusCreated, nil, ""), http.StatusCreated)) +func ExampleResp_Status() { + printExample(httpassert.Response(exampleResponse(http.StatusCreated, nil, "")).Status(http.StatusCreated)) // Output: // message="got status <201>, wanted <201>" // success=true } -func ExampleStatusInRange() { - printExample(httpassert.StatusInRange(exampleResponse(http.StatusNoContent, nil, ""), 200, 299)) +func ExampleResp_StatusInRange() { + printExample(httpassert.Response(exampleResponse(http.StatusNoContent, nil, "")).StatusInRange(200, 299)) // Output: // message="got status <204>, wanted in range <200..299>" // success=true } -func ExampleHeader() { +func ExampleResp_Header() { resp := exampleResponse(http.StatusOK, http.Header{"Content-Type": {"application/json"}}, "") - printExample(httpassert.Header(resp, "Content-Type", "application/json")) + printExample(httpassert.Response(resp).Header("Content-Type", "application/json")) // Output: // message="got header =, wanted " // success=true } -func ExampleHeaderContains() { +func ExampleResp_HeaderContains() { resp := exampleResponse(http.StatusOK, http.Header{"Content-Type": {"application/json; charset=utf-8"}}, "") - printExample(httpassert.HeaderContains(resp, "Content-Type", "application/json")) + printExample(httpassert.Response(resp).HeaderContains("Content-Type", "application/json")) // Output: // message="got header =, wanted containing " // success=true } -func ExampleBodyEqual() { - printExample(httpassert.BodyEqual(exampleResponse(http.StatusOK, nil, "hello world"), "hello world")) +func ExampleResp_BodyEqual() { + printExample(httpassert.Response(exampleResponse(http.StatusOK, nil, "hello world")).BodyEqual("hello world")) // Output: // message="got body , wanted equal to " // success=true } -func ExampleBodyContains() { - printExample(httpassert.BodyContains(exampleResponse(http.StatusOK, nil, "hello world"), "world")) +func ExampleResp_BodyContains() { + printExample(httpassert.Response(exampleResponse(http.StatusOK, nil, "hello world")).BodyContains("world")) // Output: // message="got body , wanted containing " // success=true } -func ExampleBodyMatchesRegexp() { - printExample(httpassert.BodyMatchesRegexp(exampleResponse(http.StatusOK, nil, "status 204"), `status \d+`)) +func ExampleResp_BodyMatchesRegexp() { + printExample(httpassert.Response(exampleResponse(http.StatusOK, nil, "status 204")).BodyMatchesRegexp(`status \d+`)) // Output: // message="got body , wanted regexp " // success=true diff --git a/hammy/httpassert/httpassert.go b/hammy/httpassert/httpassert.go index 5e9c04d..bbccf2b 100644 --- a/hammy/httpassert/httpassert.go +++ b/hammy/httpassert/httpassert.go @@ -10,14 +10,24 @@ import ( "github.com/gogunit/gunit/hammy" ) -func Status(resp *http.Response, expected int) hammy.AssertionMessage { +func Response(resp *http.Response) *Resp { + return &Resp{actual: resp} +} + +type Resp struct { + actual *http.Response +} + +func (r *Resp) Status(expected int) hammy.AssertionMessage { + resp := r.response() if resp == nil { return hammy.Assert(false, "got nil response, wanted status <%d>", expected) } return hammy.Assert(resp.StatusCode == expected, "got status <%d>, wanted <%d>", resp.StatusCode, expected) } -func StatusInRange(resp *http.Response, min, max int) hammy.AssertionMessage { +func (r *Resp) StatusInRange(min, max int) hammy.AssertionMessage { + resp := r.response() if min > max { return hammy.Assert(false, "got invalid status range <%d..%d>", min, max) } @@ -27,7 +37,8 @@ func StatusInRange(resp *http.Response, min, max int) hammy.AssertionMessage { return hammy.Assert(resp.StatusCode >= min && resp.StatusCode <= max, "got status <%d>, wanted in range <%d..%d>", resp.StatusCode, min, max) } -func Header(resp *http.Response, key, expected string) hammy.AssertionMessage { +func (r *Resp) Header(key, expected string) hammy.AssertionMessage { + resp := r.response() if resp == nil { return hammy.Assert(false, "got nil response, wanted header <%s> equal to <%s>", key, expected) } @@ -35,7 +46,8 @@ func Header(resp *http.Response, key, expected string) hammy.AssertionMessage { return hammy.Assert(actual == expected, "got header <%s>=<%s>, wanted <%s>", key, actual, expected) } -func HeaderContains(resp *http.Response, key, expected string) hammy.AssertionMessage { +func (r *Resp) HeaderContains(key, expected string) hammy.AssertionMessage { + resp := r.response() if resp == nil { return hammy.Assert(false, "got nil response, wanted header <%s> containing <%s>", key, expected) } @@ -43,24 +55,24 @@ func HeaderContains(resp *http.Response, key, expected string) hammy.AssertionMe return hammy.Assert(strings.Contains(actual, expected), "got header <%s>=<%s>, wanted containing <%s>", key, actual, expected) } -func BodyEqual(resp *http.Response, expected string) hammy.AssertionMessage { - actual, result := readBody(resp) +func (r *Resp) BodyEqual(expected string) hammy.AssertionMessage { + actual, result := readBody(r.response()) if !result.IsSuccessful { return result } return hammy.Assert(actual == expected, "got body <%s>, wanted equal to <%s>", actual, expected) } -func BodyContains(resp *http.Response, expected string) hammy.AssertionMessage { - actual, result := readBody(resp) +func (r *Resp) BodyContains(expected string) hammy.AssertionMessage { + actual, result := readBody(r.response()) if !result.IsSuccessful { return result } return hammy.Assert(strings.Contains(actual, expected), "got body <%s>, wanted containing <%s>", actual, expected) } -func BodyMatchesRegexp(resp *http.Response, pattern string) hammy.AssertionMessage { - actual, result := readBody(resp) +func (r *Resp) BodyMatchesRegexp(pattern string) hammy.AssertionMessage { + actual, result := readBody(r.response()) if !result.IsSuccessful { return result } @@ -72,6 +84,13 @@ func BodyMatchesRegexp(resp *http.Response, pattern string) hammy.AssertionMessa return hammy.Assert(re.MatchString(actual), "got body <%s>, wanted regexp <%s>", actual, pattern) } +func (r *Resp) response() *http.Response { + if r == nil { + return nil + } + return r.actual +} + func readBody(resp *http.Response) (string, hammy.AssertionMessage) { if resp == nil { return "", hammy.Assert(false, "got nil response, wanted response body") diff --git a/hammy/httpassert/httpassert_test.go b/hammy/httpassert/httpassert_test.go index 929ec84..02a6e01 100644 --- a/hammy/httpassert/httpassert_test.go +++ b/hammy/httpassert/httpassert_test.go @@ -5,9 +5,9 @@ import ( "io" "net/http" "net/http/httptest" - "strings" "testing" + "github.com/gogunit/gunit/eye" "github.com/gogunit/gunit/hammy" "github.com/gogunit/gunit/hammy/httpassert" ) @@ -16,137 +16,173 @@ func Test_Status_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusCreated, nil, "") - assert.Is(httpassert.Status(resp, http.StatusCreated)) + assert.Is(httpassert.Response(resp).Status(http.StatusCreated)) } func Test_Status_failure(t *testing.T) { - result := httpassert.Status(newResponse(http.StatusCreated, nil, ""), http.StatusOK) + result := httpassert.Response(newResponse(http.StatusCreated, nil, "")).Status(http.StatusOK) - requireFailure(t, result, "got status <201>, wanted <200>") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got status <201>, wanted <200>") } func Test_Status_failure_nil_response(t *testing.T) { - result := httpassert.Status(nil, http.StatusOK) + result := httpassert.Response(nil).Status(http.StatusOK) - requireFailure(t, result, "got nil response") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got nil response") } func Test_StatusInRange_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusNoContent, nil, "") - assert.Is(httpassert.StatusInRange(resp, 200, 299)) + assert.Is(httpassert.Response(resp).StatusInRange(200, 299)) } func Test_StatusInRange_failure(t *testing.T) { - result := httpassert.StatusInRange(newResponse(http.StatusBadRequest, nil, ""), 200, 299) + result := httpassert.Response(newResponse(http.StatusBadRequest, nil, "")).StatusInRange(200, 299) - requireFailure(t, result, "got status <400>, wanted in range <200..299>") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got status <400>, wanted in range <200..299>") } func Test_StatusInRange_failure_invalid_range(t *testing.T) { - result := httpassert.StatusInRange(newResponse(http.StatusOK, nil, ""), 299, 200) + result := httpassert.Response(newResponse(http.StatusOK, nil, "")).StatusInRange(299, 200) - requireFailure(t, result, "got invalid status range <299..200>") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got invalid status range <299..200>") } func Test_Header_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusOK, http.Header{"Content-Type": {"application/json"}}, "") - assert.Is(httpassert.Header(resp, "Content-Type", "application/json")) + assert.Is(httpassert.Response(resp).Header("Content-Type", "application/json")) } func Test_Header_failure(t *testing.T) { resp := newResponse(http.StatusOK, http.Header{"Content-Type": {"text/plain"}}, "") - result := httpassert.Header(resp, "Content-Type", "application/json") + result := httpassert.Response(resp).Header("Content-Type", "application/json") - requireFailure(t, result, "got header =, wanted ") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got header =, wanted ") } func Test_HeaderContains_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusOK, http.Header{"Content-Type": {"application/json; charset=utf-8"}}, "") - assert.Is(httpassert.HeaderContains(resp, "Content-Type", "application/json")) + assert.Is(httpassert.Response(resp).HeaderContains("Content-Type", "application/json")) } func Test_HeaderContains_failure(t *testing.T) { resp := newResponse(http.StatusOK, http.Header{"Content-Type": {"text/plain"}}, "") - result := httpassert.HeaderContains(resp, "Content-Type", "application/json") + result := httpassert.Response(resp).HeaderContains("Content-Type", "application/json") - requireFailure(t, result, "got header =, wanted containing ") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got header =, wanted containing ") } func Test_BodyEqual_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusOK, nil, "hello world") - assert.Is(httpassert.BodyEqual(resp, "hello world")) + assert.Is(httpassert.Response(resp).BodyEqual("hello world")) } func Test_BodyEqual_failure(t *testing.T) { resp := newResponse(http.StatusOK, nil, "hello world") - result := httpassert.BodyEqual(resp, "goodbye") + result := httpassert.Response(resp).BodyEqual("goodbye") - requireFailure(t, result, "got body , wanted equal to ") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got body , wanted equal to ") } func Test_BodyContains_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusOK, nil, "hello world") - assert.Is(httpassert.BodyContains(resp, "world")) + assert.Is(httpassert.Response(resp).BodyContains("world")) } func Test_BodyContains_failure(t *testing.T) { resp := newResponse(http.StatusOK, nil, "hello world") - result := httpassert.BodyContains(resp, "goodbye") + result := httpassert.Response(resp).BodyContains("goodbye") - requireFailure(t, result, "got body , wanted containing ") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got body , wanted containing ") } func Test_BodyMatchesRegexp_success(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusOK, nil, "status 204") - assert.Is(httpassert.BodyMatchesRegexp(resp, `status \d+`)) + assert.Is(httpassert.Response(resp).BodyMatchesRegexp(`status \d+`)) } func Test_BodyMatchesRegexp_failure(t *testing.T) { resp := newResponse(http.StatusOK, nil, "status 204") - result := httpassert.BodyMatchesRegexp(resp, `status 5\d\d`) + result := httpassert.Response(resp).BodyMatchesRegexp(`status 5\d\d`) - requireFailure(t, result, "got body , wanted regexp ") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got body , wanted regexp ") } func Test_BodyMatchesRegexp_failure_invalid_pattern(t *testing.T) { resp := newResponse(http.StatusOK, nil, "status 204") - result := httpassert.BodyMatchesRegexp(resp, `(`) + result := httpassert.Response(resp).BodyMatchesRegexp(`(`) - requireFailure(t, result, "invalid regexp <(>") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "invalid regexp <(>") } func Test_Body_assertions_restore_body(t *testing.T) { assert := hammy.New(t) resp := newResponse(http.StatusOK, nil, "hello world") - assert.Is(httpassert.BodyContains(resp, "hello")) - assert.Is(httpassert.BodyEqual(resp, "hello world")) - assert.Is(httpassert.BodyMatchesRegexp(resp, `world$`)) + assert.Is(httpassert.Response(resp).BodyContains("hello")) + assert.Is(httpassert.Response(resp).BodyEqual("hello world")) + assert.Is(httpassert.Response(resp).BodyMatchesRegexp(`world$`)) } func Test_Body_assertion_failure_nil_response(t *testing.T) { - result := httpassert.BodyEqual(nil, "hello") + result := httpassert.Response(nil).BodyEqual("hello") - requireFailure(t, result, "got nil response") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got nil response") } func Test_Body_assertion_failure_read_error(t *testing.T) { resp := &http.Response{Body: errorReadCloser{}} - result := httpassert.BodyEqual(resp, "hello") + result := httpassert.Response(resp).BodyEqual("hello") - requireFailure(t, result, "got body read error: read failed") + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got body read error: read failed") } func newResponse(status int, headers http.Header, body string) *http.Response { @@ -161,16 +197,6 @@ func newResponse(status int, headers http.Header, body string) *http.Response { return recorder.Result() } -func requireFailure(t *testing.T, result hammy.AssertionMessage, contains string) { - t.Helper() - if result.IsSuccessful { - t.Fatalf("got success, wanted failure containing %q", contains) - } - if !strings.Contains(result.Message, contains) { - t.Fatalf("got message %q, wanted containing %q", result.Message, contains) - } -} - type errorReadCloser struct{} func (errorReadCloser) Read([]byte) (int, error) { @@ -182,3 +208,13 @@ func (errorReadCloser) Close() error { } var _ io.ReadCloser = errorReadCloser{} + +func Test_Response_methods_failure_nil_receiver(t *testing.T) { + var resp *httpassert.Resp + result := resp.Status(http.StatusOK) + + aSpy := eye.Spy() + assert := hammy.New(aSpy) + assert.Is(result) + aSpy.HadErrorContaining(t, "got nil response") +}