From 4cfab1be20dd1f2ec38b607b804be01247a3a307 Mon Sep 17 00:00:00 2001 From: Tevic Date: Wed, 26 Jan 2022 11:16:09 +0800 Subject: [PATCH] return err instead of panic in JSON Render --- context.go | 86 +++++++++++++++---------------- context_test.go | 116 ++++++++++++++++++++---------------------- render/json.go | 5 +- render/redirect.go | 2 +- render/render_test.go | 9 ++-- 5 files changed, 101 insertions(+), 117 deletions(-) diff --git a/context.go b/context.go index d69df70b24..0547001211 100644 --- a/context.go +++ b/context.go @@ -195,9 +195,9 @@ func (c *Context) AbortWithStatus(code int) { // AbortWithStatusJSON calls `Abort()` and then `JSON` internally. // This method stops the chain, writes the status code and return a JSON body. // It also sets the Content-Type as "application/json". -func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) { +func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) error { c.Abort() - c.JSON(code, jsonObj) + return c.JSON(code, jsonObj) } // AbortWithError calls `AbortWithStatus()` and `Error()` internally. @@ -884,97 +884,94 @@ func (c *Context) Cookie(name string) (string, error) { } // Render writes the response headers and calls render.Render to render data. -func (c *Context) Render(code int, r render.Render) { +func (c *Context) Render(code int, r render.Render) error { c.Status(code) if !bodyAllowedForStatus(code) { r.WriteContentType(c.Writer) c.Writer.WriteHeaderNow() - return + return nil } - if err := r.Render(c.Writer); err != nil { - panic(err) - } + return r.Render(c.Writer) } // HTML renders the HTTP template specified by its file name. // It also updates the HTTP code and sets the Content-Type as "text/html". // See http://golang.org/doc/articles/wiki/ -func (c *Context) HTML(code int, name string, obj interface{}) { +func (c *Context) HTML(code int, name string, obj interface{}) error { instance := c.engine.HTMLRender.Instance(name, obj) - c.Render(code, instance) + return c.Render(code, instance) } // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. // It also sets the Content-Type as "application/json". // WARNING: we recommend using this only for development purposes since printing pretty JSON is // more CPU and bandwidth consuming. Use Context.JSON() instead. -func (c *Context) IndentedJSON(code int, obj interface{}) { - c.Render(code, render.IndentedJSON{Data: obj}) +func (c *Context) IndentedJSON(code int, obj interface{}) error { + return c.Render(code, render.IndentedJSON{Data: obj}) } // SecureJSON serializes the given struct as Secure JSON into the response body. // Default prepends "while(1)," to response body if the given struct is array values. // It also sets the Content-Type as "application/json". -func (c *Context) SecureJSON(code int, obj interface{}) { - c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj}) +func (c *Context) SecureJSON(code int, obj interface{}) error { + return c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj}) } // JSONP serializes the given struct as JSON into the response body. // It adds padding to response body to request data from a server residing in a different domain than the client. // It also sets the Content-Type as "application/javascript". -func (c *Context) JSONP(code int, obj interface{}) { +func (c *Context) JSONP(code int, obj interface{}) error { callback := c.DefaultQuery("callback", "") if callback == "" { - c.Render(code, render.JSON{Data: obj}) - return + return c.Render(code, render.JSON{Data: obj}) } - c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) + return c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) } // JSON serializes the given struct as JSON into the response body. // It also sets the Content-Type as "application/json". -func (c *Context) JSON(code int, obj interface{}) { - c.Render(code, render.JSON{Data: obj}) +func (c *Context) JSON(code int, obj interface{}) error { + return c.Render(code, render.JSON{Data: obj}) } // AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. // It also sets the Content-Type as "application/json". -func (c *Context) AsciiJSON(code int, obj interface{}) { - c.Render(code, render.AsciiJSON{Data: obj}) +func (c *Context) AsciiJSON(code int, obj interface{}) error { + return c.Render(code, render.AsciiJSON{Data: obj}) } // PureJSON serializes the given struct as JSON into the response body. // PureJSON, unlike JSON, does not replace special html characters with their unicode entities. -func (c *Context) PureJSON(code int, obj interface{}) { - c.Render(code, render.PureJSON{Data: obj}) +func (c *Context) PureJSON(code int, obj interface{}) error { + return c.Render(code, render.PureJSON{Data: obj}) } // XML serializes the given struct as XML into the response body. // It also sets the Content-Type as "application/xml". -func (c *Context) XML(code int, obj interface{}) { - c.Render(code, render.XML{Data: obj}) +func (c *Context) XML(code int, obj interface{}) error { + return c.Render(code, render.XML{Data: obj}) } // YAML serializes the given struct as YAML into the response body. -func (c *Context) YAML(code int, obj interface{}) { - c.Render(code, render.YAML{Data: obj}) +func (c *Context) YAML(code int, obj interface{}) error { + return c.Render(code, render.YAML{Data: obj}) } // ProtoBuf serializes the given struct as ProtoBuf into the response body. -func (c *Context) ProtoBuf(code int, obj interface{}) { - c.Render(code, render.ProtoBuf{Data: obj}) +func (c *Context) ProtoBuf(code int, obj interface{}) error { + return c.Render(code, render.ProtoBuf{Data: obj}) } // String writes the given string into the response body. -func (c *Context) String(code int, format string, values ...interface{}) { - c.Render(code, render.String{Format: format, Data: values}) +func (c *Context) String(code int, format string, values ...interface{}) error { + return c.Render(code, render.String{Format: format, Data: values}) } // Redirect returns an HTTP redirect to the specific location. -func (c *Context) Redirect(code int, location string) { - c.Render(-1, render.Redirect{ +func (c *Context) Redirect(code int, location string) error { + return c.Render(-1, render.Redirect{ Code: code, Location: location, Request: c.Request, @@ -982,16 +979,16 @@ func (c *Context) Redirect(code int, location string) { } // Data writes some data into the body stream and updates the HTTP code. -func (c *Context) Data(code int, contentType string, data []byte) { - c.Render(code, render.Data{ +func (c *Context) Data(code int, contentType string, data []byte) error { + return c.Render(code, render.Data{ ContentType: contentType, Data: data, }) } // DataFromReader writes the specified reader into the body stream and updates the HTTP code. -func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) { - c.Render(code, render.Reader{ +func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) error { + return c.Render(code, render.Reader{ Headers: extraHeaders, ContentType: contentType, ContentLength: contentLength, @@ -1023,8 +1020,8 @@ func (c *Context) FileAttachment(filepath, filename string) { } // SSEvent writes a Server-Sent Event into the body stream. -func (c *Context) SSEvent(name string, message interface{}) { - c.Render(-1, sse.Event{ +func (c *Context) SSEvent(name string, message interface{}) error { + return c.Render(-1, sse.Event{ Event: name, Data: message, }) @@ -1065,26 +1062,27 @@ type Negotiate struct { } // Negotiate calls different Render according to acceptable Accept format. -func (c *Context) Negotiate(code int, config Negotiate) { +func (c *Context) Negotiate(code int, config Negotiate) error { switch c.NegotiateFormat(config.Offered...) { case binding.MIMEJSON: data := chooseData(config.JSONData, config.Data) - c.JSON(code, data) + return c.JSON(code, data) case binding.MIMEHTML: data := chooseData(config.HTMLData, config.Data) - c.HTML(code, config.HTMLName, data) + return c.HTML(code, config.HTMLName, data) case binding.MIMEXML: data := chooseData(config.XMLData, config.Data) - c.XML(code, data) + return c.XML(code, data) case binding.MIMEYAML: data := chooseData(config.YAMLData, config.Data) - c.YAML(code, data) + return c.YAML(code, data) default: c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck + return nil } } diff --git a/context_test.go b/context_test.go index 9e02aede13..796df499fb 100644 --- a/context_test.go +++ b/context_test.go @@ -642,25 +642,18 @@ func TestContextBodyAllowedForStatus(t *testing.T) { assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError)) } -type TestPanicRender struct{} +type TestErrorRender struct{} -func (*TestPanicRender) Render(http.ResponseWriter) error { - return errors.New("TestPanicRender") +func (*TestErrorRender) Render(http.ResponseWriter) error { + return errors.New("TestErrorRender") } -func (*TestPanicRender) WriteContentType(http.ResponseWriter) {} +func (*TestErrorRender) WriteContentType(http.ResponseWriter) {} func TestContextRenderPanicIfErr(t *testing.T) { - defer func() { - r := recover() - assert.Equal(t, "TestPanicRender", fmt.Sprint(r)) - }() w := httptest.NewRecorder() c, _ := CreateTestContext(w) - - c.Render(http.StatusOK, &TestPanicRender{}) - - assert.Fail(t, "Panic not detected") + assert.Error(t, c.Render(http.StatusOK, &TestErrorRender{})) } // Tests that the response is serialized as JSON @@ -670,7 +663,7 @@ func TestContextRenderJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.JSON(http.StatusCreated, H{"foo": "bar", "html": ""}) + assert.NoError(t, c.JSON(http.StatusCreated, H{"foo": "bar", "html": ""})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) @@ -684,7 +677,7 @@ func TestContextRenderJSONP(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("GET", "http://example.com/?callback=x", nil) - c.JSONP(http.StatusCreated, H{"foo": "bar"}) + assert.NoError(t, c.JSONP(http.StatusCreated, H{"foo": "bar"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "x({\"foo\":\"bar\"});", w.Body.String()) @@ -698,7 +691,7 @@ func TestContextRenderJSONPWithoutCallback(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("GET", "http://example.com", nil) - c.JSONP(http.StatusCreated, H{"foo": "bar"}) + assert.NoError(t, c.JSONP(http.StatusCreated, H{"foo": "bar"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) @@ -750,8 +743,7 @@ func TestContextRenderIndentedJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) - + assert.NoError(t, c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) @@ -762,7 +754,7 @@ func TestContextRenderNoContentIndentedJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) + assert.NoError(t, c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -776,7 +768,7 @@ func TestContextRenderSecureJSON(t *testing.T) { c, router := CreateTestContext(w) router.SecureJsonPrefix("&&&START&&&") - c.SecureJSON(http.StatusCreated, []string{"foo", "bar"}) + assert.NoError(t, c.SecureJSON(http.StatusCreated, []string{"foo", "bar"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String()) @@ -788,7 +780,7 @@ func TestContextRenderNoContentSecureJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"}) + assert.NoError(t, c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"})) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -799,7 +791,7 @@ func TestContextRenderNoContentAsciiJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.AsciiJSON(http.StatusNoContent, []string{"lang", "Go语言"}) + assert.NoError(t, c.AsciiJSON(http.StatusNoContent, []string{"lang", "Go语言"})) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -812,7 +804,7 @@ func TestContextRenderNoContentAsciiJSON(t *testing.T) { func TestContextRenderPureJSON(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": ""}) + assert.NoError(t, c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": ""})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String()) assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) @@ -827,7 +819,7 @@ func TestContextRenderHTML(t *testing.T) { templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) - c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) + assert.NoError(t, c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "Hello alexandernyquist", w.Body.String()) @@ -851,7 +843,7 @@ func TestContextRenderHTML2(t *testing.T) { assert.Equal(t, "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n", re) - c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) + assert.NoError(t, c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "Hello alexandernyquist", w.Body.String()) @@ -865,7 +857,7 @@ func TestContextRenderNoContentHTML(t *testing.T) { templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) - c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"}) + assert.NoError(t, c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"})) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -878,7 +870,7 @@ func TestContextRenderXML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.XML(http.StatusCreated, H{"foo": "bar"}) + assert.NoError(t, c.XML(http.StatusCreated, H{"foo": "bar"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "bar", w.Body.String()) @@ -890,7 +882,7 @@ func TestContextRenderNoContentXML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.XML(http.StatusNoContent, H{"foo": "bar"}) + assert.NoError(t, c.XML(http.StatusNoContent, H{"foo": "bar"})) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -903,7 +895,7 @@ func TestContextRenderString(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.String(http.StatusCreated, "test %s %d", "string", 2) + assert.NoError(t, c.String(http.StatusCreated, "test %s %d", "string", 2)) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "test string 2", w.Body.String()) @@ -915,7 +907,7 @@ func TestContextRenderNoContentString(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.String(http.StatusNoContent, "test %s %d", "string", 2) + assert.NoError(t, c.String(http.StatusNoContent, "test %s %d", "string", 2)) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -929,7 +921,7 @@ func TestContextRenderHTMLString(t *testing.T) { c, _ := CreateTestContext(w) c.Header("Content-Type", "text/html; charset=utf-8") - c.String(http.StatusCreated, "%s %d", "string", 3) + assert.NoError(t, c.String(http.StatusCreated, "%s %d", "string", 3)) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "string 3", w.Body.String()) @@ -942,7 +934,7 @@ func TestContextRenderNoContentHTMLString(t *testing.T) { c, _ := CreateTestContext(w) c.Header("Content-Type", "text/html; charset=utf-8") - c.String(http.StatusNoContent, "%s %d", "string", 3) + assert.NoError(t, c.String(http.StatusNoContent, "%s %d", "string", 3)) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -955,7 +947,7 @@ func TestContextRenderData(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`)) + assert.NoError(t, c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`))) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "foo,bar", w.Body.String()) @@ -967,7 +959,7 @@ func TestContextRenderNoContentData(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`)) + assert.NoError(t, c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`))) assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) @@ -978,15 +970,15 @@ func TestContextRenderSSE(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.SSEvent("float", 1.5) - c.Render(-1, sse.Event{ + assert.NoError(t, c.SSEvent("float", 1.5)) + assert.NoError(t, c.Render(-1, sse.Event{ Id: "123", Data: "text", - }) - c.SSEvent("chat", H{ + })) + assert.NoError(t, c.SSEvent("chat", H{ "foo": "bar", "bar": "foo", - }) + })) assert.Equal(t, strings.Replace(w.Body.String(), " ", "", -1), strings.Replace("event:float\ndata:1.5\n\nid:123\ndata:text\n\nevent:chat\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n", " ", "", -1)) } @@ -1039,7 +1031,7 @@ func TestContextRenderYAML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) - c.YAML(http.StatusCreated, H{"foo": "bar"}) + assert.NoError(t, c.YAML(http.StatusCreated, H{"foo": "bar"})) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "foo: bar\n", w.Body.String()) @@ -1060,7 +1052,7 @@ func TestContextRenderProtoBuf(t *testing.T) { Reps: reps, } - c.ProtoBuf(http.StatusCreated, data) + assert.NoError(t, c.ProtoBuf(http.StatusCreated, data)) protoData, err := proto.Marshal(data) assert.NoError(t, err) @@ -1092,10 +1084,10 @@ func TestContextRenderRedirectWithRelativePath(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - assert.Panics(t, func() { c.Redirect(299, "/new_path") }) - assert.Panics(t, func() { c.Redirect(309, "/new_path") }) + assert.Error(t, c.Redirect(299, "/new_path")) + assert.Error(t, c.Redirect(309, "/new_path")) - c.Redirect(http.StatusMovedPermanently, "/path") + assert.NoError(t, c.Redirect(http.StatusMovedPermanently, "/path")) c.Writer.WriteHeaderNow() assert.Equal(t, http.StatusMovedPermanently, w.Code) assert.Equal(t, "/path", w.Header().Get("Location")) @@ -1106,7 +1098,7 @@ func TestContextRenderRedirectWithAbsolutePath(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - c.Redirect(http.StatusFound, "http://google.com") + assert.NoError(t, c.Redirect(http.StatusFound, "http://google.com")) c.Writer.WriteHeaderNow() assert.Equal(t, http.StatusFound, w.Code) @@ -1118,7 +1110,7 @@ func TestContextRenderRedirectWith201(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - c.Redirect(http.StatusCreated, "/resource") + assert.NoError(t, c.Redirect(http.StatusCreated, "/resource")) c.Writer.WriteHeaderNow() assert.Equal(t, http.StatusCreated, w.Code) @@ -1128,12 +1120,12 @@ func TestContextRenderRedirectWith201(t *testing.T) { func TestContextRenderRedirectAll(t *testing.T) { c, _ := CreateTestContext(httptest.NewRecorder()) c.Request, _ = http.NewRequest("POST", "http://example.com", nil) - assert.Panics(t, func() { c.Redirect(http.StatusOK, "/resource") }) - assert.Panics(t, func() { c.Redirect(http.StatusAccepted, "/resource") }) - assert.Panics(t, func() { c.Redirect(299, "/resource") }) - assert.Panics(t, func() { c.Redirect(309, "/resource") }) - assert.NotPanics(t, func() { c.Redirect(http.StatusMultipleChoices, "/resource") }) - assert.NotPanics(t, func() { c.Redirect(http.StatusPermanentRedirect, "/resource") }) + assert.Error(t, c.Redirect(http.StatusOK, "/resource")) + assert.Error(t, c.Redirect(http.StatusAccepted, "/resource")) + assert.Error(t, c.Redirect(299, "/resource")) + assert.Error(t, c.Redirect(309, "/resource")) + assert.NoError(t, c.Redirect(http.StatusMultipleChoices, "/resource")) + assert.NoError(t, c.Redirect(http.StatusPermanentRedirect, "/resource")) } func TestContextNegotiationWithJSON(t *testing.T) { @@ -1141,10 +1133,10 @@ func TestContextNegotiationWithJSON(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "", nil) - c.Negotiate(http.StatusOK, Negotiate{ + assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEJSON, MIMEXML, MIMEYAML}, Data: H{"foo": "bar"}, - }) + })) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) @@ -1156,10 +1148,10 @@ func TestContextNegotiationWithXML(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "", nil) - c.Negotiate(http.StatusOK, Negotiate{ + assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEXML, MIMEJSON, MIMEYAML}, Data: H{"foo": "bar"}, - }) + })) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "bar", w.Body.String()) @@ -1173,11 +1165,11 @@ func TestContextNegotiationWithHTML(t *testing.T) { templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) - c.Negotiate(http.StatusOK, Negotiate{ + assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEHTML}, Data: H{"name": "gin"}, HTMLName: "t", - }) + })) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "Hello gin", w.Body.String()) @@ -1189,9 +1181,9 @@ func TestContextNegotiationNotSupport(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest("POST", "", nil) - c.Negotiate(http.StatusOK, Negotiate{ + assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{ Offered: []string{MIMEPOSTForm}, - }) + })) assert.Equal(t, http.StatusNotAcceptable, w.Code) assert.Equal(t, c.index, abortIndex) @@ -1297,7 +1289,7 @@ func TestContextAbortWithStatusJSON(t *testing.T) { in.Bar = "barValue" in.Foo = "fooValue" - c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in) + assert.NoError(t, c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in)) assert.Equal(t, abortIndex, c.index) assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status()) @@ -1925,7 +1917,7 @@ func TestContextRenderDataFromReader(t *testing.T) { contentType := "image/png" extraHeaders := map[string]string{"Content-Disposition": `attachment; filename="gopher.png"`} - c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders) + assert.NoError(t, c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, body, w.Body.String()) @@ -1943,7 +1935,7 @@ func TestContextRenderDataFromReaderNoHeaders(t *testing.T) { contentLength := int64(len(body)) contentType := "image/png" - c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil) + assert.NoError(t, c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil)) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, body, w.Body.String()) diff --git a/render/json.go b/render/json.go index 3ebcee9706..ac0452e6d5 100644 --- a/render/json.go +++ b/render/json.go @@ -54,10 +54,7 @@ var ( // Render (JSON) writes data with custom ContentType. func (r JSON) Render(w http.ResponseWriter) (err error) { - if err = WriteJSON(w, r.Data); err != nil { - panic(err) - } - return + return WriteJSON(w, r.Data) } // WriteContentType (JSON) writes JSON ContentType. diff --git a/render/redirect.go b/render/redirect.go index c006691ca6..034031f04a 100644 --- a/render/redirect.go +++ b/render/redirect.go @@ -19,7 +19,7 @@ type Redirect struct { // Render (Redirect) redirects the http request to new location and writes redirect response. func (r Redirect) Render(w http.ResponseWriter) error { if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated { - panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) + return fmt.Errorf("Cannot redirect with status code %d", r.Code) } http.Redirect(w, r.Request, r.Location, r.Code) return nil diff --git a/render/render_test.go b/render/render_test.go index e417731a89..c66cf57b9d 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -39,12 +39,12 @@ func TestRenderJSON(t *testing.T) { assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } -func TestRenderJSONPanics(t *testing.T) { +func TestRenderJSONError(t *testing.T) { w := httptest.NewRecorder() data := make(chan int) // json: unsupported type: chan int - assert.Panics(t, func() { assert.NoError(t, (JSON{data}).Render(w)) }) + assert.Error(t, (JSON{data}).Render(w)) } func TestRenderIndentedJSON(t *testing.T) { @@ -320,10 +320,7 @@ func TestRenderRedirect(t *testing.T) { } w = httptest.NewRecorder() - assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() { - err := data2.Render(w) - assert.NoError(t, err) - }) + assert.EqualError(t, data2.Render(w), "Cannot redirect with status code 200") data3 := Redirect{ Code: http.StatusCreated,